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