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