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