]> Git Repo - qemu.git/blob - scripts/qapi/common.py
14d1e34c2c822a6b772695bb1daf45832a64065a
[qemu.git] / scripts / qapi / common.py
1 #
2 # QAPI helper library
3 #
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2018 Red Hat Inc.
6 #
7 # Authors:
8 #  Anthony Liguori <[email protected]>
9 #  Markus Armbruster <[email protected]>
10 #
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
13
14 from __future__ import print_function
15 from contextlib import contextmanager
16 import copy
17 import errno
18 import os
19 import re
20 import string
21 import sys
22 from collections import OrderedDict
23
24 builtin_types = {
25     'null':     'QTYPE_QNULL',
26     'str':      'QTYPE_QSTRING',
27     'int':      'QTYPE_QNUM',
28     'number':   'QTYPE_QNUM',
29     'bool':     'QTYPE_QBOOL',
30     'int8':     'QTYPE_QNUM',
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',
38     'size':     'QTYPE_QNUM',
39     'any':      None,           # any QType possible, actually
40     'QType':    'QTYPE_QSTRING',
41 }
42
43 # Are documentation comments required?
44 doc_required = False
45
46 # Whitelist of commands allowed to return a non-dictionary
47 returns_whitelist = []
48
49 # Whitelist of entities allowed to violate case conventions
50 name_case_whitelist = []
51
52 enum_types = {}
53 struct_types = {}
54 union_types = {}
55 all_names = {}
56
57
58 #
59 # Parsing the schema into expressions
60 #
61
62 class QAPISourceInfo(object):
63     def __init__(self, fname, line, parent):
64         self.fname = fname
65         self.line = line
66         self.parent = parent
67         self.defn_meta = None
68         self.defn_name = None
69
70     def set_defn(self, meta, name):
71         self.defn_meta = meta
72         self.defn_name = name
73
74     def next_line(self):
75         info = copy.copy(self)
76         info.line += 1
77         return info
78
79     def loc(self):
80         return '%s:%d' % (self.fname, self.line)
81
82     def in_defn(self):
83         if self.defn_name:
84             return "%s: In %s '%s':\n" % (self.fname,
85                                           self.defn_meta, self.defn_name)
86         return ''
87
88     def include_path(self):
89         ret = ''
90         parent = self.parent
91         while parent:
92             ret = 'In file included from %s:\n' % parent.loc() + ret
93             parent = parent.parent
94         return ret
95
96     def __str__(self):
97         return self.include_path() + self.in_defn() + self.loc()
98
99
100 class QAPIError(Exception):
101     def __init__(self, info, col, msg):
102         Exception.__init__(self)
103         self.info = info
104         self.col = col
105         self.msg = msg
106
107     def __str__(self):
108         loc = str(self.info)
109         if self.col is not None:
110             assert self.info.line is not None
111             loc += ':%s' % self.col
112         return loc + ': ' + self.msg
113
114
115 class QAPIParseError(QAPIError):
116     def __init__(self, parser, msg):
117         col = 1
118         for ch in parser.src[parser.line_pos:parser.pos]:
119             if ch == '\t':
120                 col = (col + 7) % 8 + 1
121             else:
122                 col += 1
123         QAPIError.__init__(self, parser.info, col, msg)
124
125
126 class QAPISemError(QAPIError):
127     def __init__(self, info, msg):
128         QAPIError.__init__(self, info, None, msg)
129
130
131 class QAPIDoc(object):
132     """
133     A documentation comment block, either definition or free-form
134
135     Definition documentation blocks consist of
136
137     * a body section: one line naming the definition, followed by an
138       overview (any number of lines)
139
140     * argument sections: a description of each argument (for commands
141       and events) or member (for structs, unions and alternates)
142
143     * features sections: a description of each feature flag
144
145     * additional (non-argument) sections, possibly tagged
146
147     Free-form documentation blocks consist only of a body section.
148     """
149
150     class Section(object):
151         def __init__(self, name=None):
152             # optional section name (argument/member or section name)
153             self.name = name
154             # the list of lines for this section
155             self.text = ''
156
157         def append(self, line):
158             self.text += line.rstrip() + '\n'
159
160     class ArgSection(Section):
161         def __init__(self, name):
162             QAPIDoc.Section.__init__(self, name)
163             self.member = None
164
165         def connect(self, member):
166             self.member = member
167
168     def __init__(self, parser, info):
169         # self._parser is used to report errors with QAPIParseError.  The
170         # resulting error position depends on the state of the parser.
171         # It happens to be the beginning of the comment.  More or less
172         # servicable, but action at a distance.
173         self._parser = parser
174         self.info = info
175         self.symbol = None
176         self.body = QAPIDoc.Section()
177         # dict mapping parameter name to ArgSection
178         self.args = OrderedDict()
179         self.features = OrderedDict()
180         # a list of Section
181         self.sections = []
182         # the current section
183         self._section = self.body
184         self._append_line = self._append_body_line
185
186     def has_section(self, name):
187         """Return True if we have a section with this name."""
188         for i in self.sections:
189             if i.name == name:
190                 return True
191         return False
192
193     def append(self, line):
194         """
195         Parse a comment line and add it to the documentation.
196
197         The way that the line is dealt with depends on which part of
198         the documentation we're parsing right now:
199         * The body section: ._append_line is ._append_body_line
200         * An argument section: ._append_line is ._append_args_line
201         * A features section: ._append_line is ._append_features_line
202         * An additional section: ._append_line is ._append_various_line
203         """
204         line = line[1:]
205         if not line:
206             self._append_freeform(line)
207             return
208
209         if line[0] != ' ':
210             raise QAPIParseError(self._parser, "missing space after #")
211         line = line[1:]
212         self._append_line(line)
213
214     def end_comment(self):
215         self._end_section()
216
217     @staticmethod
218     def _is_section_tag(name):
219         return name in ('Returns:', 'Since:',
220                         # those are often singular or plural
221                         'Note:', 'Notes:',
222                         'Example:', 'Examples:',
223                         'TODO:')
224
225     def _append_body_line(self, line):
226         """
227         Process a line of documentation text in the body section.
228
229         If this a symbol line and it is the section's first line, this
230         is a definition documentation block for that symbol.
231
232         If it's a definition documentation block, another symbol line
233         begins the argument section for the argument named by it, and
234         a section tag begins an additional section.  Start that
235         section and append the line to it.
236
237         Else, append the line to the current section.
238         """
239         name = line.split(' ', 1)[0]
240         # FIXME not nice: things like '#  @foo:' and '# @foo: ' aren't
241         # recognized, and get silently treated as ordinary text
242         if not self.symbol and not self.body.text and line.startswith('@'):
243             if not line.endswith(':'):
244                 raise QAPIParseError(self._parser, "line should end with ':'")
245             self.symbol = line[1:-1]
246             # FIXME invalid names other than the empty string aren't flagged
247             if not self.symbol:
248                 raise QAPIParseError(self._parser, "invalid name")
249         elif self.symbol:
250             # This is a definition documentation block
251             if name.startswith('@') and name.endswith(':'):
252                 self._append_line = self._append_args_line
253                 self._append_args_line(line)
254             elif line == 'Features:':
255                 self._append_line = self._append_features_line
256             elif self._is_section_tag(name):
257                 self._append_line = self._append_various_line
258                 self._append_various_line(line)
259             else:
260                 self._append_freeform(line.strip())
261         else:
262             # This is a free-form documentation block
263             self._append_freeform(line.strip())
264
265     def _append_args_line(self, line):
266         """
267         Process a line of documentation text in an argument section.
268
269         A symbol line begins the next argument section, a section tag
270         section or a non-indented line after a blank line begins an
271         additional section.  Start that section and append the line to
272         it.
273
274         Else, append the line to the current section.
275
276         """
277         name = line.split(' ', 1)[0]
278
279         if name.startswith('@') and name.endswith(':'):
280             line = line[len(name)+1:]
281             self._start_args_section(name[1:-1])
282         elif self._is_section_tag(name):
283             self._append_line = self._append_various_line
284             self._append_various_line(line)
285             return
286         elif (self._section.text.endswith('\n\n')
287               and line and not line[0].isspace()):
288             if line == 'Features:':
289                 self._append_line = self._append_features_line
290             else:
291                 self._start_section()
292                 self._append_line = self._append_various_line
293                 self._append_various_line(line)
294             return
295
296         self._append_freeform(line.strip())
297
298     def _append_features_line(self, line):
299         name = line.split(' ', 1)[0]
300
301         if name.startswith('@') and name.endswith(':'):
302             line = line[len(name)+1:]
303             self._start_features_section(name[1:-1])
304         elif self._is_section_tag(name):
305             self._append_line = self._append_various_line
306             self._append_various_line(line)
307             return
308         elif (self._section.text.endswith('\n\n')
309               and line and not line[0].isspace()):
310             self._start_section()
311             self._append_line = self._append_various_line
312             self._append_various_line(line)
313             return
314
315         self._append_freeform(line.strip())
316
317     def _append_various_line(self, line):
318         """
319         Process a line of documentation text in an additional section.
320
321         A symbol line is an error.
322
323         A section tag begins an additional section.  Start that
324         section and append the line to it.
325
326         Else, append the line to the current section.
327         """
328         name = line.split(' ', 1)[0]
329
330         if name.startswith('@') and name.endswith(':'):
331             raise QAPIParseError(self._parser,
332                                  "'%s' can't follow '%s' section"
333                                  % (name, self.sections[0].name))
334         elif self._is_section_tag(name):
335             line = line[len(name)+1:]
336             self._start_section(name[:-1])
337
338         if (not self._section.name or
339                 not self._section.name.startswith('Example')):
340             line = line.strip()
341
342         self._append_freeform(line)
343
344     def _start_symbol_section(self, symbols_dict, name):
345         # FIXME invalid names other than the empty string aren't flagged
346         if not name:
347             raise QAPIParseError(self._parser, "invalid parameter name")
348         if name in symbols_dict:
349             raise QAPIParseError(self._parser,
350                                  "'%s' parameter name duplicated" % name)
351         assert not self.sections
352         self._end_section()
353         self._section = QAPIDoc.ArgSection(name)
354         symbols_dict[name] = self._section
355
356     def _start_args_section(self, name):
357         self._start_symbol_section(self.args, name)
358
359     def _start_features_section(self, name):
360         self._start_symbol_section(self.features, name)
361
362     def _start_section(self, name=None):
363         if name in ('Returns', 'Since') and self.has_section(name):
364             raise QAPIParseError(self._parser,
365                                  "duplicated '%s' section" % name)
366         self._end_section()
367         self._section = QAPIDoc.Section(name)
368         self.sections.append(self._section)
369
370     def _end_section(self):
371         if self._section:
372             text = self._section.text = self._section.text.strip()
373             if self._section.name and (not text or text.isspace()):
374                 raise QAPIParseError(
375                     self._parser,
376                     "empty doc section '%s'" % self._section.name)
377             self._section = None
378
379     def _append_freeform(self, line):
380         match = re.match(r'(@\S+:)', line)
381         if match:
382             raise QAPIParseError(self._parser,
383                                  "'%s' not allowed in free-form documentation"
384                                  % match.group(1))
385         self._section.append(line)
386
387     def connect_member(self, member):
388         if member.name not in self.args:
389             # Undocumented TODO outlaw
390             self.args[member.name] = QAPIDoc.ArgSection(member.name)
391         self.args[member.name].connect(member)
392
393     def check_expr(self, expr):
394         if self.has_section('Returns') and 'command' not in expr:
395             raise QAPISemError(self.info,
396                                "'Returns:' is only valid for commands")
397
398     def check(self):
399         bogus = [name for name, section in self.args.items()
400                  if not section.member]
401         if bogus:
402             raise QAPISemError(
403                 self.info,
404                 "the following documented members are not in "
405                 "the declaration: %s" % ", ".join(bogus))
406
407
408 class QAPISchemaParser(object):
409
410     def __init__(self, fp, previously_included=[], incl_info=None):
411         self.fname = fp.name
412         previously_included.append(os.path.abspath(fp.name))
413         self.src = fp.read()
414         if self.src == '' or self.src[-1] != '\n':
415             self.src += '\n'
416         self.cursor = 0
417         self.info = QAPISourceInfo(self.fname, 1, incl_info)
418         self.line_pos = 0
419         self.exprs = []
420         self.docs = []
421         self.accept()
422         cur_doc = None
423
424         while self.tok is not None:
425             info = self.info
426             if self.tok == '#':
427                 self.reject_expr_doc(cur_doc)
428                 cur_doc = self.get_doc(info)
429                 self.docs.append(cur_doc)
430                 continue
431
432             expr = self.get_expr(False)
433             if 'include' in expr:
434                 self.reject_expr_doc(cur_doc)
435                 if len(expr) != 1:
436                     raise QAPISemError(info, "invalid 'include' directive")
437                 include = expr['include']
438                 if not isinstance(include, str):
439                     raise QAPISemError(info,
440                                        "value of 'include' must be a string")
441                 incl_fname = os.path.join(os.path.dirname(self.fname),
442                                           include)
443                 self.exprs.append({'expr': {'include': incl_fname},
444                                    'info': info})
445                 exprs_include = self._include(include, info, incl_fname,
446                                               previously_included)
447                 if exprs_include:
448                     self.exprs.extend(exprs_include.exprs)
449                     self.docs.extend(exprs_include.docs)
450             elif "pragma" in expr:
451                 self.reject_expr_doc(cur_doc)
452                 if len(expr) != 1:
453                     raise QAPISemError(info, "invalid 'pragma' directive")
454                 pragma = expr['pragma']
455                 if not isinstance(pragma, dict):
456                     raise QAPISemError(
457                         info, "value of 'pragma' must be an object")
458                 for name, value in pragma.items():
459                     self._pragma(name, value, info)
460             else:
461                 expr_elem = {'expr': expr,
462                              'info': info}
463                 if cur_doc:
464                     if not cur_doc.symbol:
465                         raise QAPISemError(
466                             cur_doc.info, "definition documentation required")
467                     expr_elem['doc'] = cur_doc
468                 self.exprs.append(expr_elem)
469             cur_doc = None
470         self.reject_expr_doc(cur_doc)
471
472     @staticmethod
473     def reject_expr_doc(doc):
474         if doc and doc.symbol:
475             raise QAPISemError(
476                 doc.info,
477                 "documentation for '%s' is not followed by the definition"
478                 % doc.symbol)
479
480     def _include(self, include, info, incl_fname, previously_included):
481         incl_abs_fname = os.path.abspath(incl_fname)
482         # catch inclusion cycle
483         inf = info
484         while inf:
485             if incl_abs_fname == os.path.abspath(inf.fname):
486                 raise QAPISemError(info, "inclusion loop for %s" % include)
487             inf = inf.parent
488
489         # skip multiple include of the same file
490         if incl_abs_fname in previously_included:
491             return None
492
493         try:
494             if sys.version_info[0] >= 3:
495                 fobj = open(incl_fname, 'r', encoding='utf-8')
496             else:
497                 fobj = open(incl_fname, 'r')
498         except IOError as e:
499             raise QAPISemError(info, "%s: %s" % (e.strerror, incl_fname))
500         return QAPISchemaParser(fobj, previously_included, info)
501
502     def _pragma(self, name, value, info):
503         global doc_required, returns_whitelist, name_case_whitelist
504         if name == 'doc-required':
505             if not isinstance(value, bool):
506                 raise QAPISemError(info,
507                                    "pragma 'doc-required' must be boolean")
508             doc_required = value
509         elif name == 'returns-whitelist':
510             if (not isinstance(value, list)
511                     or any([not isinstance(elt, str) for elt in value])):
512                 raise QAPISemError(
513                     info,
514                     "pragma returns-whitelist must be a list of strings")
515             returns_whitelist = value
516         elif name == 'name-case-whitelist':
517             if (not isinstance(value, list)
518                     or any([not isinstance(elt, str) for elt in value])):
519                 raise QAPISemError(
520                     info,
521                     "pragma name-case-whitelist must be a list of strings")
522             name_case_whitelist = value
523         else:
524             raise QAPISemError(info, "unknown pragma '%s'" % name)
525
526     def accept(self, skip_comment=True):
527         while True:
528             self.tok = self.src[self.cursor]
529             self.pos = self.cursor
530             self.cursor += 1
531             self.val = None
532
533             if self.tok == '#':
534                 if self.src[self.cursor] == '#':
535                     # Start of doc comment
536                     skip_comment = False
537                 self.cursor = self.src.find('\n', self.cursor)
538                 if not skip_comment:
539                     self.val = self.src[self.pos:self.cursor]
540                     return
541             elif self.tok in '{}:,[]':
542                 return
543             elif self.tok == "'":
544                 # Note: we accept only printable ASCII
545                 string = ''
546                 esc = False
547                 while True:
548                     ch = self.src[self.cursor]
549                     self.cursor += 1
550                     if ch == '\n':
551                         raise QAPIParseError(self, "missing terminating \"'\"")
552                     if esc:
553                         # Note: we recognize only \\ because we have
554                         # no use for funny characters in strings
555                         if ch != '\\':
556                             raise QAPIParseError(self,
557                                                  "unknown escape \\%s" % ch)
558                         esc = False
559                     elif ch == '\\':
560                         esc = True
561                         continue
562                     elif ch == "'":
563                         self.val = string
564                         return
565                     if ord(ch) < 32 or ord(ch) >= 127:
566                         raise QAPIParseError(
567                             self, "funny character in string")
568                     string += ch
569             elif self.src.startswith('true', self.pos):
570                 self.val = True
571                 self.cursor += 3
572                 return
573             elif self.src.startswith('false', self.pos):
574                 self.val = False
575                 self.cursor += 4
576                 return
577             elif self.tok == '\n':
578                 if self.cursor == len(self.src):
579                     self.tok = None
580                     return
581                 self.info = self.info.next_line()
582                 self.line_pos = self.cursor
583             elif not self.tok.isspace():
584                 # Show up to next structural, whitespace or quote
585                 # character
586                 match = re.match('[^[\\]{}:,\\s\'"]+',
587                                  self.src[self.cursor-1:])
588                 raise QAPIParseError(self, "stray '%s'" % match.group(0))
589
590     def get_members(self):
591         expr = OrderedDict()
592         if self.tok == '}':
593             self.accept()
594             return expr
595         if self.tok != "'":
596             raise QAPIParseError(self, "expected string or '}'")
597         while True:
598             key = self.val
599             self.accept()
600             if self.tok != ':':
601                 raise QAPIParseError(self, "expected ':'")
602             self.accept()
603             if key in expr:
604                 raise QAPIParseError(self, "duplicate key '%s'" % key)
605             expr[key] = self.get_expr(True)
606             if self.tok == '}':
607                 self.accept()
608                 return expr
609             if self.tok != ',':
610                 raise QAPIParseError(self, "expected ',' or '}'")
611             self.accept()
612             if self.tok != "'":
613                 raise QAPIParseError(self, "expected string")
614
615     def get_values(self):
616         expr = []
617         if self.tok == ']':
618             self.accept()
619             return expr
620         if self.tok not in "{['tfn":
621             raise QAPIParseError(
622                 self, "expected '{', '[', ']', string, boolean or 'null'")
623         while True:
624             expr.append(self.get_expr(True))
625             if self.tok == ']':
626                 self.accept()
627                 return expr
628             if self.tok != ',':
629                 raise QAPIParseError(self, "expected ',' or ']'")
630             self.accept()
631
632     def get_expr(self, nested):
633         if self.tok != '{' and not nested:
634             raise QAPIParseError(self, "expected '{'")
635         if self.tok == '{':
636             self.accept()
637             expr = self.get_members()
638         elif self.tok == '[':
639             self.accept()
640             expr = self.get_values()
641         elif self.tok in "'tfn":
642             expr = self.val
643             self.accept()
644         else:
645             raise QAPIParseError(
646                 self, "expected '{', '[', string, boolean or 'null'")
647         return expr
648
649     def get_doc(self, info):
650         if self.val != '##':
651             raise QAPIParseError(
652                 self, "junk after '##' at start of documentation comment")
653
654         doc = QAPIDoc(self, info)
655         self.accept(False)
656         while self.tok == '#':
657             if self.val.startswith('##'):
658                 # End of doc comment
659                 if self.val != '##':
660                     raise QAPIParseError(
661                         self,
662                         "junk after '##' at end of documentation comment")
663                 doc.end_comment()
664                 self.accept()
665                 return doc
666             else:
667                 doc.append(self.val)
668             self.accept(False)
669
670         raise QAPIParseError(self, "documentation comment must end with '##'")
671
672
673 #
674 # Semantic analysis of schema expressions
675 # TODO fold into QAPISchema
676 # TODO catching name collisions in generated code would be nice
677 #
678
679
680 def find_base_members(base):
681     if isinstance(base, dict):
682         return base
683     base_struct_define = struct_types.get(base)
684     if not base_struct_define:
685         return None
686     return base_struct_define['data']
687
688
689 # Return the qtype of an alternate branch, or None on error.
690 def find_alternate_member_qtype(qapi_type):
691     if qapi_type in builtin_types:
692         return builtin_types[qapi_type]
693     elif qapi_type in struct_types:
694         return 'QTYPE_QDICT'
695     elif qapi_type in enum_types:
696         return 'QTYPE_QSTRING'
697     elif qapi_type in union_types:
698         return 'QTYPE_QDICT'
699     return None
700
701
702 # Names must be letters, numbers, -, and _.  They must start with letter,
703 # except for downstream extensions which must start with __RFQDN_.
704 # Dots are only valid in the downstream extension prefix.
705 valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
706                         '[a-zA-Z][a-zA-Z0-9_-]*$')
707
708
709 def check_name(info, source, name,
710                allow_optional=False, enum_member=False, permit_upper=False):
711     global valid_name
712     membername = name
713
714     if not isinstance(name, str):
715         raise QAPISemError(info, "%s requires a string name" % source)
716     if name.startswith('*'):
717         membername = name[1:]
718         if not allow_optional:
719             raise QAPISemError(info, "%s does not allow optional name '%s'"
720                                % (source, name))
721     # Enum members can start with a digit, because the generated C
722     # code always prefixes it with the enum name
723     if enum_member and membername[0].isdigit():
724         membername = 'D' + membername
725     # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
726     # and 'q_obj_*' implicit type names.
727     if not valid_name.match(membername) or \
728        c_name(membername, False).startswith('q_'):
729         raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
730     if not permit_upper and name.lower() != name:
731         raise QAPISemError(
732             info, "%s uses uppercase in name '%s'" % (source, name))
733
734
735 def add_name(name, info, meta):
736     global all_names
737     check_name(info, "'%s'" % meta, name, permit_upper=True)
738     # FIXME should reject names that differ only in '_' vs. '.'
739     # vs. '-', because they're liable to clash in generated C.
740     if name in all_names:
741         raise QAPISemError(info, "%s '%s' is already defined"
742                            % (all_names[name], name))
743     if name.endswith('Kind') or name.endswith('List'):
744         raise QAPISemError(info, "%s '%s' should not end in '%s'"
745                            % (meta, name, name[-4:]))
746     all_names[name] = meta
747
748
749 def check_if(expr, info):
750
751     def check_if_str(ifcond, info):
752         if not isinstance(ifcond, str):
753             raise QAPISemError(
754                 info, "'if' condition must be a string or a list of strings")
755         if ifcond.strip() == '':
756             raise QAPISemError(info, "'if' condition '%s' makes no sense"
757                                % ifcond)
758
759     ifcond = expr.get('if')
760     if ifcond is None:
761         return
762     if isinstance(ifcond, list):
763         if ifcond == []:
764             raise QAPISemError(info, "'if' condition [] is useless")
765         for elt in ifcond:
766             check_if_str(elt, info)
767     else:
768         check_if_str(ifcond, info)
769
770
771 def check_type(info, source, value,
772                allow_array=False, allow_dict=False, allow_metas=[]):
773     global all_names
774
775     if value is None:
776         return
777
778     # Check if array type for value is okay
779     if isinstance(value, list):
780         if not allow_array:
781             raise QAPISemError(info, "%s cannot be an array" % source)
782         if len(value) != 1 or not isinstance(value[0], str):
783             raise QAPISemError(info,
784                                "%s: array type must contain single type name" %
785                                source)
786         value = value[0]
787
788     # Check if type name for value is okay
789     if isinstance(value, str):
790         if value not in all_names:
791             raise QAPISemError(info, "%s uses unknown type '%s'"
792                                % (source, value))
793         if not all_names[value] in allow_metas:
794             raise QAPISemError(info, "%s cannot use %s type '%s'" %
795                                (source, all_names[value], value))
796         return
797
798     if not allow_dict:
799         raise QAPISemError(info, "%s should be a type name" % source)
800
801     if not isinstance(value, OrderedDict):
802         raise QAPISemError(info,
803                            "%s should be an object or type name" % source)
804
805     permit_upper = allow_dict in name_case_whitelist
806
807     # value is a dictionary, check that each member is okay
808     for (key, arg) in value.items():
809         check_name(info, "member of %s" % source, key,
810                    allow_optional=True, permit_upper=permit_upper)
811         if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
812             raise QAPISemError(
813                 info, "member of %s uses reserved name '%s'" % (source, key))
814         # Todo: allow dictionaries to represent default values of
815         # an optional argument.
816         check_known_keys(info, "member '%s' of %s" % (key, source),
817                          arg, ['type'], ['if'])
818         check_if(arg, info)
819         normalize_if(arg)
820         check_type(info, "member '%s' of %s" % (key, source),
821                    arg['type'], allow_array=True,
822                    allow_metas=['built-in', 'union', 'alternate', 'struct',
823                                 'enum'])
824
825
826 def check_command(expr, info):
827     name = expr['command']
828     boxed = expr.get('boxed', False)
829
830     args_meta = ['struct']
831     if boxed:
832         args_meta += ['union']
833     check_type(info, "'data' for command '%s'" % name,
834                expr.get('data'), allow_dict=not boxed,
835                allow_metas=args_meta)
836     returns_meta = ['union', 'struct']
837     if name in returns_whitelist:
838         returns_meta += ['built-in', 'alternate', 'enum']
839     check_type(info, "'returns' for command '%s'" % name,
840                expr.get('returns'), allow_array=True,
841                allow_metas=returns_meta)
842
843
844 def check_event(expr, info):
845     name = expr['event']
846     boxed = expr.get('boxed', False)
847
848     meta = ['struct']
849     if boxed:
850         meta += ['union']
851     check_type(info, "'data' for event '%s'" % name,
852                expr.get('data'), allow_dict=not boxed,
853                allow_metas=meta)
854
855
856 def enum_get_names(expr):
857     return [e['name'] for e in expr['data']]
858
859
860 def check_union(expr, info):
861     name = expr['union']
862     base = expr.get('base')
863     discriminator = expr.get('discriminator')
864     members = expr['data']
865
866     # Two types of unions, determined by discriminator.
867
868     # With no discriminator it is a simple union.
869     if discriminator is None:
870         enum_values = members.keys()
871         allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
872         if base is not None:
873             raise QAPISemError(
874                 info, "simple union '%s' must not have a base" % name)
875
876     # Else, it's a flat union.
877     else:
878         # The object must have a string or dictionary 'base'.
879         check_type(info, "'base' for union '%s'" % name,
880                    base, allow_dict=name,
881                    allow_metas=['struct'])
882         if not base:
883             raise QAPISemError(
884                 info, "flat union '%s' must have a base" % name)
885         base_members = find_base_members(base)
886         assert base_members is not None
887
888         # The value of member 'discriminator' must name a non-optional
889         # member of the base struct.
890         check_name(info, "discriminator of flat union '%s'" % name,
891                    discriminator)
892         discriminator_value = base_members.get(discriminator)
893         if not discriminator_value:
894             raise QAPISemError(info,
895                                "discriminator '%s' is not a member of 'base'"
896                                % discriminator)
897         if discriminator_value.get('if'):
898             raise QAPISemError(
899                 info,
900                 "the discriminator '%s' for union %s must not be conditional"
901                 % (discriminator, name))
902         enum_define = enum_types.get(discriminator_value['type'])
903         # Do not allow string discriminator
904         if not enum_define:
905             raise QAPISemError(
906                 info,
907                 "discriminator '%s' must be of enumeration type"
908                 % discriminator)
909         enum_values = enum_get_names(enum_define)
910         allow_metas = ['struct']
911
912     if (len(enum_values) == 0):
913         raise QAPISemError(info, "union '%s' has no branches" % name)
914
915     for (key, value) in members.items():
916         check_name(info, "member of union '%s'" % name, key)
917
918         check_known_keys(info, "member '%s' of union '%s'" % (key, name),
919                          value, ['type'], ['if'])
920         check_if(value, info)
921         normalize_if(value)
922         # Each value must name a known type
923         check_type(info, "member '%s' of union '%s'" % (key, name),
924                    value['type'],
925                    allow_array=not base, allow_metas=allow_metas)
926
927         # If the discriminator names an enum type, then all members
928         # of 'data' must also be members of the enum type.
929         if discriminator is not None:
930             if key not in enum_values:
931                 raise QAPISemError(
932                     info,
933                     "discriminator value '%s' is not found in enum '%s'"
934                     % (key, enum_define['enum']))
935
936
937 def check_alternate(expr, info):
938     name = expr['alternate']
939     members = expr['data']
940     types_seen = {}
941
942     if len(members) == 0:
943         raise QAPISemError(info,
944                            "alternate '%s' cannot have empty 'data'" % name)
945     for (key, value) in members.items():
946         check_name(info, "member of alternate '%s'" % name, key)
947         check_known_keys(info,
948                          "member '%s' of alternate '%s'" % (key, name),
949                          value, ['type'], ['if'])
950         check_if(value, info)
951         normalize_if(value)
952         typ = value['type']
953
954         # Ensure alternates have no type conflicts.
955         check_type(info, "member '%s' of alternate '%s'" % (key, name), typ,
956                    allow_metas=['built-in', 'union', 'struct', 'enum'])
957         qtype = find_alternate_member_qtype(typ)
958         if not qtype:
959             raise QAPISemError(
960                 info,
961                 "alternate '%s' member '%s' cannot use type '%s'"
962                 % (name, key, typ))
963         conflicting = set([qtype])
964         if qtype == 'QTYPE_QSTRING':
965             enum_expr = enum_types.get(typ)
966             if enum_expr:
967                 for v in enum_get_names(enum_expr):
968                     if v in ['on', 'off']:
969                         conflicting.add('QTYPE_QBOOL')
970                     if re.match(r'[-+0-9.]', v): # lazy, could be tightened
971                         conflicting.add('QTYPE_QNUM')
972             else:
973                 conflicting.add('QTYPE_QNUM')
974                 conflicting.add('QTYPE_QBOOL')
975         for qt in conflicting:
976             if qt in types_seen:
977                 raise QAPISemError(
978                     info,
979                     "alternate '%s' member '%s' can't be distinguished "
980                     "from member '%s'"
981                     % (name, key, types_seen[qt]))
982             types_seen[qt] = key
983
984
985 def check_enum(expr, info):
986     name = expr['enum']
987     members = expr['data']
988     prefix = expr.get('prefix')
989
990     if not isinstance(members, list):
991         raise QAPISemError(info,
992                            "enum '%s' requires an array for 'data'" % name)
993     if prefix is not None and not isinstance(prefix, str):
994         raise QAPISemError(info,
995                            "enum '%s' requires a string for 'prefix'" % name)
996
997     permit_upper = name in name_case_whitelist
998
999     for member in members:
1000         check_known_keys(info, "member of enum '%s'" % name, member,
1001                          ['name'], ['if'])
1002         check_if(member, info)
1003         normalize_if(member)
1004         check_name(info, "member of enum '%s'" % name, member['name'],
1005                    enum_member=True, permit_upper=permit_upper)
1006
1007
1008 def check_struct(expr, info):
1009     name = expr['struct']
1010     members = expr['data']
1011     features = expr.get('features')
1012
1013     check_type(info, "'data' for struct '%s'" % name, members,
1014                allow_dict=name)
1015     check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
1016                allow_metas=['struct'])
1017
1018     if features:
1019         if not isinstance(features, list):
1020             raise QAPISemError(
1021                 info, "struct '%s' requires an array for 'features'" % name)
1022         for f in features:
1023             assert isinstance(f, dict)
1024             check_known_keys(info, "feature of struct %s" % name, f,
1025                              ['name'], ['if'])
1026
1027             check_if(f, info)
1028             normalize_if(f)
1029             check_name(info, "feature of struct %s" % name, f['name'])
1030
1031
1032 def check_known_keys(info, source, value, required, optional):
1033
1034     def pprint(elems):
1035         return ', '.join("'" + e + "'" for e in sorted(elems))
1036
1037     missing = set(required) - set(value)
1038     if missing:
1039         raise QAPISemError(
1040             info,
1041             "key%s %s %s missing from %s"
1042             % ('s' if len(missing) > 1 else '', pprint(missing),
1043                'are' if len(missing) > 1 else 'is', source))
1044     allowed = set(required + optional)
1045     unknown = set(value) - allowed
1046     if unknown:
1047         raise QAPISemError(
1048             info,
1049             "unknown key%s %s in %s\nValid keys are %s."
1050             % ('s' if len(unknown) > 1 else '', pprint(unknown),
1051                source, pprint(allowed)))
1052
1053
1054 def check_keys(expr, info, meta, required, optional=[]):
1055     name = expr[meta]
1056     if not isinstance(name, str):
1057         raise QAPISemError(info, "'%s' key must have a string value" % meta)
1058     required = required + [meta]
1059     source = "%s '%s'" % (meta, name)
1060     check_known_keys(info, source, expr, required, optional)
1061     for (key, value) in expr.items():
1062         if key in ['gen', 'success-response'] and value is not False:
1063             raise QAPISemError(info,
1064                                "'%s' of %s '%s' should only use false value"
1065                                % (key, meta, name))
1066         if (key in ['boxed', 'allow-oob', 'allow-preconfig']
1067                 and value is not True):
1068             raise QAPISemError(info,
1069                                "'%s' of %s '%s' should only use true value"
1070                                % (key, meta, name))
1071         if key == 'if':
1072             check_if(expr, info)
1073
1074
1075 def normalize_enum(expr):
1076     if isinstance(expr['data'], list):
1077         expr['data'] = [m if isinstance(m, dict) else {'name': m}
1078                         for m in expr['data']]
1079
1080
1081 def normalize_members(members):
1082     if isinstance(members, OrderedDict):
1083         for key, arg in members.items():
1084             if isinstance(arg, dict):
1085                 continue
1086             members[key] = {'type': arg}
1087
1088
1089 def normalize_features(features):
1090     if isinstance(features, list):
1091         features[:] = [f if isinstance(f, dict) else {'name': f}
1092                        for f in features]
1093
1094
1095 def normalize_if(expr):
1096     ifcond = expr.get('if')
1097     if isinstance(ifcond, str):
1098         expr['if'] = [ifcond]
1099
1100
1101 def check_exprs(exprs):
1102     global all_names
1103
1104     # Populate name table with names of built-in types
1105     for builtin in builtin_types.keys():
1106         all_names[builtin] = 'built-in'
1107
1108     # Learn the types and check for valid expression keys
1109     for expr_elem in exprs:
1110         expr = expr_elem['expr']
1111         info = expr_elem['info']
1112         doc = expr_elem.get('doc')
1113
1114         if 'include' in expr:
1115             continue
1116
1117         if not doc and doc_required:
1118             raise QAPISemError(info,
1119                                "definition missing documentation comment")
1120
1121         if 'enum' in expr:
1122             meta = 'enum'
1123             check_keys(expr, info, 'enum', ['data'], ['if', 'prefix'])
1124             normalize_enum(expr)
1125             enum_types[expr[meta]] = expr
1126         elif 'union' in expr:
1127             meta = 'union'
1128             check_keys(expr, info, 'union', ['data'],
1129                        ['base', 'discriminator', 'if'])
1130             normalize_members(expr.get('base'))
1131             normalize_members(expr['data'])
1132             union_types[expr[meta]] = expr
1133         elif 'alternate' in expr:
1134             meta = 'alternate'
1135             check_keys(expr, info, 'alternate', ['data'], ['if'])
1136             normalize_members(expr['data'])
1137         elif 'struct' in expr:
1138             meta = 'struct'
1139             check_keys(expr, info, 'struct', ['data'],
1140                        ['base', 'if', 'features'])
1141             normalize_members(expr['data'])
1142             normalize_features(expr.get('features'))
1143             struct_types[expr[meta]] = expr
1144         elif 'command' in expr:
1145             meta = 'command'
1146             check_keys(expr, info, 'command', [],
1147                        ['data', 'returns', 'gen', 'success-response',
1148                         'boxed', 'allow-oob', 'allow-preconfig', 'if'])
1149             normalize_members(expr.get('data'))
1150         elif 'event' in expr:
1151             meta = 'event'
1152             check_keys(expr, info, 'event', [], ['data', 'boxed', 'if'])
1153             normalize_members(expr.get('data'))
1154         else:
1155             raise QAPISemError(info, "expression is missing metatype")
1156         normalize_if(expr)
1157         name = expr[meta]
1158         add_name(name, info, meta)
1159         info.set_defn(meta, name)
1160         if doc and doc.symbol != name:
1161             raise QAPISemError(
1162                 info,
1163                 "definition of '%s' follows documentation for '%s'"
1164                 % (name, doc.symbol))
1165
1166     # Validate that exprs make sense
1167     for expr_elem in exprs:
1168         expr = expr_elem['expr']
1169         info = expr_elem['info']
1170         doc = expr_elem.get('doc')
1171
1172         if 'include' in expr:
1173             continue
1174         if 'enum' in expr:
1175             check_enum(expr, info)
1176         elif 'union' in expr:
1177             check_union(expr, info)
1178         elif 'alternate' in expr:
1179             check_alternate(expr, info)
1180         elif 'struct' in expr:
1181             check_struct(expr, info)
1182         elif 'command' in expr:
1183             check_command(expr, info)
1184         elif 'event' in expr:
1185             check_event(expr, info)
1186         else:
1187             assert False, 'unexpected meta type'
1188
1189         if doc:
1190             doc.check_expr(expr)
1191
1192     return exprs
1193
1194
1195 #
1196 # Schema compiler frontend
1197 #
1198
1199 class QAPISchemaEntity(object):
1200     def __init__(self, name, info, doc, ifcond=None):
1201         assert name is None or isinstance(name, str)
1202         self.name = name
1203         self._module = None
1204         # For explicitly defined entities, info points to the (explicit)
1205         # definition.  For builtins (and their arrays), info is None.
1206         # For implicitly defined entities, info points to a place that
1207         # triggered the implicit definition (there may be more than one
1208         # such place).
1209         self.info = info
1210         self.doc = doc
1211         self._ifcond = ifcond or []
1212         self._checked = False
1213
1214     def c_name(self):
1215         return c_name(self.name)
1216
1217     def check(self, schema):
1218         assert not self._checked
1219         if self.info:
1220             self._module = os.path.relpath(self.info.fname,
1221                                            os.path.dirname(schema.fname))
1222         self._checked = True
1223
1224     @property
1225     def ifcond(self):
1226         assert self._checked
1227         return self._ifcond
1228
1229     @property
1230     def module(self):
1231         assert self._checked
1232         return self._module
1233
1234     def is_implicit(self):
1235         return not self.info
1236
1237     def visit(self, visitor):
1238         assert self._checked
1239
1240
1241 class QAPISchemaVisitor(object):
1242     def visit_begin(self, schema):
1243         pass
1244
1245     def visit_end(self):
1246         pass
1247
1248     def visit_module(self, fname):
1249         pass
1250
1251     def visit_needed(self, entity):
1252         # Default to visiting everything
1253         return True
1254
1255     def visit_include(self, fname, info):
1256         pass
1257
1258     def visit_builtin_type(self, name, info, json_type):
1259         pass
1260
1261     def visit_enum_type(self, name, info, ifcond, members, prefix):
1262         pass
1263
1264     def visit_array_type(self, name, info, ifcond, element_type):
1265         pass
1266
1267     def visit_object_type(self, name, info, ifcond, base, members, variants,
1268                           features):
1269         pass
1270
1271     def visit_object_type_flat(self, name, info, ifcond, members, variants,
1272                                features):
1273         pass
1274
1275     def visit_alternate_type(self, name, info, ifcond, variants):
1276         pass
1277
1278     def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
1279                       success_response, boxed, allow_oob, allow_preconfig):
1280         pass
1281
1282     def visit_event(self, name, info, ifcond, arg_type, boxed):
1283         pass
1284
1285
1286 class QAPISchemaInclude(QAPISchemaEntity):
1287
1288     def __init__(self, fname, info):
1289         QAPISchemaEntity.__init__(self, None, info, None)
1290         self.fname = fname
1291
1292     def visit(self, visitor):
1293         QAPISchemaEntity.visit(self, visitor)
1294         visitor.visit_include(self.fname, self.info)
1295
1296
1297 class QAPISchemaType(QAPISchemaEntity):
1298     # Return the C type for common use.
1299     # For the types we commonly box, this is a pointer type.
1300     def c_type(self):
1301         pass
1302
1303     # Return the C type to be used in a parameter list.
1304     def c_param_type(self):
1305         return self.c_type()
1306
1307     # Return the C type to be used where we suppress boxing.
1308     def c_unboxed_type(self):
1309         return self.c_type()
1310
1311     def json_type(self):
1312         pass
1313
1314     def alternate_qtype(self):
1315         json2qtype = {
1316             'null':    'QTYPE_QNULL',
1317             'string':  'QTYPE_QSTRING',
1318             'number':  'QTYPE_QNUM',
1319             'int':     'QTYPE_QNUM',
1320             'boolean': 'QTYPE_QBOOL',
1321             'object':  'QTYPE_QDICT'
1322         }
1323         return json2qtype.get(self.json_type())
1324
1325     def doc_type(self):
1326         if self.is_implicit():
1327             return None
1328         return self.name
1329
1330
1331 class QAPISchemaBuiltinType(QAPISchemaType):
1332     def __init__(self, name, json_type, c_type):
1333         QAPISchemaType.__init__(self, name, None, None)
1334         assert not c_type or isinstance(c_type, str)
1335         assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1336                              'value')
1337         self._json_type_name = json_type
1338         self._c_type_name = c_type
1339
1340     def c_name(self):
1341         return self.name
1342
1343     def c_type(self):
1344         return self._c_type_name
1345
1346     def c_param_type(self):
1347         if self.name == 'str':
1348             return 'const ' + self._c_type_name
1349         return self._c_type_name
1350
1351     def json_type(self):
1352         return self._json_type_name
1353
1354     def doc_type(self):
1355         return self.json_type()
1356
1357     def visit(self, visitor):
1358         QAPISchemaType.visit(self, visitor)
1359         visitor.visit_builtin_type(self.name, self.info, self.json_type())
1360
1361
1362 class QAPISchemaEnumType(QAPISchemaType):
1363     def __init__(self, name, info, doc, ifcond, members, prefix):
1364         QAPISchemaType.__init__(self, name, info, doc, ifcond)
1365         for m in members:
1366             assert isinstance(m, QAPISchemaEnumMember)
1367             m.set_defined_in(name)
1368         assert prefix is None or isinstance(prefix, str)
1369         self.members = members
1370         self.prefix = prefix
1371
1372     def check(self, schema):
1373         QAPISchemaType.check(self, schema)
1374         seen = {}
1375         for m in self.members:
1376             m.check_clash(self.info, seen)
1377             if self.doc:
1378                 self.doc.connect_member(m)
1379
1380     def is_implicit(self):
1381         # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1382         return self.name.endswith('Kind') or self.name == 'QType'
1383
1384     def c_type(self):
1385         return c_name(self.name)
1386
1387     def member_names(self):
1388         return [m.name for m in self.members]
1389
1390     def json_type(self):
1391         return 'string'
1392
1393     def visit(self, visitor):
1394         QAPISchemaType.visit(self, visitor)
1395         visitor.visit_enum_type(self.name, self.info, self.ifcond,
1396                                 self.members, self.prefix)
1397
1398
1399 class QAPISchemaArrayType(QAPISchemaType):
1400     def __init__(self, name, info, element_type):
1401         QAPISchemaType.__init__(self, name, info, None, None)
1402         assert isinstance(element_type, str)
1403         self._element_type_name = element_type
1404         self.element_type = None
1405
1406     def check(self, schema):
1407         QAPISchemaType.check(self, schema)
1408         self.element_type = schema.lookup_type(self._element_type_name)
1409         assert self.element_type
1410         assert not isinstance(self.element_type, QAPISchemaArrayType)
1411
1412     @property
1413     def ifcond(self):
1414         assert self._checked
1415         return self.element_type.ifcond
1416
1417     @property
1418     def module(self):
1419         assert self._checked
1420         return self.element_type.module
1421
1422     def is_implicit(self):
1423         return True
1424
1425     def c_type(self):
1426         return c_name(self.name) + pointer_suffix
1427
1428     def json_type(self):
1429         return 'array'
1430
1431     def doc_type(self):
1432         elt_doc_type = self.element_type.doc_type()
1433         if not elt_doc_type:
1434             return None
1435         return 'array of ' + elt_doc_type
1436
1437     def visit(self, visitor):
1438         QAPISchemaType.visit(self, visitor)
1439         visitor.visit_array_type(self.name, self.info, self.ifcond,
1440                                  self.element_type)
1441
1442
1443 class QAPISchemaObjectType(QAPISchemaType):
1444     def __init__(self, name, info, doc, ifcond,
1445                  base, local_members, variants, features):
1446         # struct has local_members, optional base, and no variants
1447         # flat union has base, variants, and no local_members
1448         # simple union has local_members, variants, and no base
1449         QAPISchemaType.__init__(self, name, info, doc, ifcond)
1450         assert base is None or isinstance(base, str)
1451         for m in local_members:
1452             assert isinstance(m, QAPISchemaObjectTypeMember)
1453             m.set_defined_in(name)
1454         if variants is not None:
1455             assert isinstance(variants, QAPISchemaObjectTypeVariants)
1456             variants.set_defined_in(name)
1457         for f in features:
1458             assert isinstance(f, QAPISchemaFeature)
1459             f.set_defined_in(name)
1460         self._base_name = base
1461         self.base = None
1462         self.local_members = local_members
1463         self.variants = variants
1464         self.members = None
1465         self.features = features
1466
1467     def check(self, schema):
1468         # This calls another type T's .check() exactly when the C
1469         # struct emitted by gen_object() contains that T's C struct
1470         # (pointers don't count).
1471         if self.members is not None:
1472             # A previous .check() completed: nothing to do
1473             return
1474         if self._checked:
1475             # Recursed: C struct contains itself
1476             raise QAPISemError(self.info,
1477                                "object %s contains itself" % self.name)
1478
1479         QAPISchemaType.check(self, schema)
1480         assert self._checked and self.members is None
1481
1482         seen = OrderedDict()
1483         if self._base_name:
1484             self.base = schema.lookup_type(self._base_name)
1485             assert isinstance(self.base, QAPISchemaObjectType)
1486             self.base.check(schema)
1487             self.base.check_clash(self.info, seen)
1488         for m in self.local_members:
1489             m.check(schema)
1490             m.check_clash(self.info, seen)
1491             if self.doc:
1492                 self.doc.connect_member(m)
1493         members = seen.values()
1494
1495         if self.variants:
1496             self.variants.check(schema, seen)
1497             assert self.variants.tag_member in members
1498             self.variants.check_clash(self.info, seen)
1499
1500         # Features are in a name space separate from members
1501         seen = {}
1502         for f in self.features:
1503             f.check_clash(self.info, seen)
1504
1505         if self.doc:
1506             self.doc.check()
1507
1508         self.members = members  # mark completed
1509
1510     # Check that the members of this type do not cause duplicate JSON members,
1511     # and update seen to track the members seen so far. Report any errors
1512     # on behalf of info, which is not necessarily self.info
1513     def check_clash(self, info, seen):
1514         assert self._checked
1515         assert not self.variants       # not implemented
1516         for m in self.members:
1517             m.check_clash(info, seen)
1518
1519     @property
1520     def ifcond(self):
1521         assert self._checked
1522         if isinstance(self._ifcond, QAPISchemaType):
1523             # Simple union wrapper type inherits from wrapped type;
1524             # see _make_implicit_object_type()
1525             return self._ifcond.ifcond
1526         return self._ifcond
1527
1528     def is_implicit(self):
1529         # See QAPISchema._make_implicit_object_type(), as well as
1530         # _def_predefineds()
1531         return self.name.startswith('q_')
1532
1533     def is_empty(self):
1534         assert self.members is not None
1535         return not self.members and not self.variants
1536
1537     def c_name(self):
1538         assert self.name != 'q_empty'
1539         return QAPISchemaType.c_name(self)
1540
1541     def c_type(self):
1542         assert not self.is_implicit()
1543         return c_name(self.name) + pointer_suffix
1544
1545     def c_unboxed_type(self):
1546         return c_name(self.name)
1547
1548     def json_type(self):
1549         return 'object'
1550
1551     def visit(self, visitor):
1552         QAPISchemaType.visit(self, visitor)
1553         visitor.visit_object_type(self.name, self.info, self.ifcond,
1554                                   self.base, self.local_members, self.variants,
1555                                   self.features)
1556         visitor.visit_object_type_flat(self.name, self.info, self.ifcond,
1557                                        self.members, self.variants,
1558                                        self.features)
1559
1560
1561 class QAPISchemaMember(object):
1562     """ Represents object members, enum members and features """
1563     role = 'member'
1564
1565     def __init__(self, name, ifcond=None):
1566         assert isinstance(name, str)
1567         self.name = name
1568         self.ifcond = ifcond or []
1569         self.defined_in = None
1570
1571     def set_defined_in(self, name):
1572         assert not self.defined_in
1573         self.defined_in = name
1574
1575     def check_clash(self, info, seen):
1576         cname = c_name(self.name)
1577         if cname in seen:
1578             raise QAPISemError(
1579                 info,
1580                 "%s collides with %s"
1581                 % (self.describe(info), seen[cname].describe(info)))
1582         seen[cname] = self
1583
1584     def describe(self, info):
1585         role = self.role
1586         defined_in = self.defined_in
1587         assert defined_in
1588
1589         if defined_in.startswith('q_obj_'):
1590             # See QAPISchema._make_implicit_object_type() - reverse the
1591             # mapping there to create a nice human-readable description
1592             defined_in = defined_in[6:]
1593             if defined_in.endswith('-arg'):
1594                 # Implicit type created for a command's dict 'data'
1595                 assert role == 'member'
1596                 role = 'parameter'
1597             elif defined_in.endswith('-base'):
1598                 # Implicit type created for a flat union's dict 'base'
1599                 role = 'base ' + role
1600             else:
1601                 # Implicit type created for a simple union's branch
1602                 assert defined_in.endswith('-wrapper')
1603                 # Unreachable and not implemented
1604                 assert False
1605         elif defined_in.endswith('Kind'):
1606             # See QAPISchema._make_implicit_enum_type()
1607             # Implicit enum created for simple union's branches
1608             assert role == 'value'
1609             role = 'branch'
1610         elif defined_in != info.defn_name:
1611             return "%s '%s' of type '%s'" % (role, self.name, defined_in)
1612         return "%s '%s'" % (role, self.name)
1613
1614
1615 class QAPISchemaEnumMember(QAPISchemaMember):
1616     role = 'value'
1617
1618
1619 class QAPISchemaFeature(QAPISchemaMember):
1620     role = 'feature'
1621
1622
1623 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1624     def __init__(self, name, typ, optional, ifcond=None):
1625         QAPISchemaMember.__init__(self, name, ifcond)
1626         assert isinstance(typ, str)
1627         assert isinstance(optional, bool)
1628         self._type_name = typ
1629         self.type = None
1630         self.optional = optional
1631
1632     def check(self, schema):
1633         assert self.defined_in
1634         self.type = schema.lookup_type(self._type_name)
1635         assert self.type
1636
1637
1638 class QAPISchemaObjectTypeVariants(object):
1639     def __init__(self, tag_name, tag_member, variants):
1640         # Flat unions pass tag_name but not tag_member.
1641         # Simple unions and alternates pass tag_member but not tag_name.
1642         # After check(), tag_member is always set, and tag_name remains
1643         # a reliable witness of being used by a flat union.
1644         assert bool(tag_member) != bool(tag_name)
1645         assert (isinstance(tag_name, str) or
1646                 isinstance(tag_member, QAPISchemaObjectTypeMember))
1647         for v in variants:
1648             assert isinstance(v, QAPISchemaObjectTypeVariant)
1649         self._tag_name = tag_name
1650         self.tag_member = tag_member
1651         self.variants = variants
1652
1653     def set_defined_in(self, name):
1654         for v in self.variants:
1655             v.set_defined_in(name)
1656
1657     def check(self, schema, seen):
1658         if not self.tag_member:    # flat union
1659             self.tag_member = seen[c_name(self._tag_name)]
1660             assert self._tag_name == self.tag_member.name
1661         assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1662         assert not self.tag_member.optional
1663         assert self.tag_member.ifcond == []
1664         if self._tag_name:    # flat union
1665             # branches that are not explicitly covered get an empty type
1666             cases = set([v.name for v in self.variants])
1667             for m in self.tag_member.type.members:
1668                 if m.name not in cases:
1669                     v = QAPISchemaObjectTypeVariant(m.name, 'q_empty',
1670                                                     m.ifcond)
1671                     v.set_defined_in(self.tag_member.defined_in)
1672                     self.variants.append(v)
1673         assert self.variants
1674         for v in self.variants:
1675             v.check(schema)
1676             # Union names must match enum values; alternate names are
1677             # checked separately. Use 'seen' to tell the two apart.
1678             if seen:
1679                 assert v.name in self.tag_member.type.member_names()
1680                 assert (isinstance(v.type, QAPISchemaObjectType)
1681                         and not v.type.variants)
1682                 v.type.check(schema)
1683
1684     def check_clash(self, info, seen):
1685         for v in self.variants:
1686             # Reset seen map for each variant, since qapi names from one
1687             # branch do not affect another branch
1688             v.type.check_clash(info, dict(seen))
1689
1690
1691 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1692     role = 'branch'
1693
1694     def __init__(self, name, typ, ifcond=None):
1695         QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
1696
1697
1698 class QAPISchemaAlternateType(QAPISchemaType):
1699     def __init__(self, name, info, doc, ifcond, variants):
1700         QAPISchemaType.__init__(self, name, info, doc, ifcond)
1701         assert isinstance(variants, QAPISchemaObjectTypeVariants)
1702         assert variants.tag_member
1703         variants.set_defined_in(name)
1704         variants.tag_member.set_defined_in(self.name)
1705         self.variants = variants
1706
1707     def check(self, schema):
1708         QAPISchemaType.check(self, schema)
1709         self.variants.tag_member.check(schema)
1710         # Not calling self.variants.check_clash(), because there's nothing
1711         # to clash with
1712         self.variants.check(schema, {})
1713         # Alternate branch names have no relation to the tag enum values;
1714         # so we have to check for potential name collisions ourselves.
1715         seen = {}
1716         for v in self.variants.variants:
1717             v.check_clash(self.info, seen)
1718             # TODO check conflicting qtypes
1719             if self.doc:
1720                 self.doc.connect_member(v)
1721         if self.doc:
1722             self.doc.check()
1723
1724     def c_type(self):
1725         return c_name(self.name) + pointer_suffix
1726
1727     def json_type(self):
1728         return 'value'
1729
1730     def visit(self, visitor):
1731         QAPISchemaType.visit(self, visitor)
1732         visitor.visit_alternate_type(self.name, self.info, self.ifcond,
1733                                      self.variants)
1734
1735
1736 class QAPISchemaCommand(QAPISchemaEntity):
1737     def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
1738                  gen, success_response, boxed, allow_oob, allow_preconfig):
1739         QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
1740         assert not arg_type or isinstance(arg_type, str)
1741         assert not ret_type or isinstance(ret_type, str)
1742         self._arg_type_name = arg_type
1743         self.arg_type = None
1744         self._ret_type_name = ret_type
1745         self.ret_type = None
1746         self.gen = gen
1747         self.success_response = success_response
1748         self.boxed = boxed
1749         self.allow_oob = allow_oob
1750         self.allow_preconfig = allow_preconfig
1751
1752     def check(self, schema):
1753         QAPISchemaEntity.check(self, schema)
1754         if self._arg_type_name:
1755             self.arg_type = schema.lookup_type(self._arg_type_name)
1756             assert isinstance(self.arg_type, QAPISchemaObjectType)
1757             assert not self.arg_type.variants or self.boxed
1758         elif self.boxed:
1759             raise QAPISemError(self.info, "use of 'boxed' requires 'data'")
1760         if self._ret_type_name:
1761             self.ret_type = schema.lookup_type(self._ret_type_name)
1762             assert isinstance(self.ret_type, QAPISchemaType)
1763
1764     def visit(self, visitor):
1765         QAPISchemaEntity.visit(self, visitor)
1766         visitor.visit_command(self.name, self.info, self.ifcond,
1767                               self.arg_type, self.ret_type,
1768                               self.gen, self.success_response,
1769                               self.boxed, self.allow_oob,
1770                               self.allow_preconfig)
1771
1772
1773 class QAPISchemaEvent(QAPISchemaEntity):
1774     def __init__(self, name, info, doc, ifcond, arg_type, boxed):
1775         QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
1776         assert not arg_type or isinstance(arg_type, str)
1777         self._arg_type_name = arg_type
1778         self.arg_type = None
1779         self.boxed = boxed
1780
1781     def check(self, schema):
1782         QAPISchemaEntity.check(self, schema)
1783         if self._arg_type_name:
1784             self.arg_type = schema.lookup_type(self._arg_type_name)
1785             assert isinstance(self.arg_type, QAPISchemaObjectType)
1786             assert not self.arg_type.variants or self.boxed
1787         elif self.boxed:
1788             raise QAPISemError(self.info, "use of 'boxed' requires 'data'")
1789
1790     def visit(self, visitor):
1791         QAPISchemaEntity.visit(self, visitor)
1792         visitor.visit_event(self.name, self.info, self.ifcond,
1793                             self.arg_type, self.boxed)
1794
1795
1796 class QAPISchema(object):
1797     def __init__(self, fname):
1798         self.fname = fname
1799         if sys.version_info[0] >= 3:
1800             f = open(fname, 'r', encoding='utf-8')
1801         else:
1802             f = open(fname, 'r')
1803         parser = QAPISchemaParser(f)
1804         exprs = check_exprs(parser.exprs)
1805         self.docs = parser.docs
1806         self._entity_list = []
1807         self._entity_dict = {}
1808         self._predefining = True
1809         self._def_predefineds()
1810         self._predefining = False
1811         self._def_exprs(exprs)
1812         self.check()
1813
1814     def _def_entity(self, ent):
1815         # Only the predefined types are allowed to not have info
1816         assert ent.info or self._predefining
1817         assert ent.name is None or ent.name not in self._entity_dict
1818         self._entity_list.append(ent)
1819         if ent.name is not None:
1820             self._entity_dict[ent.name] = ent
1821
1822     def lookup_entity(self, name, typ=None):
1823         ent = self._entity_dict.get(name)
1824         if typ and not isinstance(ent, typ):
1825             return None
1826         return ent
1827
1828     def lookup_type(self, name):
1829         return self.lookup_entity(name, QAPISchemaType)
1830
1831     def _def_include(self, expr, info, doc):
1832         include = expr['include']
1833         assert doc is None
1834         main_info = info
1835         while main_info.parent:
1836             main_info = main_info.parent
1837         fname = os.path.relpath(include, os.path.dirname(main_info.fname))
1838         self._def_entity(QAPISchemaInclude(fname, info))
1839
1840     def _def_builtin_type(self, name, json_type, c_type):
1841         self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1842         # Instantiating only the arrays that are actually used would
1843         # be nice, but we can't as long as their generated code
1844         # (qapi-builtin-types.[ch]) may be shared by some other
1845         # schema.
1846         self._make_array_type(name, None)
1847
1848     def _def_predefineds(self):
1849         for t in [('str',    'string',  'char' + pointer_suffix),
1850                   ('number', 'number',  'double'),
1851                   ('int',    'int',     'int64_t'),
1852                   ('int8',   'int',     'int8_t'),
1853                   ('int16',  'int',     'int16_t'),
1854                   ('int32',  'int',     'int32_t'),
1855                   ('int64',  'int',     'int64_t'),
1856                   ('uint8',  'int',     'uint8_t'),
1857                   ('uint16', 'int',     'uint16_t'),
1858                   ('uint32', 'int',     'uint32_t'),
1859                   ('uint64', 'int',     'uint64_t'),
1860                   ('size',   'int',     'uint64_t'),
1861                   ('bool',   'boolean', 'bool'),
1862                   ('any',    'value',   'QObject' + pointer_suffix),
1863                   ('null',   'null',    'QNull' + pointer_suffix)]:
1864             self._def_builtin_type(*t)
1865         self.the_empty_object_type = QAPISchemaObjectType(
1866             'q_empty', None, None, None, None, [], None, [])
1867         self._def_entity(self.the_empty_object_type)
1868
1869         qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
1870                   'qbool']
1871         qtype_values = self._make_enum_members([{'name': n} for n in qtypes])
1872
1873         self._def_entity(QAPISchemaEnumType('QType', None, None, None,
1874                                             qtype_values, 'QTYPE'))
1875
1876     def _make_features(self, features):
1877         return [QAPISchemaFeature(f['name'], f.get('if')) for f in features]
1878
1879     def _make_enum_members(self, values):
1880         return [QAPISchemaEnumMember(v['name'], v.get('if'))
1881                 for v in values]
1882
1883     def _make_implicit_enum_type(self, name, info, ifcond, values):
1884         # See also QAPISchemaObjectTypeMember.describe()
1885         name = name + 'Kind'   # Use namespace reserved by add_name()
1886         self._def_entity(QAPISchemaEnumType(
1887             name, info, None, ifcond, self._make_enum_members(values), None))
1888         return name
1889
1890     def _make_array_type(self, element_type, info):
1891         name = element_type + 'List'   # Use namespace reserved by add_name()
1892         if not self.lookup_type(name):
1893             self._def_entity(QAPISchemaArrayType(name, info, element_type))
1894         return name
1895
1896     def _make_implicit_object_type(self, name, info, doc, ifcond,
1897                                    role, members):
1898         if not members:
1899             return None
1900         # See also QAPISchemaObjectTypeMember.describe()
1901         name = 'q_obj_%s-%s' % (name, role)
1902         typ = self.lookup_entity(name, QAPISchemaObjectType)
1903         if typ:
1904             # The implicit object type has multiple users.  This can
1905             # happen only for simple unions' implicit wrapper types.
1906             # Its ifcond should be the disjunction of its user's
1907             # ifconds.  Not implemented.  Instead, we always pass the
1908             # wrapped type's ifcond, which is trivially the same for all
1909             # users.  It's also necessary for the wrapper to compile.
1910             # But it's not tight: the disjunction need not imply it.  We
1911             # may end up compiling useless wrapper types.
1912             # TODO kill simple unions or implement the disjunction
1913             assert ifcond == typ._ifcond # pylint: disable=protected-access
1914         else:
1915             self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
1916                                                   None, members, None, []))
1917         return name
1918
1919     def _def_enum_type(self, expr, info, doc):
1920         name = expr['enum']
1921         data = expr['data']
1922         prefix = expr.get('prefix')
1923         ifcond = expr.get('if')
1924         self._def_entity(QAPISchemaEnumType(
1925             name, info, doc, ifcond,
1926             self._make_enum_members(data), prefix))
1927
1928     def _make_member(self, name, typ, ifcond, info):
1929         optional = False
1930         if name.startswith('*'):
1931             name = name[1:]
1932             optional = True
1933         if isinstance(typ, list):
1934             assert len(typ) == 1
1935             typ = self._make_array_type(typ[0], info)
1936         return QAPISchemaObjectTypeMember(name, typ, optional, ifcond)
1937
1938     def _make_members(self, data, info):
1939         return [self._make_member(key, value['type'], value.get('if'), info)
1940                 for (key, value) in data.items()]
1941
1942     def _def_struct_type(self, expr, info, doc):
1943         name = expr['struct']
1944         base = expr.get('base')
1945         data = expr['data']
1946         ifcond = expr.get('if')
1947         features = expr.get('features', [])
1948         self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, base,
1949                                               self._make_members(data, info),
1950                                               None,
1951                                               self._make_features(features)))
1952
1953     def _make_variant(self, case, typ, ifcond):
1954         return QAPISchemaObjectTypeVariant(case, typ, ifcond)
1955
1956     def _make_simple_variant(self, case, typ, ifcond, info):
1957         if isinstance(typ, list):
1958             assert len(typ) == 1
1959             typ = self._make_array_type(typ[0], info)
1960         typ = self._make_implicit_object_type(
1961             typ, info, None, self.lookup_type(typ),
1962             'wrapper', [self._make_member('data', typ, None, info)])
1963         return QAPISchemaObjectTypeVariant(case, typ, ifcond)
1964
1965     def _def_union_type(self, expr, info, doc):
1966         name = expr['union']
1967         data = expr['data']
1968         base = expr.get('base')
1969         ifcond = expr.get('if')
1970         tag_name = expr.get('discriminator')
1971         tag_member = None
1972         if isinstance(base, dict):
1973             base = self._make_implicit_object_type(
1974                 name, info, doc, ifcond,
1975                 'base', self._make_members(base, info))
1976         if tag_name:
1977             variants = [self._make_variant(key, value['type'], value.get('if'))
1978                         for (key, value) in data.items()]
1979             members = []
1980         else:
1981             variants = [self._make_simple_variant(key, value['type'],
1982                                                   value.get('if'), info)
1983                         for (key, value) in data.items()]
1984             enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
1985             typ = self._make_implicit_enum_type(name, info, ifcond, enum)
1986             tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1987             members = [tag_member]
1988         self._def_entity(
1989             QAPISchemaObjectType(name, info, doc, ifcond, base, members,
1990                                  QAPISchemaObjectTypeVariants(tag_name,
1991                                                               tag_member,
1992                                                               variants), []))
1993
1994     def _def_alternate_type(self, expr, info, doc):
1995         name = expr['alternate']
1996         data = expr['data']
1997         ifcond = expr.get('if')
1998         variants = [self._make_variant(key, value['type'], value.get('if'))
1999                     for (key, value) in data.items()]
2000         tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
2001         self._def_entity(
2002             QAPISchemaAlternateType(name, info, doc, ifcond,
2003                                     QAPISchemaObjectTypeVariants(None,
2004                                                                  tag_member,
2005                                                                  variants)))
2006
2007     def _def_command(self, expr, info, doc):
2008         name = expr['command']
2009         data = expr.get('data')
2010         rets = expr.get('returns')
2011         gen = expr.get('gen', True)
2012         success_response = expr.get('success-response', True)
2013         boxed = expr.get('boxed', False)
2014         allow_oob = expr.get('allow-oob', False)
2015         allow_preconfig = expr.get('allow-preconfig', False)
2016         ifcond = expr.get('if')
2017         if isinstance(data, OrderedDict):
2018             data = self._make_implicit_object_type(
2019                 name, info, doc, ifcond, 'arg', self._make_members(data, info))
2020         if isinstance(rets, list):
2021             assert len(rets) == 1
2022             rets = self._make_array_type(rets[0], info)
2023         self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets,
2024                                            gen, success_response,
2025                                            boxed, allow_oob, allow_preconfig))
2026
2027     def _def_event(self, expr, info, doc):
2028         name = expr['event']
2029         data = expr.get('data')
2030         boxed = expr.get('boxed', False)
2031         ifcond = expr.get('if')
2032         if isinstance(data, OrderedDict):
2033             data = self._make_implicit_object_type(
2034                 name, info, doc, ifcond, 'arg', self._make_members(data, info))
2035         self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed))
2036
2037     def _def_exprs(self, exprs):
2038         for expr_elem in exprs:
2039             expr = expr_elem['expr']
2040             info = expr_elem['info']
2041             doc = expr_elem.get('doc')
2042             if 'enum' in expr:
2043                 self._def_enum_type(expr, info, doc)
2044             elif 'struct' in expr:
2045                 self._def_struct_type(expr, info, doc)
2046             elif 'union' in expr:
2047                 self._def_union_type(expr, info, doc)
2048             elif 'alternate' in expr:
2049                 self._def_alternate_type(expr, info, doc)
2050             elif 'command' in expr:
2051                 self._def_command(expr, info, doc)
2052             elif 'event' in expr:
2053                 self._def_event(expr, info, doc)
2054             elif 'include' in expr:
2055                 self._def_include(expr, info, doc)
2056             else:
2057                 assert False
2058
2059     def check(self):
2060         for ent in self._entity_list:
2061             ent.check(self)
2062
2063     def visit(self, visitor):
2064         visitor.visit_begin(self)
2065         module = None
2066         visitor.visit_module(module)
2067         for entity in self._entity_list:
2068             if visitor.visit_needed(entity):
2069                 if entity.module != module:
2070                     module = entity.module
2071                     visitor.visit_module(module)
2072                 entity.visit(visitor)
2073         visitor.visit_end()
2074
2075
2076 #
2077 # Code generation helpers
2078 #
2079
2080 def camel_case(name):
2081     new_name = ''
2082     first = True
2083     for ch in name:
2084         if ch in ['_', '-']:
2085             first = True
2086         elif first:
2087             new_name += ch.upper()
2088             first = False
2089         else:
2090             new_name += ch.lower()
2091     return new_name
2092
2093
2094 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
2095 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
2096 # ENUM24_Name -> ENUM24_NAME
2097 def camel_to_upper(value):
2098     c_fun_str = c_name(value, False)
2099     if value.isupper():
2100         return c_fun_str
2101
2102     new_name = ''
2103     length = len(c_fun_str)
2104     for i in range(length):
2105         c = c_fun_str[i]
2106         # When c is upper and no '_' appears before, do more checks
2107         if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
2108             if i < length - 1 and c_fun_str[i + 1].islower():
2109                 new_name += '_'
2110             elif c_fun_str[i - 1].isdigit():
2111                 new_name += '_'
2112         new_name += c
2113     return new_name.lstrip('_').upper()
2114
2115
2116 def c_enum_const(type_name, const_name, prefix=None):
2117     if prefix is not None:
2118         type_name = prefix
2119     return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
2120
2121
2122 if hasattr(str, 'maketrans'):
2123     c_name_trans = str.maketrans('.-', '__')
2124 else:
2125     c_name_trans = string.maketrans('.-', '__')
2126
2127
2128 # Map @name to a valid C identifier.
2129 # If @protect, avoid returning certain ticklish identifiers (like
2130 # C keywords) by prepending 'q_'.
2131 #
2132 # Used for converting 'name' from a 'name':'type' qapi definition
2133 # into a generated struct member, as well as converting type names
2134 # into substrings of a generated C function name.
2135 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
2136 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
2137 def c_name(name, protect=True):
2138     # ANSI X3J11/88-090, 3.1.1
2139     c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
2140                      'default', 'do', 'double', 'else', 'enum', 'extern',
2141                      'float', 'for', 'goto', 'if', 'int', 'long', 'register',
2142                      'return', 'short', 'signed', 'sizeof', 'static',
2143                      'struct', 'switch', 'typedef', 'union', 'unsigned',
2144                      'void', 'volatile', 'while'])
2145     # ISO/IEC 9899:1999, 6.4.1
2146     c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
2147     # ISO/IEC 9899:2011, 6.4.1
2148     c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
2149                      '_Noreturn', '_Static_assert', '_Thread_local'])
2150     # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
2151     # excluding _.*
2152     gcc_words = set(['asm', 'typeof'])
2153     # C++ ISO/IEC 14882:2003 2.11
2154     cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
2155                      'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
2156                      'namespace', 'new', 'operator', 'private', 'protected',
2157                      'public', 'reinterpret_cast', 'static_cast', 'template',
2158                      'this', 'throw', 'true', 'try', 'typeid', 'typename',
2159                      'using', 'virtual', 'wchar_t',
2160                      # alternative representations
2161                      'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
2162                      'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
2163     # namespace pollution:
2164     polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386'])
2165     name = name.translate(c_name_trans)
2166     if protect and (name in c89_words | c99_words | c11_words | gcc_words
2167                     | cpp_words | polluted_words):
2168         return 'q_' + name
2169     return name
2170
2171
2172 eatspace = '\033EATSPACE.'
2173 pointer_suffix = ' *' + eatspace
2174
2175
2176 def genindent(count):
2177     ret = ''
2178     for _ in range(count):
2179         ret += ' '
2180     return ret
2181
2182
2183 indent_level = 0
2184
2185
2186 def push_indent(indent_amount=4):
2187     global indent_level
2188     indent_level += indent_amount
2189
2190
2191 def pop_indent(indent_amount=4):
2192     global indent_level
2193     indent_level -= indent_amount
2194
2195
2196 # Generate @code with @kwds interpolated.
2197 # Obey indent_level, and strip eatspace.
2198 def cgen(code, **kwds):
2199     raw = code % kwds
2200     if indent_level:
2201         indent = genindent(indent_level)
2202         # re.subn() lacks flags support before Python 2.7, use re.compile()
2203         raw = re.subn(re.compile(r'^(?!(#|$))', re.MULTILINE),
2204                       indent, raw)
2205         raw = raw[0]
2206     return re.sub(re.escape(eatspace) + r' *', '', raw)
2207
2208
2209 def mcgen(code, **kwds):
2210     if code[0] == '\n':
2211         code = code[1:]
2212     return cgen(code, **kwds)
2213
2214
2215 def c_fname(filename):
2216     return re.sub(r'[^A-Za-z0-9_]', '_', filename)
2217
2218
2219 def guardstart(name):
2220     return mcgen('''
2221 #ifndef %(name)s
2222 #define %(name)s
2223
2224 ''',
2225                  name=c_fname(name).upper())
2226
2227
2228 def guardend(name):
2229     return mcgen('''
2230
2231 #endif /* %(name)s */
2232 ''',
2233                  name=c_fname(name).upper())
2234
2235
2236 def gen_if(ifcond):
2237     ret = ''
2238     for ifc in ifcond:
2239         ret += mcgen('''
2240 #if %(cond)s
2241 ''', cond=ifc)
2242     return ret
2243
2244
2245 def gen_endif(ifcond):
2246     ret = ''
2247     for ifc in reversed(ifcond):
2248         ret += mcgen('''
2249 #endif /* %(cond)s */
2250 ''', cond=ifc)
2251     return ret
2252
2253
2254 def _wrap_ifcond(ifcond, before, after):
2255     if before == after:
2256         return after   # suppress empty #if ... #endif
2257
2258     assert after.startswith(before)
2259     out = before
2260     added = after[len(before):]
2261     if added[0] == '\n':
2262         out += '\n'
2263         added = added[1:]
2264     out += gen_if(ifcond)
2265     out += added
2266     out += gen_endif(ifcond)
2267     return out
2268
2269
2270 def gen_enum_lookup(name, members, prefix=None):
2271     ret = mcgen('''
2272
2273 const QEnumLookup %(c_name)s_lookup = {
2274     .array = (const char *const[]) {
2275 ''',
2276                 c_name=c_name(name))
2277     for m in members:
2278         ret += gen_if(m.ifcond)
2279         index = c_enum_const(name, m.name, prefix)
2280         ret += mcgen('''
2281         [%(index)s] = "%(name)s",
2282 ''',
2283                      index=index, name=m.name)
2284         ret += gen_endif(m.ifcond)
2285
2286     ret += mcgen('''
2287     },
2288     .size = %(max_index)s
2289 };
2290 ''',
2291                  max_index=c_enum_const(name, '_MAX', prefix))
2292     return ret
2293
2294
2295 def gen_enum(name, members, prefix=None):
2296     # append automatically generated _MAX value
2297     enum_members = members + [QAPISchemaEnumMember('_MAX')]
2298
2299     ret = mcgen('''
2300
2301 typedef enum %(c_name)s {
2302 ''',
2303                 c_name=c_name(name))
2304
2305     for m in enum_members:
2306         ret += gen_if(m.ifcond)
2307         ret += mcgen('''
2308     %(c_enum)s,
2309 ''',
2310                      c_enum=c_enum_const(name, m.name, prefix))
2311         ret += gen_endif(m.ifcond)
2312
2313     ret += mcgen('''
2314 } %(c_name)s;
2315 ''',
2316                  c_name=c_name(name))
2317
2318     ret += mcgen('''
2319
2320 #define %(c_name)s_str(val) \\
2321     qapi_enum_lookup(&%(c_name)s_lookup, (val))
2322
2323 extern const QEnumLookup %(c_name)s_lookup;
2324 ''',
2325                  c_name=c_name(name))
2326     return ret
2327
2328
2329 def build_params(arg_type, boxed, extra=None):
2330     ret = ''
2331     sep = ''
2332     if boxed:
2333         assert arg_type
2334         ret += '%s arg' % arg_type.c_param_type()
2335         sep = ', '
2336     elif arg_type:
2337         assert not arg_type.variants
2338         for memb in arg_type.members:
2339             ret += sep
2340             sep = ', '
2341             if memb.optional:
2342                 ret += 'bool has_%s, ' % c_name(memb.name)
2343             ret += '%s %s' % (memb.type.c_param_type(),
2344                               c_name(memb.name))
2345     if extra:
2346         ret += sep + extra
2347     return ret if ret else 'void'
2348
2349
2350 #
2351 # Accumulate and write output
2352 #
2353
2354 class QAPIGen(object):
2355
2356     def __init__(self, fname):
2357         self.fname = fname
2358         self._preamble = ''
2359         self._body = ''
2360
2361     def preamble_add(self, text):
2362         self._preamble += text
2363
2364     def add(self, text):
2365         self._body += text
2366
2367     def get_content(self):
2368         return self._top() + self._preamble + self._body + self._bottom()
2369
2370     def _top(self):
2371         return ''
2372
2373     def _bottom(self):
2374         return ''
2375
2376     def write(self, output_dir):
2377         pathname = os.path.join(output_dir, self.fname)
2378         dir = os.path.dirname(pathname)
2379         if dir:
2380             try:
2381                 os.makedirs(dir)
2382             except os.error as e:
2383                 if e.errno != errno.EEXIST:
2384                     raise
2385         fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666)
2386         if sys.version_info[0] >= 3:
2387             f = open(fd, 'r+', encoding='utf-8')
2388         else:
2389             f = os.fdopen(fd, 'r+')
2390         text = self.get_content()
2391         oldtext = f.read(len(text) + 1)
2392         if text != oldtext:
2393             f.seek(0)
2394             f.truncate(0)
2395             f.write(text)
2396         f.close()
2397
2398
2399 @contextmanager
2400 def ifcontext(ifcond, *args):
2401     """A 'with' statement context manager to wrap with start_if()/end_if()
2402
2403     *args: any number of QAPIGenCCode
2404
2405     Example::
2406
2407         with ifcontext(ifcond, self._genh, self._genc):
2408             modify self._genh and self._genc ...
2409
2410     Is equivalent to calling::
2411
2412         self._genh.start_if(ifcond)
2413         self._genc.start_if(ifcond)
2414         modify self._genh and self._genc ...
2415         self._genh.end_if()
2416         self._genc.end_if()
2417     """
2418     for arg in args:
2419         arg.start_if(ifcond)
2420     yield
2421     for arg in args:
2422         arg.end_if()
2423
2424
2425 class QAPIGenCCode(QAPIGen):
2426
2427     def __init__(self, fname):
2428         QAPIGen.__init__(self, fname)
2429         self._start_if = None
2430
2431     def start_if(self, ifcond):
2432         assert self._start_if is None
2433         self._start_if = (ifcond, self._body, self._preamble)
2434
2435     def end_if(self):
2436         assert self._start_if
2437         self._wrap_ifcond()
2438         self._start_if = None
2439
2440     def _wrap_ifcond(self):
2441         self._body = _wrap_ifcond(self._start_if[0],
2442                                   self._start_if[1], self._body)
2443         self._preamble = _wrap_ifcond(self._start_if[0],
2444                                       self._start_if[2], self._preamble)
2445
2446     def get_content(self):
2447         assert self._start_if is None
2448         return QAPIGen.get_content(self)
2449
2450
2451 class QAPIGenC(QAPIGenCCode):
2452
2453     def __init__(self, fname, blurb, pydoc):
2454         QAPIGenCCode.__init__(self, fname)
2455         self._blurb = blurb
2456         self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
2457                                                   re.MULTILINE))
2458
2459     def _top(self):
2460         return mcgen('''
2461 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2462
2463 /*
2464 %(blurb)s
2465  *
2466  * %(copyright)s
2467  *
2468  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
2469  * See the COPYING.LIB file in the top-level directory.
2470  */
2471
2472 ''',
2473                      blurb=self._blurb, copyright=self._copyright)
2474
2475     def _bottom(self):
2476         return mcgen('''
2477
2478 /* Dummy declaration to prevent empty .o file */
2479 char qapi_dummy_%(name)s;
2480 ''',
2481                      name=c_fname(self.fname))
2482
2483
2484 class QAPIGenH(QAPIGenC):
2485
2486     def _top(self):
2487         return QAPIGenC._top(self) + guardstart(self.fname)
2488
2489     def _bottom(self):
2490         return guardend(self.fname)
2491
2492
2493 class QAPIGenDoc(QAPIGen):
2494
2495     def _top(self):
2496         return (QAPIGen._top(self)
2497                 + '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')
2498
2499
2500 class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):
2501
2502     def __init__(self, prefix, what, blurb, pydoc):
2503         self._prefix = prefix
2504         self._what = what
2505         self._genc = QAPIGenC(self._prefix + self._what + '.c',
2506                               blurb, pydoc)
2507         self._genh = QAPIGenH(self._prefix + self._what + '.h',
2508                               blurb, pydoc)
2509
2510     def write(self, output_dir):
2511         self._genc.write(output_dir)
2512         self._genh.write(output_dir)
2513
2514
2515 class QAPISchemaModularCVisitor(QAPISchemaVisitor):
2516
2517     def __init__(self, prefix, what, blurb, pydoc):
2518         self._prefix = prefix
2519         self._what = what
2520         self._blurb = blurb
2521         self._pydoc = pydoc
2522         self._genc = None
2523         self._genh = None
2524         self._module = {}
2525         self._main_module = None
2526
2527     @staticmethod
2528     def _is_user_module(name):
2529         return name and not name.startswith('./')
2530
2531     @staticmethod
2532     def _is_builtin_module(name):
2533         return not name
2534
2535     def _module_dirname(self, what, name):
2536         if self._is_user_module(name):
2537             return os.path.dirname(name)
2538         return ''
2539
2540     def _module_basename(self, what, name):
2541         ret = '' if self._is_builtin_module(name) else self._prefix
2542         if self._is_user_module(name):
2543             basename = os.path.basename(name)
2544             ret += what
2545             if name != self._main_module:
2546                 ret += '-' + os.path.splitext(basename)[0]
2547         else:
2548             name = name[2:] if name else 'builtin'
2549             ret += re.sub(r'-', '-' + name + '-', what)
2550         return ret
2551
2552     def _module_filename(self, what, name):
2553         return os.path.join(self._module_dirname(what, name),
2554                             self._module_basename(what, name))
2555
2556     def _add_module(self, name, blurb):
2557         basename = self._module_filename(self._what, name)
2558         genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
2559         genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
2560         self._module[name] = (genc, genh)
2561         self._set_module(name)
2562
2563     def _add_user_module(self, name, blurb):
2564         assert self._is_user_module(name)
2565         if self._main_module is None:
2566             self._main_module = name
2567         self._add_module(name, blurb)
2568
2569     def _add_system_module(self, name, blurb):
2570         self._add_module(name and './' + name, blurb)
2571
2572     def _set_module(self, name):
2573         self._genc, self._genh = self._module[name]
2574
2575     def write(self, output_dir, opt_builtins=False):
2576         for name in self._module:
2577             if self._is_builtin_module(name) and not opt_builtins:
2578                 continue
2579             (genc, genh) = self._module[name]
2580             genc.write(output_dir)
2581             genh.write(output_dir)
2582
2583     def _begin_user_module(self, name):
2584         pass
2585
2586     def visit_module(self, name):
2587         if name in self._module:
2588             self._set_module(name)
2589         elif self._is_builtin_module(name):
2590             # The built-in module has not been created.  No code may
2591             # be generated.
2592             self._genc = None
2593             self._genh = None
2594         else:
2595             self._add_user_module(name, self._blurb)
2596             self._begin_user_module(name)
2597
2598     def visit_include(self, name, info):
2599         relname = os.path.relpath(self._module_filename(self._what, name),
2600                                   os.path.dirname(self._genh.fname))
2601         self._genh.preamble_add(mcgen('''
2602 #include "%(relname)s.h"
2603 ''',
2604                                       relname=relname))
This page took 0.21242 seconds and 2 git commands to generate.