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