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