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