xref: /openbmc/qemu/scripts/qapi/common.py (revision 2ab218aad6e2ddf4e95a7d583492ad7142927ca5)
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(info, source, name,
710               allow_optional=False, enum_member=False, permit_upper=False):
711    global valid_name
712    membername = name
713
714    if not isinstance(name, str):
715        raise QAPISemError(info, "%s requires a string name" % source)
716    if name.startswith('*'):
717        membername = name[1:]
718        if not allow_optional:
719            raise QAPISemError(info, "%s does not allow optional name '%s'"
720                               % (source, name))
721    # Enum members can start with a digit, because the generated C
722    # code always prefixes it with the enum name
723    if enum_member and membername[0].isdigit():
724        membername = 'D' + membername
725    # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
726    # and 'q_obj_*' implicit type names.
727    if not valid_name.match(membername) or \
728       c_name(membername, False).startswith('q_'):
729        raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
730    if not permit_upper and name.lower() != name:
731        raise QAPISemError(
732            info, "%s uses uppercase in name '%s'" % (source, name))
733
734
735def add_name(name, info, meta):
736    global all_names
737    check_name(info, "'%s'" % meta, name, permit_upper=True)
738    # FIXME should reject names that differ only in '_' vs. '.'
739    # vs. '-', because they're liable to clash in generated C.
740    if name in all_names:
741        raise QAPISemError(info, "%s '%s' is already defined"
742                           % (all_names[name], name))
743    if name.endswith('Kind') or name.endswith('List'):
744        raise QAPISemError(info, "%s '%s' should not end in '%s'"
745                           % (meta, name, name[-4:]))
746    all_names[name] = meta
747
748
749def check_if(expr, info):
750
751    def check_if_str(ifcond, info):
752        if not isinstance(ifcond, str):
753            raise QAPISemError(
754                info, "'if' condition must be a string or a list of strings")
755        if ifcond.strip() == '':
756            raise QAPISemError(info, "'if' condition '%s' makes no sense"
757                               % ifcond)
758
759    ifcond = expr.get('if')
760    if ifcond is None:
761        return
762    if isinstance(ifcond, list):
763        if ifcond == []:
764            raise QAPISemError(info, "'if' condition [] is useless")
765        for elt in ifcond:
766            check_if_str(elt, info)
767    else:
768        check_if_str(ifcond, info)
769
770
771def check_type(info, source, value,
772               allow_array=False, allow_dict=False, allow_metas=[]):
773    global all_names
774
775    if value is None:
776        return
777
778    # Check if array type for value is okay
779    if isinstance(value, list):
780        if not allow_array:
781            raise QAPISemError(info, "%s cannot be an array" % source)
782        if len(value) != 1 or not isinstance(value[0], str):
783            raise QAPISemError(info,
784                               "%s: array type must contain single type name" %
785                               source)
786        value = value[0]
787
788    # Check if type name for value is okay
789    if isinstance(value, str):
790        if value not in all_names:
791            raise QAPISemError(info, "%s uses unknown type '%s'"
792                               % (source, value))
793        if not all_names[value] in allow_metas:
794            raise QAPISemError(info, "%s cannot use %s type '%s'" %
795                               (source, all_names[value], value))
796        return
797
798    if not allow_dict:
799        raise QAPISemError(info, "%s should be a type name" % source)
800
801    if not isinstance(value, OrderedDict):
802        raise QAPISemError(info,
803                           "%s should be an object or type name" % source)
804
805    permit_upper = allow_dict in name_case_whitelist
806
807    # value is a dictionary, check that each member is okay
808    for (key, arg) in value.items():
809        check_name(info, "member of %s" % source, key,
810                   allow_optional=True, permit_upper=permit_upper)
811        if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
812            raise QAPISemError(
813                info, "member of %s uses reserved name '%s'" % (source, key))
814        # Todo: allow dictionaries to represent default values of
815        # an optional argument.
816        check_known_keys(info, "member '%s' of %s" % (key, source),
817                         arg, ['type'], ['if'])
818        check_if(arg, info)
819        normalize_if(arg)
820        check_type(info, "member '%s' of %s" % (key, source),
821                   arg['type'], allow_array=True,
822                   allow_metas=['built-in', 'union', 'alternate', 'struct',
823                                'enum'])
824
825
826def check_command(expr, info):
827    name = expr['command']
828    boxed = expr.get('boxed', False)
829
830    args_meta = ['struct']
831    if boxed:
832        args_meta += ['union']
833    check_type(info, "'data' for command '%s'" % name,
834               expr.get('data'), allow_dict=not boxed,
835               allow_metas=args_meta)
836    returns_meta = ['union', 'struct']
837    if name in returns_whitelist:
838        returns_meta += ['built-in', 'alternate', 'enum']
839    check_type(info, "'returns' for command '%s'" % name,
840               expr.get('returns'), allow_array=True,
841               allow_metas=returns_meta)
842
843
844def check_event(expr, info):
845    name = expr['event']
846    boxed = expr.get('boxed', False)
847
848    meta = ['struct']
849    if boxed:
850        meta += ['union']
851    check_type(info, "'data' for event '%s'" % name,
852               expr.get('data'), allow_dict=not boxed,
853               allow_metas=meta)
854
855
856def enum_get_names(expr):
857    return [e['name'] for e in expr['data']]
858
859
860def check_union(expr, info):
861    name = expr['union']
862    base = expr.get('base')
863    discriminator = expr.get('discriminator')
864    members = expr['data']
865
866    # Two types of unions, determined by discriminator.
867
868    # With no discriminator it is a simple union.
869    if discriminator is None:
870        enum_values = members.keys()
871        allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
872        if base is not None:
873            raise QAPISemError(
874                info, "simple union '%s' must not have a base" % name)
875
876    # Else, it's a flat union.
877    else:
878        # The object must have a string or dictionary 'base'.
879        check_type(info, "'base' for union '%s'" % name,
880                   base, allow_dict=name,
881                   allow_metas=['struct'])
882        if not base:
883            raise QAPISemError(
884                info, "flat union '%s' must have a base" % name)
885        base_members = find_base_members(base)
886        assert base_members is not None
887
888        # The value of member 'discriminator' must name a non-optional
889        # member of the base struct.
890        check_name(info, "discriminator of flat union '%s'" % name,
891                   discriminator)
892        discriminator_value = base_members.get(discriminator)
893        if not discriminator_value:
894            raise QAPISemError(info,
895                               "discriminator '%s' is not a member of 'base'"
896                               % discriminator)
897        if discriminator_value.get('if'):
898            raise QAPISemError(
899                info,
900                "the discriminator '%s' for union %s must not be conditional"
901                % (discriminator, name))
902        enum_define = enum_types.get(discriminator_value['type'])
903        # Do not allow string discriminator
904        if not enum_define:
905            raise QAPISemError(
906                info,
907                "discriminator '%s' must be of enumeration type"
908                % discriminator)
909        enum_values = enum_get_names(enum_define)
910        allow_metas = ['struct']
911
912    if (len(enum_values) == 0):
913        raise QAPISemError(info, "union '%s' has no branches" % name)
914
915    for (key, value) in members.items():
916        check_name(info, "member of union '%s'" % name, key)
917
918        check_known_keys(info, "member '%s' of union '%s'" % (key, name),
919                         value, ['type'], ['if'])
920        check_if(value, info)
921        normalize_if(value)
922        # Each value must name a known type
923        check_type(info, "member '%s' of union '%s'" % (key, name),
924                   value['type'],
925                   allow_array=not base, allow_metas=allow_metas)
926
927        # If the discriminator names an enum type, then all members
928        # of 'data' must also be members of the enum type.
929        if discriminator is not None:
930            if key not in enum_values:
931                raise QAPISemError(
932                    info,
933                    "discriminator value '%s' is not found in enum '%s'"
934                    % (key, enum_define['enum']))
935
936
937def check_alternate(expr, info):
938    name = expr['alternate']
939    members = expr['data']
940    types_seen = {}
941
942    if len(members) == 0:
943        raise QAPISemError(info,
944                           "alternate '%s' cannot have empty 'data'" % name)
945    for (key, value) in members.items():
946        check_name(info, "member of alternate '%s'" % name, key)
947        check_known_keys(info,
948                         "member '%s' of alternate '%s'" % (key, name),
949                         value, ['type'], ['if'])
950        check_if(value, info)
951        normalize_if(value)
952        typ = value['type']
953
954        # Ensure alternates have no type conflicts.
955        check_type(info, "member '%s' of alternate '%s'" % (key, name), typ,
956                   allow_metas=['built-in', 'union', 'struct', 'enum'])
957        qtype = find_alternate_member_qtype(typ)
958        if not qtype:
959            raise QAPISemError(
960                info,
961                "alternate '%s' member '%s' cannot use type '%s'"
962                % (name, key, typ))
963        conflicting = set([qtype])
964        if qtype == 'QTYPE_QSTRING':
965            enum_expr = enum_types.get(typ)
966            if enum_expr:
967                for v in enum_get_names(enum_expr):
968                    if v in ['on', 'off']:
969                        conflicting.add('QTYPE_QBOOL')
970                    if re.match(r'[-+0-9.]', v): # lazy, could be tightened
971                        conflicting.add('QTYPE_QNUM')
972            else:
973                conflicting.add('QTYPE_QNUM')
974                conflicting.add('QTYPE_QBOOL')
975        for qt in conflicting:
976            if qt in types_seen:
977                raise QAPISemError(
978                    info,
979                    "alternate '%s' member '%s' can't be distinguished "
980                    "from member '%s'"
981                    % (name, key, types_seen[qt]))
982            types_seen[qt] = key
983
984
985def check_enum(expr, info):
986    name = expr['enum']
987    members = expr['data']
988    prefix = expr.get('prefix')
989
990    if not isinstance(members, list):
991        raise QAPISemError(info,
992                           "enum '%s' requires an array for 'data'" % name)
993    if prefix is not None and not isinstance(prefix, str):
994        raise QAPISemError(info,
995                           "enum '%s' requires a string for 'prefix'" % name)
996
997    permit_upper = name in name_case_whitelist
998
999    for member in members:
1000        check_known_keys(info, "member of enum '%s'" % name, member,
1001                         ['name'], ['if'])
1002        check_if(member, info)
1003        normalize_if(member)
1004        check_name(info, "member of enum '%s'" % name, member['name'],
1005                   enum_member=True, permit_upper=permit_upper)
1006
1007
1008def check_struct(expr, info):
1009    name = expr['struct']
1010    members = expr['data']
1011    features = expr.get('features')
1012
1013    check_type(info, "'data' for struct '%s'" % name, members,
1014               allow_dict=name)
1015    check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
1016               allow_metas=['struct'])
1017
1018    if features:
1019        if not isinstance(features, list):
1020            raise QAPISemError(
1021                info, "struct '%s' requires an array for 'features'" % name)
1022        for f in features:
1023            assert isinstance(f, dict)
1024            check_known_keys(info, "feature of struct %s" % name, f,
1025                             ['name'], ['if'])
1026
1027            check_if(f, info)
1028            normalize_if(f)
1029            check_name(info, "feature of struct %s" % name, f['name'])
1030
1031
1032def check_known_keys(info, source, value, required, optional):
1033
1034    def pprint(elems):
1035        return ', '.join("'" + e + "'" for e in sorted(elems))
1036
1037    missing = set(required) - set(value)
1038    if missing:
1039        raise QAPISemError(
1040            info,
1041            "key%s %s %s missing from %s"
1042            % ('s' if len(missing) > 1 else '', pprint(missing),
1043               'are' if len(missing) > 1 else 'is', source))
1044    allowed = set(required + optional)
1045    unknown = set(value) - allowed
1046    if unknown:
1047        raise QAPISemError(
1048            info,
1049            "unknown key%s %s in %s\nValid keys are %s."
1050            % ('s' if len(unknown) > 1 else '', pprint(unknown),
1051               source, pprint(allowed)))
1052
1053
1054def check_keys(expr, info, meta, required, optional=[]):
1055    name = expr[meta]
1056    if not isinstance(name, str):
1057        raise QAPISemError(info, "'%s' key must have a string value" % meta)
1058    required = required + [meta]
1059    source = "%s '%s'" % (meta, name)
1060    check_known_keys(info, source, expr, required, optional)
1061    for (key, value) in expr.items():
1062        if key in ['gen', 'success-response'] and value is not False:
1063            raise QAPISemError(info,
1064                               "'%s' of %s '%s' should only use false value"
1065                               % (key, meta, name))
1066        if (key in ['boxed', 'allow-oob', 'allow-preconfig']
1067                and value is not True):
1068            raise QAPISemError(info,
1069                               "'%s' of %s '%s' should only use true value"
1070                               % (key, meta, name))
1071        if key == 'if':
1072            check_if(expr, info)
1073
1074
1075def normalize_enum(expr):
1076    if isinstance(expr['data'], list):
1077        expr['data'] = [m if isinstance(m, dict) else {'name': m}
1078                        for m in expr['data']]
1079
1080
1081def normalize_members(members):
1082    if isinstance(members, OrderedDict):
1083        for key, arg in members.items():
1084            if isinstance(arg, dict):
1085                continue
1086            members[key] = {'type': arg}
1087
1088
1089def normalize_features(features):
1090    if isinstance(features, list):
1091        features[:] = [f if isinstance(f, dict) else {'name': f}
1092                       for f in features]
1093
1094
1095def normalize_if(expr):
1096    ifcond = expr.get('if')
1097    if isinstance(ifcond, str):
1098        expr['if'] = [ifcond]
1099
1100
1101def check_exprs(exprs):
1102    global all_names
1103
1104    # Populate name table with names of built-in types
1105    for builtin in builtin_types.keys():
1106        all_names[builtin] = 'built-in'
1107
1108    # Learn the types and check for valid expression keys
1109    for expr_elem in exprs:
1110        expr = expr_elem['expr']
1111        info = expr_elem['info']
1112        doc = expr_elem.get('doc')
1113
1114        if 'include' in expr:
1115            continue
1116
1117        if not doc and doc_required:
1118            raise QAPISemError(info,
1119                               "definition missing documentation comment")
1120
1121        if 'enum' in expr:
1122            meta = 'enum'
1123            check_keys(expr, info, 'enum', ['data'], ['if', 'prefix'])
1124            normalize_enum(expr)
1125            enum_types[expr[meta]] = expr
1126        elif 'union' in expr:
1127            meta = 'union'
1128            check_keys(expr, info, 'union', ['data'],
1129                       ['base', 'discriminator', 'if'])
1130            normalize_members(expr.get('base'))
1131            normalize_members(expr['data'])
1132            union_types[expr[meta]] = expr
1133        elif 'alternate' in expr:
1134            meta = 'alternate'
1135            check_keys(expr, info, 'alternate', ['data'], ['if'])
1136            normalize_members(expr['data'])
1137        elif 'struct' in expr:
1138            meta = 'struct'
1139            check_keys(expr, info, 'struct', ['data'],
1140                       ['base', 'if', 'features'])
1141            normalize_members(expr['data'])
1142            normalize_features(expr.get('features'))
1143            struct_types[expr[meta]] = expr
1144        elif 'command' in expr:
1145            meta = 'command'
1146            check_keys(expr, info, 'command', [],
1147                       ['data', 'returns', 'gen', 'success-response',
1148                        'boxed', 'allow-oob', 'allow-preconfig', 'if'])
1149            normalize_members(expr.get('data'))
1150        elif 'event' in expr:
1151            meta = 'event'
1152            check_keys(expr, info, 'event', [], ['data', 'boxed', 'if'])
1153            normalize_members(expr.get('data'))
1154        else:
1155            raise QAPISemError(info, "expression is missing metatype")
1156        normalize_if(expr)
1157        name = expr[meta]
1158        add_name(name, info, meta)
1159        info.set_defn(meta, name)
1160        if doc and doc.symbol != name:
1161            raise QAPISemError(
1162                info,
1163                "definition of '%s' follows documentation for '%s'"
1164                % (name, doc.symbol))
1165
1166    # Validate that exprs make sense
1167    for expr_elem in exprs:
1168        expr = expr_elem['expr']
1169        info = expr_elem['info']
1170        doc = expr_elem.get('doc')
1171
1172        if 'include' in expr:
1173            continue
1174        if 'enum' in expr:
1175            check_enum(expr, info)
1176        elif 'union' in expr:
1177            check_union(expr, info)
1178        elif 'alternate' in expr:
1179            check_alternate(expr, info)
1180        elif 'struct' in expr:
1181            check_struct(expr, info)
1182        elif 'command' in expr:
1183            check_command(expr, info)
1184        elif 'event' in expr:
1185            check_event(expr, info)
1186        else:
1187            assert False, 'unexpected meta type'
1188
1189        if doc:
1190            doc.check_expr(expr)
1191
1192    return exprs
1193
1194
1195#
1196# Schema compiler frontend
1197#
1198
1199class QAPISchemaEntity(object):
1200    def __init__(self, name, info, doc, ifcond=None):
1201        assert name is None or isinstance(name, str)
1202        self.name = name
1203        self._module = None
1204        # For explicitly defined entities, info points to the (explicit)
1205        # definition.  For builtins (and their arrays), info is None.
1206        # For implicitly defined entities, info points to a place that
1207        # triggered the implicit definition (there may be more than one
1208        # such place).
1209        self.info = info
1210        self.doc = doc
1211        self._ifcond = ifcond or []
1212        self._checked = False
1213
1214    def c_name(self):
1215        return c_name(self.name)
1216
1217    def check(self, schema):
1218        assert not self._checked
1219        if self.info:
1220            self._module = os.path.relpath(self.info.fname,
1221                                           os.path.dirname(schema.fname))
1222        self._checked = True
1223
1224    @property
1225    def ifcond(self):
1226        assert self._checked
1227        return self._ifcond
1228
1229    @property
1230    def module(self):
1231        assert self._checked
1232        return self._module
1233
1234    def is_implicit(self):
1235        return not self.info
1236
1237    def visit(self, visitor):
1238        assert self._checked
1239
1240
1241class QAPISchemaVisitor(object):
1242    def visit_begin(self, schema):
1243        pass
1244
1245    def visit_end(self):
1246        pass
1247
1248    def visit_module(self, fname):
1249        pass
1250
1251    def visit_needed(self, entity):
1252        # Default to visiting everything
1253        return True
1254
1255    def visit_include(self, fname, info):
1256        pass
1257
1258    def visit_builtin_type(self, name, info, json_type):
1259        pass
1260
1261    def visit_enum_type(self, name, info, ifcond, members, prefix):
1262        pass
1263
1264    def visit_array_type(self, name, info, ifcond, element_type):
1265        pass
1266
1267    def visit_object_type(self, name, info, ifcond, base, members, variants,
1268                          features):
1269        pass
1270
1271    def visit_object_type_flat(self, name, info, ifcond, members, variants,
1272                               features):
1273        pass
1274
1275    def visit_alternate_type(self, name, info, ifcond, variants):
1276        pass
1277
1278    def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
1279                      success_response, boxed, allow_oob, allow_preconfig):
1280        pass
1281
1282    def visit_event(self, name, info, ifcond, arg_type, boxed):
1283        pass
1284
1285
1286class QAPISchemaInclude(QAPISchemaEntity):
1287
1288    def __init__(self, fname, info):
1289        QAPISchemaEntity.__init__(self, None, info, None)
1290        self.fname = fname
1291
1292    def visit(self, visitor):
1293        QAPISchemaEntity.visit(self, visitor)
1294        visitor.visit_include(self.fname, self.info)
1295
1296
1297class QAPISchemaType(QAPISchemaEntity):
1298    # Return the C type for common use.
1299    # For the types we commonly box, this is a pointer type.
1300    def c_type(self):
1301        pass
1302
1303    # Return the C type to be used in a parameter list.
1304    def c_param_type(self):
1305        return self.c_type()
1306
1307    # Return the C type to be used where we suppress boxing.
1308    def c_unboxed_type(self):
1309        return self.c_type()
1310
1311    def json_type(self):
1312        pass
1313
1314    def alternate_qtype(self):
1315        json2qtype = {
1316            'null':    'QTYPE_QNULL',
1317            'string':  'QTYPE_QSTRING',
1318            'number':  'QTYPE_QNUM',
1319            'int':     'QTYPE_QNUM',
1320            'boolean': 'QTYPE_QBOOL',
1321            'object':  'QTYPE_QDICT'
1322        }
1323        return json2qtype.get(self.json_type())
1324
1325    def doc_type(self):
1326        if self.is_implicit():
1327            return None
1328        return self.name
1329
1330
1331class QAPISchemaBuiltinType(QAPISchemaType):
1332    def __init__(self, name, json_type, c_type):
1333        QAPISchemaType.__init__(self, name, None, None)
1334        assert not c_type or isinstance(c_type, str)
1335        assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1336                             'value')
1337        self._json_type_name = json_type
1338        self._c_type_name = c_type
1339
1340    def c_name(self):
1341        return self.name
1342
1343    def c_type(self):
1344        return self._c_type_name
1345
1346    def c_param_type(self):
1347        if self.name == 'str':
1348            return 'const ' + self._c_type_name
1349        return self._c_type_name
1350
1351    def json_type(self):
1352        return self._json_type_name
1353
1354    def doc_type(self):
1355        return self.json_type()
1356
1357    def visit(self, visitor):
1358        QAPISchemaType.visit(self, visitor)
1359        visitor.visit_builtin_type(self.name, self.info, self.json_type())
1360
1361
1362class QAPISchemaEnumType(QAPISchemaType):
1363    def __init__(self, name, info, doc, ifcond, members, prefix):
1364        QAPISchemaType.__init__(self, name, info, doc, ifcond)
1365        for m in members:
1366            assert isinstance(m, QAPISchemaEnumMember)
1367            m.set_defined_in(name)
1368        assert prefix is None or isinstance(prefix, str)
1369        self.members = members
1370        self.prefix = prefix
1371
1372    def check(self, schema):
1373        QAPISchemaType.check(self, schema)
1374        seen = {}
1375        for m in self.members:
1376            m.check_clash(self.info, seen)
1377            if self.doc:
1378                self.doc.connect_member(m)
1379
1380    def is_implicit(self):
1381        # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1382        return self.name.endswith('Kind') or self.name == 'QType'
1383
1384    def c_type(self):
1385        return c_name(self.name)
1386
1387    def member_names(self):
1388        return [m.name for m in self.members]
1389
1390    def json_type(self):
1391        return 'string'
1392
1393    def visit(self, visitor):
1394        QAPISchemaType.visit(self, visitor)
1395        visitor.visit_enum_type(self.name, self.info, self.ifcond,
1396                                self.members, self.prefix)
1397
1398
1399class QAPISchemaArrayType(QAPISchemaType):
1400    def __init__(self, name, info, element_type):
1401        QAPISchemaType.__init__(self, name, info, None, None)
1402        assert isinstance(element_type, str)
1403        self._element_type_name = element_type
1404        self.element_type = None
1405
1406    def check(self, schema):
1407        QAPISchemaType.check(self, schema)
1408        self.element_type = schema.lookup_type(self._element_type_name)
1409        assert self.element_type
1410        assert not isinstance(self.element_type, QAPISchemaArrayType)
1411
1412    @property
1413    def ifcond(self):
1414        assert self._checked
1415        return self.element_type.ifcond
1416
1417    @property
1418    def module(self):
1419        assert self._checked
1420        return self.element_type.module
1421
1422    def is_implicit(self):
1423        return True
1424
1425    def c_type(self):
1426        return c_name(self.name) + pointer_suffix
1427
1428    def json_type(self):
1429        return 'array'
1430
1431    def doc_type(self):
1432        elt_doc_type = self.element_type.doc_type()
1433        if not elt_doc_type:
1434            return None
1435        return 'array of ' + elt_doc_type
1436
1437    def visit(self, visitor):
1438        QAPISchemaType.visit(self, visitor)
1439        visitor.visit_array_type(self.name, self.info, self.ifcond,
1440                                 self.element_type)
1441
1442
1443class QAPISchemaObjectType(QAPISchemaType):
1444    def __init__(self, name, info, doc, ifcond,
1445                 base, local_members, variants, features):
1446        # struct has local_members, optional base, and no variants
1447        # flat union has base, variants, and no local_members
1448        # simple union has local_members, variants, and no base
1449        QAPISchemaType.__init__(self, name, info, doc, ifcond)
1450        assert base is None or isinstance(base, str)
1451        for m in local_members:
1452            assert isinstance(m, QAPISchemaObjectTypeMember)
1453            m.set_defined_in(name)
1454        if variants is not None:
1455            assert isinstance(variants, QAPISchemaObjectTypeVariants)
1456            variants.set_defined_in(name)
1457        for f in features:
1458            assert isinstance(f, QAPISchemaFeature)
1459            f.set_defined_in(name)
1460        self._base_name = base
1461        self.base = None
1462        self.local_members = local_members
1463        self.variants = variants
1464        self.members = None
1465        self.features = features
1466
1467    def check(self, schema):
1468        # This calls another type T's .check() exactly when the C
1469        # struct emitted by gen_object() contains that T's C struct
1470        # (pointers don't count).
1471        if self.members is not None:
1472            # A previous .check() completed: nothing to do
1473            return
1474        if self._checked:
1475            # Recursed: C struct contains itself
1476            raise QAPISemError(self.info,
1477                               "object %s contains itself" % self.name)
1478
1479        QAPISchemaType.check(self, schema)
1480        assert self._checked and self.members is None
1481
1482        seen = OrderedDict()
1483        if self._base_name:
1484            self.base = schema.lookup_type(self._base_name)
1485            assert isinstance(self.base, QAPISchemaObjectType)
1486            self.base.check(schema)
1487            self.base.check_clash(self.info, seen)
1488        for m in self.local_members:
1489            m.check(schema)
1490            m.check_clash(self.info, seen)
1491            if self.doc:
1492                self.doc.connect_member(m)
1493        members = seen.values()
1494
1495        if self.variants:
1496            self.variants.check(schema, seen)
1497            assert self.variants.tag_member in members
1498            self.variants.check_clash(self.info, seen)
1499
1500        # Features are in a name space separate from members
1501        seen = {}
1502        for f in self.features:
1503            f.check_clash(self.info, seen)
1504
1505        if self.doc:
1506            self.doc.check()
1507
1508        self.members = members  # mark completed
1509
1510    # Check that the members of this type do not cause duplicate JSON members,
1511    # and update seen to track the members seen so far. Report any errors
1512    # on behalf of info, which is not necessarily self.info
1513    def check_clash(self, info, seen):
1514        assert self._checked
1515        assert not self.variants       # not implemented
1516        for m in self.members:
1517            m.check_clash(info, seen)
1518
1519    @property
1520    def ifcond(self):
1521        assert self._checked
1522        if isinstance(self._ifcond, QAPISchemaType):
1523            # Simple union wrapper type inherits from wrapped type;
1524            # see _make_implicit_object_type()
1525            return self._ifcond.ifcond
1526        return self._ifcond
1527
1528    def is_implicit(self):
1529        # See QAPISchema._make_implicit_object_type(), as well as
1530        # _def_predefineds()
1531        return self.name.startswith('q_')
1532
1533    def is_empty(self):
1534        assert self.members is not None
1535        return not self.members and not self.variants
1536
1537    def c_name(self):
1538        assert self.name != 'q_empty'
1539        return QAPISchemaType.c_name(self)
1540
1541    def c_type(self):
1542        assert not self.is_implicit()
1543        return c_name(self.name) + pointer_suffix
1544
1545    def c_unboxed_type(self):
1546        return c_name(self.name)
1547
1548    def json_type(self):
1549        return 'object'
1550
1551    def visit(self, visitor):
1552        QAPISchemaType.visit(self, visitor)
1553        visitor.visit_object_type(self.name, self.info, self.ifcond,
1554                                  self.base, self.local_members, self.variants,
1555                                  self.features)
1556        visitor.visit_object_type_flat(self.name, self.info, self.ifcond,
1557                                       self.members, self.variants,
1558                                       self.features)
1559
1560
1561class QAPISchemaMember(object):
1562    """ Represents object members, enum members and features """
1563    role = 'member'
1564
1565    def __init__(self, name, ifcond=None):
1566        assert isinstance(name, str)
1567        self.name = name
1568        self.ifcond = ifcond or []
1569        self.defined_in = None
1570
1571    def set_defined_in(self, name):
1572        assert not self.defined_in
1573        self.defined_in = name
1574
1575    def check_clash(self, info, seen):
1576        cname = c_name(self.name)
1577        if cname in seen:
1578            raise QAPISemError(info, "%s collides with %s" %
1579                               (self.describe(), seen[cname].describe()))
1580        seen[cname] = self
1581
1582    def _pretty_defined_in(self):
1583        defined_in = self.defined_in
1584        if defined_in.startswith('q_obj_'):
1585            # See QAPISchema._make_implicit_object_type() - reverse the
1586            # mapping there to create a nice human-readable description
1587            defined_in = defined_in[6:]
1588            if defined_in.endswith('-arg'):
1589                return '(parameter of %s)' % defined_in[:-4]
1590            elif defined_in.endswith('-base'):
1591                return '(base of %s)' % defined_in[:-5]
1592            else:
1593                assert defined_in.endswith('-wrapper')
1594                # Unreachable and not implemented
1595                assert False
1596        if defined_in.endswith('Kind'):
1597            # See QAPISchema._make_implicit_enum_type()
1598            return '(branch of %s)' % defined_in[:-4]
1599        return '(%s of %s)' % (self.role, defined_in)
1600
1601    def describe(self):
1602        return "'%s' %s" % (self.name, self._pretty_defined_in())
1603
1604
1605class QAPISchemaEnumMember(QAPISchemaMember):
1606    role = 'value'
1607
1608
1609class QAPISchemaFeature(QAPISchemaMember):
1610    role = 'feature'
1611
1612
1613class QAPISchemaObjectTypeMember(QAPISchemaMember):
1614    def __init__(self, name, typ, optional, ifcond=None):
1615        QAPISchemaMember.__init__(self, name, ifcond)
1616        assert isinstance(typ, str)
1617        assert isinstance(optional, bool)
1618        self._type_name = typ
1619        self.type = None
1620        self.optional = optional
1621
1622    def check(self, schema):
1623        assert self.defined_in
1624        self.type = schema.lookup_type(self._type_name)
1625        assert self.type
1626
1627
1628class QAPISchemaObjectTypeVariants(object):
1629    def __init__(self, tag_name, tag_member, variants):
1630        # Flat unions pass tag_name but not tag_member.
1631        # Simple unions and alternates pass tag_member but not tag_name.
1632        # After check(), tag_member is always set, and tag_name remains
1633        # a reliable witness of being used by a flat union.
1634        assert bool(tag_member) != bool(tag_name)
1635        assert (isinstance(tag_name, str) or
1636                isinstance(tag_member, QAPISchemaObjectTypeMember))
1637        for v in variants:
1638            assert isinstance(v, QAPISchemaObjectTypeVariant)
1639        self._tag_name = tag_name
1640        self.tag_member = tag_member
1641        self.variants = variants
1642
1643    def set_defined_in(self, name):
1644        for v in self.variants:
1645            v.set_defined_in(name)
1646
1647    def check(self, schema, seen):
1648        if not self.tag_member:    # flat union
1649            self.tag_member = seen[c_name(self._tag_name)]
1650            assert self._tag_name == self.tag_member.name
1651        assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1652        assert not self.tag_member.optional
1653        assert self.tag_member.ifcond == []
1654        if self._tag_name:    # flat union
1655            # branches that are not explicitly covered get an empty type
1656            cases = set([v.name for v in self.variants])
1657            for m in self.tag_member.type.members:
1658                if m.name not in cases:
1659                    v = QAPISchemaObjectTypeVariant(m.name, 'q_empty',
1660                                                    m.ifcond)
1661                    v.set_defined_in(self.tag_member.defined_in)
1662                    self.variants.append(v)
1663        assert self.variants
1664        for v in self.variants:
1665            v.check(schema)
1666            # Union names must match enum values; alternate names are
1667            # checked separately. Use 'seen' to tell the two apart.
1668            if seen:
1669                assert v.name in self.tag_member.type.member_names()
1670                assert (isinstance(v.type, QAPISchemaObjectType)
1671                        and not v.type.variants)
1672                v.type.check(schema)
1673
1674    def check_clash(self, info, seen):
1675        for v in self.variants:
1676            # Reset seen map for each variant, since qapi names from one
1677            # branch do not affect another branch
1678            v.type.check_clash(info, dict(seen))
1679
1680
1681class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1682    role = 'branch'
1683
1684    def __init__(self, name, typ, ifcond=None):
1685        QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
1686
1687
1688class QAPISchemaAlternateType(QAPISchemaType):
1689    def __init__(self, name, info, doc, ifcond, variants):
1690        QAPISchemaType.__init__(self, name, info, doc, ifcond)
1691        assert isinstance(variants, QAPISchemaObjectTypeVariants)
1692        assert variants.tag_member
1693        variants.set_defined_in(name)
1694        variants.tag_member.set_defined_in(self.name)
1695        self.variants = variants
1696
1697    def check(self, schema):
1698        QAPISchemaType.check(self, schema)
1699        self.variants.tag_member.check(schema)
1700        # Not calling self.variants.check_clash(), because there's nothing
1701        # to clash with
1702        self.variants.check(schema, {})
1703        # Alternate branch names have no relation to the tag enum values;
1704        # so we have to check for potential name collisions ourselves.
1705        seen = {}
1706        for v in self.variants.variants:
1707            v.check_clash(self.info, seen)
1708            # TODO check conflicting qtypes
1709            if self.doc:
1710                self.doc.connect_member(v)
1711        if self.doc:
1712            self.doc.check()
1713
1714    def c_type(self):
1715        return c_name(self.name) + pointer_suffix
1716
1717    def json_type(self):
1718        return 'value'
1719
1720    def visit(self, visitor):
1721        QAPISchemaType.visit(self, visitor)
1722        visitor.visit_alternate_type(self.name, self.info, self.ifcond,
1723                                     self.variants)
1724
1725
1726class QAPISchemaCommand(QAPISchemaEntity):
1727    def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
1728                 gen, success_response, boxed, allow_oob, allow_preconfig):
1729        QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
1730        assert not arg_type or isinstance(arg_type, str)
1731        assert not ret_type or isinstance(ret_type, str)
1732        self._arg_type_name = arg_type
1733        self.arg_type = None
1734        self._ret_type_name = ret_type
1735        self.ret_type = None
1736        self.gen = gen
1737        self.success_response = success_response
1738        self.boxed = boxed
1739        self.allow_oob = allow_oob
1740        self.allow_preconfig = allow_preconfig
1741
1742    def check(self, schema):
1743        QAPISchemaEntity.check(self, schema)
1744        if self._arg_type_name:
1745            self.arg_type = schema.lookup_type(self._arg_type_name)
1746            assert isinstance(self.arg_type, QAPISchemaObjectType)
1747            assert not self.arg_type.variants or self.boxed
1748        elif self.boxed:
1749            raise QAPISemError(self.info, "use of 'boxed' requires 'data'")
1750        if self._ret_type_name:
1751            self.ret_type = schema.lookup_type(self._ret_type_name)
1752            assert isinstance(self.ret_type, QAPISchemaType)
1753
1754    def visit(self, visitor):
1755        QAPISchemaEntity.visit(self, visitor)
1756        visitor.visit_command(self.name, self.info, self.ifcond,
1757                              self.arg_type, self.ret_type,
1758                              self.gen, self.success_response,
1759                              self.boxed, self.allow_oob,
1760                              self.allow_preconfig)
1761
1762
1763class QAPISchemaEvent(QAPISchemaEntity):
1764    def __init__(self, name, info, doc, ifcond, arg_type, boxed):
1765        QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
1766        assert not arg_type or isinstance(arg_type, str)
1767        self._arg_type_name = arg_type
1768        self.arg_type = None
1769        self.boxed = boxed
1770
1771    def check(self, schema):
1772        QAPISchemaEntity.check(self, schema)
1773        if self._arg_type_name:
1774            self.arg_type = schema.lookup_type(self._arg_type_name)
1775            assert isinstance(self.arg_type, QAPISchemaObjectType)
1776            assert not self.arg_type.variants or self.boxed
1777        elif self.boxed:
1778            raise QAPISemError(self.info, "use of 'boxed' requires 'data'")
1779
1780    def visit(self, visitor):
1781        QAPISchemaEntity.visit(self, visitor)
1782        visitor.visit_event(self.name, self.info, self.ifcond,
1783                            self.arg_type, self.boxed)
1784
1785
1786class QAPISchema(object):
1787    def __init__(self, fname):
1788        self.fname = fname
1789        if sys.version_info[0] >= 3:
1790            f = open(fname, 'r', encoding='utf-8')
1791        else:
1792            f = open(fname, 'r')
1793        parser = QAPISchemaParser(f)
1794        exprs = check_exprs(parser.exprs)
1795        self.docs = parser.docs
1796        self._entity_list = []
1797        self._entity_dict = {}
1798        self._predefining = True
1799        self._def_predefineds()
1800        self._predefining = False
1801        self._def_exprs(exprs)
1802        self.check()
1803
1804    def _def_entity(self, ent):
1805        # Only the predefined types are allowed to not have info
1806        assert ent.info or self._predefining
1807        assert ent.name is None or ent.name not in self._entity_dict
1808        self._entity_list.append(ent)
1809        if ent.name is not None:
1810            self._entity_dict[ent.name] = ent
1811
1812    def lookup_entity(self, name, typ=None):
1813        ent = self._entity_dict.get(name)
1814        if typ and not isinstance(ent, typ):
1815            return None
1816        return ent
1817
1818    def lookup_type(self, name):
1819        return self.lookup_entity(name, QAPISchemaType)
1820
1821    def _def_include(self, expr, info, doc):
1822        include = expr['include']
1823        assert doc is None
1824        main_info = info
1825        while main_info.parent:
1826            main_info = main_info.parent
1827        fname = os.path.relpath(include, os.path.dirname(main_info.fname))
1828        self._def_entity(QAPISchemaInclude(fname, info))
1829
1830    def _def_builtin_type(self, name, json_type, c_type):
1831        self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1832        # Instantiating only the arrays that are actually used would
1833        # be nice, but we can't as long as their generated code
1834        # (qapi-builtin-types.[ch]) may be shared by some other
1835        # schema.
1836        self._make_array_type(name, None)
1837
1838    def _def_predefineds(self):
1839        for t in [('str',    'string',  'char' + pointer_suffix),
1840                  ('number', 'number',  'double'),
1841                  ('int',    'int',     'int64_t'),
1842                  ('int8',   'int',     'int8_t'),
1843                  ('int16',  'int',     'int16_t'),
1844                  ('int32',  'int',     'int32_t'),
1845                  ('int64',  'int',     'int64_t'),
1846                  ('uint8',  'int',     'uint8_t'),
1847                  ('uint16', 'int',     'uint16_t'),
1848                  ('uint32', 'int',     'uint32_t'),
1849                  ('uint64', 'int',     'uint64_t'),
1850                  ('size',   'int',     'uint64_t'),
1851                  ('bool',   'boolean', 'bool'),
1852                  ('any',    'value',   'QObject' + pointer_suffix),
1853                  ('null',   'null',    'QNull' + pointer_suffix)]:
1854            self._def_builtin_type(*t)
1855        self.the_empty_object_type = QAPISchemaObjectType(
1856            'q_empty', None, None, None, None, [], None, [])
1857        self._def_entity(self.the_empty_object_type)
1858
1859        qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
1860                  'qbool']
1861        qtype_values = self._make_enum_members([{'name': n} for n in qtypes])
1862
1863        self._def_entity(QAPISchemaEnumType('QType', None, None, None,
1864                                            qtype_values, 'QTYPE'))
1865
1866    def _make_features(self, features):
1867        return [QAPISchemaFeature(f['name'], f.get('if')) for f in features]
1868
1869    def _make_enum_members(self, values):
1870        return [QAPISchemaEnumMember(v['name'], v.get('if'))
1871                for v in values]
1872
1873    def _make_implicit_enum_type(self, name, info, ifcond, values):
1874        # See also QAPISchemaObjectTypeMember._pretty_defined_in()
1875        name = name + 'Kind'   # Use namespace reserved by add_name()
1876        self._def_entity(QAPISchemaEnumType(
1877            name, info, None, ifcond, self._make_enum_members(values), None))
1878        return name
1879
1880    def _make_array_type(self, element_type, info):
1881        name = element_type + 'List'   # Use namespace reserved by add_name()
1882        if not self.lookup_type(name):
1883            self._def_entity(QAPISchemaArrayType(name, info, element_type))
1884        return name
1885
1886    def _make_implicit_object_type(self, name, info, doc, ifcond,
1887                                   role, members):
1888        if not members:
1889            return None
1890        # See also QAPISchemaObjectTypeMember._pretty_defined_in()
1891        name = 'q_obj_%s-%s' % (name, role)
1892        typ = self.lookup_entity(name, QAPISchemaObjectType)
1893        if typ:
1894            # The implicit object type has multiple users.  This can
1895            # happen only for simple unions' implicit wrapper types.
1896            # Its ifcond should be the disjunction of its user's
1897            # ifconds.  Not implemented.  Instead, we always pass the
1898            # wrapped type's ifcond, which is trivially the same for all
1899            # users.  It's also necessary for the wrapper to compile.
1900            # But it's not tight: the disjunction need not imply it.  We
1901            # may end up compiling useless wrapper types.
1902            # TODO kill simple unions or implement the disjunction
1903            assert ifcond == typ._ifcond # pylint: disable=protected-access
1904        else:
1905            self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
1906                                                  None, members, None, []))
1907        return name
1908
1909    def _def_enum_type(self, expr, info, doc):
1910        name = expr['enum']
1911        data = expr['data']
1912        prefix = expr.get('prefix')
1913        ifcond = expr.get('if')
1914        self._def_entity(QAPISchemaEnumType(
1915            name, info, doc, ifcond,
1916            self._make_enum_members(data), prefix))
1917
1918    def _make_member(self, name, typ, ifcond, info):
1919        optional = False
1920        if name.startswith('*'):
1921            name = name[1:]
1922            optional = True
1923        if isinstance(typ, list):
1924            assert len(typ) == 1
1925            typ = self._make_array_type(typ[0], info)
1926        return QAPISchemaObjectTypeMember(name, typ, optional, ifcond)
1927
1928    def _make_members(self, data, info):
1929        return [self._make_member(key, value['type'], value.get('if'), info)
1930                for (key, value) in data.items()]
1931
1932    def _def_struct_type(self, expr, info, doc):
1933        name = expr['struct']
1934        base = expr.get('base')
1935        data = expr['data']
1936        ifcond = expr.get('if')
1937        features = expr.get('features', [])
1938        self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, base,
1939                                              self._make_members(data, info),
1940                                              None,
1941                                              self._make_features(features)))
1942
1943    def _make_variant(self, case, typ, ifcond):
1944        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
1945
1946    def _make_simple_variant(self, case, typ, ifcond, info):
1947        if isinstance(typ, list):
1948            assert len(typ) == 1
1949            typ = self._make_array_type(typ[0], info)
1950        typ = self._make_implicit_object_type(
1951            typ, info, None, self.lookup_type(typ),
1952            'wrapper', [self._make_member('data', typ, None, info)])
1953        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
1954
1955    def _def_union_type(self, expr, info, doc):
1956        name = expr['union']
1957        data = expr['data']
1958        base = expr.get('base')
1959        ifcond = expr.get('if')
1960        tag_name = expr.get('discriminator')
1961        tag_member = None
1962        if isinstance(base, dict):
1963            base = self._make_implicit_object_type(
1964                name, info, doc, ifcond,
1965                'base', self._make_members(base, info))
1966        if tag_name:
1967            variants = [self._make_variant(key, value['type'], value.get('if'))
1968                        for (key, value) in data.items()]
1969            members = []
1970        else:
1971            variants = [self._make_simple_variant(key, value['type'],
1972                                                  value.get('if'), info)
1973                        for (key, value) in data.items()]
1974            enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
1975            typ = self._make_implicit_enum_type(name, info, ifcond, enum)
1976            tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1977            members = [tag_member]
1978        self._def_entity(
1979            QAPISchemaObjectType(name, info, doc, ifcond, base, members,
1980                                 QAPISchemaObjectTypeVariants(tag_name,
1981                                                              tag_member,
1982                                                              variants), []))
1983
1984    def _def_alternate_type(self, expr, info, doc):
1985        name = expr['alternate']
1986        data = expr['data']
1987        ifcond = expr.get('if')
1988        variants = [self._make_variant(key, value['type'], value.get('if'))
1989                    for (key, value) in data.items()]
1990        tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1991        self._def_entity(
1992            QAPISchemaAlternateType(name, info, doc, ifcond,
1993                                    QAPISchemaObjectTypeVariants(None,
1994                                                                 tag_member,
1995                                                                 variants)))
1996
1997    def _def_command(self, expr, info, doc):
1998        name = expr['command']
1999        data = expr.get('data')
2000        rets = expr.get('returns')
2001        gen = expr.get('gen', True)
2002        success_response = expr.get('success-response', True)
2003        boxed = expr.get('boxed', False)
2004        allow_oob = expr.get('allow-oob', False)
2005        allow_preconfig = expr.get('allow-preconfig', False)
2006        ifcond = expr.get('if')
2007        if isinstance(data, OrderedDict):
2008            data = self._make_implicit_object_type(
2009                name, info, doc, ifcond, 'arg', self._make_members(data, info))
2010        if isinstance(rets, list):
2011            assert len(rets) == 1
2012            rets = self._make_array_type(rets[0], info)
2013        self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets,
2014                                           gen, success_response,
2015                                           boxed, allow_oob, allow_preconfig))
2016
2017    def _def_event(self, expr, info, doc):
2018        name = expr['event']
2019        data = expr.get('data')
2020        boxed = expr.get('boxed', False)
2021        ifcond = expr.get('if')
2022        if isinstance(data, OrderedDict):
2023            data = self._make_implicit_object_type(
2024                name, info, doc, ifcond, 'arg', self._make_members(data, info))
2025        self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed))
2026
2027    def _def_exprs(self, exprs):
2028        for expr_elem in exprs:
2029            expr = expr_elem['expr']
2030            info = expr_elem['info']
2031            doc = expr_elem.get('doc')
2032            if 'enum' in expr:
2033                self._def_enum_type(expr, info, doc)
2034            elif 'struct' in expr:
2035                self._def_struct_type(expr, info, doc)
2036            elif 'union' in expr:
2037                self._def_union_type(expr, info, doc)
2038            elif 'alternate' in expr:
2039                self._def_alternate_type(expr, info, doc)
2040            elif 'command' in expr:
2041                self._def_command(expr, info, doc)
2042            elif 'event' in expr:
2043                self._def_event(expr, info, doc)
2044            elif 'include' in expr:
2045                self._def_include(expr, info, doc)
2046            else:
2047                assert False
2048
2049    def check(self):
2050        for ent in self._entity_list:
2051            ent.check(self)
2052
2053    def visit(self, visitor):
2054        visitor.visit_begin(self)
2055        module = None
2056        visitor.visit_module(module)
2057        for entity in self._entity_list:
2058            if visitor.visit_needed(entity):
2059                if entity.module != module:
2060                    module = entity.module
2061                    visitor.visit_module(module)
2062                entity.visit(visitor)
2063        visitor.visit_end()
2064
2065
2066#
2067# Code generation helpers
2068#
2069
2070def camel_case(name):
2071    new_name = ''
2072    first = True
2073    for ch in name:
2074        if ch in ['_', '-']:
2075            first = True
2076        elif first:
2077            new_name += ch.upper()
2078            first = False
2079        else:
2080            new_name += ch.lower()
2081    return new_name
2082
2083
2084# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
2085# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
2086# ENUM24_Name -> ENUM24_NAME
2087def camel_to_upper(value):
2088    c_fun_str = c_name(value, False)
2089    if value.isupper():
2090        return c_fun_str
2091
2092    new_name = ''
2093    length = len(c_fun_str)
2094    for i in range(length):
2095        c = c_fun_str[i]
2096        # When c is upper and no '_' appears before, do more checks
2097        if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
2098            if i < length - 1 and c_fun_str[i + 1].islower():
2099                new_name += '_'
2100            elif c_fun_str[i - 1].isdigit():
2101                new_name += '_'
2102        new_name += c
2103    return new_name.lstrip('_').upper()
2104
2105
2106def c_enum_const(type_name, const_name, prefix=None):
2107    if prefix is not None:
2108        type_name = prefix
2109    return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
2110
2111
2112if hasattr(str, 'maketrans'):
2113    c_name_trans = str.maketrans('.-', '__')
2114else:
2115    c_name_trans = string.maketrans('.-', '__')
2116
2117
2118# Map @name to a valid C identifier.
2119# If @protect, avoid returning certain ticklish identifiers (like
2120# C keywords) by prepending 'q_'.
2121#
2122# Used for converting 'name' from a 'name':'type' qapi definition
2123# into a generated struct member, as well as converting type names
2124# into substrings of a generated C function name.
2125# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
2126# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
2127def c_name(name, protect=True):
2128    # ANSI X3J11/88-090, 3.1.1
2129    c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
2130                     'default', 'do', 'double', 'else', 'enum', 'extern',
2131                     'float', 'for', 'goto', 'if', 'int', 'long', 'register',
2132                     'return', 'short', 'signed', 'sizeof', 'static',
2133                     'struct', 'switch', 'typedef', 'union', 'unsigned',
2134                     'void', 'volatile', 'while'])
2135    # ISO/IEC 9899:1999, 6.4.1
2136    c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
2137    # ISO/IEC 9899:2011, 6.4.1
2138    c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
2139                     '_Noreturn', '_Static_assert', '_Thread_local'])
2140    # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
2141    # excluding _.*
2142    gcc_words = set(['asm', 'typeof'])
2143    # C++ ISO/IEC 14882:2003 2.11
2144    cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
2145                     'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
2146                     'namespace', 'new', 'operator', 'private', 'protected',
2147                     'public', 'reinterpret_cast', 'static_cast', 'template',
2148                     'this', 'throw', 'true', 'try', 'typeid', 'typename',
2149                     'using', 'virtual', 'wchar_t',
2150                     # alternative representations
2151                     'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
2152                     'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
2153    # namespace pollution:
2154    polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386'])
2155    name = name.translate(c_name_trans)
2156    if protect and (name in c89_words | c99_words | c11_words | gcc_words
2157                    | cpp_words | polluted_words):
2158        return 'q_' + name
2159    return name
2160
2161
2162eatspace = '\033EATSPACE.'
2163pointer_suffix = ' *' + eatspace
2164
2165
2166def genindent(count):
2167    ret = ''
2168    for _ in range(count):
2169        ret += ' '
2170    return ret
2171
2172
2173indent_level = 0
2174
2175
2176def push_indent(indent_amount=4):
2177    global indent_level
2178    indent_level += indent_amount
2179
2180
2181def pop_indent(indent_amount=4):
2182    global indent_level
2183    indent_level -= indent_amount
2184
2185
2186# Generate @code with @kwds interpolated.
2187# Obey indent_level, and strip eatspace.
2188def cgen(code, **kwds):
2189    raw = code % kwds
2190    if indent_level:
2191        indent = genindent(indent_level)
2192        # re.subn() lacks flags support before Python 2.7, use re.compile()
2193        raw = re.subn(re.compile(r'^(?!(#|$))', re.MULTILINE),
2194                      indent, raw)
2195        raw = raw[0]
2196    return re.sub(re.escape(eatspace) + r' *', '', raw)
2197
2198
2199def mcgen(code, **kwds):
2200    if code[0] == '\n':
2201        code = code[1:]
2202    return cgen(code, **kwds)
2203
2204
2205def c_fname(filename):
2206    return re.sub(r'[^A-Za-z0-9_]', '_', filename)
2207
2208
2209def guardstart(name):
2210    return mcgen('''
2211#ifndef %(name)s
2212#define %(name)s
2213
2214''',
2215                 name=c_fname(name).upper())
2216
2217
2218def guardend(name):
2219    return mcgen('''
2220
2221#endif /* %(name)s */
2222''',
2223                 name=c_fname(name).upper())
2224
2225
2226def gen_if(ifcond):
2227    ret = ''
2228    for ifc in ifcond:
2229        ret += mcgen('''
2230#if %(cond)s
2231''', cond=ifc)
2232    return ret
2233
2234
2235def gen_endif(ifcond):
2236    ret = ''
2237    for ifc in reversed(ifcond):
2238        ret += mcgen('''
2239#endif /* %(cond)s */
2240''', cond=ifc)
2241    return ret
2242
2243
2244def _wrap_ifcond(ifcond, before, after):
2245    if before == after:
2246        return after   # suppress empty #if ... #endif
2247
2248    assert after.startswith(before)
2249    out = before
2250    added = after[len(before):]
2251    if added[0] == '\n':
2252        out += '\n'
2253        added = added[1:]
2254    out += gen_if(ifcond)
2255    out += added
2256    out += gen_endif(ifcond)
2257    return out
2258
2259
2260def gen_enum_lookup(name, members, prefix=None):
2261    ret = mcgen('''
2262
2263const QEnumLookup %(c_name)s_lookup = {
2264    .array = (const char *const[]) {
2265''',
2266                c_name=c_name(name))
2267    for m in members:
2268        ret += gen_if(m.ifcond)
2269        index = c_enum_const(name, m.name, prefix)
2270        ret += mcgen('''
2271        [%(index)s] = "%(name)s",
2272''',
2273                     index=index, name=m.name)
2274        ret += gen_endif(m.ifcond)
2275
2276    ret += mcgen('''
2277    },
2278    .size = %(max_index)s
2279};
2280''',
2281                 max_index=c_enum_const(name, '_MAX', prefix))
2282    return ret
2283
2284
2285def gen_enum(name, members, prefix=None):
2286    # append automatically generated _MAX value
2287    enum_members = members + [QAPISchemaEnumMember('_MAX')]
2288
2289    ret = mcgen('''
2290
2291typedef enum %(c_name)s {
2292''',
2293                c_name=c_name(name))
2294
2295    for m in enum_members:
2296        ret += gen_if(m.ifcond)
2297        ret += mcgen('''
2298    %(c_enum)s,
2299''',
2300                     c_enum=c_enum_const(name, m.name, prefix))
2301        ret += gen_endif(m.ifcond)
2302
2303    ret += mcgen('''
2304} %(c_name)s;
2305''',
2306                 c_name=c_name(name))
2307
2308    ret += mcgen('''
2309
2310#define %(c_name)s_str(val) \\
2311    qapi_enum_lookup(&%(c_name)s_lookup, (val))
2312
2313extern const QEnumLookup %(c_name)s_lookup;
2314''',
2315                 c_name=c_name(name))
2316    return ret
2317
2318
2319def build_params(arg_type, boxed, extra=None):
2320    ret = ''
2321    sep = ''
2322    if boxed:
2323        assert arg_type
2324        ret += '%s arg' % arg_type.c_param_type()
2325        sep = ', '
2326    elif arg_type:
2327        assert not arg_type.variants
2328        for memb in arg_type.members:
2329            ret += sep
2330            sep = ', '
2331            if memb.optional:
2332                ret += 'bool has_%s, ' % c_name(memb.name)
2333            ret += '%s %s' % (memb.type.c_param_type(),
2334                              c_name(memb.name))
2335    if extra:
2336        ret += sep + extra
2337    return ret if ret else 'void'
2338
2339
2340#
2341# Accumulate and write output
2342#
2343
2344class QAPIGen(object):
2345
2346    def __init__(self, fname):
2347        self.fname = fname
2348        self._preamble = ''
2349        self._body = ''
2350
2351    def preamble_add(self, text):
2352        self._preamble += text
2353
2354    def add(self, text):
2355        self._body += text
2356
2357    def get_content(self):
2358        return self._top() + self._preamble + self._body + self._bottom()
2359
2360    def _top(self):
2361        return ''
2362
2363    def _bottom(self):
2364        return ''
2365
2366    def write(self, output_dir):
2367        pathname = os.path.join(output_dir, self.fname)
2368        dir = os.path.dirname(pathname)
2369        if dir:
2370            try:
2371                os.makedirs(dir)
2372            except os.error as e:
2373                if e.errno != errno.EEXIST:
2374                    raise
2375        fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666)
2376        if sys.version_info[0] >= 3:
2377            f = open(fd, 'r+', encoding='utf-8')
2378        else:
2379            f = os.fdopen(fd, 'r+')
2380        text = self.get_content()
2381        oldtext = f.read(len(text) + 1)
2382        if text != oldtext:
2383            f.seek(0)
2384            f.truncate(0)
2385            f.write(text)
2386        f.close()
2387
2388
2389@contextmanager
2390def ifcontext(ifcond, *args):
2391    """A 'with' statement context manager to wrap with start_if()/end_if()
2392
2393    *args: any number of QAPIGenCCode
2394
2395    Example::
2396
2397        with ifcontext(ifcond, self._genh, self._genc):
2398            modify self._genh and self._genc ...
2399
2400    Is equivalent to calling::
2401
2402        self._genh.start_if(ifcond)
2403        self._genc.start_if(ifcond)
2404        modify self._genh and self._genc ...
2405        self._genh.end_if()
2406        self._genc.end_if()
2407    """
2408    for arg in args:
2409        arg.start_if(ifcond)
2410    yield
2411    for arg in args:
2412        arg.end_if()
2413
2414
2415class QAPIGenCCode(QAPIGen):
2416
2417    def __init__(self, fname):
2418        QAPIGen.__init__(self, fname)
2419        self._start_if = None
2420
2421    def start_if(self, ifcond):
2422        assert self._start_if is None
2423        self._start_if = (ifcond, self._body, self._preamble)
2424
2425    def end_if(self):
2426        assert self._start_if
2427        self._wrap_ifcond()
2428        self._start_if = None
2429
2430    def _wrap_ifcond(self):
2431        self._body = _wrap_ifcond(self._start_if[0],
2432                                  self._start_if[1], self._body)
2433        self._preamble = _wrap_ifcond(self._start_if[0],
2434                                      self._start_if[2], self._preamble)
2435
2436    def get_content(self):
2437        assert self._start_if is None
2438        return QAPIGen.get_content(self)
2439
2440
2441class QAPIGenC(QAPIGenCCode):
2442
2443    def __init__(self, fname, blurb, pydoc):
2444        QAPIGenCCode.__init__(self, fname)
2445        self._blurb = blurb
2446        self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
2447                                                  re.MULTILINE))
2448
2449    def _top(self):
2450        return mcgen('''
2451/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2452
2453/*
2454%(blurb)s
2455 *
2456 * %(copyright)s
2457 *
2458 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
2459 * See the COPYING.LIB file in the top-level directory.
2460 */
2461
2462''',
2463                     blurb=self._blurb, copyright=self._copyright)
2464
2465    def _bottom(self):
2466        return mcgen('''
2467
2468/* Dummy declaration to prevent empty .o file */
2469char qapi_dummy_%(name)s;
2470''',
2471                     name=c_fname(self.fname))
2472
2473
2474class QAPIGenH(QAPIGenC):
2475
2476    def _top(self):
2477        return QAPIGenC._top(self) + guardstart(self.fname)
2478
2479    def _bottom(self):
2480        return guardend(self.fname)
2481
2482
2483class QAPIGenDoc(QAPIGen):
2484
2485    def _top(self):
2486        return (QAPIGen._top(self)
2487                + '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')
2488
2489
2490class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):
2491
2492    def __init__(self, prefix, what, blurb, pydoc):
2493        self._prefix = prefix
2494        self._what = what
2495        self._genc = QAPIGenC(self._prefix + self._what + '.c',
2496                              blurb, pydoc)
2497        self._genh = QAPIGenH(self._prefix + self._what + '.h',
2498                              blurb, pydoc)
2499
2500    def write(self, output_dir):
2501        self._genc.write(output_dir)
2502        self._genh.write(output_dir)
2503
2504
2505class QAPISchemaModularCVisitor(QAPISchemaVisitor):
2506
2507    def __init__(self, prefix, what, blurb, pydoc):
2508        self._prefix = prefix
2509        self._what = what
2510        self._blurb = blurb
2511        self._pydoc = pydoc
2512        self._genc = None
2513        self._genh = None
2514        self._module = {}
2515        self._main_module = None
2516
2517    @staticmethod
2518    def _is_user_module(name):
2519        return name and not name.startswith('./')
2520
2521    @staticmethod
2522    def _is_builtin_module(name):
2523        return not name
2524
2525    def _module_dirname(self, what, name):
2526        if self._is_user_module(name):
2527            return os.path.dirname(name)
2528        return ''
2529
2530    def _module_basename(self, what, name):
2531        ret = '' if self._is_builtin_module(name) else self._prefix
2532        if self._is_user_module(name):
2533            basename = os.path.basename(name)
2534            ret += what
2535            if name != self._main_module:
2536                ret += '-' + os.path.splitext(basename)[0]
2537        else:
2538            name = name[2:] if name else 'builtin'
2539            ret += re.sub(r'-', '-' + name + '-', what)
2540        return ret
2541
2542    def _module_filename(self, what, name):
2543        return os.path.join(self._module_dirname(what, name),
2544                            self._module_basename(what, name))
2545
2546    def _add_module(self, name, blurb):
2547        basename = self._module_filename(self._what, name)
2548        genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
2549        genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
2550        self._module[name] = (genc, genh)
2551        self._set_module(name)
2552
2553    def _add_user_module(self, name, blurb):
2554        assert self._is_user_module(name)
2555        if self._main_module is None:
2556            self._main_module = name
2557        self._add_module(name, blurb)
2558
2559    def _add_system_module(self, name, blurb):
2560        self._add_module(name and './' + name, blurb)
2561
2562    def _set_module(self, name):
2563        self._genc, self._genh = self._module[name]
2564
2565    def write(self, output_dir, opt_builtins=False):
2566        for name in self._module:
2567            if self._is_builtin_module(name) and not opt_builtins:
2568                continue
2569            (genc, genh) = self._module[name]
2570            genc.write(output_dir)
2571            genh.write(output_dir)
2572
2573    def _begin_user_module(self, name):
2574        pass
2575
2576    def visit_module(self, name):
2577        if name in self._module:
2578            self._set_module(name)
2579        elif self._is_builtin_module(name):
2580            # The built-in module has not been created.  No code may
2581            # be generated.
2582            self._genc = None
2583            self._genh = None
2584        else:
2585            self._add_user_module(name, self._blurb)
2586            self._begin_user_module(name)
2587
2588    def visit_include(self, name, info):
2589        relname = os.path.relpath(self._module_filename(self._what, name),
2590                                  os.path.dirname(self._genh.fname))
2591        self._genh.preamble_add(mcgen('''
2592#include "%(relname)s.h"
2593''',
2594                                      relname=relname))
2595