4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2018 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.
14 from __future__ import print_function
20 from collections import OrderedDict
22 from ordereddict import OrderedDict
25 'null': 'QTYPE_QNULL',
26 'str': 'QTYPE_QSTRING',
28 'number': 'QTYPE_QNUM',
29 'bool': 'QTYPE_QBOOL',
31 'int16': 'QTYPE_QNUM',
32 'int32': 'QTYPE_QNUM',
33 'int64': 'QTYPE_QNUM',
34 'uint8': 'QTYPE_QNUM',
35 'uint16': 'QTYPE_QNUM',
36 'uint32': 'QTYPE_QNUM',
37 'uint64': 'QTYPE_QNUM',
39 'any': None, # any QType possible, actually
40 'QType': 'QTYPE_QSTRING',
43 # Are documentation comments required?
46 # Whitelist of commands allowed to return a non-dictionary
47 returns_whitelist = []
49 # Whitelist of entities allowed to violate case conventions
50 name_case_whitelist = []
58 # Parsing the schema into expressions
62 def error_path(parent):
65 res = ('In file included from %s:%d:\n' % (parent['file'],
66 parent['line'])) + res
67 parent = parent['parent']
71 class QAPIError(Exception):
72 def __init__(self, fname, line, col, incl_info, msg):
73 Exception.__init__(self)
81 loc = '%s:%d' % (self.fname, self.line)
82 if self.col is not None:
83 loc += ':%s' % self.col
84 return error_path(self.info) + '%s: %s' % (loc, self.msg)
87 class QAPIParseError(QAPIError):
88 def __init__(self, parser, msg):
90 for ch in parser.src[parser.line_pos:parser.pos]:
92 col = (col + 7) % 8 + 1
95 QAPIError.__init__(self, parser.fname, parser.line, col,
96 parser.incl_info, msg)
99 class QAPISemError(QAPIError):
100 def __init__(self, info, msg):
101 QAPIError.__init__(self, info['file'], info['line'], None,
105 class QAPIDoc(object):
106 class Section(object):
107 def __init__(self, name=None):
108 # optional section name (argument/member or section name)
110 # the list of lines for this section
113 def append(self, line):
114 self.text += line.rstrip() + '\n'
116 class ArgSection(Section):
117 def __init__(self, name):
118 QAPIDoc.Section.__init__(self, name)
121 def connect(self, member):
124 def __init__(self, parser, info):
125 # self._parser is used to report errors with QAPIParseError. The
126 # resulting error position depends on the state of the parser.
127 # It happens to be the beginning of the comment. More or less
128 # servicable, but action at a distance.
129 self._parser = parser
132 self.body = QAPIDoc.Section()
133 # dict mapping parameter name to ArgSection
134 self.args = OrderedDict()
137 # the current section
138 self._section = self.body
140 def has_section(self, name):
141 """Return True if we have a section with this name."""
142 for i in self.sections:
147 def append(self, line):
148 """Parse a comment line and add it to the documentation."""
151 self._append_freeform(line)
155 raise QAPIParseError(self._parser, "Missing space after #")
158 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
159 # recognized, and get silently treated as ordinary text
161 self._append_symbol_line(line)
162 elif not self.body.text and line.startswith('@'):
163 if not line.endswith(':'):
164 raise QAPIParseError(self._parser, "Line should end with :")
165 self.symbol = line[1:-1]
166 # FIXME invalid names other than the empty string aren't flagged
168 raise QAPIParseError(self._parser, "Invalid name")
170 self._append_freeform(line)
172 def end_comment(self):
175 def _append_symbol_line(self, line):
176 name = line.split(' ', 1)[0]
178 if name.startswith('@') and name.endswith(':'):
179 line = line[len(name)+1:]
180 self._start_args_section(name[1:-1])
181 elif name in ('Returns:', 'Since:',
182 # those are often singular or plural
184 'Example:', 'Examples:',
186 line = line[len(name)+1:]
187 self._start_section(name[:-1])
189 self._append_freeform(line)
191 def _start_args_section(self, name):
192 # FIXME invalid names other than the empty string aren't flagged
194 raise QAPIParseError(self._parser, "Invalid parameter name")
195 if name in self.args:
196 raise QAPIParseError(self._parser,
197 "'%s' parameter name duplicated" % name)
199 raise QAPIParseError(self._parser,
200 "'@%s:' can't follow '%s' section"
201 % (name, self.sections[0].name))
203 self._section = QAPIDoc.ArgSection(name)
204 self.args[name] = self._section
206 def _start_section(self, name=None):
207 if name in ('Returns', 'Since') and self.has_section(name):
208 raise QAPIParseError(self._parser,
209 "Duplicated '%s' section" % name)
211 self._section = QAPIDoc.Section(name)
212 self.sections.append(self._section)
214 def _end_section(self):
216 text = self._section.text = self._section.text.strip()
217 if self._section.name and (not text or text.isspace()):
218 raise QAPIParseError(self._parser, "Empty doc section '%s'"
219 % self._section.name)
222 def _append_freeform(self, line):
223 in_arg = isinstance(self._section, QAPIDoc.ArgSection)
224 if (in_arg and self._section.text.endswith('\n\n')
225 and line and not line[0].isspace()):
226 self._start_section()
227 if (in_arg or not self._section.name
228 or not self._section.name.startswith('Example')):
230 match = re.match(r'(@\S+:)', line)
232 raise QAPIParseError(self._parser,
233 "'%s' not allowed in free-form documentation"
235 self._section.append(line)
237 def connect_member(self, member):
238 if member.name not in self.args:
239 # Undocumented TODO outlaw
240 self.args[member.name] = QAPIDoc.ArgSection(member.name)
241 self.args[member.name].connect(member)
243 def check_expr(self, expr):
244 if self.has_section('Returns') and 'command' not in expr:
245 raise QAPISemError(self.info,
246 "'Returns:' is only valid for commands")
249 bogus = [name for name, section in self.args.items()
250 if not section.member]
254 "The following documented members are not in "
255 "the declaration: %s" % ", ".join(bogus))
258 class QAPISchemaParser(object):
260 def __init__(self, fp, previously_included=[], incl_info=None):
262 previously_included.append(os.path.abspath(fp.name))
263 self.incl_info = incl_info
265 if self.src == '' or self.src[-1] != '\n':
275 while self.tok is not None:
276 info = {'file': self.fname, 'line': self.line,
277 'parent': self.incl_info}
279 self.reject_expr_doc(cur_doc)
280 cur_doc = self.get_doc(info)
281 self.docs.append(cur_doc)
284 expr = self.get_expr(False)
285 if 'include' in expr:
286 self.reject_expr_doc(cur_doc)
288 raise QAPISemError(info, "Invalid 'include' directive")
289 include = expr['include']
290 if not isinstance(include, str):
291 raise QAPISemError(info,
292 "Value of 'include' must be a string")
293 incl_fname = os.path.join(os.path.dirname(self.fname),
295 self.exprs.append({'expr': {'include': incl_fname},
297 exprs_include = self._include(include, info, incl_fname,
300 self.exprs.extend(exprs_include.exprs)
301 self.docs.extend(exprs_include.docs)
302 elif "pragma" in expr:
303 self.reject_expr_doc(cur_doc)
305 raise QAPISemError(info, "Invalid 'pragma' directive")
306 pragma = expr['pragma']
307 if not isinstance(pragma, dict):
309 info, "Value of 'pragma' must be a dictionary")
310 for name, value in pragma.items():
311 self._pragma(name, value, info)
313 expr_elem = {'expr': expr,
316 if not cur_doc.symbol:
318 cur_doc.info, "Expression documentation required")
319 expr_elem['doc'] = cur_doc
320 self.exprs.append(expr_elem)
322 self.reject_expr_doc(cur_doc)
325 def reject_expr_doc(doc):
326 if doc and doc.symbol:
329 "Documentation for '%s' is not followed by the definition"
332 def _include(self, include, info, incl_fname, previously_included):
333 incl_abs_fname = os.path.abspath(incl_fname)
334 # catch inclusion cycle
337 if incl_abs_fname == os.path.abspath(inf['file']):
338 raise QAPISemError(info, "Inclusion loop for %s" % include)
341 # skip multiple include of the same file
342 if incl_abs_fname in previously_included:
346 fobj = open(incl_fname, 'r')
348 raise QAPISemError(info, '%s: %s' % (e.strerror, incl_fname))
349 return QAPISchemaParser(fobj, previously_included, info)
351 def _pragma(self, name, value, info):
352 global doc_required, returns_whitelist, name_case_whitelist
353 if name == 'doc-required':
354 if not isinstance(value, bool):
355 raise QAPISemError(info,
356 "Pragma 'doc-required' must be boolean")
358 elif name == 'returns-whitelist':
359 if (not isinstance(value, list)
360 or any([not isinstance(elt, str) for elt in value])):
361 raise QAPISemError(info,
362 "Pragma returns-whitelist must be"
363 " a list of strings")
364 returns_whitelist = value
365 elif name == 'name-case-whitelist':
366 if (not isinstance(value, list)
367 or any([not isinstance(elt, str) for elt in value])):
368 raise QAPISemError(info,
369 "Pragma name-case-whitelist must be"
370 " a list of strings")
371 name_case_whitelist = value
373 raise QAPISemError(info, "Unknown pragma '%s'" % name)
375 def accept(self, skip_comment=True):
377 self.tok = self.src[self.cursor]
378 self.pos = self.cursor
383 if self.src[self.cursor] == '#':
384 # Start of doc comment
386 self.cursor = self.src.find('\n', self.cursor)
388 self.val = self.src[self.pos:self.cursor]
390 elif self.tok in '{}:,[]':
392 elif self.tok == "'":
396 ch = self.src[self.cursor]
399 raise QAPIParseError(self, 'Missing terminating "\'"')
413 for _ in range(0, 4):
414 ch = self.src[self.cursor]
416 if ch not in '0123456789abcdefABCDEF':
417 raise QAPIParseError(self,
418 '\\u escape needs 4 '
420 value = (value << 4) + int(ch, 16)
421 # If Python 2 and 3 didn't disagree so much on
422 # how to handle Unicode, then we could allow
423 # Unicode string defaults. But most of QAPI is
424 # ASCII-only, so we aren't losing much for now.
425 if not value or value > 0x7f:
426 raise QAPIParseError(self,
427 'For now, \\u escape '
428 'only supports non-zero '
429 'values up to \\u007f')
434 raise QAPIParseError(self,
435 "Unknown escape \\%s" % ch)
444 elif self.src.startswith('true', self.pos):
448 elif self.src.startswith('false', self.pos):
452 elif self.src.startswith('null', self.pos):
456 elif self.tok == '\n':
457 if self.cursor == len(self.src):
461 self.line_pos = self.cursor
462 elif not self.tok.isspace():
463 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
465 def get_members(self):
471 raise QAPIParseError(self, 'Expected string or "}"')
476 raise QAPIParseError(self, 'Expected ":"')
479 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
480 expr[key] = self.get_expr(True)
485 raise QAPIParseError(self, 'Expected "," or "}"')
488 raise QAPIParseError(self, 'Expected string')
490 def get_values(self):
495 if self.tok not in "{['tfn":
496 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
499 expr.append(self.get_expr(True))
504 raise QAPIParseError(self, 'Expected "," or "]"')
507 def get_expr(self, nested):
508 if self.tok != '{' and not nested:
509 raise QAPIParseError(self, 'Expected "{"')
512 expr = self.get_members()
513 elif self.tok == '[':
515 expr = self.get_values()
516 elif self.tok in "'tfn":
520 raise QAPIParseError(self, 'Expected "{", "[", string, '
524 def get_doc(self, info):
526 raise QAPIParseError(self, "Junk after '##' at start of "
527 "documentation comment")
529 doc = QAPIDoc(self, info)
531 while self.tok == '#':
532 if self.val.startswith('##'):
535 raise QAPIParseError(self, "Junk after '##' at end of "
536 "documentation comment")
544 raise QAPIParseError(self, "Documentation comment must end with '##'")
548 # Semantic analysis of schema expressions
549 # TODO fold into QAPISchema
550 # TODO catching name collisions in generated code would be nice
554 def find_base_members(base):
555 if isinstance(base, dict):
557 base_struct_define = struct_types.get(base)
558 if not base_struct_define:
560 return base_struct_define['data']
563 # Return the qtype of an alternate branch, or None on error.
564 def find_alternate_member_qtype(qapi_type):
565 if qapi_type in builtin_types:
566 return builtin_types[qapi_type]
567 elif qapi_type in struct_types:
569 elif qapi_type in enum_types:
570 return 'QTYPE_QSTRING'
571 elif qapi_type in union_types:
576 # Return the discriminator enum define if discriminator is specified as an
577 # enum type, otherwise return None.
578 def discriminator_find_enum_define(expr):
579 base = expr.get('base')
580 discriminator = expr.get('discriminator')
582 if not (discriminator and base):
585 base_members = find_base_members(base)
589 discriminator_type = base_members.get(discriminator)
590 if not discriminator_type:
593 return enum_types.get(discriminator_type)
596 # Names must be letters, numbers, -, and _. They must start with letter,
597 # except for downstream extensions which must start with __RFQDN_.
598 # Dots are only valid in the downstream extension prefix.
599 valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
600 '[a-zA-Z][a-zA-Z0-9_-]*$')
603 def check_name(info, source, name, allow_optional=False,
608 if not isinstance(name, str):
609 raise QAPISemError(info, "%s requires a string name" % source)
610 if name.startswith('*'):
611 membername = name[1:]
612 if not allow_optional:
613 raise QAPISemError(info, "%s does not allow optional name '%s'"
615 # Enum members can start with a digit, because the generated C
616 # code always prefixes it with the enum name
617 if enum_member and membername[0].isdigit():
618 membername = 'D' + membername
619 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
620 # and 'q_obj_*' implicit type names.
621 if not valid_name.match(membername) or \
622 c_name(membername, False).startswith('q_'):
623 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
626 def add_name(name, info, meta, implicit=False):
628 check_name(info, "'%s'" % meta, name)
629 # FIXME should reject names that differ only in '_' vs. '.'
630 # vs. '-', because they're liable to clash in generated C.
631 if name in all_names:
632 raise QAPISemError(info, "%s '%s' is already defined"
633 % (all_names[name], name))
634 if not implicit and (name.endswith('Kind') or name.endswith('List')):
635 raise QAPISemError(info, "%s '%s' should not end in '%s'"
636 % (meta, name, name[-4:]))
637 all_names[name] = meta
640 def check_type(info, source, value, allow_array=False,
641 allow_dict=False, allow_optional=False,
648 # Check if array type for value is okay
649 if isinstance(value, list):
651 raise QAPISemError(info, "%s cannot be an array" % source)
652 if len(value) != 1 or not isinstance(value[0], str):
653 raise QAPISemError(info,
654 "%s: array type must contain single type name" %
658 # Check if type name for value is okay
659 if isinstance(value, str):
660 if value not in all_names:
661 raise QAPISemError(info, "%s uses unknown type '%s'"
663 if not all_names[value] in allow_metas:
664 raise QAPISemError(info, "%s cannot use %s type '%s'" %
665 (source, all_names[value], value))
669 raise QAPISemError(info, "%s should be a type name" % source)
671 if not isinstance(value, OrderedDict):
672 raise QAPISemError(info,
673 "%s should be a dictionary or type name" % source)
675 # value is a dictionary, check that each member is okay
676 for (key, arg) in value.items():
677 check_name(info, "Member of %s" % source, key,
678 allow_optional=allow_optional)
679 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
680 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
682 # Todo: allow dictionaries to represent default values of
683 # an optional argument.
684 check_type(info, "Member '%s' of %s" % (key, source), arg,
686 allow_metas=['built-in', 'union', 'alternate', 'struct',
690 def check_command(expr, info):
691 name = expr['command']
692 boxed = expr.get('boxed', False)
694 args_meta = ['struct']
696 args_meta += ['union', 'alternate']
697 check_type(info, "'data' for command '%s'" % name,
698 expr.get('data'), allow_dict=not boxed, allow_optional=True,
699 allow_metas=args_meta)
700 returns_meta = ['union', 'struct']
701 if name in returns_whitelist:
702 returns_meta += ['built-in', 'alternate', 'enum']
703 check_type(info, "'returns' for command '%s'" % name,
704 expr.get('returns'), allow_array=True,
705 allow_optional=True, allow_metas=returns_meta)
708 def check_event(expr, info):
710 boxed = expr.get('boxed', False)
714 meta += ['union', 'alternate']
715 check_type(info, "'data' for event '%s'" % name,
716 expr.get('data'), allow_dict=not boxed, allow_optional=True,
720 def check_union(expr, info):
722 base = expr.get('base')
723 discriminator = expr.get('discriminator')
724 members = expr['data']
726 # Two types of unions, determined by discriminator.
728 # With no discriminator it is a simple union.
729 if discriminator is None:
731 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
733 raise QAPISemError(info, "Simple union '%s' must not have a base" %
736 # Else, it's a flat union.
738 # The object must have a string or dictionary 'base'.
739 check_type(info, "'base' for union '%s'" % name,
740 base, allow_dict=True, allow_optional=True,
741 allow_metas=['struct'])
743 raise QAPISemError(info, "Flat union '%s' must have a base"
745 base_members = find_base_members(base)
746 assert base_members is not None
748 # The value of member 'discriminator' must name a non-optional
749 # member of the base struct.
750 check_name(info, "Discriminator of flat union '%s'" % name,
752 discriminator_type = base_members.get(discriminator)
753 if not discriminator_type:
754 raise QAPISemError(info,
755 "Discriminator '%s' is not a member of base "
757 % (discriminator, base))
758 enum_define = enum_types.get(discriminator_type)
759 allow_metas = ['struct']
760 # Do not allow string discriminator
762 raise QAPISemError(info,
763 "Discriminator '%s' must be of enumeration "
764 "type" % discriminator)
766 # Check every branch; don't allow an empty union
767 if len(members) == 0:
768 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
769 for (key, value) in members.items():
770 check_name(info, "Member of union '%s'" % name, key)
772 # Each value must name a known type
773 check_type(info, "Member '%s' of union '%s'" % (key, name),
774 value, allow_array=not base, allow_metas=allow_metas)
776 # If the discriminator names an enum type, then all members
777 # of 'data' must also be members of the enum type.
779 if key not in enum_define['data']:
780 raise QAPISemError(info,
781 "Discriminator value '%s' is not found in "
783 % (key, enum_define['enum']))
785 # If discriminator is user-defined, ensure all values are covered
787 for value in enum_define['data']:
788 if value not in members.keys():
789 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
793 def check_alternate(expr, info):
794 name = expr['alternate']
795 members = expr['data']
798 # Check every branch; require at least two branches
800 raise QAPISemError(info,
801 "Alternate '%s' should have at least two branches "
803 for (key, value) in members.items():
804 check_name(info, "Member of alternate '%s'" % name, key)
806 # Ensure alternates have no type conflicts.
807 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
809 allow_metas=['built-in', 'union', 'struct', 'enum'])
810 qtype = find_alternate_member_qtype(value)
812 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
813 "type '%s'" % (name, key, value))
814 conflicting = set([qtype])
815 if qtype == 'QTYPE_QSTRING':
816 enum_expr = enum_types.get(value)
818 for v in enum_expr['data']:
819 if v in ['on', 'off']:
820 conflicting.add('QTYPE_QBOOL')
821 if re.match(r'[-+0-9.]', v): # lazy, could be tightened
822 conflicting.add('QTYPE_QNUM')
824 conflicting.add('QTYPE_QNUM')
825 conflicting.add('QTYPE_QBOOL')
826 for qt in conflicting:
828 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
829 "be distinguished from member '%s'"
830 % (name, key, types_seen[qt]))
834 def check_enum(expr, info):
836 members = expr.get('data')
837 prefix = expr.get('prefix')
839 if not isinstance(members, list):
840 raise QAPISemError(info,
841 "Enum '%s' requires an array for 'data'" % name)
842 if prefix is not None and not isinstance(prefix, str):
843 raise QAPISemError(info,
844 "Enum '%s' requires a string for 'prefix'" % name)
845 for member in members:
846 check_name(info, "Member of enum '%s'" % name, member,
850 def check_struct(expr, info):
851 name = expr['struct']
852 members = expr['data']
854 check_type(info, "'data' for struct '%s'" % name, members,
855 allow_dict=True, allow_optional=True)
856 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
857 allow_metas=['struct'])
860 def check_keys(expr_elem, meta, required, optional=[]):
861 expr = expr_elem['expr']
862 info = expr_elem['info']
864 if not isinstance(name, str):
865 raise QAPISemError(info, "'%s' key must have a string value" % meta)
866 required = required + [meta]
867 for (key, value) in expr.items():
868 if key not in required and key not in optional:
869 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
871 if (key == 'gen' or key == 'success-response') and value is not False:
872 raise QAPISemError(info,
873 "'%s' of %s '%s' should only use false value"
875 if key == 'boxed' and value is not True:
876 raise QAPISemError(info,
877 "'%s' of %s '%s' should only use true value"
881 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
885 def check_exprs(exprs):
888 # Populate name table with names of built-in types
889 for builtin in builtin_types.keys():
890 all_names[builtin] = 'built-in'
892 # Learn the types and check for valid expression keys
893 for expr_elem in exprs:
894 expr = expr_elem['expr']
895 info = expr_elem['info']
896 doc = expr_elem.get('doc')
898 if 'include' in expr:
901 if not doc and doc_required:
902 raise QAPISemError(info,
903 "Expression missing documentation comment")
907 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
908 enum_types[expr[meta]] = expr
909 elif 'union' in expr:
911 check_keys(expr_elem, 'union', ['data'],
912 ['base', 'discriminator'])
913 union_types[expr[meta]] = expr
914 elif 'alternate' in expr:
916 check_keys(expr_elem, 'alternate', ['data'])
917 elif 'struct' in expr:
919 check_keys(expr_elem, 'struct', ['data'], ['base'])
920 struct_types[expr[meta]] = expr
921 elif 'command' in expr:
923 check_keys(expr_elem, 'command', [],
924 ['data', 'returns', 'gen', 'success-response', 'boxed'])
925 elif 'event' in expr:
927 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
929 raise QAPISemError(expr_elem['info'],
930 "Expression is missing metatype")
932 add_name(name, info, meta)
933 if doc and doc.symbol != name:
934 raise QAPISemError(info, "Definition of '%s' follows documentation"
935 " for '%s'" % (name, doc.symbol))
937 # Try again for hidden UnionKind enum
938 for expr_elem in exprs:
939 expr = expr_elem['expr']
941 if 'include' in expr:
943 if 'union' in expr and not discriminator_find_enum_define(expr):
944 name = '%sKind' % expr['union']
945 elif 'alternate' in expr:
946 name = '%sKind' % expr['alternate']
949 enum_types[name] = {'enum': name}
950 add_name(name, info, 'enum', implicit=True)
952 # Validate that exprs make sense
953 for expr_elem in exprs:
954 expr = expr_elem['expr']
955 info = expr_elem['info']
956 doc = expr_elem.get('doc')
958 if 'include' in expr:
961 check_enum(expr, info)
962 elif 'union' in expr:
963 check_union(expr, info)
964 elif 'alternate' in expr:
965 check_alternate(expr, info)
966 elif 'struct' in expr:
967 check_struct(expr, info)
968 elif 'command' in expr:
969 check_command(expr, info)
970 elif 'event' in expr:
971 check_event(expr, info)
973 assert False, 'unexpected meta type'
982 # Schema compiler frontend
985 class QAPISchemaEntity(object):
986 def __init__(self, name, info, doc):
987 assert isinstance(name, str)
989 # For explicitly defined entities, info points to the (explicit)
990 # definition. For builtins (and their arrays), info is None.
991 # For implicitly defined entities, info points to a place that
992 # triggered the implicit definition (there may be more than one
998 return c_name(self.name)
1000 def check(self, schema):
1003 def is_implicit(self):
1004 return not self.info
1006 def visit(self, visitor):
1010 class QAPISchemaVisitor(object):
1011 def visit_begin(self, schema):
1014 def visit_end(self):
1017 def visit_needed(self, entity):
1018 # Default to visiting everything
1021 def visit_builtin_type(self, name, info, json_type):
1024 def visit_enum_type(self, name, info, values, prefix):
1027 def visit_array_type(self, name, info, element_type):
1030 def visit_object_type(self, name, info, base, members, variants):
1033 def visit_object_type_flat(self, name, info, members, variants):
1036 def visit_alternate_type(self, name, info, variants):
1039 def visit_command(self, name, info, arg_type, ret_type,
1040 gen, success_response, boxed):
1043 def visit_event(self, name, info, arg_type, boxed):
1047 class QAPISchemaType(QAPISchemaEntity):
1048 # Return the C type for common use.
1049 # For the types we commonly box, this is a pointer type.
1053 # Return the C type to be used in a parameter list.
1054 def c_param_type(self):
1055 return self.c_type()
1057 # Return the C type to be used where we suppress boxing.
1058 def c_unboxed_type(self):
1059 return self.c_type()
1061 def json_type(self):
1064 def alternate_qtype(self):
1066 'null': 'QTYPE_QNULL',
1067 'string': 'QTYPE_QSTRING',
1068 'number': 'QTYPE_QNUM',
1069 'int': 'QTYPE_QNUM',
1070 'boolean': 'QTYPE_QBOOL',
1071 'object': 'QTYPE_QDICT'
1073 return json2qtype.get(self.json_type())
1076 if self.is_implicit():
1081 class QAPISchemaBuiltinType(QAPISchemaType):
1082 def __init__(self, name, json_type, c_type):
1083 QAPISchemaType.__init__(self, name, None, None)
1084 assert not c_type or isinstance(c_type, str)
1085 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1087 self._json_type_name = json_type
1088 self._c_type_name = c_type
1094 return self._c_type_name
1096 def c_param_type(self):
1097 if self.name == 'str':
1098 return 'const ' + self._c_type_name
1099 return self._c_type_name
1101 def json_type(self):
1102 return self._json_type_name
1105 return self.json_type()
1107 def visit(self, visitor):
1108 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1111 class QAPISchemaEnumType(QAPISchemaType):
1112 def __init__(self, name, info, doc, values, prefix):
1113 QAPISchemaType.__init__(self, name, info, doc)
1115 assert isinstance(v, QAPISchemaMember)
1117 assert prefix is None or isinstance(prefix, str)
1118 self.values = values
1119 self.prefix = prefix
1121 def check(self, schema):
1123 for v in self.values:
1124 v.check_clash(self.info, seen)
1126 self.doc.connect_member(v)
1128 def is_implicit(self):
1129 # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1130 return self.name.endswith('Kind') or self.name == 'QType'
1133 return c_name(self.name)
1135 def member_names(self):
1136 return [v.name for v in self.values]
1138 def json_type(self):
1141 def visit(self, visitor):
1142 visitor.visit_enum_type(self.name, self.info,
1143 self.member_names(), self.prefix)
1146 class QAPISchemaArrayType(QAPISchemaType):
1147 def __init__(self, name, info, element_type):
1148 QAPISchemaType.__init__(self, name, info, None)
1149 assert isinstance(element_type, str)
1150 self._element_type_name = element_type
1151 self.element_type = None
1153 def check(self, schema):
1154 self.element_type = schema.lookup_type(self._element_type_name)
1155 assert self.element_type
1157 def is_implicit(self):
1161 return c_name(self.name) + pointer_suffix
1163 def json_type(self):
1167 elt_doc_type = self.element_type.doc_type()
1168 if not elt_doc_type:
1170 return 'array of ' + elt_doc_type
1172 def visit(self, visitor):
1173 visitor.visit_array_type(self.name, self.info, self.element_type)
1176 class QAPISchemaObjectType(QAPISchemaType):
1177 def __init__(self, name, info, doc, base, local_members, variants):
1178 # struct has local_members, optional base, and no variants
1179 # flat union has base, variants, and no local_members
1180 # simple union has local_members, variants, and no base
1181 QAPISchemaType.__init__(self, name, info, doc)
1182 assert base is None or isinstance(base, str)
1183 for m in local_members:
1184 assert isinstance(m, QAPISchemaObjectTypeMember)
1186 if variants is not None:
1187 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1188 variants.set_owner(name)
1189 self._base_name = base
1191 self.local_members = local_members
1192 self.variants = variants
1195 def check(self, schema):
1196 if self.members is False: # check for cycles
1197 raise QAPISemError(self.info,
1198 "Object %s contains itself" % self.name)
1201 self.members = False # mark as being checked
1202 seen = OrderedDict()
1204 self.base = schema.lookup_type(self._base_name)
1205 assert isinstance(self.base, QAPISchemaObjectType)
1206 self.base.check(schema)
1207 self.base.check_clash(self.info, seen)
1208 for m in self.local_members:
1210 m.check_clash(self.info, seen)
1212 self.doc.connect_member(m)
1213 self.members = seen.values()
1215 self.variants.check(schema, seen)
1216 assert self.variants.tag_member in self.members
1217 self.variants.check_clash(self.info, seen)
1221 # Check that the members of this type do not cause duplicate JSON members,
1222 # and update seen to track the members seen so far. Report any errors
1223 # on behalf of info, which is not necessarily self.info
1224 def check_clash(self, info, seen):
1225 assert not self.variants # not implemented
1226 for m in self.members:
1227 m.check_clash(info, seen)
1229 def is_implicit(self):
1230 # See QAPISchema._make_implicit_object_type(), as well as
1231 # _def_predefineds()
1232 return self.name.startswith('q_')
1235 assert self.members is not None
1236 return not self.members and not self.variants
1239 assert self.name != 'q_empty'
1240 return QAPISchemaType.c_name(self)
1243 assert not self.is_implicit()
1244 return c_name(self.name) + pointer_suffix
1246 def c_unboxed_type(self):
1247 return c_name(self.name)
1249 def json_type(self):
1252 def visit(self, visitor):
1253 visitor.visit_object_type(self.name, self.info,
1254 self.base, self.local_members, self.variants)
1255 visitor.visit_object_type_flat(self.name, self.info,
1256 self.members, self.variants)
1259 class QAPISchemaMember(object):
1262 def __init__(self, name):
1263 assert isinstance(name, str)
1267 def set_owner(self, name):
1268 assert not self.owner
1271 def check_clash(self, info, seen):
1272 cname = c_name(self.name)
1273 if cname.lower() != cname and self.owner not in name_case_whitelist:
1274 raise QAPISemError(info,
1275 "%s should not use uppercase" % self.describe())
1277 raise QAPISemError(info, "%s collides with %s" %
1278 (self.describe(), seen[cname].describe()))
1281 def _pretty_owner(self):
1283 if owner.startswith('q_obj_'):
1284 # See QAPISchema._make_implicit_object_type() - reverse the
1285 # mapping there to create a nice human-readable description
1287 if owner.endswith('-arg'):
1288 return '(parameter of %s)' % owner[:-4]
1289 elif owner.endswith('-base'):
1290 return '(base of %s)' % owner[:-5]
1292 assert owner.endswith('-wrapper')
1293 # Unreachable and not implemented
1295 if owner.endswith('Kind'):
1296 # See QAPISchema._make_implicit_enum_type()
1297 return '(branch of %s)' % owner[:-4]
1298 return '(%s of %s)' % (self.role, owner)
1301 return "'%s' %s" % (self.name, self._pretty_owner())
1304 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1305 def __init__(self, name, typ, optional):
1306 QAPISchemaMember.__init__(self, name)
1307 assert isinstance(typ, str)
1308 assert isinstance(optional, bool)
1309 self._type_name = typ
1311 self.optional = optional
1313 def check(self, schema):
1315 self.type = schema.lookup_type(self._type_name)
1319 class QAPISchemaObjectTypeVariants(object):
1320 def __init__(self, tag_name, tag_member, variants):
1321 # Flat unions pass tag_name but not tag_member.
1322 # Simple unions and alternates pass tag_member but not tag_name.
1323 # After check(), tag_member is always set, and tag_name remains
1324 # a reliable witness of being used by a flat union.
1325 assert bool(tag_member) != bool(tag_name)
1326 assert (isinstance(tag_name, str) or
1327 isinstance(tag_member, QAPISchemaObjectTypeMember))
1328 assert len(variants) > 0
1330 assert isinstance(v, QAPISchemaObjectTypeVariant)
1331 self._tag_name = tag_name
1332 self.tag_member = tag_member
1333 self.variants = variants
1335 def set_owner(self, name):
1336 for v in self.variants:
1339 def check(self, schema, seen):
1340 if not self.tag_member: # flat union
1341 self.tag_member = seen[c_name(self._tag_name)]
1342 assert self._tag_name == self.tag_member.name
1343 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1344 for v in self.variants:
1346 # Union names must match enum values; alternate names are
1347 # checked separately. Use 'seen' to tell the two apart.
1349 assert v.name in self.tag_member.type.member_names()
1350 assert isinstance(v.type, QAPISchemaObjectType)
1351 v.type.check(schema)
1353 def check_clash(self, info, seen):
1354 for v in self.variants:
1355 # Reset seen map for each variant, since qapi names from one
1356 # branch do not affect another branch
1357 assert isinstance(v.type, QAPISchemaObjectType)
1358 v.type.check_clash(info, dict(seen))
1361 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1364 def __init__(self, name, typ):
1365 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1368 class QAPISchemaAlternateType(QAPISchemaType):
1369 def __init__(self, name, info, doc, variants):
1370 QAPISchemaType.__init__(self, name, info, doc)
1371 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1372 assert variants.tag_member
1373 variants.set_owner(name)
1374 variants.tag_member.set_owner(self.name)
1375 self.variants = variants
1377 def check(self, schema):
1378 self.variants.tag_member.check(schema)
1379 # Not calling self.variants.check_clash(), because there's nothing
1381 self.variants.check(schema, {})
1382 # Alternate branch names have no relation to the tag enum values;
1383 # so we have to check for potential name collisions ourselves.
1385 for v in self.variants.variants:
1386 v.check_clash(self.info, seen)
1388 self.doc.connect_member(v)
1393 return c_name(self.name) + pointer_suffix
1395 def json_type(self):
1398 def visit(self, visitor):
1399 visitor.visit_alternate_type(self.name, self.info, self.variants)
1405 class QAPISchemaCommand(QAPISchemaEntity):
1406 def __init__(self, name, info, doc, arg_type, ret_type,
1407 gen, success_response, boxed):
1408 QAPISchemaEntity.__init__(self, name, info, doc)
1409 assert not arg_type or isinstance(arg_type, str)
1410 assert not ret_type or isinstance(ret_type, str)
1411 self._arg_type_name = arg_type
1412 self.arg_type = None
1413 self._ret_type_name = ret_type
1414 self.ret_type = None
1416 self.success_response = success_response
1419 def check(self, schema):
1420 if self._arg_type_name:
1421 self.arg_type = schema.lookup_type(self._arg_type_name)
1422 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1423 isinstance(self.arg_type, QAPISchemaAlternateType))
1424 self.arg_type.check(schema)
1426 if self.arg_type.is_empty():
1427 raise QAPISemError(self.info,
1428 "Cannot use 'boxed' with empty type")
1430 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1431 assert not self.arg_type.variants
1433 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1434 if self._ret_type_name:
1435 self.ret_type = schema.lookup_type(self._ret_type_name)
1436 assert isinstance(self.ret_type, QAPISchemaType)
1438 def visit(self, visitor):
1439 visitor.visit_command(self.name, self.info,
1440 self.arg_type, self.ret_type,
1441 self.gen, self.success_response, self.boxed)
1444 class QAPISchemaEvent(QAPISchemaEntity):
1445 def __init__(self, name, info, doc, arg_type, boxed):
1446 QAPISchemaEntity.__init__(self, name, info, doc)
1447 assert not arg_type or isinstance(arg_type, str)
1448 self._arg_type_name = arg_type
1449 self.arg_type = None
1452 def check(self, schema):
1453 if self._arg_type_name:
1454 self.arg_type = schema.lookup_type(self._arg_type_name)
1455 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1456 isinstance(self.arg_type, QAPISchemaAlternateType))
1457 self.arg_type.check(schema)
1459 if self.arg_type.is_empty():
1460 raise QAPISemError(self.info,
1461 "Cannot use 'boxed' with empty type")
1463 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1464 assert not self.arg_type.variants
1466 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1468 def visit(self, visitor):
1469 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
1472 class QAPISchema(object):
1473 def __init__(self, fname):
1474 parser = QAPISchemaParser(open(fname, 'r'))
1475 exprs = check_exprs(parser.exprs)
1476 self.docs = parser.docs
1477 self._entity_dict = {}
1478 self._predefining = True
1479 self._def_predefineds()
1480 self._predefining = False
1481 self._def_exprs(exprs)
1484 def _def_entity(self, ent):
1485 # Only the predefined types are allowed to not have info
1486 assert ent.info or self._predefining
1487 assert ent.name not in self._entity_dict
1488 self._entity_dict[ent.name] = ent
1490 def lookup_entity(self, name, typ=None):
1491 ent = self._entity_dict.get(name)
1492 if typ and not isinstance(ent, typ):
1496 def lookup_type(self, name):
1497 return self.lookup_entity(name, QAPISchemaType)
1499 def _def_builtin_type(self, name, json_type, c_type):
1500 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1501 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1502 # qapi-types.h from a single .c, all arrays of builtins must be
1503 # declared in the first file whether or not they are used. Nicer
1504 # would be to use lazy instantiation, while figuring out how to
1505 # avoid compilation issues with multiple qapi-types.h.
1506 self._make_array_type(name, None)
1508 def _def_predefineds(self):
1509 for t in [('str', 'string', 'char' + pointer_suffix),
1510 ('number', 'number', 'double'),
1511 ('int', 'int', 'int64_t'),
1512 ('int8', 'int', 'int8_t'),
1513 ('int16', 'int', 'int16_t'),
1514 ('int32', 'int', 'int32_t'),
1515 ('int64', 'int', 'int64_t'),
1516 ('uint8', 'int', 'uint8_t'),
1517 ('uint16', 'int', 'uint16_t'),
1518 ('uint32', 'int', 'uint32_t'),
1519 ('uint64', 'int', 'uint64_t'),
1520 ('size', 'int', 'uint64_t'),
1521 ('bool', 'boolean', 'bool'),
1522 ('any', 'value', 'QObject' + pointer_suffix),
1523 ('null', 'null', 'QNull' + pointer_suffix)]:
1524 self._def_builtin_type(*t)
1525 self.the_empty_object_type = QAPISchemaObjectType(
1526 'q_empty', None, None, None, [], None)
1527 self._def_entity(self.the_empty_object_type)
1528 qtype_values = self._make_enum_members(['none', 'qnull', 'qnum',
1529 'qstring', 'qdict', 'qlist',
1531 self._def_entity(QAPISchemaEnumType('QType', None, None,
1532 qtype_values, 'QTYPE'))
1534 def _make_enum_members(self, values):
1535 return [QAPISchemaMember(v) for v in values]
1537 def _make_implicit_enum_type(self, name, info, values):
1538 # See also QAPISchemaObjectTypeMember._pretty_owner()
1539 name = name + 'Kind' # Use namespace reserved by add_name()
1540 self._def_entity(QAPISchemaEnumType(
1541 name, info, None, self._make_enum_members(values), None))
1544 def _make_array_type(self, element_type, info):
1545 name = element_type + 'List' # Use namespace reserved by add_name()
1546 if not self.lookup_type(name):
1547 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1550 def _make_implicit_object_type(self, name, info, doc, role, members):
1553 # See also QAPISchemaObjectTypeMember._pretty_owner()
1554 name = 'q_obj_%s-%s' % (name, role)
1555 if not self.lookup_entity(name, QAPISchemaObjectType):
1556 self._def_entity(QAPISchemaObjectType(name, info, doc, None,
1560 def _def_enum_type(self, expr, info, doc):
1563 prefix = expr.get('prefix')
1564 self._def_entity(QAPISchemaEnumType(
1565 name, info, doc, self._make_enum_members(data), prefix))
1567 def _make_member(self, name, typ, info):
1569 if name.startswith('*'):
1572 if isinstance(typ, list):
1573 assert len(typ) == 1
1574 typ = self._make_array_type(typ[0], info)
1575 return QAPISchemaObjectTypeMember(name, typ, optional)
1577 def _make_members(self, data, info):
1578 return [self._make_member(key, value, info)
1579 for (key, value) in data.items()]
1581 def _def_struct_type(self, expr, info, doc):
1582 name = expr['struct']
1583 base = expr.get('base')
1585 self._def_entity(QAPISchemaObjectType(name, info, doc, base,
1586 self._make_members(data, info),
1589 def _make_variant(self, case, typ):
1590 return QAPISchemaObjectTypeVariant(case, typ)
1592 def _make_simple_variant(self, case, typ, info):
1593 if isinstance(typ, list):
1594 assert len(typ) == 1
1595 typ = self._make_array_type(typ[0], info)
1596 typ = self._make_implicit_object_type(
1597 typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
1598 return QAPISchemaObjectTypeVariant(case, typ)
1600 def _def_union_type(self, expr, info, doc):
1601 name = expr['union']
1603 base = expr.get('base')
1604 tag_name = expr.get('discriminator')
1606 if isinstance(base, dict):
1607 base = (self._make_implicit_object_type(
1608 name, info, doc, 'base', self._make_members(base, info)))
1610 variants = [self._make_variant(key, value)
1611 for (key, value) in data.items()]
1614 variants = [self._make_simple_variant(key, value, info)
1615 for (key, value) in data.items()]
1616 typ = self._make_implicit_enum_type(name, info,
1617 [v.name for v in variants])
1618 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1619 members = [tag_member]
1621 QAPISchemaObjectType(name, info, doc, base, members,
1622 QAPISchemaObjectTypeVariants(tag_name,
1626 def _def_alternate_type(self, expr, info, doc):
1627 name = expr['alternate']
1629 variants = [self._make_variant(key, value)
1630 for (key, value) in data.items()]
1631 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1633 QAPISchemaAlternateType(name, info, doc,
1634 QAPISchemaObjectTypeVariants(None,
1638 def _def_command(self, expr, info, doc):
1639 name = expr['command']
1640 data = expr.get('data')
1641 rets = expr.get('returns')
1642 gen = expr.get('gen', True)
1643 success_response = expr.get('success-response', True)
1644 boxed = expr.get('boxed', False)
1645 if isinstance(data, OrderedDict):
1646 data = self._make_implicit_object_type(
1647 name, info, doc, 'arg', self._make_members(data, info))
1648 if isinstance(rets, list):
1649 assert len(rets) == 1
1650 rets = self._make_array_type(rets[0], info)
1651 self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
1652 gen, success_response, boxed))
1654 def _def_event(self, expr, info, doc):
1655 name = expr['event']
1656 data = expr.get('data')
1657 boxed = expr.get('boxed', False)
1658 if isinstance(data, OrderedDict):
1659 data = self._make_implicit_object_type(
1660 name, info, doc, 'arg', self._make_members(data, info))
1661 self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
1663 def _def_exprs(self, exprs):
1664 for expr_elem in exprs:
1665 expr = expr_elem['expr']
1666 info = expr_elem['info']
1667 doc = expr_elem.get('doc')
1669 self._def_enum_type(expr, info, doc)
1670 elif 'struct' in expr:
1671 self._def_struct_type(expr, info, doc)
1672 elif 'union' in expr:
1673 self._def_union_type(expr, info, doc)
1674 elif 'alternate' in expr:
1675 self._def_alternate_type(expr, info, doc)
1676 elif 'command' in expr:
1677 self._def_command(expr, info, doc)
1678 elif 'event' in expr:
1679 self._def_event(expr, info, doc)
1680 elif 'include' in expr:
1686 for (name, ent) in sorted(self._entity_dict.items()):
1689 def visit(self, visitor):
1690 visitor.visit_begin(self)
1691 for (name, entity) in sorted(self._entity_dict.items()):
1692 if visitor.visit_needed(entity):
1693 entity.visit(visitor)
1698 # Code generation helpers
1701 def camel_case(name):
1705 if ch in ['_', '-']:
1708 new_name += ch.upper()
1711 new_name += ch.lower()
1715 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1716 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1717 # ENUM24_Name -> ENUM24_NAME
1718 def camel_to_upper(value):
1719 c_fun_str = c_name(value, False)
1727 # When c is upper and no '_' appears before, do more checks
1728 if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
1729 if i < l - 1 and c_fun_str[i + 1].islower():
1731 elif c_fun_str[i - 1].isdigit():
1734 return new_name.lstrip('_').upper()
1737 def c_enum_const(type_name, const_name, prefix=None):
1738 if prefix is not None:
1740 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1742 if hasattr(str, 'maketrans'):
1743 c_name_trans = str.maketrans('.-', '__')
1745 c_name_trans = string.maketrans('.-', '__')
1748 # Map @name to a valid C identifier.
1749 # If @protect, avoid returning certain ticklish identifiers (like
1750 # C keywords) by prepending 'q_'.
1752 # Used for converting 'name' from a 'name':'type' qapi definition
1753 # into a generated struct member, as well as converting type names
1754 # into substrings of a generated C function name.
1755 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1756 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1757 def c_name(name, protect=True):
1758 # ANSI X3J11/88-090, 3.1.1
1759 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1760 'default', 'do', 'double', 'else', 'enum', 'extern',
1761 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1762 'return', 'short', 'signed', 'sizeof', 'static',
1763 'struct', 'switch', 'typedef', 'union', 'unsigned',
1764 'void', 'volatile', 'while'])
1765 # ISO/IEC 9899:1999, 6.4.1
1766 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1767 # ISO/IEC 9899:2011, 6.4.1
1768 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1769 '_Noreturn', '_Static_assert', '_Thread_local'])
1770 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1772 gcc_words = set(['asm', 'typeof'])
1773 # C++ ISO/IEC 14882:2003 2.11
1774 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1775 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1776 'namespace', 'new', 'operator', 'private', 'protected',
1777 'public', 'reinterpret_cast', 'static_cast', 'template',
1778 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1779 'using', 'virtual', 'wchar_t',
1780 # alternative representations
1781 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1782 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1783 # namespace pollution:
1784 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1785 name = name.translate(c_name_trans)
1786 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1787 | cpp_words | polluted_words):
1791 eatspace = '\033EATSPACE.'
1792 pointer_suffix = ' *' + eatspace
1795 def genindent(count):
1797 for _ in range(count):
1804 def push_indent(indent_amount=4):
1806 indent_level += indent_amount
1809 def pop_indent(indent_amount=4):
1811 indent_level -= indent_amount
1814 # Generate @code with @kwds interpolated.
1815 # Obey indent_level, and strip eatspace.
1816 def cgen(code, **kwds):
1819 indent = genindent(indent_level)
1820 # re.subn() lacks flags support before Python 2.7, use re.compile()
1821 raw = re.subn(re.compile(r'^.', re.MULTILINE),
1822 indent + r'\g<0>', raw)
1824 return re.sub(re.escape(eatspace) + r' *', '', raw)
1827 def mcgen(code, **kwds):
1830 return cgen(code, **kwds)
1833 def guardname(filename):
1834 return c_name(filename, protect=False).upper()
1837 def guardstart(name):
1843 name=guardname(name))
1849 #endif /* %(name)s */
1851 name=guardname(name))
1854 def gen_enum_lookup(name, values, prefix=None):
1857 const QEnumLookup %(c_name)s_lookup = {
1858 .array = (const char *const[]) {
1860 c_name=c_name(name))
1861 for value in values:
1862 index = c_enum_const(name, value, prefix)
1864 [%(index)s] = "%(value)s",
1866 index=index, value=value)
1870 .size = %(max_index)s
1873 max_index=c_enum_const(name, '_MAX', prefix))
1877 def gen_enum(name, values, prefix=None):
1878 # append automatically generated _MAX value
1879 enum_values = values + ['_MAX']
1883 typedef enum %(c_name)s {
1885 c_name=c_name(name))
1888 for value in enum_values:
1892 c_enum=c_enum_const(name, value, prefix),
1899 c_name=c_name(name))
1903 #define %(c_name)s_str(val) \\
1904 qapi_enum_lookup(&%(c_name)s_lookup, (val))
1906 extern const QEnumLookup %(c_name)s_lookup;
1908 c_name=c_name(name))
1912 def build_params(arg_type, boxed, extra):
1919 ret += '%s arg' % arg_type.c_param_type()
1922 assert not arg_type.variants
1923 for memb in arg_type.members:
1927 ret += 'bool has_%s, ' % c_name(memb.name)
1928 ret += '%s %s' % (memb.type.c_param_type(),
1936 # Accumulate and write output
1939 class QAPIGen(object):
1945 def preamble_add(self, text):
1946 self._preamble += text
1948 def add(self, text):
1951 def _top(self, fname):
1954 def _bottom(self, fname):
1957 def write(self, output_dir, fname):
1960 os.makedirs(output_dir)
1961 except os.error as e:
1962 if e.errno != errno.EEXIST:
1964 fd = os.open(os.path.join(output_dir, fname),
1965 os.O_RDWR | os.O_CREAT, 0o666)
1966 f = os.fdopen(fd, 'r+')
1967 text = (self._top(fname) + self._preamble + self._body
1968 + self._bottom(fname))
1969 oldtext = f.read(len(text) + 1)
1977 class QAPIGenC(QAPIGen):
1979 def __init__(self, blurb, pydoc):
1980 QAPIGen.__init__(self)
1982 self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
1985 def _top(self, fname):
1987 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1994 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
1995 * See the COPYING.LIB file in the top-level directory.
1999 blurb=self._blurb, copyright=self._copyright)
2002 class QAPIGenH(QAPIGenC):
2004 def _top(self, fname):
2005 return QAPIGenC._top(self, fname) + guardstart(fname)
2007 def _bottom(self, fname):
2008 return guardend(fname)
2011 class QAPIGenDoc(QAPIGen):
2013 def _top(self, fname):
2014 return (QAPIGen._top(self, fname)
2015 + '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')