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