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