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