]> Git Repo - qemu.git/blob - scripts/qapi.py
qapi: Eliminate QAPISchemaObjectType.check() variable members
[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         seen = OrderedDict()
981         if self._base_name:
982             self.base = schema.lookup_type(self._base_name)
983             assert isinstance(self.base, QAPISchemaObjectType)
984             assert not self.base.variants       # not implemented
985             self.base.check(schema)
986             for m in self.base.members:
987                 assert m.name not in seen
988                 seen[m.name] = m
989         for m in self.local_members:
990             m.check(schema)
991             assert m.name not in seen
992             seen[m.name] = m
993         if self.variants:
994             self.variants.check(schema, seen)
995         self.members = seen.values()
996
997     def is_implicit(self):
998         # See QAPISchema._make_implicit_object_type()
999         return self.name[0] == ':'
1000
1001     def c_name(self):
1002         assert not self.is_implicit()
1003         return QAPISchemaType.c_name(self)
1004
1005     def c_type(self, is_param=False):
1006         assert not self.is_implicit()
1007         return QAPISchemaType.c_type(self)
1008
1009     def json_type(self):
1010         return 'object'
1011
1012     def visit(self, visitor):
1013         visitor.visit_object_type(self.name, self.info,
1014                                   self.base, self.local_members, self.variants)
1015         visitor.visit_object_type_flat(self.name, self.info,
1016                                        self.members, self.variants)
1017
1018
1019 class QAPISchemaObjectTypeMember(object):
1020     def __init__(self, name, typ, optional):
1021         assert isinstance(name, str)
1022         assert isinstance(typ, str)
1023         assert isinstance(optional, bool)
1024         self.name = name
1025         self._type_name = typ
1026         self.type = None
1027         self.optional = optional
1028
1029     def check(self, schema):
1030         self.type = schema.lookup_type(self._type_name)
1031         assert self.type
1032
1033
1034 class QAPISchemaObjectTypeVariants(object):
1035     def __init__(self, tag_name, tag_member, variants):
1036         # Flat unions pass tag_name but not tag_member.
1037         # Simple unions and alternates pass tag_member but not tag_name.
1038         # After check(), tag_member is always set, and tag_name remains
1039         # a reliable witness of being used by a flat union.
1040         assert bool(tag_member) != bool(tag_name)
1041         assert (isinstance(tag_name, str) or
1042                 isinstance(tag_member, QAPISchemaObjectTypeMember))
1043         for v in variants:
1044             assert isinstance(v, QAPISchemaObjectTypeVariant)
1045         self.tag_name = tag_name
1046         self.tag_member = tag_member
1047         self.variants = variants
1048
1049     def check(self, schema, seen):
1050         if self.tag_name:    # flat union
1051             self.tag_member = seen[self.tag_name]
1052         if seen:
1053             assert self.tag_member in seen.itervalues()
1054         assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1055         for v in self.variants:
1056             v.check(schema, self.tag_member.type)
1057
1058
1059 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1060     def __init__(self, name, typ):
1061         QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1062
1063     def check(self, schema, tag_type):
1064         QAPISchemaObjectTypeMember.check(self, schema)
1065         assert self.name in tag_type.values
1066
1067     # This function exists to support ugly simple union special cases
1068     # TODO get rid of them, and drop the function
1069     def simple_union_type(self):
1070         if (self.type.is_implicit() and
1071                 isinstance(self.type, QAPISchemaObjectType)):
1072             assert len(self.type.members) == 1
1073             assert not self.type.variants
1074             return self.type.members[0].type
1075         return None
1076
1077
1078 class QAPISchemaAlternateType(QAPISchemaType):
1079     def __init__(self, name, info, variants):
1080         QAPISchemaType.__init__(self, name, info)
1081         assert isinstance(variants, QAPISchemaObjectTypeVariants)
1082         assert not variants.tag_name
1083         self.variants = variants
1084
1085     def check(self, schema):
1086         self.variants.tag_member.check(schema)
1087         self.variants.check(schema, {})
1088
1089     def json_type(self):
1090         return 'value'
1091
1092     def visit(self, visitor):
1093         visitor.visit_alternate_type(self.name, self.info, self.variants)
1094
1095
1096 class QAPISchemaCommand(QAPISchemaEntity):
1097     def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1098         QAPISchemaEntity.__init__(self, name, info)
1099         assert not arg_type or isinstance(arg_type, str)
1100         assert not ret_type or isinstance(ret_type, str)
1101         self._arg_type_name = arg_type
1102         self.arg_type = None
1103         self._ret_type_name = ret_type
1104         self.ret_type = None
1105         self.gen = gen
1106         self.success_response = success_response
1107
1108     def check(self, schema):
1109         if self._arg_type_name:
1110             self.arg_type = schema.lookup_type(self._arg_type_name)
1111             assert isinstance(self.arg_type, QAPISchemaObjectType)
1112             assert not self.arg_type.variants   # not implemented
1113         if self._ret_type_name:
1114             self.ret_type = schema.lookup_type(self._ret_type_name)
1115             assert isinstance(self.ret_type, QAPISchemaType)
1116
1117     def visit(self, visitor):
1118         visitor.visit_command(self.name, self.info,
1119                               self.arg_type, self.ret_type,
1120                               self.gen, self.success_response)
1121
1122
1123 class QAPISchemaEvent(QAPISchemaEntity):
1124     def __init__(self, name, info, arg_type):
1125         QAPISchemaEntity.__init__(self, name, info)
1126         assert not arg_type or isinstance(arg_type, str)
1127         self._arg_type_name = arg_type
1128         self.arg_type = None
1129
1130     def check(self, schema):
1131         if self._arg_type_name:
1132             self.arg_type = schema.lookup_type(self._arg_type_name)
1133             assert isinstance(self.arg_type, QAPISchemaObjectType)
1134             assert not self.arg_type.variants   # not implemented
1135
1136     def visit(self, visitor):
1137         visitor.visit_event(self.name, self.info, self.arg_type)
1138
1139
1140 class QAPISchema(object):
1141     def __init__(self, fname):
1142         try:
1143             self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1144             self._entity_dict = {}
1145             self._predefining = True
1146             self._def_predefineds()
1147             self._predefining = False
1148             self._def_exprs()
1149             self.check()
1150         except (QAPISchemaError, QAPIExprError), err:
1151             print >>sys.stderr, err
1152             exit(1)
1153
1154     def _def_entity(self, ent):
1155         # Only the predefined types are allowed to not have info
1156         assert ent.info or self._predefining
1157         assert ent.name not in self._entity_dict
1158         self._entity_dict[ent.name] = ent
1159
1160     def lookup_entity(self, name, typ=None):
1161         ent = self._entity_dict.get(name)
1162         if typ and not isinstance(ent, typ):
1163             return None
1164         return ent
1165
1166     def lookup_type(self, name):
1167         return self.lookup_entity(name, QAPISchemaType)
1168
1169     def _def_builtin_type(self, name, json_type, c_type, c_null):
1170         self._def_entity(QAPISchemaBuiltinType(name, json_type,
1171                                                c_type, c_null))
1172         # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1173         # qapi-types.h from a single .c, all arrays of builtins must be
1174         # declared in the first file whether or not they are used.  Nicer
1175         # would be to use lazy instantiation, while figuring out how to
1176         # avoid compilation issues with multiple qapi-types.h.
1177         self._make_array_type(name, None)
1178
1179     def _def_predefineds(self):
1180         for t in [('str',    'string',  'char' + pointer_suffix, 'NULL'),
1181                   ('number', 'number',  'double',   '0'),
1182                   ('int',    'int',     'int64_t',  '0'),
1183                   ('int8',   'int',     'int8_t',   '0'),
1184                   ('int16',  'int',     'int16_t',  '0'),
1185                   ('int32',  'int',     'int32_t',  '0'),
1186                   ('int64',  'int',     'int64_t',  '0'),
1187                   ('uint8',  'int',     'uint8_t',  '0'),
1188                   ('uint16', 'int',     'uint16_t', '0'),
1189                   ('uint32', 'int',     'uint32_t', '0'),
1190                   ('uint64', 'int',     'uint64_t', '0'),
1191                   ('size',   'int',     'uint64_t', '0'),
1192                   ('bool',   'boolean', 'bool',     'false'),
1193                   ('any',    'value',   'QObject' + pointer_suffix, 'NULL')]:
1194             self._def_builtin_type(*t)
1195         self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1196                                                           [], None)
1197         self._def_entity(self.the_empty_object_type)
1198
1199     def _make_implicit_enum_type(self, name, info, values):
1200         name = name + 'Kind'   # Use namespace reserved by add_name()
1201         self._def_entity(QAPISchemaEnumType(name, info, values, None))
1202         return name
1203
1204     def _make_array_type(self, element_type, info):
1205         name = element_type + 'List'   # Use namespace reserved by add_name()
1206         if not self.lookup_type(name):
1207             self._def_entity(QAPISchemaArrayType(name, info, element_type))
1208         return name
1209
1210     def _make_implicit_object_type(self, name, info, role, members):
1211         if not members:
1212             return None
1213         name = ':obj-%s-%s' % (name, role)
1214         if not self.lookup_entity(name, QAPISchemaObjectType):
1215             self._def_entity(QAPISchemaObjectType(name, info, None,
1216                                                   members, None))
1217         return name
1218
1219     def _def_enum_type(self, expr, info):
1220         name = expr['enum']
1221         data = expr['data']
1222         prefix = expr.get('prefix')
1223         self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1224
1225     def _make_member(self, name, typ, info):
1226         optional = False
1227         if name.startswith('*'):
1228             name = name[1:]
1229             optional = True
1230         if isinstance(typ, list):
1231             assert len(typ) == 1
1232             typ = self._make_array_type(typ[0], info)
1233         return QAPISchemaObjectTypeMember(name, typ, optional)
1234
1235     def _make_members(self, data, info):
1236         return [self._make_member(key, value, info)
1237                 for (key, value) in data.iteritems()]
1238
1239     def _def_struct_type(self, expr, info):
1240         name = expr['struct']
1241         base = expr.get('base')
1242         data = expr['data']
1243         self._def_entity(QAPISchemaObjectType(name, info, base,
1244                                               self._make_members(data, info),
1245                                               None))
1246
1247     def _make_variant(self, case, typ):
1248         return QAPISchemaObjectTypeVariant(case, typ)
1249
1250     def _make_simple_variant(self, case, typ, info):
1251         if isinstance(typ, list):
1252             assert len(typ) == 1
1253             typ = self._make_array_type(typ[0], info)
1254         typ = self._make_implicit_object_type(
1255             typ, info, 'wrapper', [self._make_member('data', typ, info)])
1256         return QAPISchemaObjectTypeVariant(case, typ)
1257
1258     def _make_implicit_tag(self, type_name, info, variants):
1259         typ = self._make_implicit_enum_type(type_name, info,
1260                                             [v.name for v in variants])
1261         return QAPISchemaObjectTypeMember('type', typ, False)
1262
1263     def _def_union_type(self, expr, info):
1264         name = expr['union']
1265         data = expr['data']
1266         base = expr.get('base')
1267         tag_name = expr.get('discriminator')
1268         tag_member = None
1269         if tag_name:
1270             variants = [self._make_variant(key, value)
1271                         for (key, value) in data.iteritems()]
1272             members = []
1273         else:
1274             variants = [self._make_simple_variant(key, value, info)
1275                         for (key, value) in data.iteritems()]
1276             tag_member = self._make_implicit_tag(name, info, variants)
1277             members = [tag_member]
1278         self._def_entity(
1279             QAPISchemaObjectType(name, info, base, members,
1280                                  QAPISchemaObjectTypeVariants(tag_name,
1281                                                               tag_member,
1282                                                               variants)))
1283
1284     def _def_alternate_type(self, expr, info):
1285         name = expr['alternate']
1286         data = expr['data']
1287         variants = [self._make_variant(key, value)
1288                     for (key, value) in data.iteritems()]
1289         tag_member = self._make_implicit_tag(name, info, variants)
1290         self._def_entity(
1291             QAPISchemaAlternateType(name, info,
1292                                     QAPISchemaObjectTypeVariants(None,
1293                                                                  tag_member,
1294                                                                  variants)))
1295
1296     def _def_command(self, expr, info):
1297         name = expr['command']
1298         data = expr.get('data')
1299         rets = expr.get('returns')
1300         gen = expr.get('gen', True)
1301         success_response = expr.get('success-response', True)
1302         if isinstance(data, OrderedDict):
1303             data = self._make_implicit_object_type(
1304                 name, info, 'arg', self._make_members(data, info))
1305         if isinstance(rets, list):
1306             assert len(rets) == 1
1307             rets = self._make_array_type(rets[0], info)
1308         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1309                                            success_response))
1310
1311     def _def_event(self, expr, info):
1312         name = expr['event']
1313         data = expr.get('data')
1314         if isinstance(data, OrderedDict):
1315             data = self._make_implicit_object_type(
1316                 name, info, 'arg', self._make_members(data, info))
1317         self._def_entity(QAPISchemaEvent(name, info, data))
1318
1319     def _def_exprs(self):
1320         for expr_elem in self.exprs:
1321             expr = expr_elem['expr']
1322             info = expr_elem['info']
1323             if 'enum' in expr:
1324                 self._def_enum_type(expr, info)
1325             elif 'struct' in expr:
1326                 self._def_struct_type(expr, info)
1327             elif 'union' in expr:
1328                 self._def_union_type(expr, info)
1329             elif 'alternate' in expr:
1330                 self._def_alternate_type(expr, info)
1331             elif 'command' in expr:
1332                 self._def_command(expr, info)
1333             elif 'event' in expr:
1334                 self._def_event(expr, info)
1335             else:
1336                 assert False
1337
1338     def check(self):
1339         for ent in self._entity_dict.values():
1340             ent.check(self)
1341
1342     def visit(self, visitor):
1343         visitor.visit_begin(self)
1344         for (name, entity) in sorted(self._entity_dict.items()):
1345             if visitor.visit_needed(entity):
1346                 entity.visit(visitor)
1347         visitor.visit_end()
1348
1349
1350 #
1351 # Code generation helpers
1352 #
1353
1354 def camel_case(name):
1355     new_name = ''
1356     first = True
1357     for ch in name:
1358         if ch in ['_', '-']:
1359             first = True
1360         elif first:
1361             new_name += ch.upper()
1362             first = False
1363         else:
1364             new_name += ch.lower()
1365     return new_name
1366
1367
1368 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1369 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1370 # ENUM24_Name -> ENUM24_NAME
1371 def camel_to_upper(value):
1372     c_fun_str = c_name(value, False)
1373     if value.isupper():
1374         return c_fun_str
1375
1376     new_name = ''
1377     l = len(c_fun_str)
1378     for i in range(l):
1379         c = c_fun_str[i]
1380         # When c is upper and no "_" appears before, do more checks
1381         if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1382             if i < l - 1 and c_fun_str[i + 1].islower():
1383                 new_name += '_'
1384             elif c_fun_str[i - 1].isdigit():
1385                 new_name += '_'
1386         new_name += c
1387     return new_name.lstrip('_').upper()
1388
1389
1390 def c_enum_const(type_name, const_name, prefix=None):
1391     if prefix is not None:
1392         type_name = prefix
1393     return camel_to_upper(type_name + '_' + const_name)
1394
1395 c_name_trans = string.maketrans('.-', '__')
1396
1397
1398 # Map @name to a valid C identifier.
1399 # If @protect, avoid returning certain ticklish identifiers (like
1400 # C keywords) by prepending "q_".
1401 #
1402 # Used for converting 'name' from a 'name':'type' qapi definition
1403 # into a generated struct member, as well as converting type names
1404 # into substrings of a generated C function name.
1405 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1406 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1407 def c_name(name, protect=True):
1408     # ANSI X3J11/88-090, 3.1.1
1409     c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1410                      'default', 'do', 'double', 'else', 'enum', 'extern',
1411                      'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1412                      'return', 'short', 'signed', 'sizeof', 'static',
1413                      'struct', 'switch', 'typedef', 'union', 'unsigned',
1414                      'void', 'volatile', 'while'])
1415     # ISO/IEC 9899:1999, 6.4.1
1416     c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1417     # ISO/IEC 9899:2011, 6.4.1
1418     c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1419                      '_Noreturn', '_Static_assert', '_Thread_local'])
1420     # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1421     # excluding _.*
1422     gcc_words = set(['asm', 'typeof'])
1423     # C++ ISO/IEC 14882:2003 2.11
1424     cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1425                      'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1426                      'namespace', 'new', 'operator', 'private', 'protected',
1427                      'public', 'reinterpret_cast', 'static_cast', 'template',
1428                      'this', 'throw', 'true', 'try', 'typeid', 'typename',
1429                      'using', 'virtual', 'wchar_t',
1430                      # alternative representations
1431                      'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1432                      'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1433     # namespace pollution:
1434     polluted_words = set(['unix', 'errno'])
1435     if protect and (name in c89_words | c99_words | c11_words | gcc_words
1436                     | cpp_words | polluted_words):
1437         return "q_" + name
1438     return name.translate(c_name_trans)
1439
1440 eatspace = '\033EATSPACE.'
1441 pointer_suffix = ' *' + eatspace
1442
1443
1444 def genindent(count):
1445     ret = ""
1446     for _ in range(count):
1447         ret += " "
1448     return ret
1449
1450 indent_level = 0
1451
1452
1453 def push_indent(indent_amount=4):
1454     global indent_level
1455     indent_level += indent_amount
1456
1457
1458 def pop_indent(indent_amount=4):
1459     global indent_level
1460     indent_level -= indent_amount
1461
1462
1463 # Generate @code with @kwds interpolated.
1464 # Obey indent_level, and strip eatspace.
1465 def cgen(code, **kwds):
1466     raw = code % kwds
1467     if indent_level:
1468         indent = genindent(indent_level)
1469         # re.subn() lacks flags support before Python 2.7, use re.compile()
1470         raw = re.subn(re.compile("^.", re.MULTILINE),
1471                       indent + r'\g<0>', raw)
1472         raw = raw[0]
1473     return re.sub(re.escape(eatspace) + ' *', '', raw)
1474
1475
1476 def mcgen(code, **kwds):
1477     if code[0] == '\n':
1478         code = code[1:]
1479     return cgen(code, **kwds)
1480
1481
1482 def guardname(filename):
1483     return c_name(filename, protect=False).upper()
1484
1485
1486 def guardstart(name):
1487     return mcgen('''
1488
1489 #ifndef %(name)s
1490 #define %(name)s
1491
1492 ''',
1493                  name=guardname(name))
1494
1495
1496 def guardend(name):
1497     return mcgen('''
1498
1499 #endif /* %(name)s */
1500
1501 ''',
1502                  name=guardname(name))
1503
1504
1505 def gen_enum_lookup(name, values, prefix=None):
1506     ret = mcgen('''
1507
1508 const char *const %(c_name)s_lookup[] = {
1509 ''',
1510                 c_name=c_name(name))
1511     for value in values:
1512         index = c_enum_const(name, value, prefix)
1513         ret += mcgen('''
1514     [%(index)s] = "%(value)s",
1515 ''',
1516                      index=index, value=value)
1517
1518     max_index = c_enum_const(name, 'MAX', prefix)
1519     ret += mcgen('''
1520     [%(max_index)s] = NULL,
1521 };
1522 ''',
1523                  max_index=max_index)
1524     return ret
1525
1526
1527 def gen_enum(name, values, prefix=None):
1528     # append automatically generated _MAX value
1529     enum_values = values + ['MAX']
1530
1531     ret = mcgen('''
1532
1533 typedef enum %(c_name)s {
1534 ''',
1535                 c_name=c_name(name))
1536
1537     i = 0
1538     for value in enum_values:
1539         ret += mcgen('''
1540     %(c_enum)s = %(i)d,
1541 ''',
1542                      c_enum=c_enum_const(name, value, prefix),
1543                      i=i)
1544         i += 1
1545
1546     ret += mcgen('''
1547 } %(c_name)s;
1548 ''',
1549                  c_name=c_name(name))
1550
1551     ret += mcgen('''
1552
1553 extern const char *const %(c_name)s_lookup[];
1554 ''',
1555                  c_name=c_name(name))
1556     return ret
1557
1558
1559 def gen_params(arg_type, extra):
1560     if not arg_type:
1561         return extra
1562     assert not arg_type.variants
1563     ret = ''
1564     sep = ''
1565     for memb in arg_type.members:
1566         ret += sep
1567         sep = ', '
1568         if memb.optional:
1569             ret += 'bool has_%s, ' % c_name(memb.name)
1570         ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1571     if extra:
1572         ret += sep + extra
1573     return ret
1574
1575
1576 def gen_err_check(label='out', skiperr=False):
1577     if skiperr:
1578         return ''
1579     return mcgen('''
1580     if (err) {
1581         goto %(label)s;
1582     }
1583 ''',
1584                  label=label)
1585
1586
1587 def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
1588     ret = ''
1589     if skiperr:
1590         errparg = 'NULL'
1591     else:
1592         errparg = '&err'
1593
1594     for memb in members:
1595         if memb.optional:
1596             ret += mcgen('''
1597     visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1598 ''',
1599                          prefix=prefix, c_name=c_name(memb.name),
1600                          name=memb.name, errp=errparg)
1601             ret += gen_err_check(skiperr=skiperr)
1602             ret += mcgen('''
1603     if (%(prefix)shas_%(c_name)s) {
1604 ''',
1605                          prefix=prefix, c_name=c_name(memb.name))
1606             push_indent()
1607
1608         # Ugly: sometimes we need to cast away const
1609         if need_cast and memb.type.name == 'str':
1610             cast = '(char **)'
1611         else:
1612             cast = ''
1613
1614         ret += mcgen('''
1615     visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1616 ''',
1617                      c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1618                      c_name=c_name(memb.name), name=memb.name,
1619                      errp=errparg)
1620         ret += gen_err_check(skiperr=skiperr)
1621
1622         if memb.optional:
1623             pop_indent()
1624             ret += mcgen('''
1625     }
1626 ''')
1627     return ret
1628
1629
1630 #
1631 # Common command line parsing
1632 #
1633
1634
1635 def parse_command_line(extra_options="", extra_long_options=[]):
1636
1637     try:
1638         opts, args = getopt.gnu_getopt(sys.argv[1:],
1639                                        "chp:o:" + extra_options,
1640                                        ["source", "header", "prefix=",
1641                                         "output-dir="] + extra_long_options)
1642     except getopt.GetoptError, err:
1643         print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1644         sys.exit(1)
1645
1646     output_dir = ""
1647     prefix = ""
1648     do_c = False
1649     do_h = False
1650     extra_opts = []
1651
1652     for oa in opts:
1653         o, a = oa
1654         if o in ("-p", "--prefix"):
1655             match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1656             if match.end() != len(a):
1657                 print >>sys.stderr, \
1658                     "%s: 'funny character '%s' in argument of --prefix" \
1659                     % (sys.argv[0], a[match.end()])
1660                 sys.exit(1)
1661             prefix = a
1662         elif o in ("-o", "--output-dir"):
1663             output_dir = a + "/"
1664         elif o in ("-c", "--source"):
1665             do_c = True
1666         elif o in ("-h", "--header"):
1667             do_h = True
1668         else:
1669             extra_opts.append(oa)
1670
1671     if not do_c and not do_h:
1672         do_c = True
1673         do_h = True
1674
1675     if len(args) != 1:
1676         print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1677         sys.exit(1)
1678     fname = args[0]
1679
1680     return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1681
1682 #
1683 # Generate output files with boilerplate
1684 #
1685
1686
1687 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1688                 c_comment, h_comment):
1689     guard = guardname(prefix + h_file)
1690     c_file = output_dir + prefix + c_file
1691     h_file = output_dir + prefix + h_file
1692
1693     if output_dir:
1694         try:
1695             os.makedirs(output_dir)
1696         except os.error, e:
1697             if e.errno != errno.EEXIST:
1698                 raise
1699
1700     def maybe_open(really, name, opt):
1701         if really:
1702             return open(name, opt)
1703         else:
1704             import StringIO
1705             return StringIO.StringIO()
1706
1707     fdef = maybe_open(do_c, c_file, 'w')
1708     fdecl = maybe_open(do_h, h_file, 'w')
1709
1710     fdef.write(mcgen('''
1711 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1712 %(comment)s
1713 ''',
1714                      comment=c_comment))
1715
1716     fdecl.write(mcgen('''
1717 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1718 %(comment)s
1719 #ifndef %(guard)s
1720 #define %(guard)s
1721
1722 ''',
1723                       comment=h_comment, guard=guard))
1724
1725     return (fdef, fdecl)
1726
1727
1728 def close_output(fdef, fdecl):
1729     fdecl.write('''
1730 #endif
1731 ''')
1732     fdecl.close()
1733     fdef.close()
This page took 0.125912 seconds and 4 git commands to generate.