4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
20 from ordereddict import OrderedDict
23 'null': 'QTYPE_QNULL',
24 'str': 'QTYPE_QSTRING',
26 'number': 'QTYPE_QNUM',
27 'bool': 'QTYPE_QBOOL',
29 'int16': 'QTYPE_QNUM',
30 'int32': 'QTYPE_QNUM',
31 'int64': 'QTYPE_QNUM',
32 'uint8': 'QTYPE_QNUM',
33 'uint16': 'QTYPE_QNUM',
34 'uint32': 'QTYPE_QNUM',
35 'uint64': 'QTYPE_QNUM',
37 'any': None, # any QType possible, actually
38 'QType': 'QTYPE_QSTRING',
41 # Are documentation comments required?
44 # Whitelist of commands allowed to return a non-dictionary
45 returns_whitelist = []
47 # Whitelist of entities allowed to violate case conventions
48 name_case_whitelist = []
56 # Parsing the schema into expressions
60 def error_path(parent):
63 res = ('In file included from %s:%d:\n' % (parent['file'],
64 parent['line'])) + res
65 parent = parent['parent']
69 class QAPIError(Exception):
70 def __init__(self, fname, line, col, incl_info, msg):
71 Exception.__init__(self)
79 loc = '%s:%d' % (self.fname, self.line)
80 if self.col is not None:
81 loc += ':%s' % self.col
82 return error_path(self.info) + '%s: %s' % (loc, self.msg)
85 class QAPIParseError(QAPIError):
86 def __init__(self, parser, msg):
88 for ch in parser.src[parser.line_pos:parser.pos]:
90 col = (col + 7) % 8 + 1
93 QAPIError.__init__(self, parser.fname, parser.line, col,
94 parser.incl_info, msg)
97 class QAPISemError(QAPIError):
98 def __init__(self, info, msg):
99 QAPIError.__init__(self, info['file'], info['line'], None,
103 class QAPIDoc(object):
104 class Section(object):
105 def __init__(self, name=None):
106 # optional section name (argument/member or section name)
108 # the list of lines for this section
111 def append(self, line):
112 self.text += line.rstrip() + '\n'
114 class ArgSection(Section):
115 def __init__(self, name):
116 QAPIDoc.Section.__init__(self, name)
119 def connect(self, member):
122 def __init__(self, parser, info):
123 # self._parser is used to report errors with QAPIParseError. The
124 # resulting error position depends on the state of the parser.
125 # It happens to be the beginning of the comment. More or less
126 # servicable, but action at a distance.
127 self._parser = parser
130 self.body = QAPIDoc.Section()
131 # dict mapping parameter name to ArgSection
132 self.args = OrderedDict()
135 # the current section
136 self._section = self.body
138 def has_section(self, name):
139 """Return True if we have a section with this name."""
140 for i in self.sections:
145 def append(self, line):
146 """Parse a comment line and add it to the documentation."""
149 self._append_freeform(line)
153 raise QAPIParseError(self._parser, "Missing space after #")
156 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
157 # recognized, and get silently treated as ordinary text
159 self._append_symbol_line(line)
160 elif not self.body.text and line.startswith('@'):
161 if not line.endswith(':'):
162 raise QAPIParseError(self._parser, "Line should end with :")
163 self.symbol = line[1:-1]
164 # FIXME invalid names other than the empty string aren't flagged
166 raise QAPIParseError(self._parser, "Invalid name")
168 self._append_freeform(line)
170 def end_comment(self):
173 def _append_symbol_line(self, line):
174 name = line.split(' ', 1)[0]
176 if name.startswith('@') and name.endswith(':'):
177 line = line[len(name)+1:]
178 self._start_args_section(name[1:-1])
179 elif name in ('Returns:', 'Since:',
180 # those are often singular or plural
182 'Example:', 'Examples:',
184 line = line[len(name)+1:]
185 self._start_section(name[:-1])
187 self._append_freeform(line)
189 def _start_args_section(self, name):
190 # FIXME invalid names other than the empty string aren't flagged
192 raise QAPIParseError(self._parser, "Invalid parameter name")
193 if name in self.args:
194 raise QAPIParseError(self._parser,
195 "'%s' parameter name duplicated" % name)
197 raise QAPIParseError(self._parser,
198 "'@%s:' can't follow '%s' section"
199 % (name, self.sections[0].name))
201 self._section = QAPIDoc.ArgSection(name)
202 self.args[name] = self._section
204 def _start_section(self, name=None):
205 if name in ('Returns', 'Since') and self.has_section(name):
206 raise QAPIParseError(self._parser,
207 "Duplicated '%s' section" % name)
209 self._section = QAPIDoc.Section(name)
210 self.sections.append(self._section)
212 def _end_section(self):
214 text = self._section.text = self._section.text.strip()
215 if self._section.name and (not text or text.isspace()):
216 raise QAPIParseError(self._parser, "Empty doc section '%s'"
217 % self._section.name)
220 def _append_freeform(self, line):
221 in_arg = isinstance(self._section, QAPIDoc.ArgSection)
222 if (in_arg and self._section.text.endswith('\n\n')
223 and line and not line[0].isspace()):
224 self._start_section()
225 if (in_arg or not self._section.name
226 or not self._section.name.startswith('Example')):
228 match = re.match(r'(@\S+:)', line)
230 raise QAPIParseError(self._parser,
231 "'%s' not allowed in free-form documentation"
233 self._section.append(line)
235 def connect_member(self, member):
236 if member.name not in self.args:
237 # Undocumented TODO outlaw
238 self.args[member.name] = QAPIDoc.ArgSection(member.name)
239 self.args[member.name].connect(member)
241 def check_expr(self, expr):
242 if self.has_section('Returns') and 'command' not in expr:
243 raise QAPISemError(self.info,
244 "'Returns:' is only valid for commands")
247 bogus = [name for name, section in self.args.iteritems()
248 if not section.member]
252 "The following documented members are not in "
253 "the declaration: %s" % ", ".join(bogus))
256 class QAPISchemaParser(object):
258 def __init__(self, fp, previously_included=[], incl_info=None):
259 abs_fname = os.path.abspath(fp.name)
261 previously_included.append(abs_fname)
262 self.incl_info = incl_info
264 if self.src == '' or self.src[-1] != '\n':
274 while self.tok is not None:
275 info = {'file': self.fname, 'line': self.line,
276 'parent': self.incl_info}
278 self.reject_expr_doc(cur_doc)
279 cur_doc = self.get_doc(info)
280 self.docs.append(cur_doc)
283 expr = self.get_expr(False)
284 if 'include' in expr:
285 self.reject_expr_doc(cur_doc)
287 raise QAPISemError(info, "Invalid 'include' directive")
288 include = expr['include']
289 if not isinstance(include, str):
290 raise QAPISemError(info,
291 "Value of 'include' must be a string")
292 self._include(include, info, os.path.dirname(abs_fname),
294 elif "pragma" in expr:
295 self.reject_expr_doc(cur_doc)
297 raise QAPISemError(info, "Invalid 'pragma' directive")
298 pragma = expr['pragma']
299 if not isinstance(pragma, dict):
301 info, "Value of 'pragma' must be a dictionary")
302 for name, value in pragma.iteritems():
303 self._pragma(name, value, info)
305 expr_elem = {'expr': expr,
308 if not cur_doc.symbol:
310 cur_doc.info, "Expression documentation required")
311 expr_elem['doc'] = cur_doc
312 self.exprs.append(expr_elem)
314 self.reject_expr_doc(cur_doc)
317 def reject_expr_doc(doc):
318 if doc and doc.symbol:
321 "Documentation for '%s' is not followed by the definition"
324 def _include(self, include, info, base_dir, previously_included):
325 incl_abs_fname = os.path.join(base_dir, include)
326 # catch inclusion cycle
329 if incl_abs_fname == os.path.abspath(inf['file']):
330 raise QAPISemError(info, "Inclusion loop for %s" % include)
333 # skip multiple include of the same file
334 if incl_abs_fname in previously_included:
337 fobj = open(incl_abs_fname, 'r')
339 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
340 exprs_include = QAPISchemaParser(fobj, previously_included, info)
341 self.exprs.extend(exprs_include.exprs)
342 self.docs.extend(exprs_include.docs)
344 def _pragma(self, name, value, info):
345 global doc_required, returns_whitelist, name_case_whitelist
346 if name == 'doc-required':
347 if not isinstance(value, bool):
348 raise QAPISemError(info,
349 "Pragma 'doc-required' must be boolean")
351 elif name == 'returns-whitelist':
352 if (not isinstance(value, list)
353 or any([not isinstance(elt, str) for elt in value])):
354 raise QAPISemError(info,
355 "Pragma returns-whitelist must be"
356 " a list of strings")
357 returns_whitelist = value
358 elif name == 'name-case-whitelist':
359 if (not isinstance(value, list)
360 or any([not isinstance(elt, str) for elt in value])):
361 raise QAPISemError(info,
362 "Pragma name-case-whitelist must be"
363 " a list of strings")
364 name_case_whitelist = value
366 raise QAPISemError(info, "Unknown pragma '%s'" % name)
368 def accept(self, skip_comment=True):
370 self.tok = self.src[self.cursor]
371 self.pos = self.cursor
376 if self.src[self.cursor] == '#':
377 # Start of doc comment
379 self.cursor = self.src.find('\n', self.cursor)
381 self.val = self.src[self.pos:self.cursor]
383 elif self.tok in '{}:,[]':
385 elif self.tok == "'":
389 ch = self.src[self.cursor]
392 raise QAPIParseError(self, 'Missing terminating "\'"')
406 for _ in range(0, 4):
407 ch = self.src[self.cursor]
409 if ch not in '0123456789abcdefABCDEF':
410 raise QAPIParseError(self,
411 '\\u escape needs 4 '
413 value = (value << 4) + int(ch, 16)
414 # If Python 2 and 3 didn't disagree so much on
415 # how to handle Unicode, then we could allow
416 # Unicode string defaults. But most of QAPI is
417 # ASCII-only, so we aren't losing much for now.
418 if not value or value > 0x7f:
419 raise QAPIParseError(self,
420 'For now, \\u escape '
421 'only supports non-zero '
422 'values up to \\u007f')
427 raise QAPIParseError(self,
428 "Unknown escape \\%s" % ch)
437 elif self.src.startswith('true', self.pos):
441 elif self.src.startswith('false', self.pos):
445 elif self.src.startswith('null', self.pos):
449 elif self.tok == '\n':
450 if self.cursor == len(self.src):
454 self.line_pos = self.cursor
455 elif not self.tok.isspace():
456 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
458 def get_members(self):
464 raise QAPIParseError(self, 'Expected string or "}"')
469 raise QAPIParseError(self, 'Expected ":"')
472 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
473 expr[key] = self.get_expr(True)
478 raise QAPIParseError(self, 'Expected "," or "}"')
481 raise QAPIParseError(self, 'Expected string')
483 def get_values(self):
488 if self.tok not in "{['tfn":
489 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
492 expr.append(self.get_expr(True))
497 raise QAPIParseError(self, 'Expected "," or "]"')
500 def get_expr(self, nested):
501 if self.tok != '{' and not nested:
502 raise QAPIParseError(self, 'Expected "{"')
505 expr = self.get_members()
506 elif self.tok == '[':
508 expr = self.get_values()
509 elif self.tok in "'tfn":
513 raise QAPIParseError(self, 'Expected "{", "[", string, '
517 def get_doc(self, info):
519 raise QAPIParseError(self, "Junk after '##' at start of "
520 "documentation comment")
522 doc = QAPIDoc(self, info)
524 while self.tok == '#':
525 if self.val.startswith('##'):
528 raise QAPIParseError(self, "Junk after '##' at end of "
529 "documentation comment")
537 raise QAPIParseError(self, "Documentation comment must end with '##'")
541 # Semantic analysis of schema expressions
542 # TODO fold into QAPISchema
543 # TODO catching name collisions in generated code would be nice
547 def find_base_members(base):
548 if isinstance(base, dict):
550 base_struct_define = struct_types.get(base)
551 if not base_struct_define:
553 return base_struct_define['data']
556 # Return the qtype of an alternate branch, or None on error.
557 def find_alternate_member_qtype(qapi_type):
558 if qapi_type in builtin_types:
559 return builtin_types[qapi_type]
560 elif qapi_type in struct_types:
562 elif qapi_type in enum_types:
563 return 'QTYPE_QSTRING'
564 elif qapi_type in union_types:
569 # Return the discriminator enum define if discriminator is specified as an
570 # enum type, otherwise return None.
571 def discriminator_find_enum_define(expr):
572 base = expr.get('base')
573 discriminator = expr.get('discriminator')
575 if not (discriminator and base):
578 base_members = find_base_members(base)
582 discriminator_type = base_members.get(discriminator)
583 if not discriminator_type:
586 return enum_types.get(discriminator_type)
589 # Names must be letters, numbers, -, and _. They must start with letter,
590 # except for downstream extensions which must start with __RFQDN_.
591 # Dots are only valid in the downstream extension prefix.
592 valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
593 '[a-zA-Z][a-zA-Z0-9_-]*$')
596 def check_name(info, source, name, allow_optional=False,
601 if not isinstance(name, str):
602 raise QAPISemError(info, "%s requires a string name" % source)
603 if name.startswith('*'):
604 membername = name[1:]
605 if not allow_optional:
606 raise QAPISemError(info, "%s does not allow optional name '%s'"
608 # Enum members can start with a digit, because the generated C
609 # code always prefixes it with the enum name
610 if enum_member and membername[0].isdigit():
611 membername = 'D' + membername
612 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
613 # and 'q_obj_*' implicit type names.
614 if not valid_name.match(membername) or \
615 c_name(membername, False).startswith('q_'):
616 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
619 def add_name(name, info, meta, implicit=False):
621 check_name(info, "'%s'" % meta, name)
622 # FIXME should reject names that differ only in '_' vs. '.'
623 # vs. '-', because they're liable to clash in generated C.
624 if name in all_names:
625 raise QAPISemError(info, "%s '%s' is already defined"
626 % (all_names[name], name))
627 if not implicit and (name.endswith('Kind') or name.endswith('List')):
628 raise QAPISemError(info, "%s '%s' should not end in '%s'"
629 % (meta, name, name[-4:]))
630 all_names[name] = meta
633 def check_type(info, source, value, allow_array=False,
634 allow_dict=False, allow_optional=False,
641 # Check if array type for value is okay
642 if isinstance(value, list):
644 raise QAPISemError(info, "%s cannot be an array" % source)
645 if len(value) != 1 or not isinstance(value[0], str):
646 raise QAPISemError(info,
647 "%s: array type must contain single type name" %
651 # Check if type name for value is okay
652 if isinstance(value, str):
653 if value not in all_names:
654 raise QAPISemError(info, "%s uses unknown type '%s'"
656 if not all_names[value] in allow_metas:
657 raise QAPISemError(info, "%s cannot use %s type '%s'" %
658 (source, all_names[value], value))
662 raise QAPISemError(info, "%s should be a type name" % source)
664 if not isinstance(value, OrderedDict):
665 raise QAPISemError(info,
666 "%s should be a dictionary or type name" % source)
668 # value is a dictionary, check that each member is okay
669 for (key, arg) in value.items():
670 check_name(info, "Member of %s" % source, key,
671 allow_optional=allow_optional)
672 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
673 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
675 # Todo: allow dictionaries to represent default values of
676 # an optional argument.
677 check_type(info, "Member '%s' of %s" % (key, source), arg,
679 allow_metas=['built-in', 'union', 'alternate', 'struct',
683 def check_command(expr, info):
684 name = expr['command']
685 boxed = expr.get('boxed', False)
687 args_meta = ['struct']
689 args_meta += ['union', 'alternate']
690 check_type(info, "'data' for command '%s'" % name,
691 expr.get('data'), allow_dict=not boxed, allow_optional=True,
692 allow_metas=args_meta)
693 returns_meta = ['union', 'struct']
694 if name in returns_whitelist:
695 returns_meta += ['built-in', 'alternate', 'enum']
696 check_type(info, "'returns' for command '%s'" % name,
697 expr.get('returns'), allow_array=True,
698 allow_optional=True, allow_metas=returns_meta)
701 def check_event(expr, info):
703 boxed = expr.get('boxed', False)
707 meta += ['union', 'alternate']
708 check_type(info, "'data' for event '%s'" % name,
709 expr.get('data'), allow_dict=not boxed, allow_optional=True,
713 def check_union(expr, info):
715 base = expr.get('base')
716 discriminator = expr.get('discriminator')
717 members = expr['data']
719 # Two types of unions, determined by discriminator.
721 # With no discriminator it is a simple union.
722 if discriminator is None:
724 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
726 raise QAPISemError(info, "Simple union '%s' must not have a base" %
729 # Else, it's a flat union.
731 # The object must have a string or dictionary 'base'.
732 check_type(info, "'base' for union '%s'" % name,
733 base, allow_dict=True, allow_optional=True,
734 allow_metas=['struct'])
736 raise QAPISemError(info, "Flat union '%s' must have a base"
738 base_members = find_base_members(base)
739 assert base_members is not None
741 # The value of member 'discriminator' must name a non-optional
742 # member of the base struct.
743 check_name(info, "Discriminator of flat union '%s'" % name,
745 discriminator_type = base_members.get(discriminator)
746 if not discriminator_type:
747 raise QAPISemError(info,
748 "Discriminator '%s' is not a member of base "
750 % (discriminator, base))
751 enum_define = enum_types.get(discriminator_type)
752 allow_metas = ['struct']
753 # Do not allow string discriminator
755 raise QAPISemError(info,
756 "Discriminator '%s' must be of enumeration "
757 "type" % discriminator)
759 # Check every branch; don't allow an empty union
760 if len(members) == 0:
761 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
762 for (key, value) in members.items():
763 check_name(info, "Member of union '%s'" % name, key)
765 # Each value must name a known type
766 check_type(info, "Member '%s' of union '%s'" % (key, name),
767 value, allow_array=not base, allow_metas=allow_metas)
769 # If the discriminator names an enum type, then all members
770 # of 'data' must also be members of the enum type.
772 if key not in enum_define['data']:
773 raise QAPISemError(info,
774 "Discriminator value '%s' is not found in "
776 % (key, enum_define['enum']))
778 # If discriminator is user-defined, ensure all values are covered
780 for value in enum_define['data']:
781 if value not in members.keys():
782 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
786 def check_alternate(expr, info):
787 name = expr['alternate']
788 members = expr['data']
791 # Check every branch; require at least two branches
793 raise QAPISemError(info,
794 "Alternate '%s' should have at least two branches "
796 for (key, value) in members.items():
797 check_name(info, "Member of alternate '%s'" % name, key)
799 # Ensure alternates have no type conflicts.
800 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
802 allow_metas=['built-in', 'union', 'struct', 'enum'])
803 qtype = find_alternate_member_qtype(value)
805 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
806 "type '%s'" % (name, key, value))
807 conflicting = set([qtype])
808 if qtype == 'QTYPE_QSTRING':
809 enum_expr = enum_types.get(value)
811 for v in enum_expr['data']:
812 if v in ['on', 'off']:
813 conflicting.add('QTYPE_QBOOL')
814 if re.match(r'[-+0-9.]', v): # lazy, could be tightened
815 conflicting.add('QTYPE_QNUM')
817 conflicting.add('QTYPE_QNUM')
818 conflicting.add('QTYPE_QBOOL')
819 for qt in conflicting:
821 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
822 "be distinguished from member '%s'"
823 % (name, key, types_seen[qt]))
827 def check_enum(expr, info):
829 members = expr.get('data')
830 prefix = expr.get('prefix')
832 if not isinstance(members, list):
833 raise QAPISemError(info,
834 "Enum '%s' requires an array for 'data'" % name)
835 if prefix is not None and not isinstance(prefix, str):
836 raise QAPISemError(info,
837 "Enum '%s' requires a string for 'prefix'" % name)
838 for member in members:
839 check_name(info, "Member of enum '%s'" % name, member,
843 def check_struct(expr, info):
844 name = expr['struct']
845 members = expr['data']
847 check_type(info, "'data' for struct '%s'" % name, members,
848 allow_dict=True, allow_optional=True)
849 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
850 allow_metas=['struct'])
853 def check_keys(expr_elem, meta, required, optional=[]):
854 expr = expr_elem['expr']
855 info = expr_elem['info']
857 if not isinstance(name, str):
858 raise QAPISemError(info, "'%s' key must have a string value" % meta)
859 required = required + [meta]
860 for (key, value) in expr.items():
861 if key not in required and key not in optional:
862 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
864 if (key == 'gen' or key == 'success-response') and value is not False:
865 raise QAPISemError(info,
866 "'%s' of %s '%s' should only use false value"
868 if key == 'boxed' and value is not True:
869 raise QAPISemError(info,
870 "'%s' of %s '%s' should only use true value"
874 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
878 def check_exprs(exprs):
881 # Populate name table with names of built-in types
882 for builtin in builtin_types.keys():
883 all_names[builtin] = 'built-in'
885 # Learn the types and check for valid expression keys
886 for expr_elem in exprs:
887 expr = expr_elem['expr']
888 info = expr_elem['info']
889 doc = expr_elem.get('doc')
891 if not doc and doc_required:
892 raise QAPISemError(info,
893 "Expression missing documentation comment")
897 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
898 enum_types[expr[meta]] = expr
899 elif 'union' in expr:
901 check_keys(expr_elem, 'union', ['data'],
902 ['base', 'discriminator'])
903 union_types[expr[meta]] = expr
904 elif 'alternate' in expr:
906 check_keys(expr_elem, 'alternate', ['data'])
907 elif 'struct' in expr:
909 check_keys(expr_elem, 'struct', ['data'], ['base'])
910 struct_types[expr[meta]] = expr
911 elif 'command' in expr:
913 check_keys(expr_elem, 'command', [],
914 ['data', 'returns', 'gen', 'success-response', 'boxed'])
915 elif 'event' in expr:
917 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
919 raise QAPISemError(expr_elem['info'],
920 "Expression is missing metatype")
922 add_name(name, info, meta)
923 if doc and doc.symbol != name:
924 raise QAPISemError(info, "Definition of '%s' follows documentation"
925 " for '%s'" % (name, doc.symbol))
927 # Try again for hidden UnionKind enum
928 for expr_elem in exprs:
929 expr = expr_elem['expr']
930 if 'union' in expr and not discriminator_find_enum_define(expr):
931 name = '%sKind' % expr['union']
932 elif 'alternate' in expr:
933 name = '%sKind' % expr['alternate']
936 enum_types[name] = {'enum': name}
937 add_name(name, info, 'enum', implicit=True)
939 # Validate that exprs make sense
940 for expr_elem in exprs:
941 expr = expr_elem['expr']
942 info = expr_elem['info']
943 doc = expr_elem.get('doc')
946 check_enum(expr, info)
947 elif 'union' in expr:
948 check_union(expr, info)
949 elif 'alternate' in expr:
950 check_alternate(expr, info)
951 elif 'struct' in expr:
952 check_struct(expr, info)
953 elif 'command' in expr:
954 check_command(expr, info)
955 elif 'event' in expr:
956 check_event(expr, info)
958 assert False, 'unexpected meta type'
967 # Schema compiler frontend
970 class QAPISchemaEntity(object):
971 def __init__(self, name, info, doc):
972 assert isinstance(name, str)
974 # For explicitly defined entities, info points to the (explicit)
975 # definition. For builtins (and their arrays), info is None.
976 # For implicitly defined entities, info points to a place that
977 # triggered the implicit definition (there may be more than one
983 return c_name(self.name)
985 def check(self, schema):
988 def is_implicit(self):
991 def visit(self, visitor):
995 class QAPISchemaVisitor(object):
996 def visit_begin(self, schema):
1002 def visit_needed(self, entity):
1003 # Default to visiting everything
1006 def visit_builtin_type(self, name, info, json_type):
1009 def visit_enum_type(self, name, info, values, prefix):
1012 def visit_array_type(self, name, info, element_type):
1015 def visit_object_type(self, name, info, base, members, variants):
1018 def visit_object_type_flat(self, name, info, members, variants):
1021 def visit_alternate_type(self, name, info, variants):
1024 def visit_command(self, name, info, arg_type, ret_type,
1025 gen, success_response, boxed):
1028 def visit_event(self, name, info, arg_type, boxed):
1032 class QAPISchemaType(QAPISchemaEntity):
1033 # Return the C type for common use.
1034 # For the types we commonly box, this is a pointer type.
1038 # Return the C type to be used in a parameter list.
1039 def c_param_type(self):
1040 return self.c_type()
1042 # Return the C type to be used where we suppress boxing.
1043 def c_unboxed_type(self):
1044 return self.c_type()
1046 def json_type(self):
1049 def alternate_qtype(self):
1051 'null': 'QTYPE_QNULL',
1052 'string': 'QTYPE_QSTRING',
1053 'number': 'QTYPE_QNUM',
1054 'int': 'QTYPE_QNUM',
1055 'boolean': 'QTYPE_QBOOL',
1056 'object': 'QTYPE_QDICT'
1058 return json2qtype.get(self.json_type())
1061 if self.is_implicit():
1066 class QAPISchemaBuiltinType(QAPISchemaType):
1067 def __init__(self, name, json_type, c_type):
1068 QAPISchemaType.__init__(self, name, None, None)
1069 assert not c_type or isinstance(c_type, str)
1070 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1072 self._json_type_name = json_type
1073 self._c_type_name = c_type
1079 return self._c_type_name
1081 def c_param_type(self):
1082 if self.name == 'str':
1083 return 'const ' + self._c_type_name
1084 return self._c_type_name
1086 def json_type(self):
1087 return self._json_type_name
1090 return self.json_type()
1092 def visit(self, visitor):
1093 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1096 class QAPISchemaEnumType(QAPISchemaType):
1097 def __init__(self, name, info, doc, values, prefix):
1098 QAPISchemaType.__init__(self, name, info, doc)
1100 assert isinstance(v, QAPISchemaMember)
1102 assert prefix is None or isinstance(prefix, str)
1103 self.values = values
1104 self.prefix = prefix
1106 def check(self, schema):
1108 for v in self.values:
1109 v.check_clash(self.info, seen)
1111 self.doc.connect_member(v)
1113 def is_implicit(self):
1114 # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1115 return self.name.endswith('Kind') or self.name == 'QType'
1118 return c_name(self.name)
1120 def member_names(self):
1121 return [v.name for v in self.values]
1123 def json_type(self):
1126 def visit(self, visitor):
1127 visitor.visit_enum_type(self.name, self.info,
1128 self.member_names(), self.prefix)
1131 class QAPISchemaArrayType(QAPISchemaType):
1132 def __init__(self, name, info, element_type):
1133 QAPISchemaType.__init__(self, name, info, None)
1134 assert isinstance(element_type, str)
1135 self._element_type_name = element_type
1136 self.element_type = None
1138 def check(self, schema):
1139 self.element_type = schema.lookup_type(self._element_type_name)
1140 assert self.element_type
1142 def is_implicit(self):
1146 return c_name(self.name) + pointer_suffix
1148 def json_type(self):
1152 elt_doc_type = self.element_type.doc_type()
1153 if not elt_doc_type:
1155 return 'array of ' + elt_doc_type
1157 def visit(self, visitor):
1158 visitor.visit_array_type(self.name, self.info, self.element_type)
1161 class QAPISchemaObjectType(QAPISchemaType):
1162 def __init__(self, name, info, doc, base, local_members, variants):
1163 # struct has local_members, optional base, and no variants
1164 # flat union has base, variants, and no local_members
1165 # simple union has local_members, variants, and no base
1166 QAPISchemaType.__init__(self, name, info, doc)
1167 assert base is None or isinstance(base, str)
1168 for m in local_members:
1169 assert isinstance(m, QAPISchemaObjectTypeMember)
1171 if variants is not None:
1172 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1173 variants.set_owner(name)
1174 self._base_name = base
1176 self.local_members = local_members
1177 self.variants = variants
1180 def check(self, schema):
1181 if self.members is False: # check for cycles
1182 raise QAPISemError(self.info,
1183 "Object %s contains itself" % self.name)
1186 self.members = False # mark as being checked
1187 seen = OrderedDict()
1189 self.base = schema.lookup_type(self._base_name)
1190 assert isinstance(self.base, QAPISchemaObjectType)
1191 self.base.check(schema)
1192 self.base.check_clash(self.info, seen)
1193 for m in self.local_members:
1195 m.check_clash(self.info, seen)
1197 self.doc.connect_member(m)
1198 self.members = seen.values()
1200 self.variants.check(schema, seen)
1201 assert self.variants.tag_member in self.members
1202 self.variants.check_clash(self.info, seen)
1206 # Check that the members of this type do not cause duplicate JSON members,
1207 # and update seen to track the members seen so far. Report any errors
1208 # on behalf of info, which is not necessarily self.info
1209 def check_clash(self, info, seen):
1210 assert not self.variants # not implemented
1211 for m in self.members:
1212 m.check_clash(info, seen)
1214 def is_implicit(self):
1215 # See QAPISchema._make_implicit_object_type(), as well as
1216 # _def_predefineds()
1217 return self.name.startswith('q_')
1220 assert self.members is not None
1221 return not self.members and not self.variants
1224 assert self.name != 'q_empty'
1225 return QAPISchemaType.c_name(self)
1228 assert not self.is_implicit()
1229 return c_name(self.name) + pointer_suffix
1231 def c_unboxed_type(self):
1232 return c_name(self.name)
1234 def json_type(self):
1237 def visit(self, visitor):
1238 visitor.visit_object_type(self.name, self.info,
1239 self.base, self.local_members, self.variants)
1240 visitor.visit_object_type_flat(self.name, self.info,
1241 self.members, self.variants)
1244 class QAPISchemaMember(object):
1247 def __init__(self, name):
1248 assert isinstance(name, str)
1252 def set_owner(self, name):
1253 assert not self.owner
1256 def check_clash(self, info, seen):
1257 cname = c_name(self.name)
1258 if cname.lower() != cname and self.owner not in name_case_whitelist:
1259 raise QAPISemError(info,
1260 "%s should not use uppercase" % self.describe())
1262 raise QAPISemError(info, "%s collides with %s" %
1263 (self.describe(), seen[cname].describe()))
1266 def _pretty_owner(self):
1268 if owner.startswith('q_obj_'):
1269 # See QAPISchema._make_implicit_object_type() - reverse the
1270 # mapping there to create a nice human-readable description
1272 if owner.endswith('-arg'):
1273 return '(parameter of %s)' % owner[:-4]
1274 elif owner.endswith('-base'):
1275 return '(base of %s)' % owner[:-5]
1277 assert owner.endswith('-wrapper')
1278 # Unreachable and not implemented
1280 if owner.endswith('Kind'):
1281 # See QAPISchema._make_implicit_enum_type()
1282 return '(branch of %s)' % owner[:-4]
1283 return '(%s of %s)' % (self.role, owner)
1286 return "'%s' %s" % (self.name, self._pretty_owner())
1289 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1290 def __init__(self, name, typ, optional):
1291 QAPISchemaMember.__init__(self, name)
1292 assert isinstance(typ, str)
1293 assert isinstance(optional, bool)
1294 self._type_name = typ
1296 self.optional = optional
1298 def check(self, schema):
1300 self.type = schema.lookup_type(self._type_name)
1304 class QAPISchemaObjectTypeVariants(object):
1305 def __init__(self, tag_name, tag_member, variants):
1306 # Flat unions pass tag_name but not tag_member.
1307 # Simple unions and alternates pass tag_member but not tag_name.
1308 # After check(), tag_member is always set, and tag_name remains
1309 # a reliable witness of being used by a flat union.
1310 assert bool(tag_member) != bool(tag_name)
1311 assert (isinstance(tag_name, str) or
1312 isinstance(tag_member, QAPISchemaObjectTypeMember))
1313 assert len(variants) > 0
1315 assert isinstance(v, QAPISchemaObjectTypeVariant)
1316 self._tag_name = tag_name
1317 self.tag_member = tag_member
1318 self.variants = variants
1320 def set_owner(self, name):
1321 for v in self.variants:
1324 def check(self, schema, seen):
1325 if not self.tag_member: # flat union
1326 self.tag_member = seen[c_name(self._tag_name)]
1327 assert self._tag_name == self.tag_member.name
1328 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1329 for v in self.variants:
1331 # Union names must match enum values; alternate names are
1332 # checked separately. Use 'seen' to tell the two apart.
1334 assert v.name in self.tag_member.type.member_names()
1335 assert isinstance(v.type, QAPISchemaObjectType)
1336 v.type.check(schema)
1338 def check_clash(self, info, seen):
1339 for v in self.variants:
1340 # Reset seen map for each variant, since qapi names from one
1341 # branch do not affect another branch
1342 assert isinstance(v.type, QAPISchemaObjectType)
1343 v.type.check_clash(info, dict(seen))
1346 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1349 def __init__(self, name, typ):
1350 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1353 class QAPISchemaAlternateType(QAPISchemaType):
1354 def __init__(self, name, info, doc, variants):
1355 QAPISchemaType.__init__(self, name, info, doc)
1356 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1357 assert variants.tag_member
1358 variants.set_owner(name)
1359 variants.tag_member.set_owner(self.name)
1360 self.variants = variants
1362 def check(self, schema):
1363 self.variants.tag_member.check(schema)
1364 # Not calling self.variants.check_clash(), because there's nothing
1366 self.variants.check(schema, {})
1367 # Alternate branch names have no relation to the tag enum values;
1368 # so we have to check for potential name collisions ourselves.
1370 for v in self.variants.variants:
1371 v.check_clash(self.info, seen)
1373 self.doc.connect_member(v)
1378 return c_name(self.name) + pointer_suffix
1380 def json_type(self):
1383 def visit(self, visitor):
1384 visitor.visit_alternate_type(self.name, self.info, self.variants)
1390 class QAPISchemaCommand(QAPISchemaEntity):
1391 def __init__(self, name, info, doc, arg_type, ret_type,
1392 gen, success_response, boxed):
1393 QAPISchemaEntity.__init__(self, name, info, doc)
1394 assert not arg_type or isinstance(arg_type, str)
1395 assert not ret_type or isinstance(ret_type, str)
1396 self._arg_type_name = arg_type
1397 self.arg_type = None
1398 self._ret_type_name = ret_type
1399 self.ret_type = None
1401 self.success_response = success_response
1404 def check(self, schema):
1405 if self._arg_type_name:
1406 self.arg_type = schema.lookup_type(self._arg_type_name)
1407 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1408 isinstance(self.arg_type, QAPISchemaAlternateType))
1409 self.arg_type.check(schema)
1411 if self.arg_type.is_empty():
1412 raise QAPISemError(self.info,
1413 "Cannot use 'boxed' with empty type")
1415 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1416 assert not self.arg_type.variants
1418 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1419 if self._ret_type_name:
1420 self.ret_type = schema.lookup_type(self._ret_type_name)
1421 assert isinstance(self.ret_type, QAPISchemaType)
1423 def visit(self, visitor):
1424 visitor.visit_command(self.name, self.info,
1425 self.arg_type, self.ret_type,
1426 self.gen, self.success_response, self.boxed)
1429 class QAPISchemaEvent(QAPISchemaEntity):
1430 def __init__(self, name, info, doc, arg_type, boxed):
1431 QAPISchemaEntity.__init__(self, name, info, doc)
1432 assert not arg_type or isinstance(arg_type, str)
1433 self._arg_type_name = arg_type
1434 self.arg_type = None
1437 def check(self, schema):
1438 if self._arg_type_name:
1439 self.arg_type = schema.lookup_type(self._arg_type_name)
1440 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1441 isinstance(self.arg_type, QAPISchemaAlternateType))
1442 self.arg_type.check(schema)
1444 if self.arg_type.is_empty():
1445 raise QAPISemError(self.info,
1446 "Cannot use 'boxed' with empty type")
1448 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1449 assert not self.arg_type.variants
1451 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1453 def visit(self, visitor):
1454 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
1457 class QAPISchema(object):
1458 def __init__(self, fname):
1460 parser = QAPISchemaParser(open(fname, 'r'))
1461 self.exprs = check_exprs(parser.exprs)
1462 self.docs = parser.docs
1463 self._entity_dict = {}
1464 self._predefining = True
1465 self._def_predefineds()
1466 self._predefining = False
1469 except QAPIError as err:
1470 print >>sys.stderr, err
1473 def _def_entity(self, ent):
1474 # Only the predefined types are allowed to not have info
1475 assert ent.info or self._predefining
1476 assert ent.name not in self._entity_dict
1477 self._entity_dict[ent.name] = ent
1479 def lookup_entity(self, name, typ=None):
1480 ent = self._entity_dict.get(name)
1481 if typ and not isinstance(ent, typ):
1485 def lookup_type(self, name):
1486 return self.lookup_entity(name, QAPISchemaType)
1488 def _def_builtin_type(self, name, json_type, c_type):
1489 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1490 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1491 # qapi-types.h from a single .c, all arrays of builtins must be
1492 # declared in the first file whether or not they are used. Nicer
1493 # would be to use lazy instantiation, while figuring out how to
1494 # avoid compilation issues with multiple qapi-types.h.
1495 self._make_array_type(name, None)
1497 def _def_predefineds(self):
1498 for t in [('str', 'string', 'char' + pointer_suffix),
1499 ('number', 'number', 'double'),
1500 ('int', 'int', 'int64_t'),
1501 ('int8', 'int', 'int8_t'),
1502 ('int16', 'int', 'int16_t'),
1503 ('int32', 'int', 'int32_t'),
1504 ('int64', 'int', 'int64_t'),
1505 ('uint8', 'int', 'uint8_t'),
1506 ('uint16', 'int', 'uint16_t'),
1507 ('uint32', 'int', 'uint32_t'),
1508 ('uint64', 'int', 'uint64_t'),
1509 ('size', 'int', 'uint64_t'),
1510 ('bool', 'boolean', 'bool'),
1511 ('any', 'value', 'QObject' + pointer_suffix),
1512 ('null', 'null', 'QNull' + pointer_suffix)]:
1513 self._def_builtin_type(*t)
1514 self.the_empty_object_type = QAPISchemaObjectType(
1515 'q_empty', None, None, None, [], None)
1516 self._def_entity(self.the_empty_object_type)
1517 qtype_values = self._make_enum_members(['none', 'qnull', 'qnum',
1518 'qstring', 'qdict', 'qlist',
1520 self._def_entity(QAPISchemaEnumType('QType', None, None,
1521 qtype_values, 'QTYPE'))
1523 def _make_enum_members(self, values):
1524 return [QAPISchemaMember(v) for v in values]
1526 def _make_implicit_enum_type(self, name, info, values):
1527 # See also QAPISchemaObjectTypeMember._pretty_owner()
1528 name = name + 'Kind' # Use namespace reserved by add_name()
1529 self._def_entity(QAPISchemaEnumType(
1530 name, info, None, self._make_enum_members(values), None))
1533 def _make_array_type(self, element_type, info):
1534 name = element_type + 'List' # Use namespace reserved by add_name()
1535 if not self.lookup_type(name):
1536 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1539 def _make_implicit_object_type(self, name, info, doc, role, members):
1542 # See also QAPISchemaObjectTypeMember._pretty_owner()
1543 name = 'q_obj_%s-%s' % (name, role)
1544 if not self.lookup_entity(name, QAPISchemaObjectType):
1545 self._def_entity(QAPISchemaObjectType(name, info, doc, None,
1549 def _def_enum_type(self, expr, info, doc):
1552 prefix = expr.get('prefix')
1553 self._def_entity(QAPISchemaEnumType(
1554 name, info, doc, self._make_enum_members(data), prefix))
1556 def _make_member(self, name, typ, info):
1558 if name.startswith('*'):
1561 if isinstance(typ, list):
1562 assert len(typ) == 1
1563 typ = self._make_array_type(typ[0], info)
1564 return QAPISchemaObjectTypeMember(name, typ, optional)
1566 def _make_members(self, data, info):
1567 return [self._make_member(key, value, info)
1568 for (key, value) in data.iteritems()]
1570 def _def_struct_type(self, expr, info, doc):
1571 name = expr['struct']
1572 base = expr.get('base')
1574 self._def_entity(QAPISchemaObjectType(name, info, doc, base,
1575 self._make_members(data, info),
1578 def _make_variant(self, case, typ):
1579 return QAPISchemaObjectTypeVariant(case, typ)
1581 def _make_simple_variant(self, case, typ, info):
1582 if isinstance(typ, list):
1583 assert len(typ) == 1
1584 typ = self._make_array_type(typ[0], info)
1585 typ = self._make_implicit_object_type(
1586 typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
1587 return QAPISchemaObjectTypeVariant(case, typ)
1589 def _def_union_type(self, expr, info, doc):
1590 name = expr['union']
1592 base = expr.get('base')
1593 tag_name = expr.get('discriminator')
1595 if isinstance(base, dict):
1596 base = (self._make_implicit_object_type(
1597 name, info, doc, 'base', self._make_members(base, info)))
1599 variants = [self._make_variant(key, value)
1600 for (key, value) in data.iteritems()]
1603 variants = [self._make_simple_variant(key, value, info)
1604 for (key, value) in data.iteritems()]
1605 typ = self._make_implicit_enum_type(name, info,
1606 [v.name for v in variants])
1607 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1608 members = [tag_member]
1610 QAPISchemaObjectType(name, info, doc, base, members,
1611 QAPISchemaObjectTypeVariants(tag_name,
1615 def _def_alternate_type(self, expr, info, doc):
1616 name = expr['alternate']
1618 variants = [self._make_variant(key, value)
1619 for (key, value) in data.iteritems()]
1620 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1622 QAPISchemaAlternateType(name, info, doc,
1623 QAPISchemaObjectTypeVariants(None,
1627 def _def_command(self, expr, info, doc):
1628 name = expr['command']
1629 data = expr.get('data')
1630 rets = expr.get('returns')
1631 gen = expr.get('gen', True)
1632 success_response = expr.get('success-response', True)
1633 boxed = expr.get('boxed', False)
1634 if isinstance(data, OrderedDict):
1635 data = self._make_implicit_object_type(
1636 name, info, doc, 'arg', self._make_members(data, info))
1637 if isinstance(rets, list):
1638 assert len(rets) == 1
1639 rets = self._make_array_type(rets[0], info)
1640 self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
1641 gen, success_response, boxed))
1643 def _def_event(self, expr, info, doc):
1644 name = expr['event']
1645 data = expr.get('data')
1646 boxed = expr.get('boxed', False)
1647 if isinstance(data, OrderedDict):
1648 data = self._make_implicit_object_type(
1649 name, info, doc, 'arg', self._make_members(data, info))
1650 self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
1652 def _def_exprs(self):
1653 for expr_elem in self.exprs:
1654 expr = expr_elem['expr']
1655 info = expr_elem['info']
1656 doc = expr_elem.get('doc')
1658 self._def_enum_type(expr, info, doc)
1659 elif 'struct' in expr:
1660 self._def_struct_type(expr, info, doc)
1661 elif 'union' in expr:
1662 self._def_union_type(expr, info, doc)
1663 elif 'alternate' in expr:
1664 self._def_alternate_type(expr, info, doc)
1665 elif 'command' in expr:
1666 self._def_command(expr, info, doc)
1667 elif 'event' in expr:
1668 self._def_event(expr, info, doc)
1673 for ent in self._entity_dict.values():
1676 def visit(self, visitor):
1677 visitor.visit_begin(self)
1678 for (name, entity) in sorted(self._entity_dict.items()):
1679 if visitor.visit_needed(entity):
1680 entity.visit(visitor)
1685 # Code generation helpers
1688 def camel_case(name):
1692 if ch in ['_', '-']:
1695 new_name += ch.upper()
1698 new_name += ch.lower()
1702 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1703 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1704 # ENUM24_Name -> ENUM24_NAME
1705 def camel_to_upper(value):
1706 c_fun_str = c_name(value, False)
1714 # When c is upper and no '_' appears before, do more checks
1715 if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
1716 if i < l - 1 and c_fun_str[i + 1].islower():
1718 elif c_fun_str[i - 1].isdigit():
1721 return new_name.lstrip('_').upper()
1724 def c_enum_const(type_name, const_name, prefix=None):
1725 if prefix is not None:
1727 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1729 c_name_trans = string.maketrans('.-', '__')
1732 # Map @name to a valid C identifier.
1733 # If @protect, avoid returning certain ticklish identifiers (like
1734 # C keywords) by prepending 'q_'.
1736 # Used for converting 'name' from a 'name':'type' qapi definition
1737 # into a generated struct member, as well as converting type names
1738 # into substrings of a generated C function name.
1739 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1740 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1741 def c_name(name, protect=True):
1742 # ANSI X3J11/88-090, 3.1.1
1743 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1744 'default', 'do', 'double', 'else', 'enum', 'extern',
1745 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1746 'return', 'short', 'signed', 'sizeof', 'static',
1747 'struct', 'switch', 'typedef', 'union', 'unsigned',
1748 'void', 'volatile', 'while'])
1749 # ISO/IEC 9899:1999, 6.4.1
1750 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1751 # ISO/IEC 9899:2011, 6.4.1
1752 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1753 '_Noreturn', '_Static_assert', '_Thread_local'])
1754 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1756 gcc_words = set(['asm', 'typeof'])
1757 # C++ ISO/IEC 14882:2003 2.11
1758 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1759 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1760 'namespace', 'new', 'operator', 'private', 'protected',
1761 'public', 'reinterpret_cast', 'static_cast', 'template',
1762 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1763 'using', 'virtual', 'wchar_t',
1764 # alternative representations
1765 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1766 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1767 # namespace pollution:
1768 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1769 name = name.translate(c_name_trans)
1770 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1771 | cpp_words | polluted_words):
1775 eatspace = '\033EATSPACE.'
1776 pointer_suffix = ' *' + eatspace
1779 def genindent(count):
1781 for _ in range(count):
1788 def push_indent(indent_amount=4):
1790 indent_level += indent_amount
1793 def pop_indent(indent_amount=4):
1795 indent_level -= indent_amount
1798 # Generate @code with @kwds interpolated.
1799 # Obey indent_level, and strip eatspace.
1800 def cgen(code, **kwds):
1803 indent = genindent(indent_level)
1804 # re.subn() lacks flags support before Python 2.7, use re.compile()
1805 raw = re.subn(re.compile(r'^.', re.MULTILINE),
1806 indent + r'\g<0>', raw)
1808 return re.sub(re.escape(eatspace) + r' *', '', raw)
1811 def mcgen(code, **kwds):
1814 return cgen(code, **kwds)
1817 def guardname(filename):
1818 return c_name(filename, protect=False).upper()
1821 def guardstart(name):
1828 name=guardname(name))
1834 #endif /* %(name)s */
1837 name=guardname(name))
1840 def gen_enum_lookup(name, values, prefix=None):
1843 const QEnumLookup %(c_name)s_lookup = {
1844 .array = (const char *const[]) {
1846 c_name=c_name(name))
1847 for value in values:
1848 index = c_enum_const(name, value, prefix)
1850 [%(index)s] = "%(value)s",
1852 index=index, value=value)
1856 .size = %(max_index)s
1859 max_index=c_enum_const(name, '_MAX', prefix))
1863 def gen_enum(name, values, prefix=None):
1864 # append automatically generated _MAX value
1865 enum_values = values + ['_MAX']
1869 typedef enum %(c_name)s {
1871 c_name=c_name(name))
1874 for value in enum_values:
1878 c_enum=c_enum_const(name, value, prefix),
1885 c_name=c_name(name))
1889 #define %(c_name)s_str(val) \\
1890 qapi_enum_lookup(&%(c_name)s_lookup, (val))
1892 extern const QEnumLookup %(c_name)s_lookup;
1894 c_name=c_name(name))
1898 def build_params(arg_type, boxed, extra):
1905 ret += '%s arg' % arg_type.c_param_type()
1908 assert not arg_type.variants
1909 for memb in arg_type.members:
1913 ret += 'bool has_%s, ' % c_name(memb.name)
1914 ret += '%s %s' % (memb.type.c_param_type(),
1922 # Common command line parsing
1926 def parse_command_line(extra_options='', extra_long_options=[]):
1929 opts, args = getopt.gnu_getopt(sys.argv[1:],
1930 'chp:o:' + extra_options,
1931 ['source', 'header', 'prefix=',
1932 'output-dir='] + extra_long_options)
1933 except getopt.GetoptError as err:
1934 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1945 if o in ('-p', '--prefix'):
1946 match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1947 if match.end() != len(a):
1948 print >>sys.stderr, \
1949 "%s: 'funny character '%s' in argument of --prefix" \
1950 % (sys.argv[0], a[match.end()])
1953 elif o in ('-o', '--output-dir'):
1954 output_dir = a + '/'
1955 elif o in ('-c', '--source'):
1957 elif o in ('-h', '--header'):
1960 extra_opts.append(oa)
1962 if not do_c and not do_h:
1967 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1971 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1974 # Generate output files with boilerplate
1978 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1979 c_comment, h_comment):
1980 guard = guardname(prefix + h_file)
1981 c_file = output_dir + prefix + c_file
1982 h_file = output_dir + prefix + h_file
1986 os.makedirs(output_dir)
1987 except os.error as e:
1988 if e.errno != errno.EEXIST:
1991 def maybe_open(really, name, opt):
1993 return open(name, opt)
1996 return StringIO.StringIO()
1998 fdef = maybe_open(do_c, c_file, 'w')
1999 fdecl = maybe_open(do_h, h_file, 'w')
2001 fdef.write(mcgen('''
2002 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2007 fdecl.write(mcgen('''
2008 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2014 comment=h_comment, guard=guard))
2016 return (fdef, fdecl)
2019 def close_output(fdef, fdecl):