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