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