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