qapi: Add type.is_empty() helper
[qemu/kevin.git] / scripts / qapi.py
blob27284be1443a82175f77f029742579ca2b77648e
2 # QAPI helper library
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
7 # Authors:
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Markus Armbruster <armbru@redhat.com>
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
14 import re
15 from ordereddict import OrderedDict
16 import errno
17 import getopt
18 import os
19 import sys
20 import string
22 builtin_types = {
23 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
35 'size': 'QTYPE_QINT',
36 'any': None, # any QType possible, actually
37 'QType': 'QTYPE_QSTRING',
40 # Whitelist of commands allowed to return a non-dictionary
41 returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
44 'qom-get',
45 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
62 # Whitelist of entities allowed to violate case conventions
63 case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
68 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
71 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
74 enum_types = []
75 struct_types = []
76 union_types = []
77 events = []
78 all_names = {}
81 # Parsing the schema into expressions
85 def error_path(parent):
86 res = ""
87 while parent:
88 res = ("In file included from %s:%d:\n" % (parent['file'],
89 parent['line'])) + res
90 parent = parent['parent']
91 return res
94 class QAPISchemaError(Exception):
95 def __init__(self, schema, msg):
96 Exception.__init__(self)
97 self.fname = schema.fname
98 self.msg = msg
99 self.col = 1
100 self.line = schema.line
101 for ch in schema.src[schema.line_pos:schema.pos]:
102 if ch == '\t':
103 self.col = (self.col + 7) % 8 + 1
104 else:
105 self.col += 1
106 self.info = schema.incl_info
108 def __str__(self):
109 return error_path(self.info) + \
110 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
113 class QAPIExprError(Exception):
114 def __init__(self, expr_info, msg):
115 Exception.__init__(self)
116 assert expr_info
117 self.info = expr_info
118 self.msg = msg
120 def __str__(self):
121 return error_path(self.info['parent']) + \
122 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
125 class QAPISchemaParser(object):
127 def __init__(self, fp, previously_included=[], incl_info=None):
128 abs_fname = os.path.abspath(fp.name)
129 fname = fp.name
130 self.fname = fname
131 previously_included.append(abs_fname)
132 self.incl_info = incl_info
133 self.src = fp.read()
134 if self.src == '' or self.src[-1] != '\n':
135 self.src += '\n'
136 self.cursor = 0
137 self.line = 1
138 self.line_pos = 0
139 self.exprs = []
140 self.accept()
142 while self.tok is not None:
143 expr_info = {'file': fname, 'line': self.line,
144 'parent': self.incl_info}
145 expr = self.get_expr(False)
146 if isinstance(expr, dict) and "include" in expr:
147 if len(expr) != 1:
148 raise QAPIExprError(expr_info,
149 "Invalid 'include' directive")
150 include = expr["include"]
151 if not isinstance(include, str):
152 raise QAPIExprError(expr_info,
153 "Value of 'include' must be a string")
154 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
155 include)
156 # catch inclusion cycle
157 inf = expr_info
158 while inf:
159 if incl_abs_fname == os.path.abspath(inf['file']):
160 raise QAPIExprError(expr_info, "Inclusion loop for %s"
161 % include)
162 inf = inf['parent']
163 # skip multiple include of the same file
164 if incl_abs_fname in previously_included:
165 continue
166 try:
167 fobj = open(incl_abs_fname, 'r')
168 except IOError as e:
169 raise QAPIExprError(expr_info,
170 '%s: %s' % (e.strerror, include))
171 exprs_include = QAPISchemaParser(fobj, previously_included,
172 expr_info)
173 self.exprs.extend(exprs_include.exprs)
174 else:
175 expr_elem = {'expr': expr,
176 'info': expr_info}
177 self.exprs.append(expr_elem)
179 def accept(self):
180 while True:
181 self.tok = self.src[self.cursor]
182 self.pos = self.cursor
183 self.cursor += 1
184 self.val = None
186 if self.tok == '#':
187 self.cursor = self.src.find('\n', self.cursor)
188 elif self.tok in "{}:,[]":
189 return
190 elif self.tok == "'":
191 string = ''
192 esc = False
193 while True:
194 ch = self.src[self.cursor]
195 self.cursor += 1
196 if ch == '\n':
197 raise QAPISchemaError(self,
198 'Missing terminating "\'"')
199 if esc:
200 if ch == 'b':
201 string += '\b'
202 elif ch == 'f':
203 string += '\f'
204 elif ch == 'n':
205 string += '\n'
206 elif ch == 'r':
207 string += '\r'
208 elif ch == 't':
209 string += '\t'
210 elif ch == 'u':
211 value = 0
212 for _ in range(0, 4):
213 ch = self.src[self.cursor]
214 self.cursor += 1
215 if ch not in "0123456789abcdefABCDEF":
216 raise QAPISchemaError(self,
217 '\\u escape needs 4 '
218 'hex digits')
219 value = (value << 4) + int(ch, 16)
220 # If Python 2 and 3 didn't disagree so much on
221 # how to handle Unicode, then we could allow
222 # Unicode string defaults. But most of QAPI is
223 # ASCII-only, so we aren't losing much for now.
224 if not value or value > 0x7f:
225 raise QAPISchemaError(self,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
229 string += chr(value)
230 elif ch in "\\/'\"":
231 string += ch
232 else:
233 raise QAPISchemaError(self,
234 "Unknown escape \\%s" % ch)
235 esc = False
236 elif ch == "\\":
237 esc = True
238 elif ch == "'":
239 self.val = string
240 return
241 else:
242 string += ch
243 elif self.src.startswith("true", self.pos):
244 self.val = True
245 self.cursor += 3
246 return
247 elif self.src.startswith("false", self.pos):
248 self.val = False
249 self.cursor += 4
250 return
251 elif self.src.startswith("null", self.pos):
252 self.val = None
253 self.cursor += 3
254 return
255 elif self.tok == '\n':
256 if self.cursor == len(self.src):
257 self.tok = None
258 return
259 self.line += 1
260 self.line_pos = self.cursor
261 elif not self.tok.isspace():
262 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
264 def get_members(self):
265 expr = OrderedDict()
266 if self.tok == '}':
267 self.accept()
268 return expr
269 if self.tok != "'":
270 raise QAPISchemaError(self, 'Expected string or "}"')
271 while True:
272 key = self.val
273 self.accept()
274 if self.tok != ':':
275 raise QAPISchemaError(self, 'Expected ":"')
276 self.accept()
277 if key in expr:
278 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
279 expr[key] = self.get_expr(True)
280 if self.tok == '}':
281 self.accept()
282 return expr
283 if self.tok != ',':
284 raise QAPISchemaError(self, 'Expected "," or "}"')
285 self.accept()
286 if self.tok != "'":
287 raise QAPISchemaError(self, 'Expected string')
289 def get_values(self):
290 expr = []
291 if self.tok == ']':
292 self.accept()
293 return expr
294 if self.tok not in "{['tfn":
295 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
296 'boolean or "null"')
297 while True:
298 expr.append(self.get_expr(True))
299 if self.tok == ']':
300 self.accept()
301 return expr
302 if self.tok != ',':
303 raise QAPISchemaError(self, 'Expected "," or "]"')
304 self.accept()
306 def get_expr(self, nested):
307 if self.tok != '{' and not nested:
308 raise QAPISchemaError(self, 'Expected "{"')
309 if self.tok == '{':
310 self.accept()
311 expr = self.get_members()
312 elif self.tok == '[':
313 self.accept()
314 expr = self.get_values()
315 elif self.tok in "'tfn":
316 expr = self.val
317 self.accept()
318 else:
319 raise QAPISchemaError(self, 'Expected "{", "[" or string')
320 return expr
323 # Semantic analysis of schema expressions
324 # TODO fold into QAPISchema
325 # TODO catching name collisions in generated code would be nice
329 def find_base_members(base):
330 if isinstance(base, dict):
331 return base
332 base_struct_define = find_struct(base)
333 if not base_struct_define:
334 return None
335 return base_struct_define['data']
338 # Return the qtype of an alternate branch, or None on error.
339 def find_alternate_member_qtype(qapi_type):
340 if qapi_type in builtin_types:
341 return builtin_types[qapi_type]
342 elif find_struct(qapi_type):
343 return "QTYPE_QDICT"
344 elif find_enum(qapi_type):
345 return "QTYPE_QSTRING"
346 elif find_union(qapi_type):
347 return "QTYPE_QDICT"
348 return None
351 # Return the discriminator enum define if discriminator is specified as an
352 # enum type, otherwise return None.
353 def discriminator_find_enum_define(expr):
354 base = expr.get('base')
355 discriminator = expr.get('discriminator')
357 if not (discriminator and base):
358 return None
360 base_members = find_base_members(base)
361 if not base_members:
362 return None
364 discriminator_type = base_members.get(discriminator)
365 if not discriminator_type:
366 return None
368 return find_enum(discriminator_type)
371 # Names must be letters, numbers, -, and _. They must start with letter,
372 # except for downstream extensions which must start with __RFQDN_.
373 # Dots are only valid in the downstream extension prefix.
374 valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
378 def check_name(expr_info, source, name, allow_optional=False,
379 enum_member=False):
380 global valid_name
381 membername = name
383 if not isinstance(name, str):
384 raise QAPIExprError(expr_info,
385 "%s requires a string name" % source)
386 if name.startswith('*'):
387 membername = name[1:]
388 if not allow_optional:
389 raise QAPIExprError(expr_info,
390 "%s does not allow optional name '%s'"
391 % (source, name))
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
394 if enum_member and membername[0].isdigit():
395 membername = 'D' + membername
396 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
397 # and 'q_obj_*' implicit type names.
398 if not valid_name.match(membername) or \
399 c_name(membername, False).startswith('q_'):
400 raise QAPIExprError(expr_info,
401 "%s uses invalid name '%s'" % (source, name))
404 def add_name(name, info, meta, implicit=False):
405 global all_names
406 check_name(info, "'%s'" % meta, name)
407 # FIXME should reject names that differ only in '_' vs. '.'
408 # vs. '-', because they're liable to clash in generated C.
409 if name in all_names:
410 raise QAPIExprError(info,
411 "%s '%s' is already defined"
412 % (all_names[name], name))
413 if not implicit and (name.endswith('Kind') or name.endswith('List')):
414 raise QAPIExprError(info,
415 "%s '%s' should not end in '%s'"
416 % (meta, name, name[-4:]))
417 all_names[name] = meta
420 def add_struct(definition, info):
421 global struct_types
422 name = definition['struct']
423 add_name(name, info, 'struct')
424 struct_types.append(definition)
427 def find_struct(name):
428 global struct_types
429 for struct in struct_types:
430 if struct['struct'] == name:
431 return struct
432 return None
435 def add_union(definition, info):
436 global union_types
437 name = definition['union']
438 add_name(name, info, 'union')
439 union_types.append(definition)
442 def find_union(name):
443 global union_types
444 for union in union_types:
445 if union['union'] == name:
446 return union
447 return None
450 def add_enum(name, info, enum_values=None, implicit=False):
451 global enum_types
452 add_name(name, info, 'enum', implicit)
453 enum_types.append({"enum_name": name, "enum_values": enum_values})
456 def find_enum(name):
457 global enum_types
458 for enum in enum_types:
459 if enum['enum_name'] == name:
460 return enum
461 return None
464 def is_enum(name):
465 return find_enum(name) is not None
468 def check_type(expr_info, source, value, allow_array=False,
469 allow_dict=False, allow_optional=False,
470 allow_metas=[]):
471 global all_names
473 if value is None:
474 return
476 # Check if array type for value is okay
477 if isinstance(value, list):
478 if not allow_array:
479 raise QAPIExprError(expr_info,
480 "%s cannot be an array" % source)
481 if len(value) != 1 or not isinstance(value[0], str):
482 raise QAPIExprError(expr_info,
483 "%s: array type must contain single type name"
484 % source)
485 value = value[0]
487 # Check if type name for value is okay
488 if isinstance(value, str):
489 if value not in all_names:
490 raise QAPIExprError(expr_info,
491 "%s uses unknown type '%s'"
492 % (source, value))
493 if not all_names[value] in allow_metas:
494 raise QAPIExprError(expr_info,
495 "%s cannot use %s type '%s'"
496 % (source, all_names[value], value))
497 return
499 if not allow_dict:
500 raise QAPIExprError(expr_info,
501 "%s should be a type name" % source)
503 if not isinstance(value, OrderedDict):
504 raise QAPIExprError(expr_info,
505 "%s should be a dictionary or type name" % source)
507 # value is a dictionary, check that each member is okay
508 for (key, arg) in value.items():
509 check_name(expr_info, "Member of %s" % source, key,
510 allow_optional=allow_optional)
511 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
512 raise QAPIExprError(expr_info,
513 "Member of %s uses reserved name '%s'"
514 % (source, key))
515 # Todo: allow dictionaries to represent default values of
516 # an optional argument.
517 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
518 allow_array=True,
519 allow_metas=['built-in', 'union', 'alternate', 'struct',
520 'enum'])
523 def check_command(expr, expr_info):
524 name = expr['command']
526 check_type(expr_info, "'data' for command '%s'" % name,
527 expr.get('data'), allow_dict=True, allow_optional=True,
528 allow_metas=['struct'])
529 returns_meta = ['union', 'struct']
530 if name in returns_whitelist:
531 returns_meta += ['built-in', 'alternate', 'enum']
532 check_type(expr_info, "'returns' for command '%s'" % name,
533 expr.get('returns'), allow_array=True,
534 allow_optional=True, allow_metas=returns_meta)
537 def check_event(expr, expr_info):
538 global events
539 name = expr['event']
541 events.append(name)
542 check_type(expr_info, "'data' for event '%s'" % name,
543 expr.get('data'), allow_dict=True, allow_optional=True,
544 allow_metas=['struct'])
547 def check_union(expr, expr_info):
548 name = expr['union']
549 base = expr.get('base')
550 discriminator = expr.get('discriminator')
551 members = expr['data']
553 # Two types of unions, determined by discriminator.
555 # With no discriminator it is a simple union.
556 if discriminator is None:
557 enum_define = None
558 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
559 if base is not None:
560 raise QAPIExprError(expr_info,
561 "Simple union '%s' must not have a base"
562 % name)
564 # Else, it's a flat union.
565 else:
566 # The object must have a string or dictionary 'base'.
567 check_type(expr_info, "'base' for union '%s'" % name,
568 base, allow_dict=True, allow_optional=True,
569 allow_metas=['struct'])
570 if not base:
571 raise QAPIExprError(expr_info,
572 "Flat union '%s' must have a base"
573 % name)
574 base_members = find_base_members(base)
575 assert base_members
577 # The value of member 'discriminator' must name a non-optional
578 # member of the base struct.
579 check_name(expr_info, "Discriminator of flat union '%s'" % name,
580 discriminator)
581 discriminator_type = base_members.get(discriminator)
582 if not discriminator_type:
583 raise QAPIExprError(expr_info,
584 "Discriminator '%s' is not a member of base "
585 "struct '%s'"
586 % (discriminator, base))
587 enum_define = find_enum(discriminator_type)
588 allow_metas = ['struct']
589 # Do not allow string discriminator
590 if not enum_define:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' must be of enumeration "
593 "type" % discriminator)
595 # Check every branch; don't allow an empty union
596 if len(members) == 0:
597 raise QAPIExprError(expr_info,
598 "Union '%s' cannot have empty 'data'" % name)
599 for (key, value) in members.items():
600 check_name(expr_info, "Member of union '%s'" % name, key)
602 # Each value must name a known type
603 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
604 value, allow_array=not base, allow_metas=allow_metas)
606 # If the discriminator names an enum type, then all members
607 # of 'data' must also be members of the enum type.
608 if enum_define:
609 if key not in enum_define['enum_values']:
610 raise QAPIExprError(expr_info,
611 "Discriminator value '%s' is not found in "
612 "enum '%s'" %
613 (key, enum_define["enum_name"]))
615 # If discriminator is user-defined, ensure all values are covered
616 if enum_define:
617 for value in enum_define['enum_values']:
618 if value not in members.keys():
619 raise QAPIExprError(expr_info,
620 "Union '%s' data missing '%s' branch"
621 % (name, value))
624 def check_alternate(expr, expr_info):
625 name = expr['alternate']
626 members = expr['data']
627 types_seen = {}
629 # Check every branch; require at least two branches
630 if len(members) < 2:
631 raise QAPIExprError(expr_info,
632 "Alternate '%s' should have at least two branches "
633 "in 'data'" % name)
634 for (key, value) in members.items():
635 check_name(expr_info, "Member of alternate '%s'" % name, key)
637 # Ensure alternates have no type conflicts.
638 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
639 value,
640 allow_metas=['built-in', 'union', 'struct', 'enum'])
641 qtype = find_alternate_member_qtype(value)
642 if not qtype:
643 raise QAPIExprError(expr_info,
644 "Alternate '%s' member '%s' cannot use "
645 "type '%s'" % (name, key, value))
646 if qtype in types_seen:
647 raise QAPIExprError(expr_info,
648 "Alternate '%s' member '%s' can't "
649 "be distinguished from member '%s'"
650 % (name, key, types_seen[qtype]))
651 types_seen[qtype] = key
654 def check_enum(expr, expr_info):
655 name = expr['enum']
656 members = expr.get('data')
657 prefix = expr.get('prefix')
659 if not isinstance(members, list):
660 raise QAPIExprError(expr_info,
661 "Enum '%s' requires an array for 'data'" % name)
662 if prefix is not None and not isinstance(prefix, str):
663 raise QAPIExprError(expr_info,
664 "Enum '%s' requires a string for 'prefix'" % name)
665 for member in members:
666 check_name(expr_info, "Member of enum '%s'" % name, member,
667 enum_member=True)
670 def check_struct(expr, expr_info):
671 name = expr['struct']
672 members = expr['data']
674 check_type(expr_info, "'data' for struct '%s'" % name, members,
675 allow_dict=True, allow_optional=True)
676 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
677 allow_metas=['struct'])
680 def check_keys(expr_elem, meta, required, optional=[]):
681 expr = expr_elem['expr']
682 info = expr_elem['info']
683 name = expr[meta]
684 if not isinstance(name, str):
685 raise QAPIExprError(info,
686 "'%s' key must have a string value" % meta)
687 required = required + [meta]
688 for (key, value) in expr.items():
689 if key not in required and key not in optional:
690 raise QAPIExprError(info,
691 "Unknown key '%s' in %s '%s'"
692 % (key, meta, name))
693 if (key == 'gen' or key == 'success-response') and value is not False:
694 raise QAPIExprError(info,
695 "'%s' of %s '%s' should only use false value"
696 % (key, meta, name))
697 for key in required:
698 if key not in expr:
699 raise QAPIExprError(info,
700 "Key '%s' is missing from %s '%s'"
701 % (key, meta, name))
704 def check_exprs(exprs):
705 global all_names
707 # Learn the types and check for valid expression keys
708 for builtin in builtin_types.keys():
709 all_names[builtin] = 'built-in'
710 for expr_elem in exprs:
711 expr = expr_elem['expr']
712 info = expr_elem['info']
713 if 'enum' in expr:
714 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
715 add_enum(expr['enum'], info, expr['data'])
716 elif 'union' in expr:
717 check_keys(expr_elem, 'union', ['data'],
718 ['base', 'discriminator'])
719 add_union(expr, info)
720 elif 'alternate' in expr:
721 check_keys(expr_elem, 'alternate', ['data'])
722 add_name(expr['alternate'], info, 'alternate')
723 elif 'struct' in expr:
724 check_keys(expr_elem, 'struct', ['data'], ['base'])
725 add_struct(expr, info)
726 elif 'command' in expr:
727 check_keys(expr_elem, 'command', [],
728 ['data', 'returns', 'gen', 'success-response'])
729 add_name(expr['command'], info, 'command')
730 elif 'event' in expr:
731 check_keys(expr_elem, 'event', [], ['data'])
732 add_name(expr['event'], info, 'event')
733 else:
734 raise QAPIExprError(expr_elem['info'],
735 "Expression is missing metatype")
737 # Try again for hidden UnionKind enum
738 for expr_elem in exprs:
739 expr = expr_elem['expr']
740 if 'union' in expr:
741 if not discriminator_find_enum_define(expr):
742 add_enum('%sKind' % expr['union'], expr_elem['info'],
743 implicit=True)
744 elif 'alternate' in expr:
745 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
746 implicit=True)
748 # Validate that exprs make sense
749 for expr_elem in exprs:
750 expr = expr_elem['expr']
751 info = expr_elem['info']
753 if 'enum' in expr:
754 check_enum(expr, info)
755 elif 'union' in expr:
756 check_union(expr, info)
757 elif 'alternate' in expr:
758 check_alternate(expr, info)
759 elif 'struct' in expr:
760 check_struct(expr, info)
761 elif 'command' in expr:
762 check_command(expr, info)
763 elif 'event' in expr:
764 check_event(expr, info)
765 else:
766 assert False, 'unexpected meta type'
768 return exprs
772 # Schema compiler frontend
775 class QAPISchemaEntity(object):
776 def __init__(self, name, info):
777 assert isinstance(name, str)
778 self.name = name
779 # For explicitly defined entities, info points to the (explicit)
780 # definition. For builtins (and their arrays), info is None.
781 # For implicitly defined entities, info points to a place that
782 # triggered the implicit definition (there may be more than one
783 # such place).
784 self.info = info
786 def c_name(self):
787 return c_name(self.name)
789 def check(self, schema):
790 pass
792 def is_implicit(self):
793 return not self.info
795 def visit(self, visitor):
796 pass
799 class QAPISchemaVisitor(object):
800 def visit_begin(self, schema):
801 pass
803 def visit_end(self):
804 pass
806 def visit_needed(self, entity):
807 # Default to visiting everything
808 return True
810 def visit_builtin_type(self, name, info, json_type):
811 pass
813 def visit_enum_type(self, name, info, values, prefix):
814 pass
816 def visit_array_type(self, name, info, element_type):
817 pass
819 def visit_object_type(self, name, info, base, members, variants):
820 pass
822 def visit_object_type_flat(self, name, info, members, variants):
823 pass
825 def visit_alternate_type(self, name, info, variants):
826 pass
828 def visit_command(self, name, info, arg_type, ret_type,
829 gen, success_response):
830 pass
832 def visit_event(self, name, info, arg_type):
833 pass
836 class QAPISchemaType(QAPISchemaEntity):
837 # Return the C type for common use.
838 # For the types we commonly box, this is a pointer type.
839 def c_type(self):
840 pass
842 # Return the C type to be used in a parameter list.
843 def c_param_type(self):
844 return self.c_type()
846 # Return the C type to be used where we suppress boxing.
847 def c_unboxed_type(self):
848 return self.c_type()
850 def json_type(self):
851 pass
853 def alternate_qtype(self):
854 json2qtype = {
855 'string': 'QTYPE_QSTRING',
856 'number': 'QTYPE_QFLOAT',
857 'int': 'QTYPE_QINT',
858 'boolean': 'QTYPE_QBOOL',
859 'object': 'QTYPE_QDICT'
861 return json2qtype.get(self.json_type())
864 class QAPISchemaBuiltinType(QAPISchemaType):
865 def __init__(self, name, json_type, c_type):
866 QAPISchemaType.__init__(self, name, None)
867 assert not c_type or isinstance(c_type, str)
868 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
869 'value')
870 self._json_type_name = json_type
871 self._c_type_name = c_type
873 def c_name(self):
874 return self.name
876 def c_type(self):
877 return self._c_type_name
879 def c_param_type(self):
880 if self.name == 'str':
881 return 'const ' + self._c_type_name
882 return self._c_type_name
884 def json_type(self):
885 return self._json_type_name
887 def visit(self, visitor):
888 visitor.visit_builtin_type(self.name, self.info, self.json_type())
891 class QAPISchemaEnumType(QAPISchemaType):
892 def __init__(self, name, info, values, prefix):
893 QAPISchemaType.__init__(self, name, info)
894 for v in values:
895 assert isinstance(v, QAPISchemaMember)
896 v.set_owner(name)
897 assert prefix is None or isinstance(prefix, str)
898 self.values = values
899 self.prefix = prefix
901 def check(self, schema):
902 seen = {}
903 for v in self.values:
904 v.check_clash(self.info, seen)
906 def is_implicit(self):
907 # See QAPISchema._make_implicit_enum_type()
908 return self.name.endswith('Kind')
910 def c_type(self):
911 return c_name(self.name)
913 def member_names(self):
914 return [v.name for v in self.values]
916 def json_type(self):
917 return 'string'
919 def visit(self, visitor):
920 visitor.visit_enum_type(self.name, self.info,
921 self.member_names(), self.prefix)
924 class QAPISchemaArrayType(QAPISchemaType):
925 def __init__(self, name, info, element_type):
926 QAPISchemaType.__init__(self, name, info)
927 assert isinstance(element_type, str)
928 self._element_type_name = element_type
929 self.element_type = None
931 def check(self, schema):
932 self.element_type = schema.lookup_type(self._element_type_name)
933 assert self.element_type
935 def is_implicit(self):
936 return True
938 def c_type(self):
939 return c_name(self.name) + pointer_suffix
941 def json_type(self):
942 return 'array'
944 def visit(self, visitor):
945 visitor.visit_array_type(self.name, self.info, self.element_type)
948 class QAPISchemaObjectType(QAPISchemaType):
949 def __init__(self, name, info, base, local_members, variants):
950 # struct has local_members, optional base, and no variants
951 # flat union has base, variants, and no local_members
952 # simple union has local_members, variants, and no base
953 QAPISchemaType.__init__(self, name, info)
954 assert base is None or isinstance(base, str)
955 for m in local_members:
956 assert isinstance(m, QAPISchemaObjectTypeMember)
957 m.set_owner(name)
958 if variants is not None:
959 assert isinstance(variants, QAPISchemaObjectTypeVariants)
960 variants.set_owner(name)
961 self._base_name = base
962 self.base = None
963 self.local_members = local_members
964 self.variants = variants
965 self.members = None
967 def check(self, schema):
968 if self.members is False: # check for cycles
969 raise QAPIExprError(self.info,
970 "Object %s contains itself" % self.name)
971 if self.members:
972 return
973 self.members = False # mark as being checked
974 seen = OrderedDict()
975 if self._base_name:
976 self.base = schema.lookup_type(self._base_name)
977 assert isinstance(self.base, QAPISchemaObjectType)
978 self.base.check(schema)
979 self.base.check_clash(schema, self.info, seen)
980 for m in self.local_members:
981 m.check(schema)
982 m.check_clash(self.info, seen)
983 self.members = seen.values()
984 if self.variants:
985 self.variants.check(schema, seen)
986 assert self.variants.tag_member in self.members
987 self.variants.check_clash(schema, self.info, seen)
989 # Check that the members of this type do not cause duplicate JSON members,
990 # and update seen to track the members seen so far. Report any errors
991 # on behalf of info, which is not necessarily self.info
992 def check_clash(self, schema, info, seen):
993 assert not self.variants # not implemented
994 for m in self.members:
995 m.check_clash(info, seen)
997 def is_implicit(self):
998 # See QAPISchema._make_implicit_object_type(), as well as
999 # _def_predefineds()
1000 return self.name.startswith('q_')
1002 def is_empty(self):
1003 assert self.members is not None
1004 return not self.members and not self.variants
1006 def c_name(self):
1007 assert self.name != 'q_empty'
1008 return QAPISchemaType.c_name(self)
1010 def c_type(self):
1011 assert not self.is_implicit()
1012 return c_name(self.name) + pointer_suffix
1014 def c_unboxed_type(self):
1015 return c_name(self.name)
1017 def json_type(self):
1018 return 'object'
1020 def visit(self, visitor):
1021 visitor.visit_object_type(self.name, self.info,
1022 self.base, self.local_members, self.variants)
1023 visitor.visit_object_type_flat(self.name, self.info,
1024 self.members, self.variants)
1027 class QAPISchemaMember(object):
1028 role = 'member'
1030 def __init__(self, name):
1031 assert isinstance(name, str)
1032 self.name = name
1033 self.owner = None
1035 def set_owner(self, name):
1036 assert not self.owner
1037 self.owner = name
1039 def check_clash(self, info, seen):
1040 cname = c_name(self.name)
1041 if cname.lower() != cname and self.owner not in case_whitelist:
1042 raise QAPIExprError(info,
1043 "%s should not use uppercase" % self.describe())
1044 if cname in seen:
1045 raise QAPIExprError(info,
1046 "%s collides with %s"
1047 % (self.describe(), seen[cname].describe()))
1048 seen[cname] = self
1050 def _pretty_owner(self):
1051 owner = self.owner
1052 if owner.startswith('q_obj_'):
1053 # See QAPISchema._make_implicit_object_type() - reverse the
1054 # mapping there to create a nice human-readable description
1055 owner = owner[6:]
1056 if owner.endswith('-arg'):
1057 return '(parameter of %s)' % owner[:-4]
1058 elif owner.endswith('-base'):
1059 return '(base of %s)' % owner[:-5]
1060 else:
1061 assert owner.endswith('-wrapper')
1062 # Unreachable and not implemented
1063 assert False
1064 if owner.endswith('Kind'):
1065 # See QAPISchema._make_implicit_enum_type()
1066 return '(branch of %s)' % owner[:-4]
1067 return '(%s of %s)' % (self.role, owner)
1069 def describe(self):
1070 return "'%s' %s" % (self.name, self._pretty_owner())
1073 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1074 def __init__(self, name, typ, optional):
1075 QAPISchemaMember.__init__(self, name)
1076 assert isinstance(typ, str)
1077 assert isinstance(optional, bool)
1078 self._type_name = typ
1079 self.type = None
1080 self.optional = optional
1082 def check(self, schema):
1083 assert self.owner
1084 self.type = schema.lookup_type(self._type_name)
1085 assert self.type
1088 class QAPISchemaObjectTypeVariants(object):
1089 def __init__(self, tag_name, tag_member, variants):
1090 # Flat unions pass tag_name but not tag_member.
1091 # Simple unions and alternates pass tag_member but not tag_name.
1092 # After check(), tag_member is always set, and tag_name remains
1093 # a reliable witness of being used by a flat union.
1094 assert bool(tag_member) != bool(tag_name)
1095 assert (isinstance(tag_name, str) or
1096 isinstance(tag_member, QAPISchemaObjectTypeMember))
1097 assert len(variants) > 0
1098 for v in variants:
1099 assert isinstance(v, QAPISchemaObjectTypeVariant)
1100 self._tag_name = tag_name
1101 self.tag_member = tag_member
1102 self.variants = variants
1104 def set_owner(self, name):
1105 for v in self.variants:
1106 v.set_owner(name)
1108 def check(self, schema, seen):
1109 if not self.tag_member: # flat union
1110 self.tag_member = seen[c_name(self._tag_name)]
1111 assert self._tag_name == self.tag_member.name
1112 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1113 for v in self.variants:
1114 v.check(schema)
1115 # Union names must match enum values; alternate names are
1116 # checked separately. Use 'seen' to tell the two apart.
1117 if seen:
1118 assert v.name in self.tag_member.type.member_names()
1119 assert isinstance(v.type, QAPISchemaObjectType)
1120 v.type.check(schema)
1122 def check_clash(self, schema, info, seen):
1123 for v in self.variants:
1124 # Reset seen map for each variant, since qapi names from one
1125 # branch do not affect another branch
1126 assert isinstance(v.type, QAPISchemaObjectType)
1127 v.type.check_clash(schema, info, dict(seen))
1130 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1131 role = 'branch'
1133 def __init__(self, name, typ):
1134 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1137 class QAPISchemaAlternateType(QAPISchemaType):
1138 def __init__(self, name, info, variants):
1139 QAPISchemaType.__init__(self, name, info)
1140 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1141 assert variants.tag_member
1142 variants.set_owner(name)
1143 variants.tag_member.set_owner(self.name)
1144 self.variants = variants
1146 def check(self, schema):
1147 self.variants.tag_member.check(schema)
1148 # Not calling self.variants.check_clash(), because there's nothing
1149 # to clash with
1150 self.variants.check(schema, {})
1151 # Alternate branch names have no relation to the tag enum values;
1152 # so we have to check for potential name collisions ourselves.
1153 seen = {}
1154 for v in self.variants.variants:
1155 v.check_clash(self.info, seen)
1157 def c_type(self):
1158 return c_name(self.name) + pointer_suffix
1160 def json_type(self):
1161 return 'value'
1163 def visit(self, visitor):
1164 visitor.visit_alternate_type(self.name, self.info, self.variants)
1167 class QAPISchemaCommand(QAPISchemaEntity):
1168 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1169 QAPISchemaEntity.__init__(self, name, info)
1170 assert not arg_type or isinstance(arg_type, str)
1171 assert not ret_type or isinstance(ret_type, str)
1172 self._arg_type_name = arg_type
1173 self.arg_type = None
1174 self._ret_type_name = ret_type
1175 self.ret_type = None
1176 self.gen = gen
1177 self.success_response = success_response
1179 def check(self, schema):
1180 if self._arg_type_name:
1181 self.arg_type = schema.lookup_type(self._arg_type_name)
1182 assert isinstance(self.arg_type, QAPISchemaObjectType)
1183 assert not self.arg_type.variants # not implemented
1184 if self._ret_type_name:
1185 self.ret_type = schema.lookup_type(self._ret_type_name)
1186 assert isinstance(self.ret_type, QAPISchemaType)
1188 def visit(self, visitor):
1189 visitor.visit_command(self.name, self.info,
1190 self.arg_type, self.ret_type,
1191 self.gen, self.success_response)
1194 class QAPISchemaEvent(QAPISchemaEntity):
1195 def __init__(self, name, info, arg_type):
1196 QAPISchemaEntity.__init__(self, name, info)
1197 assert not arg_type or isinstance(arg_type, str)
1198 self._arg_type_name = arg_type
1199 self.arg_type = None
1201 def check(self, schema):
1202 if self._arg_type_name:
1203 self.arg_type = schema.lookup_type(self._arg_type_name)
1204 assert isinstance(self.arg_type, QAPISchemaObjectType)
1205 assert not self.arg_type.variants # not implemented
1207 def visit(self, visitor):
1208 visitor.visit_event(self.name, self.info, self.arg_type)
1211 class QAPISchema(object):
1212 def __init__(self, fname):
1213 try:
1214 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1215 self._entity_dict = {}
1216 self._predefining = True
1217 self._def_predefineds()
1218 self._predefining = False
1219 self._def_exprs()
1220 self.check()
1221 except (QAPISchemaError, QAPIExprError) as err:
1222 print >>sys.stderr, err
1223 exit(1)
1225 def _def_entity(self, ent):
1226 # Only the predefined types are allowed to not have info
1227 assert ent.info or self._predefining
1228 assert ent.name not in self._entity_dict
1229 self._entity_dict[ent.name] = ent
1231 def lookup_entity(self, name, typ=None):
1232 ent = self._entity_dict.get(name)
1233 if typ and not isinstance(ent, typ):
1234 return None
1235 return ent
1237 def lookup_type(self, name):
1238 return self.lookup_entity(name, QAPISchemaType)
1240 def _def_builtin_type(self, name, json_type, c_type):
1241 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1242 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1243 # qapi-types.h from a single .c, all arrays of builtins must be
1244 # declared in the first file whether or not they are used. Nicer
1245 # would be to use lazy instantiation, while figuring out how to
1246 # avoid compilation issues with multiple qapi-types.h.
1247 self._make_array_type(name, None)
1249 def _def_predefineds(self):
1250 for t in [('str', 'string', 'char' + pointer_suffix),
1251 ('number', 'number', 'double'),
1252 ('int', 'int', 'int64_t'),
1253 ('int8', 'int', 'int8_t'),
1254 ('int16', 'int', 'int16_t'),
1255 ('int32', 'int', 'int32_t'),
1256 ('int64', 'int', 'int64_t'),
1257 ('uint8', 'int', 'uint8_t'),
1258 ('uint16', 'int', 'uint16_t'),
1259 ('uint32', 'int', 'uint32_t'),
1260 ('uint64', 'int', 'uint64_t'),
1261 ('size', 'int', 'uint64_t'),
1262 ('bool', 'boolean', 'bool'),
1263 ('any', 'value', 'QObject' + pointer_suffix)]:
1264 self._def_builtin_type(*t)
1265 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1266 None, [], None)
1267 self._def_entity(self.the_empty_object_type)
1268 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1269 'qstring', 'qdict', 'qlist',
1270 'qfloat', 'qbool'])
1271 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
1272 'QTYPE'))
1274 def _make_enum_members(self, values):
1275 return [QAPISchemaMember(v) for v in values]
1277 def _make_implicit_enum_type(self, name, info, values):
1278 # See also QAPISchemaObjectTypeMember._pretty_owner()
1279 name = name + 'Kind' # Use namespace reserved by add_name()
1280 self._def_entity(QAPISchemaEnumType(
1281 name, info, self._make_enum_members(values), None))
1282 return name
1284 def _make_array_type(self, element_type, info):
1285 name = element_type + 'List' # Use namespace reserved by add_name()
1286 if not self.lookup_type(name):
1287 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1288 return name
1290 def _make_implicit_object_type(self, name, info, role, members):
1291 if not members:
1292 return None
1293 # See also QAPISchemaObjectTypeMember._pretty_owner()
1294 name = 'q_obj_%s-%s' % (name, role)
1295 if not self.lookup_entity(name, QAPISchemaObjectType):
1296 self._def_entity(QAPISchemaObjectType(name, info, None,
1297 members, None))
1298 return name
1300 def _def_enum_type(self, expr, info):
1301 name = expr['enum']
1302 data = expr['data']
1303 prefix = expr.get('prefix')
1304 self._def_entity(QAPISchemaEnumType(
1305 name, info, self._make_enum_members(data), prefix))
1307 def _make_member(self, name, typ, info):
1308 optional = False
1309 if name.startswith('*'):
1310 name = name[1:]
1311 optional = True
1312 if isinstance(typ, list):
1313 assert len(typ) == 1
1314 typ = self._make_array_type(typ[0], info)
1315 return QAPISchemaObjectTypeMember(name, typ, optional)
1317 def _make_members(self, data, info):
1318 return [self._make_member(key, value, info)
1319 for (key, value) in data.iteritems()]
1321 def _def_struct_type(self, expr, info):
1322 name = expr['struct']
1323 base = expr.get('base')
1324 data = expr['data']
1325 self._def_entity(QAPISchemaObjectType(name, info, base,
1326 self._make_members(data, info),
1327 None))
1329 def _make_variant(self, case, typ):
1330 return QAPISchemaObjectTypeVariant(case, typ)
1332 def _make_simple_variant(self, case, typ, info):
1333 if isinstance(typ, list):
1334 assert len(typ) == 1
1335 typ = self._make_array_type(typ[0], info)
1336 typ = self._make_implicit_object_type(
1337 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1338 return QAPISchemaObjectTypeVariant(case, typ)
1340 def _def_union_type(self, expr, info):
1341 name = expr['union']
1342 data = expr['data']
1343 base = expr.get('base')
1344 tag_name = expr.get('discriminator')
1345 tag_member = None
1346 if isinstance(base, dict):
1347 base = (self._make_implicit_object_type(
1348 name, info, 'base', self._make_members(base, info)))
1349 if tag_name:
1350 variants = [self._make_variant(key, value)
1351 for (key, value) in data.iteritems()]
1352 members = []
1353 else:
1354 variants = [self._make_simple_variant(key, value, info)
1355 for (key, value) in data.iteritems()]
1356 typ = self._make_implicit_enum_type(name, info,
1357 [v.name for v in variants])
1358 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1359 members = [tag_member]
1360 self._def_entity(
1361 QAPISchemaObjectType(name, info, base, members,
1362 QAPISchemaObjectTypeVariants(tag_name,
1363 tag_member,
1364 variants)))
1366 def _def_alternate_type(self, expr, info):
1367 name = expr['alternate']
1368 data = expr['data']
1369 variants = [self._make_variant(key, value)
1370 for (key, value) in data.iteritems()]
1371 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1372 self._def_entity(
1373 QAPISchemaAlternateType(name, info,
1374 QAPISchemaObjectTypeVariants(None,
1375 tag_member,
1376 variants)))
1378 def _def_command(self, expr, info):
1379 name = expr['command']
1380 data = expr.get('data')
1381 rets = expr.get('returns')
1382 gen = expr.get('gen', True)
1383 success_response = expr.get('success-response', True)
1384 if isinstance(data, OrderedDict):
1385 data = self._make_implicit_object_type(
1386 name, info, 'arg', self._make_members(data, info))
1387 if isinstance(rets, list):
1388 assert len(rets) == 1
1389 rets = self._make_array_type(rets[0], info)
1390 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1391 success_response))
1393 def _def_event(self, expr, info):
1394 name = expr['event']
1395 data = expr.get('data')
1396 if isinstance(data, OrderedDict):
1397 data = self._make_implicit_object_type(
1398 name, info, 'arg', self._make_members(data, info))
1399 self._def_entity(QAPISchemaEvent(name, info, data))
1401 def _def_exprs(self):
1402 for expr_elem in self.exprs:
1403 expr = expr_elem['expr']
1404 info = expr_elem['info']
1405 if 'enum' in expr:
1406 self._def_enum_type(expr, info)
1407 elif 'struct' in expr:
1408 self._def_struct_type(expr, info)
1409 elif 'union' in expr:
1410 self._def_union_type(expr, info)
1411 elif 'alternate' in expr:
1412 self._def_alternate_type(expr, info)
1413 elif 'command' in expr:
1414 self._def_command(expr, info)
1415 elif 'event' in expr:
1416 self._def_event(expr, info)
1417 else:
1418 assert False
1420 def check(self):
1421 for ent in self._entity_dict.values():
1422 ent.check(self)
1424 def visit(self, visitor):
1425 visitor.visit_begin(self)
1426 for (name, entity) in sorted(self._entity_dict.items()):
1427 if visitor.visit_needed(entity):
1428 entity.visit(visitor)
1429 visitor.visit_end()
1433 # Code generation helpers
1436 def camel_case(name):
1437 new_name = ''
1438 first = True
1439 for ch in name:
1440 if ch in ['_', '-']:
1441 first = True
1442 elif first:
1443 new_name += ch.upper()
1444 first = False
1445 else:
1446 new_name += ch.lower()
1447 return new_name
1450 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1451 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1452 # ENUM24_Name -> ENUM24_NAME
1453 def camel_to_upper(value):
1454 c_fun_str = c_name(value, False)
1455 if value.isupper():
1456 return c_fun_str
1458 new_name = ''
1459 l = len(c_fun_str)
1460 for i in range(l):
1461 c = c_fun_str[i]
1462 # When c is upper and no "_" appears before, do more checks
1463 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1464 if i < l - 1 and c_fun_str[i + 1].islower():
1465 new_name += '_'
1466 elif c_fun_str[i - 1].isdigit():
1467 new_name += '_'
1468 new_name += c
1469 return new_name.lstrip('_').upper()
1472 def c_enum_const(type_name, const_name, prefix=None):
1473 if prefix is not None:
1474 type_name = prefix
1475 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1477 c_name_trans = string.maketrans('.-', '__')
1480 # Map @name to a valid C identifier.
1481 # If @protect, avoid returning certain ticklish identifiers (like
1482 # C keywords) by prepending "q_".
1484 # Used for converting 'name' from a 'name':'type' qapi definition
1485 # into a generated struct member, as well as converting type names
1486 # into substrings of a generated C function name.
1487 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1488 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1489 def c_name(name, protect=True):
1490 # ANSI X3J11/88-090, 3.1.1
1491 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1492 'default', 'do', 'double', 'else', 'enum', 'extern',
1493 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1494 'return', 'short', 'signed', 'sizeof', 'static',
1495 'struct', 'switch', 'typedef', 'union', 'unsigned',
1496 'void', 'volatile', 'while'])
1497 # ISO/IEC 9899:1999, 6.4.1
1498 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1499 # ISO/IEC 9899:2011, 6.4.1
1500 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1501 '_Noreturn', '_Static_assert', '_Thread_local'])
1502 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1503 # excluding _.*
1504 gcc_words = set(['asm', 'typeof'])
1505 # C++ ISO/IEC 14882:2003 2.11
1506 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1507 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1508 'namespace', 'new', 'operator', 'private', 'protected',
1509 'public', 'reinterpret_cast', 'static_cast', 'template',
1510 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1511 'using', 'virtual', 'wchar_t',
1512 # alternative representations
1513 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1514 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1515 # namespace pollution:
1516 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1517 name = name.translate(c_name_trans)
1518 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1519 | cpp_words | polluted_words):
1520 return "q_" + name
1521 return name
1523 eatspace = '\033EATSPACE.'
1524 pointer_suffix = ' *' + eatspace
1527 def genindent(count):
1528 ret = ""
1529 for _ in range(count):
1530 ret += " "
1531 return ret
1533 indent_level = 0
1536 def push_indent(indent_amount=4):
1537 global indent_level
1538 indent_level += indent_amount
1541 def pop_indent(indent_amount=4):
1542 global indent_level
1543 indent_level -= indent_amount
1546 # Generate @code with @kwds interpolated.
1547 # Obey indent_level, and strip eatspace.
1548 def cgen(code, **kwds):
1549 raw = code % kwds
1550 if indent_level:
1551 indent = genindent(indent_level)
1552 # re.subn() lacks flags support before Python 2.7, use re.compile()
1553 raw = re.subn(re.compile("^.", re.MULTILINE),
1554 indent + r'\g<0>', raw)
1555 raw = raw[0]
1556 return re.sub(re.escape(eatspace) + ' *', '', raw)
1559 def mcgen(code, **kwds):
1560 if code[0] == '\n':
1561 code = code[1:]
1562 return cgen(code, **kwds)
1565 def guardname(filename):
1566 return c_name(filename, protect=False).upper()
1569 def guardstart(name):
1570 return mcgen('''
1572 #ifndef %(name)s
1573 #define %(name)s
1575 ''',
1576 name=guardname(name))
1579 def guardend(name):
1580 return mcgen('''
1582 #endif /* %(name)s */
1584 ''',
1585 name=guardname(name))
1588 def gen_enum_lookup(name, values, prefix=None):
1589 ret = mcgen('''
1591 const char *const %(c_name)s_lookup[] = {
1592 ''',
1593 c_name=c_name(name))
1594 for value in values:
1595 index = c_enum_const(name, value, prefix)
1596 ret += mcgen('''
1597 [%(index)s] = "%(value)s",
1598 ''',
1599 index=index, value=value)
1601 max_index = c_enum_const(name, '_MAX', prefix)
1602 ret += mcgen('''
1603 [%(max_index)s] = NULL,
1605 ''',
1606 max_index=max_index)
1607 return ret
1610 def gen_enum(name, values, prefix=None):
1611 # append automatically generated _MAX value
1612 enum_values = values + ['_MAX']
1614 ret = mcgen('''
1616 typedef enum %(c_name)s {
1617 ''',
1618 c_name=c_name(name))
1620 i = 0
1621 for value in enum_values:
1622 ret += mcgen('''
1623 %(c_enum)s = %(i)d,
1624 ''',
1625 c_enum=c_enum_const(name, value, prefix),
1626 i=i)
1627 i += 1
1629 ret += mcgen('''
1630 } %(c_name)s;
1631 ''',
1632 c_name=c_name(name))
1634 ret += mcgen('''
1636 extern const char *const %(c_name)s_lookup[];
1637 ''',
1638 c_name=c_name(name))
1639 return ret
1642 def gen_params(arg_type, extra):
1643 if not arg_type:
1644 return extra
1645 assert not arg_type.variants
1646 ret = ''
1647 sep = ''
1648 for memb in arg_type.members:
1649 ret += sep
1650 sep = ', '
1651 if memb.optional:
1652 ret += 'bool has_%s, ' % c_name(memb.name)
1653 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
1654 if extra:
1655 ret += sep + extra
1656 return ret
1659 def gen_err_check():
1660 return mcgen('''
1661 if (err) {
1662 goto out;
1664 ''')
1668 # Common command line parsing
1672 def parse_command_line(extra_options="", extra_long_options=[]):
1674 try:
1675 opts, args = getopt.gnu_getopt(sys.argv[1:],
1676 "chp:o:" + extra_options,
1677 ["source", "header", "prefix=",
1678 "output-dir="] + extra_long_options)
1679 except getopt.GetoptError as err:
1680 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1681 sys.exit(1)
1683 output_dir = ""
1684 prefix = ""
1685 do_c = False
1686 do_h = False
1687 extra_opts = []
1689 for oa in opts:
1690 o, a = oa
1691 if o in ("-p", "--prefix"):
1692 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1693 if match.end() != len(a):
1694 print >>sys.stderr, \
1695 "%s: 'funny character '%s' in argument of --prefix" \
1696 % (sys.argv[0], a[match.end()])
1697 sys.exit(1)
1698 prefix = a
1699 elif o in ("-o", "--output-dir"):
1700 output_dir = a + "/"
1701 elif o in ("-c", "--source"):
1702 do_c = True
1703 elif o in ("-h", "--header"):
1704 do_h = True
1705 else:
1706 extra_opts.append(oa)
1708 if not do_c and not do_h:
1709 do_c = True
1710 do_h = True
1712 if len(args) != 1:
1713 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1714 sys.exit(1)
1715 fname = args[0]
1717 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1720 # Generate output files with boilerplate
1724 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1725 c_comment, h_comment):
1726 guard = guardname(prefix + h_file)
1727 c_file = output_dir + prefix + c_file
1728 h_file = output_dir + prefix + h_file
1730 if output_dir:
1731 try:
1732 os.makedirs(output_dir)
1733 except os.error as e:
1734 if e.errno != errno.EEXIST:
1735 raise
1737 def maybe_open(really, name, opt):
1738 if really:
1739 return open(name, opt)
1740 else:
1741 import StringIO
1742 return StringIO.StringIO()
1744 fdef = maybe_open(do_c, c_file, 'w')
1745 fdecl = maybe_open(do_h, h_file, 'w')
1747 fdef.write(mcgen('''
1748 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1749 %(comment)s
1750 ''',
1751 comment=c_comment))
1753 fdecl.write(mcgen('''
1754 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1755 %(comment)s
1756 #ifndef %(guard)s
1757 #define %(guard)s
1759 ''',
1760 comment=h_comment, guard=guard))
1762 return (fdef, fdecl)
1765 def close_output(fdef, fdecl):
1766 fdecl.write('''
1767 #endif
1768 ''')
1769 fdecl.close()
1770 fdef.close()