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