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