]> Git Repo - qemu.git/blob - scripts/qapi.py
qapi: Change data type of the FOO_lookup generated for enum FOO
[qemu.git] / scripts / qapi.py
1 #
2 # QAPI helper library
3 #
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
6 #
7 # Authors:
8 #  Anthony Liguori <[email protected]>
9 #  Markus Armbruster <[email protected]>
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
14 import errno
15 import getopt
16 import os
17 import re
18 import string
19 import sys
20 from ordereddict import OrderedDict
21
22 builtin_types = {
23     'null':     'QTYPE_QNULL',
24     'str':      'QTYPE_QSTRING',
25     'int':      'QTYPE_QNUM',
26     'number':   'QTYPE_QNUM',
27     'bool':     'QTYPE_QBOOL',
28     'int8':     'QTYPE_QNUM',
29     'int16':    'QTYPE_QNUM',
30     'int32':    'QTYPE_QNUM',
31     'int64':    'QTYPE_QNUM',
32     'uint8':    'QTYPE_QNUM',
33     'uint16':   'QTYPE_QNUM',
34     'uint32':   'QTYPE_QNUM',
35     'uint64':   'QTYPE_QNUM',
36     'size':     'QTYPE_QNUM',
37     'any':      None,           # any QType possible, actually
38     'QType':    'QTYPE_QSTRING',
39 }
40
41 # Are documentation comments required?
42 doc_required = False
43
44 # Whitelist of commands allowed to return a non-dictionary
45 returns_whitelist = []
46
47 # Whitelist of entities allowed to violate case conventions
48 name_case_whitelist = []
49
50 enum_types = {}
51 struct_types = {}
52 union_types = {}
53 all_names = {}
54
55 #
56 # Parsing the schema into expressions
57 #
58
59
60 def error_path(parent):
61     res = ''
62     while parent:
63         res = ('In file included from %s:%d:\n' % (parent['file'],
64                                                    parent['line'])) + res
65         parent = parent['parent']
66     return res
67
68
69 class QAPIError(Exception):
70     def __init__(self, fname, line, col, incl_info, msg):
71         Exception.__init__(self)
72         self.fname = fname
73         self.line = line
74         self.col = col
75         self.info = incl_info
76         self.msg = msg
77
78     def __str__(self):
79         loc = '%s:%d' % (self.fname, self.line)
80         if self.col is not None:
81             loc += ':%s' % self.col
82         return error_path(self.info) + '%s: %s' % (loc, self.msg)
83
84
85 class QAPIParseError(QAPIError):
86     def __init__(self, parser, msg):
87         col = 1
88         for ch in parser.src[parser.line_pos:parser.pos]:
89             if ch == '\t':
90                 col = (col + 7) % 8 + 1
91             else:
92                 col += 1
93         QAPIError.__init__(self, parser.fname, parser.line, col,
94                            parser.incl_info, msg)
95
96
97 class QAPISemError(QAPIError):
98     def __init__(self, info, msg):
99         QAPIError.__init__(self, info['file'], info['line'], None,
100                            info['parent'], msg)
101
102
103 class QAPIDoc(object):
104     class Section(object):
105         def __init__(self, name=None):
106             # optional section name (argument/member or section name)
107             self.name = name
108             # the list of lines for this section
109             self.content = []
110
111         def append(self, line):
112             self.content.append(line)
113
114         def __repr__(self):
115             return '\n'.join(self.content).strip()
116
117     class ArgSection(Section):
118         def __init__(self, name):
119             QAPIDoc.Section.__init__(self, name)
120             self.member = None
121
122         def connect(self, member):
123             self.member = member
124
125     def __init__(self, parser, info):
126         # self.parser is used to report errors with QAPIParseError.  The
127         # resulting error position depends on the state of the parser.
128         # It happens to be the beginning of the comment.  More or less
129         # servicable, but action at a distance.
130         self.parser = parser
131         self.info = info
132         self.symbol = None
133         self.body = QAPIDoc.Section()
134         # dict mapping parameter name to ArgSection
135         self.args = OrderedDict()
136         # a list of Section
137         self.sections = []
138         # the current section
139         self.section = self.body
140
141     def has_section(self, name):
142         """Return True if we have a section with this name."""
143         for i in self.sections:
144             if i.name == name:
145                 return True
146         return False
147
148     def append(self, line):
149         """Parse a comment line and add it to the documentation."""
150         line = line[1:]
151         if not line:
152             self._append_freeform(line)
153             return
154
155         if line[0] != ' ':
156             raise QAPIParseError(self.parser, "Missing space after #")
157         line = line[1:]
158
159         # FIXME not nice: things like '#  @foo:' and '# @foo: ' aren't
160         # recognized, and get silently treated as ordinary text
161         if self.symbol:
162             self._append_symbol_line(line)
163         elif not self.body.content and line.startswith('@'):
164             if not line.endswith(':'):
165                 raise QAPIParseError(self.parser, "Line should end with :")
166             self.symbol = line[1:-1]
167             # FIXME invalid names other than the empty string aren't flagged
168             if not self.symbol:
169                 raise QAPIParseError(self.parser, "Invalid name")
170         else:
171             self._append_freeform(line)
172
173     def end_comment(self):
174         self._end_section()
175
176     def _append_symbol_line(self, line):
177         name = line.split(' ', 1)[0]
178
179         if name.startswith('@') and name.endswith(':'):
180             line = line[len(name)+1:]
181             self._start_args_section(name[1:-1])
182         elif name in ('Returns:', 'Since:',
183                       # those are often singular or plural
184                       'Note:', 'Notes:',
185                       'Example:', 'Examples:',
186                       'TODO:'):
187             line = line[len(name)+1:]
188             self._start_section(name[:-1])
189
190         self._append_freeform(line)
191
192     def _start_args_section(self, name):
193         # FIXME invalid names other than the empty string aren't flagged
194         if not name:
195             raise QAPIParseError(self.parser, "Invalid parameter name")
196         if name in self.args:
197             raise QAPIParseError(self.parser,
198                                  "'%s' parameter name duplicated" % name)
199         if self.sections:
200             raise QAPIParseError(self.parser,
201                                  "'@%s:' can't follow '%s' section"
202                                  % (name, self.sections[0].name))
203         self._end_section()
204         self.section = QAPIDoc.ArgSection(name)
205         self.args[name] = self.section
206
207     def _start_section(self, name=''):
208         if name in ('Returns', 'Since') and self.has_section(name):
209             raise QAPIParseError(self.parser,
210                                  "Duplicated '%s' section" % name)
211         self._end_section()
212         self.section = QAPIDoc.Section(name)
213         self.sections.append(self.section)
214
215     def _end_section(self):
216         if self.section:
217             contents = str(self.section)
218             if self.section.name and (not contents or contents.isspace()):
219                 raise QAPIParseError(self.parser, "Empty doc section '%s'"
220                                      % self.section.name)
221             self.section = None
222
223     def _append_freeform(self, line):
224         in_arg = isinstance(self.section, QAPIDoc.ArgSection)
225         if (in_arg and self.section.content
226                 and not self.section.content[-1]
227                 and line and not line[0].isspace()):
228             self._start_section()
229         if (in_arg or not self.section.name
230                 or not self.section.name.startswith('Example')):
231             line = line.strip()
232         match = re.match(r'(@\S+:)', line)
233         if match:
234             raise QAPIParseError(self.parser,
235                                  "'%s' not allowed in free-form documentation"
236                                  % match.group(1))
237         # TODO Drop this once the dust has settled
238         if (isinstance(self.section, QAPIDoc.ArgSection)
239                 and '#optional' in line):
240             raise QAPISemError(self.info, "Please drop the #optional tag")
241         self.section.append(line)
242
243     def connect_member(self, member):
244         if member.name not in self.args:
245             # Undocumented TODO outlaw
246             self.args[member.name] = QAPIDoc.ArgSection(member.name)
247         self.args[member.name].connect(member)
248
249     def check_expr(self, expr):
250         if self.has_section('Returns') and 'command' not in expr:
251             raise QAPISemError(self.info,
252                                "'Returns:' is only valid for commands")
253
254     def check(self):
255         bogus = [name for name, section in self.args.iteritems()
256                  if not section.member]
257         if bogus:
258             raise QAPISemError(
259                 self.info,
260                 "The following documented members are not in "
261                 "the declaration: %s" % ", ".join(bogus))
262
263
264 class QAPISchemaParser(object):
265
266     def __init__(self, fp, previously_included=[], incl_info=None):
267         abs_fname = os.path.abspath(fp.name)
268         fname = fp.name
269         self.fname = fname
270         previously_included.append(abs_fname)
271         self.incl_info = incl_info
272         self.src = fp.read()
273         if self.src == '' or self.src[-1] != '\n':
274             self.src += '\n'
275         self.cursor = 0
276         self.line = 1
277         self.line_pos = 0
278         self.exprs = []
279         self.docs = []
280         self.cur_doc = None
281         self.accept()
282
283         while self.tok is not None:
284             info = {'file': fname, 'line': self.line,
285                     'parent': self.incl_info}
286             if self.tok == '#':
287                 self.reject_expr_doc()
288                 self.cur_doc = self.get_doc(info)
289                 self.docs.append(self.cur_doc)
290                 continue
291
292             expr = self.get_expr(False)
293             if 'include' in expr:
294                 self.reject_expr_doc()
295                 if len(expr) != 1:
296                     raise QAPISemError(info, "Invalid 'include' directive")
297                 include = expr['include']
298                 if not isinstance(include, str):
299                     raise QAPISemError(info,
300                                        "Value of 'include' must be a string")
301                 self._include(include, info, os.path.dirname(abs_fname),
302                               previously_included)
303             elif "pragma" in expr:
304                 self.reject_expr_doc()
305                 if len(expr) != 1:
306                     raise QAPISemError(info, "Invalid 'pragma' directive")
307                 pragma = expr['pragma']
308                 if not isinstance(pragma, dict):
309                     raise QAPISemError(
310                         info, "Value of 'pragma' must be a dictionary")
311                 for name, value in pragma.iteritems():
312                     self._pragma(name, value, info)
313             else:
314                 expr_elem = {'expr': expr,
315                              'info': info}
316                 if self.cur_doc:
317                     if not self.cur_doc.symbol:
318                         raise QAPISemError(
319                             self.cur_doc.info,
320                             "Expression documentation required")
321                     expr_elem['doc'] = self.cur_doc
322                 self.exprs.append(expr_elem)
323             self.cur_doc = None
324         self.reject_expr_doc()
325
326     def reject_expr_doc(self):
327         if self.cur_doc and self.cur_doc.symbol:
328             raise QAPISemError(
329                 self.cur_doc.info,
330                 "Documentation for '%s' is not followed by the definition"
331                 % self.cur_doc.symbol)
332
333     def _include(self, include, info, base_dir, previously_included):
334         incl_abs_fname = os.path.join(base_dir, include)
335         # catch inclusion cycle
336         inf = info
337         while inf:
338             if incl_abs_fname == os.path.abspath(inf['file']):
339                 raise QAPISemError(info, "Inclusion loop for %s" % include)
340             inf = inf['parent']
341
342         # skip multiple include of the same file
343         if incl_abs_fname in previously_included:
344             return
345         try:
346             fobj = open(incl_abs_fname, 'r')
347         except IOError as e:
348             raise QAPISemError(info, '%s: %s' % (e.strerror, include))
349         exprs_include = QAPISchemaParser(fobj, previously_included, info)
350         self.exprs.extend(exprs_include.exprs)
351         self.docs.extend(exprs_include.docs)
352
353     def _pragma(self, name, value, info):
354         global doc_required, returns_whitelist, name_case_whitelist
355         if name == 'doc-required':
356             if not isinstance(value, bool):
357                 raise QAPISemError(info,
358                                    "Pragma 'doc-required' must be boolean")
359             doc_required = value
360         elif name == 'returns-whitelist':
361             if (not isinstance(value, list)
362                     or any([not isinstance(elt, str) for elt in value])):
363                 raise QAPISemError(info,
364                                    "Pragma returns-whitelist must be"
365                                    " a list of strings")
366             returns_whitelist = value
367         elif name == 'name-case-whitelist':
368             if (not isinstance(value, list)
369                     or any([not isinstance(elt, str) for elt in value])):
370                 raise QAPISemError(info,
371                                    "Pragma name-case-whitelist must be"
372                                    " a list of strings")
373             name_case_whitelist = value
374         else:
375             raise QAPISemError(info, "Unknown pragma '%s'" % name)
376
377     def accept(self, skip_comment=True):
378         while True:
379             self.tok = self.src[self.cursor]
380             self.pos = self.cursor
381             self.cursor += 1
382             self.val = None
383
384             if self.tok == '#':
385                 if self.src[self.cursor] == '#':
386                     # Start of doc comment
387                     skip_comment = False
388                 self.cursor = self.src.find('\n', self.cursor)
389                 if not skip_comment:
390                     self.val = self.src[self.pos:self.cursor]
391                     return
392             elif self.tok in '{}:,[]':
393                 return
394             elif self.tok == "'":
395                 string = ''
396                 esc = False
397                 while True:
398                     ch = self.src[self.cursor]
399                     self.cursor += 1
400                     if ch == '\n':
401                         raise QAPIParseError(self, 'Missing terminating "\'"')
402                     if esc:
403                         if ch == 'b':
404                             string += '\b'
405                         elif ch == 'f':
406                             string += '\f'
407                         elif ch == 'n':
408                             string += '\n'
409                         elif ch == 'r':
410                             string += '\r'
411                         elif ch == 't':
412                             string += '\t'
413                         elif ch == 'u':
414                             value = 0
415                             for _ in range(0, 4):
416                                 ch = self.src[self.cursor]
417                                 self.cursor += 1
418                                 if ch not in '0123456789abcdefABCDEF':
419                                     raise QAPIParseError(self,
420                                                          '\\u escape needs 4 '
421                                                          'hex digits')
422                                 value = (value << 4) + int(ch, 16)
423                             # If Python 2 and 3 didn't disagree so much on
424                             # how to handle Unicode, then we could allow
425                             # Unicode string defaults.  But most of QAPI is
426                             # ASCII-only, so we aren't losing much for now.
427                             if not value or value > 0x7f:
428                                 raise QAPIParseError(self,
429                                                      'For now, \\u escape '
430                                                      'only supports non-zero '
431                                                      'values up to \\u007f')
432                             string += chr(value)
433                         elif ch in '\\/\'"':
434                             string += ch
435                         else:
436                             raise QAPIParseError(self,
437                                                  "Unknown escape \\%s" % ch)
438                         esc = False
439                     elif ch == '\\':
440                         esc = True
441                     elif ch == "'":
442                         self.val = string
443                         return
444                     else:
445                         string += ch
446             elif self.src.startswith('true', self.pos):
447                 self.val = True
448                 self.cursor += 3
449                 return
450             elif self.src.startswith('false', self.pos):
451                 self.val = False
452                 self.cursor += 4
453                 return
454             elif self.src.startswith('null', self.pos):
455                 self.val = None
456                 self.cursor += 3
457                 return
458             elif self.tok == '\n':
459                 if self.cursor == len(self.src):
460                     self.tok = None
461                     return
462                 self.line += 1
463                 self.line_pos = self.cursor
464             elif not self.tok.isspace():
465                 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
466
467     def get_members(self):
468         expr = OrderedDict()
469         if self.tok == '}':
470             self.accept()
471             return expr
472         if self.tok != "'":
473             raise QAPIParseError(self, 'Expected string or "}"')
474         while True:
475             key = self.val
476             self.accept()
477             if self.tok != ':':
478                 raise QAPIParseError(self, 'Expected ":"')
479             self.accept()
480             if key in expr:
481                 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
482             expr[key] = self.get_expr(True)
483             if self.tok == '}':
484                 self.accept()
485                 return expr
486             if self.tok != ',':
487                 raise QAPIParseError(self, 'Expected "," or "}"')
488             self.accept()
489             if self.tok != "'":
490                 raise QAPIParseError(self, 'Expected string')
491
492     def get_values(self):
493         expr = []
494         if self.tok == ']':
495             self.accept()
496             return expr
497         if self.tok not in "{['tfn":
498             raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
499                                  'boolean or "null"')
500         while True:
501             expr.append(self.get_expr(True))
502             if self.tok == ']':
503                 self.accept()
504                 return expr
505             if self.tok != ',':
506                 raise QAPIParseError(self, 'Expected "," or "]"')
507             self.accept()
508
509     def get_expr(self, nested):
510         if self.tok != '{' and not nested:
511             raise QAPIParseError(self, 'Expected "{"')
512         if self.tok == '{':
513             self.accept()
514             expr = self.get_members()
515         elif self.tok == '[':
516             self.accept()
517             expr = self.get_values()
518         elif self.tok in "'tfn":
519             expr = self.val
520             self.accept()
521         else:
522             raise QAPIParseError(self, 'Expected "{", "[", string, '
523                                  'boolean or "null"')
524         return expr
525
526     def get_doc(self, info):
527         if self.val != '##':
528             raise QAPIParseError(self, "Junk after '##' at start of "
529                                  "documentation comment")
530
531         doc = QAPIDoc(self, info)
532         self.accept(False)
533         while self.tok == '#':
534             if self.val.startswith('##'):
535                 # End of doc comment
536                 if self.val != '##':
537                     raise QAPIParseError(self, "Junk after '##' at end of "
538                                          "documentation comment")
539                 doc.end_comment()
540                 self.accept()
541                 return doc
542             else:
543                 doc.append(self.val)
544             self.accept(False)
545
546         raise QAPIParseError(self, "Documentation comment must end with '##'")
547
548
549 #
550 # Semantic analysis of schema expressions
551 # TODO fold into QAPISchema
552 # TODO catching name collisions in generated code would be nice
553 #
554
555
556 def find_base_members(base):
557     if isinstance(base, dict):
558         return base
559     base_struct_define = struct_types.get(base)
560     if not base_struct_define:
561         return None
562     return base_struct_define['data']
563
564
565 # Return the qtype of an alternate branch, or None on error.
566 def find_alternate_member_qtype(qapi_type):
567     if qapi_type in builtin_types:
568         return builtin_types[qapi_type]
569     elif qapi_type in struct_types:
570         return 'QTYPE_QDICT'
571     elif qapi_type in enum_types:
572         return 'QTYPE_QSTRING'
573     elif qapi_type in union_types:
574         return 'QTYPE_QDICT'
575     return None
576
577
578 # Return the discriminator enum define if discriminator is specified as an
579 # enum type, otherwise return None.
580 def discriminator_find_enum_define(expr):
581     base = expr.get('base')
582     discriminator = expr.get('discriminator')
583
584     if not (discriminator and base):
585         return None
586
587     base_members = find_base_members(base)
588     if not base_members:
589         return None
590
591     discriminator_type = base_members.get(discriminator)
592     if not discriminator_type:
593         return None
594
595     return enum_types.get(discriminator_type)
596
597
598 # Names must be letters, numbers, -, and _.  They must start with letter,
599 # except for downstream extensions which must start with __RFQDN_.
600 # Dots are only valid in the downstream extension prefix.
601 valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
602                         '[a-zA-Z][a-zA-Z0-9_-]*$')
603
604
605 def check_name(info, source, name, allow_optional=False,
606                enum_member=False):
607     global valid_name
608     membername = name
609
610     if not isinstance(name, str):
611         raise QAPISemError(info, "%s requires a string name" % source)
612     if name.startswith('*'):
613         membername = name[1:]
614         if not allow_optional:
615             raise QAPISemError(info, "%s does not allow optional name '%s'"
616                                % (source, name))
617     # Enum members can start with a digit, because the generated C
618     # code always prefixes it with the enum name
619     if enum_member and membername[0].isdigit():
620         membername = 'D' + membername
621     # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
622     # and 'q_obj_*' implicit type names.
623     if not valid_name.match(membername) or \
624        c_name(membername, False).startswith('q_'):
625         raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
626
627
628 def add_name(name, info, meta, implicit=False):
629     global all_names
630     check_name(info, "'%s'" % meta, name)
631     # FIXME should reject names that differ only in '_' vs. '.'
632     # vs. '-', because they're liable to clash in generated C.
633     if name in all_names:
634         raise QAPISemError(info, "%s '%s' is already defined"
635                            % (all_names[name], name))
636     if not implicit and (name.endswith('Kind') or name.endswith('List')):
637         raise QAPISemError(info, "%s '%s' should not end in '%s'"
638                            % (meta, name, name[-4:]))
639     all_names[name] = meta
640
641
642 def check_type(info, source, value, allow_array=False,
643                allow_dict=False, allow_optional=False,
644                allow_metas=[]):
645     global all_names
646
647     if value is None:
648         return
649
650     # Check if array type for value is okay
651     if isinstance(value, list):
652         if not allow_array:
653             raise QAPISemError(info, "%s cannot be an array" % source)
654         if len(value) != 1 or not isinstance(value[0], str):
655             raise QAPISemError(info,
656                                "%s: array type must contain single type name" %
657                                source)
658         value = value[0]
659
660     # Check if type name for value is okay
661     if isinstance(value, str):
662         if value not in all_names:
663             raise QAPISemError(info, "%s uses unknown type '%s'"
664                                % (source, value))
665         if not all_names[value] in allow_metas:
666             raise QAPISemError(info, "%s cannot use %s type '%s'" %
667                                (source, all_names[value], value))
668         return
669
670     if not allow_dict:
671         raise QAPISemError(info, "%s should be a type name" % source)
672
673     if not isinstance(value, OrderedDict):
674         raise QAPISemError(info,
675                            "%s should be a dictionary or type name" % source)
676
677     # value is a dictionary, check that each member is okay
678     for (key, arg) in value.items():
679         check_name(info, "Member of %s" % source, key,
680                    allow_optional=allow_optional)
681         if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
682             raise QAPISemError(info, "Member of %s uses reserved name '%s'"
683                                % (source, key))
684         # Todo: allow dictionaries to represent default values of
685         # an optional argument.
686         check_type(info, "Member '%s' of %s" % (key, source), arg,
687                    allow_array=True,
688                    allow_metas=['built-in', 'union', 'alternate', 'struct',
689                                 'enum'])
690
691
692 def check_command(expr, info):
693     name = expr['command']
694     boxed = expr.get('boxed', False)
695
696     args_meta = ['struct']
697     if boxed:
698         args_meta += ['union', 'alternate']
699     check_type(info, "'data' for command '%s'" % name,
700                expr.get('data'), allow_dict=not boxed, allow_optional=True,
701                allow_metas=args_meta)
702     returns_meta = ['union', 'struct']
703     if name in returns_whitelist:
704         returns_meta += ['built-in', 'alternate', 'enum']
705     check_type(info, "'returns' for command '%s'" % name,
706                expr.get('returns'), allow_array=True,
707                allow_optional=True, allow_metas=returns_meta)
708
709
710 def check_event(expr, info):
711     name = expr['event']
712     boxed = expr.get('boxed', False)
713
714     meta = ['struct']
715     if boxed:
716         meta += ['union', 'alternate']
717     check_type(info, "'data' for event '%s'" % name,
718                expr.get('data'), allow_dict=not boxed, allow_optional=True,
719                allow_metas=meta)
720
721
722 def check_union(expr, info):
723     name = expr['union']
724     base = expr.get('base')
725     discriminator = expr.get('discriminator')
726     members = expr['data']
727
728     # Two types of unions, determined by discriminator.
729
730     # With no discriminator it is a simple union.
731     if discriminator is None:
732         enum_define = None
733         allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
734         if base is not None:
735             raise QAPISemError(info, "Simple union '%s' must not have a base" %
736                                name)
737
738     # Else, it's a flat union.
739     else:
740         # The object must have a string or dictionary 'base'.
741         check_type(info, "'base' for union '%s'" % name,
742                    base, allow_dict=True, allow_optional=True,
743                    allow_metas=['struct'])
744         if not base:
745             raise QAPISemError(info, "Flat union '%s' must have a base"
746                                % name)
747         base_members = find_base_members(base)
748         assert base_members is not None
749
750         # The value of member 'discriminator' must name a non-optional
751         # member of the base struct.
752         check_name(info, "Discriminator of flat union '%s'" % name,
753                    discriminator)
754         discriminator_type = base_members.get(discriminator)
755         if not discriminator_type:
756             raise QAPISemError(info,
757                                "Discriminator '%s' is not a member of base "
758                                "struct '%s'"
759                                % (discriminator, base))
760         enum_define = enum_types.get(discriminator_type)
761         allow_metas = ['struct']
762         # Do not allow string discriminator
763         if not enum_define:
764             raise QAPISemError(info,
765                                "Discriminator '%s' must be of enumeration "
766                                "type" % discriminator)
767
768     # Check every branch; don't allow an empty union
769     if len(members) == 0:
770         raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
771     for (key, value) in members.items():
772         check_name(info, "Member of union '%s'" % name, key)
773
774         # Each value must name a known type
775         check_type(info, "Member '%s' of union '%s'" % (key, name),
776                    value, allow_array=not base, allow_metas=allow_metas)
777
778         # If the discriminator names an enum type, then all members
779         # of 'data' must also be members of the enum type.
780         if enum_define:
781             if key not in enum_define['data']:
782                 raise QAPISemError(info,
783                                    "Discriminator value '%s' is not found in "
784                                    "enum '%s'"
785                                    % (key, enum_define['enum']))
786
787     # If discriminator is user-defined, ensure all values are covered
788     if enum_define:
789         for value in enum_define['data']:
790             if value not in members.keys():
791                 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
792                                    % (name, value))
793
794
795 def check_alternate(expr, info):
796     name = expr['alternate']
797     members = expr['data']
798     types_seen = {}
799
800     # Check every branch; require at least two branches
801     if len(members) < 2:
802         raise QAPISemError(info,
803                            "Alternate '%s' should have at least two branches "
804                            "in 'data'" % name)
805     for (key, value) in members.items():
806         check_name(info, "Member of alternate '%s'" % name, key)
807
808         # Ensure alternates have no type conflicts.
809         check_type(info, "Member '%s' of alternate '%s'" % (key, name),
810                    value,
811                    allow_metas=['built-in', 'union', 'struct', 'enum'])
812         qtype = find_alternate_member_qtype(value)
813         if not qtype:
814             raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
815                                "type '%s'" % (name, key, value))
816         conflicting = set([qtype])
817         if qtype == 'QTYPE_QSTRING':
818             enum_expr = enum_types.get(value)
819             if enum_expr:
820                 for v in enum_expr['data']:
821                     if v in ['on', 'off']:
822                         conflicting.add('QTYPE_QBOOL')
823                     if re.match(r'[-+0-9.]', v): # lazy, could be tightened
824                         conflicting.add('QTYPE_QNUM')
825             else:
826                 conflicting.add('QTYPE_QNUM')
827                 conflicting.add('QTYPE_QBOOL')
828         for qt in conflicting:
829             if qt in types_seen:
830                 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
831                                    "be distinguished from member '%s'"
832                                    % (name, key, types_seen[qt]))
833             types_seen[qt] = key
834
835
836 def check_enum(expr, info):
837     name = expr['enum']
838     members = expr.get('data')
839     prefix = expr.get('prefix')
840
841     if not isinstance(members, list):
842         raise QAPISemError(info,
843                            "Enum '%s' requires an array for 'data'" % name)
844     if prefix is not None and not isinstance(prefix, str):
845         raise QAPISemError(info,
846                            "Enum '%s' requires a string for 'prefix'" % name)
847     for member in members:
848         check_name(info, "Member of enum '%s'" % name, member,
849                    enum_member=True)
850
851
852 def check_struct(expr, info):
853     name = expr['struct']
854     members = expr['data']
855
856     check_type(info, "'data' for struct '%s'" % name, members,
857                allow_dict=True, allow_optional=True)
858     check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
859                allow_metas=['struct'])
860
861
862 def check_keys(expr_elem, meta, required, optional=[]):
863     expr = expr_elem['expr']
864     info = expr_elem['info']
865     name = expr[meta]
866     if not isinstance(name, str):
867         raise QAPISemError(info, "'%s' key must have a string value" % meta)
868     required = required + [meta]
869     for (key, value) in expr.items():
870         if key not in required and key not in optional:
871             raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
872                                % (key, meta, name))
873         if (key == 'gen' or key == 'success-response') and value is not False:
874             raise QAPISemError(info,
875                                "'%s' of %s '%s' should only use false value"
876                                % (key, meta, name))
877         if key == 'boxed' and value is not True:
878             raise QAPISemError(info,
879                                "'%s' of %s '%s' should only use true value"
880                                % (key, meta, name))
881     for key in required:
882         if key not in expr:
883             raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
884                                % (key, meta, name))
885
886
887 def check_exprs(exprs):
888     global all_names
889
890     # Populate name table with names of built-in types
891     for builtin in builtin_types.keys():
892         all_names[builtin] = 'built-in'
893
894     # Learn the types and check for valid expression keys
895     for expr_elem in exprs:
896         expr = expr_elem['expr']
897         info = expr_elem['info']
898         doc = expr_elem.get('doc')
899
900         if not doc and doc_required:
901             raise QAPISemError(info,
902                                "Expression missing documentation comment")
903
904         if 'enum' in expr:
905             meta = 'enum'
906             check_keys(expr_elem, 'enum', ['data'], ['prefix'])
907             enum_types[expr[meta]] = expr
908         elif 'union' in expr:
909             meta = 'union'
910             check_keys(expr_elem, 'union', ['data'],
911                        ['base', 'discriminator'])
912             union_types[expr[meta]] = expr
913         elif 'alternate' in expr:
914             meta = 'alternate'
915             check_keys(expr_elem, 'alternate', ['data'])
916         elif 'struct' in expr:
917             meta = 'struct'
918             check_keys(expr_elem, 'struct', ['data'], ['base'])
919             struct_types[expr[meta]] = expr
920         elif 'command' in expr:
921             meta = 'command'
922             check_keys(expr_elem, 'command', [],
923                        ['data', 'returns', 'gen', 'success-response', 'boxed'])
924         elif 'event' in expr:
925             meta = 'event'
926             check_keys(expr_elem, 'event', [], ['data', 'boxed'])
927         else:
928             raise QAPISemError(expr_elem['info'],
929                                "Expression is missing metatype")
930         name = expr[meta]
931         add_name(name, info, meta)
932         if doc and doc.symbol != name:
933             raise QAPISemError(info, "Definition of '%s' follows documentation"
934                                " for '%s'" % (name, doc.symbol))
935
936     # Try again for hidden UnionKind enum
937     for expr_elem in exprs:
938         expr = expr_elem['expr']
939         if 'union' in expr and not discriminator_find_enum_define(expr):
940             name = '%sKind' % expr['union']
941         elif 'alternate' in expr:
942             name = '%sKind' % expr['alternate']
943         else:
944             continue
945         enum_types[name] = {'enum': name}
946         add_name(name, info, 'enum', implicit=True)
947
948     # Validate that exprs make sense
949     for expr_elem in exprs:
950         expr = expr_elem['expr']
951         info = expr_elem['info']
952         doc = expr_elem.get('doc')
953
954         if 'enum' in expr:
955             check_enum(expr, info)
956         elif 'union' in expr:
957             check_union(expr, info)
958         elif 'alternate' in expr:
959             check_alternate(expr, info)
960         elif 'struct' in expr:
961             check_struct(expr, info)
962         elif 'command' in expr:
963             check_command(expr, info)
964         elif 'event' in expr:
965             check_event(expr, info)
966         else:
967             assert False, 'unexpected meta type'
968
969         if doc:
970             doc.check_expr(expr)
971
972     return exprs
973
974
975 #
976 # Schema compiler frontend
977 #
978
979 class QAPISchemaEntity(object):
980     def __init__(self, name, info, doc):
981         assert isinstance(name, str)
982         self.name = name
983         # For explicitly defined entities, info points to the (explicit)
984         # definition.  For builtins (and their arrays), info is None.
985         # For implicitly defined entities, info points to a place that
986         # triggered the implicit definition (there may be more than one
987         # such place).
988         self.info = info
989         self.doc = doc
990
991     def c_name(self):
992         return c_name(self.name)
993
994     def check(self, schema):
995         pass
996
997     def is_implicit(self):
998         return not self.info
999
1000     def visit(self, visitor):
1001         pass
1002
1003
1004 class QAPISchemaVisitor(object):
1005     def visit_begin(self, schema):
1006         pass
1007
1008     def visit_end(self):
1009         pass
1010
1011     def visit_needed(self, entity):
1012         # Default to visiting everything
1013         return True
1014
1015     def visit_builtin_type(self, name, info, json_type):
1016         pass
1017
1018     def visit_enum_type(self, name, info, values, prefix):
1019         pass
1020
1021     def visit_array_type(self, name, info, element_type):
1022         pass
1023
1024     def visit_object_type(self, name, info, base, members, variants):
1025         pass
1026
1027     def visit_object_type_flat(self, name, info, members, variants):
1028         pass
1029
1030     def visit_alternate_type(self, name, info, variants):
1031         pass
1032
1033     def visit_command(self, name, info, arg_type, ret_type,
1034                       gen, success_response, boxed):
1035         pass
1036
1037     def visit_event(self, name, info, arg_type, boxed):
1038         pass
1039
1040
1041 class QAPISchemaType(QAPISchemaEntity):
1042     # Return the C type for common use.
1043     # For the types we commonly box, this is a pointer type.
1044     def c_type(self):
1045         pass
1046
1047     # Return the C type to be used in a parameter list.
1048     def c_param_type(self):
1049         return self.c_type()
1050
1051     # Return the C type to be used where we suppress boxing.
1052     def c_unboxed_type(self):
1053         return self.c_type()
1054
1055     def json_type(self):
1056         pass
1057
1058     def alternate_qtype(self):
1059         json2qtype = {
1060             'null':    'QTYPE_QNULL',
1061             'string':  'QTYPE_QSTRING',
1062             'number':  'QTYPE_QNUM',
1063             'int':     'QTYPE_QNUM',
1064             'boolean': 'QTYPE_QBOOL',
1065             'object':  'QTYPE_QDICT'
1066         }
1067         return json2qtype.get(self.json_type())
1068
1069     def doc_type(self):
1070         if self.is_implicit():
1071             return None
1072         return self.name
1073
1074
1075 class QAPISchemaBuiltinType(QAPISchemaType):
1076     def __init__(self, name, json_type, c_type):
1077         QAPISchemaType.__init__(self, name, None, None)
1078         assert not c_type or isinstance(c_type, str)
1079         assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1080                              'value')
1081         self._json_type_name = json_type
1082         self._c_type_name = c_type
1083
1084     def c_name(self):
1085         return self.name
1086
1087     def c_type(self):
1088         return self._c_type_name
1089
1090     def c_param_type(self):
1091         if self.name == 'str':
1092             return 'const ' + self._c_type_name
1093         return self._c_type_name
1094
1095     def json_type(self):
1096         return self._json_type_name
1097
1098     def doc_type(self):
1099         return self.json_type()
1100
1101     def visit(self, visitor):
1102         visitor.visit_builtin_type(self.name, self.info, self.json_type())
1103
1104
1105 class QAPISchemaEnumType(QAPISchemaType):
1106     def __init__(self, name, info, doc, values, prefix):
1107         QAPISchemaType.__init__(self, name, info, doc)
1108         for v in values:
1109             assert isinstance(v, QAPISchemaMember)
1110             v.set_owner(name)
1111         assert prefix is None or isinstance(prefix, str)
1112         self.values = values
1113         self.prefix = prefix
1114
1115     def check(self, schema):
1116         seen = {}
1117         for v in self.values:
1118             v.check_clash(self.info, seen)
1119             if self.doc:
1120                 self.doc.connect_member(v)
1121
1122     def is_implicit(self):
1123         # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1124         return self.name.endswith('Kind') or self.name == 'QType'
1125
1126     def c_type(self):
1127         return c_name(self.name)
1128
1129     def member_names(self):
1130         return [v.name for v in self.values]
1131
1132     def json_type(self):
1133         return 'string'
1134
1135     def visit(self, visitor):
1136         visitor.visit_enum_type(self.name, self.info,
1137                                 self.member_names(), self.prefix)
1138
1139
1140 class QAPISchemaArrayType(QAPISchemaType):
1141     def __init__(self, name, info, element_type):
1142         QAPISchemaType.__init__(self, name, info, None)
1143         assert isinstance(element_type, str)
1144         self._element_type_name = element_type
1145         self.element_type = None
1146
1147     def check(self, schema):
1148         self.element_type = schema.lookup_type(self._element_type_name)
1149         assert self.element_type
1150
1151     def is_implicit(self):
1152         return True
1153
1154     def c_type(self):
1155         return c_name(self.name) + pointer_suffix
1156
1157     def json_type(self):
1158         return 'array'
1159
1160     def doc_type(self):
1161         elt_doc_type = self.element_type.doc_type()
1162         if not elt_doc_type:
1163             return None
1164         return 'array of ' + elt_doc_type
1165
1166     def visit(self, visitor):
1167         visitor.visit_array_type(self.name, self.info, self.element_type)
1168
1169
1170 class QAPISchemaObjectType(QAPISchemaType):
1171     def __init__(self, name, info, doc, base, local_members, variants):
1172         # struct has local_members, optional base, and no variants
1173         # flat union has base, variants, and no local_members
1174         # simple union has local_members, variants, and no base
1175         QAPISchemaType.__init__(self, name, info, doc)
1176         assert base is None or isinstance(base, str)
1177         for m in local_members:
1178             assert isinstance(m, QAPISchemaObjectTypeMember)
1179             m.set_owner(name)
1180         if variants is not None:
1181             assert isinstance(variants, QAPISchemaObjectTypeVariants)
1182             variants.set_owner(name)
1183         self._base_name = base
1184         self.base = None
1185         self.local_members = local_members
1186         self.variants = variants
1187         self.members = None
1188
1189     def check(self, schema):
1190         if self.members is False:               # check for cycles
1191             raise QAPISemError(self.info,
1192                                "Object %s contains itself" % self.name)
1193         if self.members:
1194             return
1195         self.members = False                    # mark as being checked
1196         seen = OrderedDict()
1197         if self._base_name:
1198             self.base = schema.lookup_type(self._base_name)
1199             assert isinstance(self.base, QAPISchemaObjectType)
1200             self.base.check(schema)
1201             self.base.check_clash(self.info, seen)
1202         for m in self.local_members:
1203             m.check(schema)
1204             m.check_clash(self.info, seen)
1205             if self.doc:
1206                 self.doc.connect_member(m)
1207         self.members = seen.values()
1208         if self.variants:
1209             self.variants.check(schema, seen)
1210             assert self.variants.tag_member in self.members
1211             self.variants.check_clash(self.info, seen)
1212         if self.doc:
1213             self.doc.check()
1214
1215     # Check that the members of this type do not cause duplicate JSON members,
1216     # and update seen to track the members seen so far. Report any errors
1217     # on behalf of info, which is not necessarily self.info
1218     def check_clash(self, info, seen):
1219         assert not self.variants       # not implemented
1220         for m in self.members:
1221             m.check_clash(info, seen)
1222
1223     def is_implicit(self):
1224         # See QAPISchema._make_implicit_object_type(), as well as
1225         # _def_predefineds()
1226         return self.name.startswith('q_')
1227
1228     def is_empty(self):
1229         assert self.members is not None
1230         return not self.members and not self.variants
1231
1232     def c_name(self):
1233         assert self.name != 'q_empty'
1234         return QAPISchemaType.c_name(self)
1235
1236     def c_type(self):
1237         assert not self.is_implicit()
1238         return c_name(self.name) + pointer_suffix
1239
1240     def c_unboxed_type(self):
1241         return c_name(self.name)
1242
1243     def json_type(self):
1244         return 'object'
1245
1246     def visit(self, visitor):
1247         visitor.visit_object_type(self.name, self.info,
1248                                   self.base, self.local_members, self.variants)
1249         visitor.visit_object_type_flat(self.name, self.info,
1250                                        self.members, self.variants)
1251
1252
1253 class QAPISchemaMember(object):
1254     role = 'member'
1255
1256     def __init__(self, name):
1257         assert isinstance(name, str)
1258         self.name = name
1259         self.owner = None
1260
1261     def set_owner(self, name):
1262         assert not self.owner
1263         self.owner = name
1264
1265     def check_clash(self, info, seen):
1266         cname = c_name(self.name)
1267         if cname.lower() != cname and self.owner not in name_case_whitelist:
1268             raise QAPISemError(info,
1269                                "%s should not use uppercase" % self.describe())
1270         if cname in seen:
1271             raise QAPISemError(info, "%s collides with %s" %
1272                                (self.describe(), seen[cname].describe()))
1273         seen[cname] = self
1274
1275     def _pretty_owner(self):
1276         owner = self.owner
1277         if owner.startswith('q_obj_'):
1278             # See QAPISchema._make_implicit_object_type() - reverse the
1279             # mapping there to create a nice human-readable description
1280             owner = owner[6:]
1281             if owner.endswith('-arg'):
1282                 return '(parameter of %s)' % owner[:-4]
1283             elif owner.endswith('-base'):
1284                 return '(base of %s)' % owner[:-5]
1285             else:
1286                 assert owner.endswith('-wrapper')
1287                 # Unreachable and not implemented
1288                 assert False
1289         if owner.endswith('Kind'):
1290             # See QAPISchema._make_implicit_enum_type()
1291             return '(branch of %s)' % owner[:-4]
1292         return '(%s of %s)' % (self.role, owner)
1293
1294     def describe(self):
1295         return "'%s' %s" % (self.name, self._pretty_owner())
1296
1297
1298 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1299     def __init__(self, name, typ, optional):
1300         QAPISchemaMember.__init__(self, name)
1301         assert isinstance(typ, str)
1302         assert isinstance(optional, bool)
1303         self._type_name = typ
1304         self.type = None
1305         self.optional = optional
1306
1307     def check(self, schema):
1308         assert self.owner
1309         self.type = schema.lookup_type(self._type_name)
1310         assert self.type
1311
1312
1313 class QAPISchemaObjectTypeVariants(object):
1314     def __init__(self, tag_name, tag_member, variants):
1315         # Flat unions pass tag_name but not tag_member.
1316         # Simple unions and alternates pass tag_member but not tag_name.
1317         # After check(), tag_member is always set, and tag_name remains
1318         # a reliable witness of being used by a flat union.
1319         assert bool(tag_member) != bool(tag_name)
1320         assert (isinstance(tag_name, str) or
1321                 isinstance(tag_member, QAPISchemaObjectTypeMember))
1322         assert len(variants) > 0
1323         for v in variants:
1324             assert isinstance(v, QAPISchemaObjectTypeVariant)
1325         self._tag_name = tag_name
1326         self.tag_member = tag_member
1327         self.variants = variants
1328
1329     def set_owner(self, name):
1330         for v in self.variants:
1331             v.set_owner(name)
1332
1333     def check(self, schema, seen):
1334         if not self.tag_member:    # flat union
1335             self.tag_member = seen[c_name(self._tag_name)]
1336             assert self._tag_name == self.tag_member.name
1337         assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1338         for v in self.variants:
1339             v.check(schema)
1340             # Union names must match enum values; alternate names are
1341             # checked separately. Use 'seen' to tell the two apart.
1342             if seen:
1343                 assert v.name in self.tag_member.type.member_names()
1344                 assert isinstance(v.type, QAPISchemaObjectType)
1345                 v.type.check(schema)
1346
1347     def check_clash(self, info, seen):
1348         for v in self.variants:
1349             # Reset seen map for each variant, since qapi names from one
1350             # branch do not affect another branch
1351             assert isinstance(v.type, QAPISchemaObjectType)
1352             v.type.check_clash(info, dict(seen))
1353
1354
1355 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1356     role = 'branch'
1357
1358     def __init__(self, name, typ):
1359         QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1360
1361
1362 class QAPISchemaAlternateType(QAPISchemaType):
1363     def __init__(self, name, info, doc, variants):
1364         QAPISchemaType.__init__(self, name, info, doc)
1365         assert isinstance(variants, QAPISchemaObjectTypeVariants)
1366         assert variants.tag_member
1367         variants.set_owner(name)
1368         variants.tag_member.set_owner(self.name)
1369         self.variants = variants
1370
1371     def check(self, schema):
1372         self.variants.tag_member.check(schema)
1373         # Not calling self.variants.check_clash(), because there's nothing
1374         # to clash with
1375         self.variants.check(schema, {})
1376         # Alternate branch names have no relation to the tag enum values;
1377         # so we have to check for potential name collisions ourselves.
1378         seen = {}
1379         for v in self.variants.variants:
1380             v.check_clash(self.info, seen)
1381             if self.doc:
1382                 self.doc.connect_member(v)
1383         if self.doc:
1384             self.doc.check()
1385
1386     def c_type(self):
1387         return c_name(self.name) + pointer_suffix
1388
1389     def json_type(self):
1390         return 'value'
1391
1392     def visit(self, visitor):
1393         visitor.visit_alternate_type(self.name, self.info, self.variants)
1394
1395     def is_empty(self):
1396         return False
1397
1398
1399 class QAPISchemaCommand(QAPISchemaEntity):
1400     def __init__(self, name, info, doc, arg_type, ret_type,
1401                  gen, success_response, boxed):
1402         QAPISchemaEntity.__init__(self, name, info, doc)
1403         assert not arg_type or isinstance(arg_type, str)
1404         assert not ret_type or isinstance(ret_type, str)
1405         self._arg_type_name = arg_type
1406         self.arg_type = None
1407         self._ret_type_name = ret_type
1408         self.ret_type = None
1409         self.gen = gen
1410         self.success_response = success_response
1411         self.boxed = boxed
1412
1413     def check(self, schema):
1414         if self._arg_type_name:
1415             self.arg_type = schema.lookup_type(self._arg_type_name)
1416             assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1417                     isinstance(self.arg_type, QAPISchemaAlternateType))
1418             self.arg_type.check(schema)
1419             if self.boxed:
1420                 if self.arg_type.is_empty():
1421                     raise QAPISemError(self.info,
1422                                        "Cannot use 'boxed' with empty type")
1423             else:
1424                 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1425                 assert not self.arg_type.variants
1426         elif self.boxed:
1427             raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1428         if self._ret_type_name:
1429             self.ret_type = schema.lookup_type(self._ret_type_name)
1430             assert isinstance(self.ret_type, QAPISchemaType)
1431
1432     def visit(self, visitor):
1433         visitor.visit_command(self.name, self.info,
1434                               self.arg_type, self.ret_type,
1435                               self.gen, self.success_response, self.boxed)
1436
1437
1438 class QAPISchemaEvent(QAPISchemaEntity):
1439     def __init__(self, name, info, doc, arg_type, boxed):
1440         QAPISchemaEntity.__init__(self, name, info, doc)
1441         assert not arg_type or isinstance(arg_type, str)
1442         self._arg_type_name = arg_type
1443         self.arg_type = None
1444         self.boxed = boxed
1445
1446     def check(self, schema):
1447         if self._arg_type_name:
1448             self.arg_type = schema.lookup_type(self._arg_type_name)
1449             assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1450                     isinstance(self.arg_type, QAPISchemaAlternateType))
1451             self.arg_type.check(schema)
1452             if self.boxed:
1453                 if self.arg_type.is_empty():
1454                     raise QAPISemError(self.info,
1455                                        "Cannot use 'boxed' with empty type")
1456             else:
1457                 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1458                 assert not self.arg_type.variants
1459         elif self.boxed:
1460             raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1461
1462     def visit(self, visitor):
1463         visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
1464
1465
1466 class QAPISchema(object):
1467     def __init__(self, fname):
1468         try:
1469             parser = QAPISchemaParser(open(fname, 'r'))
1470             self.exprs = check_exprs(parser.exprs)
1471             self.docs = parser.docs
1472             self._entity_dict = {}
1473             self._predefining = True
1474             self._def_predefineds()
1475             self._predefining = False
1476             self._def_exprs()
1477             self.check()
1478         except QAPIError as err:
1479             print >>sys.stderr, err
1480             exit(1)
1481
1482     def _def_entity(self, ent):
1483         # Only the predefined types are allowed to not have info
1484         assert ent.info or self._predefining
1485         assert ent.name not in self._entity_dict
1486         self._entity_dict[ent.name] = ent
1487
1488     def lookup_entity(self, name, typ=None):
1489         ent = self._entity_dict.get(name)
1490         if typ and not isinstance(ent, typ):
1491             return None
1492         return ent
1493
1494     def lookup_type(self, name):
1495         return self.lookup_entity(name, QAPISchemaType)
1496
1497     def _def_builtin_type(self, name, json_type, c_type):
1498         self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1499         # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1500         # qapi-types.h from a single .c, all arrays of builtins must be
1501         # declared in the first file whether or not they are used.  Nicer
1502         # would be to use lazy instantiation, while figuring out how to
1503         # avoid compilation issues with multiple qapi-types.h.
1504         self._make_array_type(name, None)
1505
1506     def _def_predefineds(self):
1507         for t in [('str',    'string',  'char' + pointer_suffix),
1508                   ('number', 'number',  'double'),
1509                   ('int',    'int',     'int64_t'),
1510                   ('int8',   'int',     'int8_t'),
1511                   ('int16',  'int',     'int16_t'),
1512                   ('int32',  'int',     'int32_t'),
1513                   ('int64',  'int',     'int64_t'),
1514                   ('uint8',  'int',     'uint8_t'),
1515                   ('uint16', 'int',     'uint16_t'),
1516                   ('uint32', 'int',     'uint32_t'),
1517                   ('uint64', 'int',     'uint64_t'),
1518                   ('size',   'int',     'uint64_t'),
1519                   ('bool',   'boolean', 'bool'),
1520                   ('any',    'value',   'QObject' + pointer_suffix),
1521                   ('null',   'null',    'QNull' + pointer_suffix)]:
1522             self._def_builtin_type(*t)
1523         self.the_empty_object_type = QAPISchemaObjectType(
1524             'q_empty', None, None, None, [], None)
1525         self._def_entity(self.the_empty_object_type)
1526         qtype_values = self._make_enum_members(['none', 'qnull', 'qnum',
1527                                                 'qstring', 'qdict', 'qlist',
1528                                                 'qbool'])
1529         self._def_entity(QAPISchemaEnumType('QType', None, None,
1530                                             qtype_values, 'QTYPE'))
1531
1532     def _make_enum_members(self, values):
1533         return [QAPISchemaMember(v) for v in values]
1534
1535     def _make_implicit_enum_type(self, name, info, values):
1536         # See also QAPISchemaObjectTypeMember._pretty_owner()
1537         name = name + 'Kind'   # Use namespace reserved by add_name()
1538         self._def_entity(QAPISchemaEnumType(
1539             name, info, None, self._make_enum_members(values), None))
1540         return name
1541
1542     def _make_array_type(self, element_type, info):
1543         name = element_type + 'List'   # Use namespace reserved by add_name()
1544         if not self.lookup_type(name):
1545             self._def_entity(QAPISchemaArrayType(name, info, element_type))
1546         return name
1547
1548     def _make_implicit_object_type(self, name, info, doc, role, members):
1549         if not members:
1550             return None
1551         # See also QAPISchemaObjectTypeMember._pretty_owner()
1552         name = 'q_obj_%s-%s' % (name, role)
1553         if not self.lookup_entity(name, QAPISchemaObjectType):
1554             self._def_entity(QAPISchemaObjectType(name, info, doc, None,
1555                                                   members, None))
1556         return name
1557
1558     def _def_enum_type(self, expr, info, doc):
1559         name = expr['enum']
1560         data = expr['data']
1561         prefix = expr.get('prefix')
1562         self._def_entity(QAPISchemaEnumType(
1563             name, info, doc, self._make_enum_members(data), prefix))
1564
1565     def _make_member(self, name, typ, info):
1566         optional = False
1567         if name.startswith('*'):
1568             name = name[1:]
1569             optional = True
1570         if isinstance(typ, list):
1571             assert len(typ) == 1
1572             typ = self._make_array_type(typ[0], info)
1573         return QAPISchemaObjectTypeMember(name, typ, optional)
1574
1575     def _make_members(self, data, info):
1576         return [self._make_member(key, value, info)
1577                 for (key, value) in data.iteritems()]
1578
1579     def _def_struct_type(self, expr, info, doc):
1580         name = expr['struct']
1581         base = expr.get('base')
1582         data = expr['data']
1583         self._def_entity(QAPISchemaObjectType(name, info, doc, base,
1584                                               self._make_members(data, info),
1585                                               None))
1586
1587     def _make_variant(self, case, typ):
1588         return QAPISchemaObjectTypeVariant(case, typ)
1589
1590     def _make_simple_variant(self, case, typ, info):
1591         if isinstance(typ, list):
1592             assert len(typ) == 1
1593             typ = self._make_array_type(typ[0], info)
1594         typ = self._make_implicit_object_type(
1595             typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
1596         return QAPISchemaObjectTypeVariant(case, typ)
1597
1598     def _def_union_type(self, expr, info, doc):
1599         name = expr['union']
1600         data = expr['data']
1601         base = expr.get('base')
1602         tag_name = expr.get('discriminator')
1603         tag_member = None
1604         if isinstance(base, dict):
1605             base = (self._make_implicit_object_type(
1606                 name, info, doc, 'base', self._make_members(base, info)))
1607         if tag_name:
1608             variants = [self._make_variant(key, value)
1609                         for (key, value) in data.iteritems()]
1610             members = []
1611         else:
1612             variants = [self._make_simple_variant(key, value, info)
1613                         for (key, value) in data.iteritems()]
1614             typ = self._make_implicit_enum_type(name, info,
1615                                                 [v.name for v in variants])
1616             tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1617             members = [tag_member]
1618         self._def_entity(
1619             QAPISchemaObjectType(name, info, doc, base, members,
1620                                  QAPISchemaObjectTypeVariants(tag_name,
1621                                                               tag_member,
1622                                                               variants)))
1623
1624     def _def_alternate_type(self, expr, info, doc):
1625         name = expr['alternate']
1626         data = expr['data']
1627         variants = [self._make_variant(key, value)
1628                     for (key, value) in data.iteritems()]
1629         tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1630         self._def_entity(
1631             QAPISchemaAlternateType(name, info, doc,
1632                                     QAPISchemaObjectTypeVariants(None,
1633                                                                  tag_member,
1634                                                                  variants)))
1635
1636     def _def_command(self, expr, info, doc):
1637         name = expr['command']
1638         data = expr.get('data')
1639         rets = expr.get('returns')
1640         gen = expr.get('gen', True)
1641         success_response = expr.get('success-response', True)
1642         boxed = expr.get('boxed', False)
1643         if isinstance(data, OrderedDict):
1644             data = self._make_implicit_object_type(
1645                 name, info, doc, 'arg', self._make_members(data, info))
1646         if isinstance(rets, list):
1647             assert len(rets) == 1
1648             rets = self._make_array_type(rets[0], info)
1649         self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
1650                                            gen, success_response, boxed))
1651
1652     def _def_event(self, expr, info, doc):
1653         name = expr['event']
1654         data = expr.get('data')
1655         boxed = expr.get('boxed', False)
1656         if isinstance(data, OrderedDict):
1657             data = self._make_implicit_object_type(
1658                 name, info, doc, 'arg', self._make_members(data, info))
1659         self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
1660
1661     def _def_exprs(self):
1662         for expr_elem in self.exprs:
1663             expr = expr_elem['expr']
1664             info = expr_elem['info']
1665             doc = expr_elem.get('doc')
1666             if 'enum' in expr:
1667                 self._def_enum_type(expr, info, doc)
1668             elif 'struct' in expr:
1669                 self._def_struct_type(expr, info, doc)
1670             elif 'union' in expr:
1671                 self._def_union_type(expr, info, doc)
1672             elif 'alternate' in expr:
1673                 self._def_alternate_type(expr, info, doc)
1674             elif 'command' in expr:
1675                 self._def_command(expr, info, doc)
1676             elif 'event' in expr:
1677                 self._def_event(expr, info, doc)
1678             else:
1679                 assert False
1680
1681     def check(self):
1682         for ent in self._entity_dict.values():
1683             ent.check(self)
1684
1685     def visit(self, visitor):
1686         visitor.visit_begin(self)
1687         for (name, entity) in sorted(self._entity_dict.items()):
1688             if visitor.visit_needed(entity):
1689                 entity.visit(visitor)
1690         visitor.visit_end()
1691
1692
1693 #
1694 # Code generation helpers
1695 #
1696
1697 def camel_case(name):
1698     new_name = ''
1699     first = True
1700     for ch in name:
1701         if ch in ['_', '-']:
1702             first = True
1703         elif first:
1704             new_name += ch.upper()
1705             first = False
1706         else:
1707             new_name += ch.lower()
1708     return new_name
1709
1710
1711 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1712 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1713 # ENUM24_Name -> ENUM24_NAME
1714 def camel_to_upper(value):
1715     c_fun_str = c_name(value, False)
1716     if value.isupper():
1717         return c_fun_str
1718
1719     new_name = ''
1720     l = len(c_fun_str)
1721     for i in range(l):
1722         c = c_fun_str[i]
1723         # When c is upper and no '_' appears before, do more checks
1724         if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
1725             if i < l - 1 and c_fun_str[i + 1].islower():
1726                 new_name += '_'
1727             elif c_fun_str[i - 1].isdigit():
1728                 new_name += '_'
1729         new_name += c
1730     return new_name.lstrip('_').upper()
1731
1732
1733 def c_enum_const(type_name, const_name, prefix=None):
1734     if prefix is not None:
1735         type_name = prefix
1736     return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1737
1738 c_name_trans = string.maketrans('.-', '__')
1739
1740
1741 # Map @name to a valid C identifier.
1742 # If @protect, avoid returning certain ticklish identifiers (like
1743 # C keywords) by prepending 'q_'.
1744 #
1745 # Used for converting 'name' from a 'name':'type' qapi definition
1746 # into a generated struct member, as well as converting type names
1747 # into substrings of a generated C function name.
1748 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1749 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1750 def c_name(name, protect=True):
1751     # ANSI X3J11/88-090, 3.1.1
1752     c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1753                      'default', 'do', 'double', 'else', 'enum', 'extern',
1754                      'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1755                      'return', 'short', 'signed', 'sizeof', 'static',
1756                      'struct', 'switch', 'typedef', 'union', 'unsigned',
1757                      'void', 'volatile', 'while'])
1758     # ISO/IEC 9899:1999, 6.4.1
1759     c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1760     # ISO/IEC 9899:2011, 6.4.1
1761     c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1762                      '_Noreturn', '_Static_assert', '_Thread_local'])
1763     # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1764     # excluding _.*
1765     gcc_words = set(['asm', 'typeof'])
1766     # C++ ISO/IEC 14882:2003 2.11
1767     cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1768                      'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1769                      'namespace', 'new', 'operator', 'private', 'protected',
1770                      'public', 'reinterpret_cast', 'static_cast', 'template',
1771                      'this', 'throw', 'true', 'try', 'typeid', 'typename',
1772                      'using', 'virtual', 'wchar_t',
1773                      # alternative representations
1774                      'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1775                      'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1776     # namespace pollution:
1777     polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1778     name = name.translate(c_name_trans)
1779     if protect and (name in c89_words | c99_words | c11_words | gcc_words
1780                     | cpp_words | polluted_words):
1781         return 'q_' + name
1782     return name
1783
1784 eatspace = '\033EATSPACE.'
1785 pointer_suffix = ' *' + eatspace
1786
1787
1788 def genindent(count):
1789     ret = ''
1790     for _ in range(count):
1791         ret += ' '
1792     return ret
1793
1794 indent_level = 0
1795
1796
1797 def push_indent(indent_amount=4):
1798     global indent_level
1799     indent_level += indent_amount
1800
1801
1802 def pop_indent(indent_amount=4):
1803     global indent_level
1804     indent_level -= indent_amount
1805
1806
1807 # Generate @code with @kwds interpolated.
1808 # Obey indent_level, and strip eatspace.
1809 def cgen(code, **kwds):
1810     raw = code % kwds
1811     if indent_level:
1812         indent = genindent(indent_level)
1813         # re.subn() lacks flags support before Python 2.7, use re.compile()
1814         raw = re.subn(re.compile(r'^.', re.MULTILINE),
1815                       indent + r'\g<0>', raw)
1816         raw = raw[0]
1817     return re.sub(re.escape(eatspace) + r' *', '', raw)
1818
1819
1820 def mcgen(code, **kwds):
1821     if code[0] == '\n':
1822         code = code[1:]
1823     return cgen(code, **kwds)
1824
1825
1826 def guardname(filename):
1827     return c_name(filename, protect=False).upper()
1828
1829
1830 def guardstart(name):
1831     return mcgen('''
1832
1833 #ifndef %(name)s
1834 #define %(name)s
1835
1836 ''',
1837                  name=guardname(name))
1838
1839
1840 def guardend(name):
1841     return mcgen('''
1842
1843 #endif /* %(name)s */
1844
1845 ''',
1846                  name=guardname(name))
1847
1848
1849 def gen_enum_lookup(name, values, prefix=None):
1850     ret = mcgen('''
1851
1852 const QEnumLookup %(c_name)s_lookup = {
1853     .array = (const char *const[]) {
1854 ''',
1855                 c_name=c_name(name))
1856     for value in values:
1857         index = c_enum_const(name, value, prefix)
1858         ret += mcgen('''
1859         [%(index)s] = "%(value)s",
1860 ''',
1861                      index=index, value=value)
1862
1863     max_index = c_enum_const(name, '_MAX', prefix)
1864     ret += mcgen('''
1865         [%(max_index)s] = NULL,
1866     },
1867     .size = %(max_index)s
1868 };
1869 ''',
1870                  max_index=max_index)
1871     return ret
1872
1873
1874 def gen_enum(name, values, prefix=None):
1875     # append automatically generated _MAX value
1876     enum_values = values + ['_MAX']
1877
1878     ret = mcgen('''
1879
1880 typedef enum %(c_name)s {
1881 ''',
1882                 c_name=c_name(name))
1883
1884     i = 0
1885     for value in enum_values:
1886         ret += mcgen('''
1887     %(c_enum)s = %(i)d,
1888 ''',
1889                      c_enum=c_enum_const(name, value, prefix),
1890                      i=i)
1891         i += 1
1892
1893     ret += mcgen('''
1894 } %(c_name)s;
1895 ''',
1896                  c_name=c_name(name))
1897
1898     ret += mcgen('''
1899
1900 #define %(c_name)s_str(val) \\
1901     qapi_enum_lookup(&%(c_name)s_lookup, (val))
1902
1903 extern const QEnumLookup %(c_name)s_lookup;
1904 ''',
1905                  c_name=c_name(name))
1906     return ret
1907
1908
1909 def build_params(arg_type, boxed, extra):
1910     if not arg_type:
1911         assert not boxed
1912         return extra
1913     ret = ''
1914     sep = ''
1915     if boxed:
1916         ret += '%s arg' % arg_type.c_param_type()
1917         sep = ', '
1918     else:
1919         assert not arg_type.variants
1920         for memb in arg_type.members:
1921             ret += sep
1922             sep = ', '
1923             if memb.optional:
1924                 ret += 'bool has_%s, ' % c_name(memb.name)
1925             ret += '%s %s' % (memb.type.c_param_type(),
1926                               c_name(memb.name))
1927     if extra:
1928         ret += sep + extra
1929     return ret
1930
1931
1932 #
1933 # Common command line parsing
1934 #
1935
1936
1937 def parse_command_line(extra_options='', extra_long_options=[]):
1938
1939     try:
1940         opts, args = getopt.gnu_getopt(sys.argv[1:],
1941                                        'chp:o:' + extra_options,
1942                                        ['source', 'header', 'prefix=',
1943                                         'output-dir='] + extra_long_options)
1944     except getopt.GetoptError as err:
1945         print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1946         sys.exit(1)
1947
1948     output_dir = ''
1949     prefix = ''
1950     do_c = False
1951     do_h = False
1952     extra_opts = []
1953
1954     for oa in opts:
1955         o, a = oa
1956         if o in ('-p', '--prefix'):
1957             match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1958             if match.end() != len(a):
1959                 print >>sys.stderr, \
1960                     "%s: 'funny character '%s' in argument of --prefix" \
1961                     % (sys.argv[0], a[match.end()])
1962                 sys.exit(1)
1963             prefix = a
1964         elif o in ('-o', '--output-dir'):
1965             output_dir = a + '/'
1966         elif o in ('-c', '--source'):
1967             do_c = True
1968         elif o in ('-h', '--header'):
1969             do_h = True
1970         else:
1971             extra_opts.append(oa)
1972
1973     if not do_c and not do_h:
1974         do_c = True
1975         do_h = True
1976
1977     if len(args) != 1:
1978         print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1979         sys.exit(1)
1980     fname = args[0]
1981
1982     return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1983
1984 #
1985 # Generate output files with boilerplate
1986 #
1987
1988
1989 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1990                 c_comment, h_comment):
1991     guard = guardname(prefix + h_file)
1992     c_file = output_dir + prefix + c_file
1993     h_file = output_dir + prefix + h_file
1994
1995     if output_dir:
1996         try:
1997             os.makedirs(output_dir)
1998         except os.error as e:
1999             if e.errno != errno.EEXIST:
2000                 raise
2001
2002     def maybe_open(really, name, opt):
2003         if really:
2004             return open(name, opt)
2005         else:
2006             import StringIO
2007             return StringIO.StringIO()
2008
2009     fdef = maybe_open(do_c, c_file, 'w')
2010     fdecl = maybe_open(do_h, h_file, 'w')
2011
2012     fdef.write(mcgen('''
2013 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2014 %(comment)s
2015 ''',
2016                      comment=c_comment))
2017
2018     fdecl.write(mcgen('''
2019 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2020 %(comment)s
2021 #ifndef %(guard)s
2022 #define %(guard)s
2023
2024 ''',
2025                       comment=h_comment, guard=guard))
2026
2027     return (fdef, fdecl)
2028
2029
2030 def close_output(fdef, fdecl):
2031     fdecl.write('''
2032 #endif
2033 ''')
2034     fdecl.close()
2035     fdef.close()
This page took 0.141032 seconds and 4 git commands to generate.