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