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