]> Git Repo - qemu.git/blob - scripts/qapi.py
qapi: Change munging of CamelCase enum values
[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 # Names must be letters, numbers, -, and _.  They must start with letter,
357 # except for downstream extensions which must start with __RFQDN_.
358 # Dots are only valid in the downstream extension prefix.
359 valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
360                         '[a-zA-Z][a-zA-Z0-9_-]*$')
361
362
363 def check_name(expr_info, source, name, allow_optional=False,
364                enum_member=False):
365     global valid_name
366     membername = name
367
368     if not isinstance(name, str):
369         raise QAPIExprError(expr_info,
370                             "%s requires a string name" % source)
371     if name.startswith('*'):
372         membername = name[1:]
373         if not allow_optional:
374             raise QAPIExprError(expr_info,
375                                 "%s does not allow optional name '%s'"
376                                 % (source, name))
377     # Enum members can start with a digit, because the generated C
378     # code always prefixes it with the enum name
379     if enum_member and membername[0].isdigit():
380         membername = 'D' + membername
381     # Reserve the entire 'q_' namespace for c_name()
382     if not valid_name.match(membername) or \
383        c_name(membername, False).startswith('q_'):
384         raise QAPIExprError(expr_info,
385                             "%s uses invalid name '%s'" % (source, name))
386
387
388 def add_name(name, info, meta, implicit=False):
389     global all_names
390     check_name(info, "'%s'" % meta, name)
391     # FIXME should reject names that differ only in '_' vs. '.'
392     # vs. '-', because they're liable to clash in generated C.
393     if name in all_names:
394         raise QAPIExprError(info,
395                             "%s '%s' is already defined"
396                             % (all_names[name], name))
397     if not implicit and (name.endswith('Kind') or name.endswith('List')):
398         raise QAPIExprError(info,
399                             "%s '%s' should not end in '%s'"
400                             % (meta, name, name[-4:]))
401     all_names[name] = meta
402
403
404 def add_struct(definition, info):
405     global struct_types
406     name = definition['struct']
407     add_name(name, info, 'struct')
408     struct_types.append(definition)
409
410
411 def find_struct(name):
412     global struct_types
413     for struct in struct_types:
414         if struct['struct'] == name:
415             return struct
416     return None
417
418
419 def add_union(definition, info):
420     global union_types
421     name = definition['union']
422     add_name(name, info, 'union')
423     union_types.append(definition)
424
425
426 def find_union(name):
427     global union_types
428     for union in union_types:
429         if union['union'] == name:
430             return union
431     return None
432
433
434 def add_enum(name, info, enum_values=None, implicit=False):
435     global enum_types
436     add_name(name, info, 'enum', implicit)
437     enum_types.append({"enum_name": name, "enum_values": enum_values})
438
439
440 def find_enum(name):
441     global enum_types
442     for enum in enum_types:
443         if enum['enum_name'] == name:
444             return enum
445     return None
446
447
448 def is_enum(name):
449     return find_enum(name) is not None
450
451
452 def check_type(expr_info, source, value, allow_array=False,
453                allow_dict=False, allow_optional=False,
454                allow_metas=[]):
455     global all_names
456
457     if value is None:
458         return
459
460     # Check if array type for value is okay
461     if isinstance(value, list):
462         if not allow_array:
463             raise QAPIExprError(expr_info,
464                                 "%s cannot be an array" % source)
465         if len(value) != 1 or not isinstance(value[0], str):
466             raise QAPIExprError(expr_info,
467                                 "%s: array type must contain single type name"
468                                 % source)
469         value = value[0]
470
471     # Check if type name for value is okay
472     if isinstance(value, str):
473         if value not in all_names:
474             raise QAPIExprError(expr_info,
475                                 "%s uses unknown type '%s'"
476                                 % (source, value))
477         if not all_names[value] in allow_metas:
478             raise QAPIExprError(expr_info,
479                                 "%s cannot use %s type '%s'"
480                                 % (source, all_names[value], value))
481         return
482
483     if not allow_dict:
484         raise QAPIExprError(expr_info,
485                             "%s should be a type name" % source)
486
487     if not isinstance(value, OrderedDict):
488         raise QAPIExprError(expr_info,
489                             "%s should be a dictionary or type name" % source)
490
491     # value is a dictionary, check that each member is okay
492     for (key, arg) in value.items():
493         check_name(expr_info, "Member of %s" % source, key,
494                    allow_optional=allow_optional)
495         if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
496             raise QAPIExprError(expr_info,
497                                 "Member of %s uses reserved name '%s'"
498                                 % (source, key))
499         # Todo: allow dictionaries to represent default values of
500         # an optional argument.
501         check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
502                    allow_array=True,
503                    allow_metas=['built-in', 'union', 'alternate', 'struct',
504                                 'enum'])
505
506
507 def check_member_clash(expr_info, base_name, data, source=""):
508     base = find_struct(base_name)
509     assert base
510     base_members = base['data']
511     for key in data.keys():
512         if key.startswith('*'):
513             key = key[1:]
514         if key in base_members or "*" + key in base_members:
515             raise QAPIExprError(expr_info,
516                                 "Member name '%s'%s clashes with base '%s'"
517                                 % (key, source, base_name))
518     if base.get('base'):
519         check_member_clash(expr_info, base['base'], data, source)
520
521
522 def check_command(expr, expr_info):
523     name = expr['command']
524
525     check_type(expr_info, "'data' for command '%s'" % name,
526                expr.get('data'), allow_dict=True, allow_optional=True,
527                allow_metas=['struct'])
528     returns_meta = ['union', 'struct']
529     if name in returns_whitelist:
530         returns_meta += ['built-in', 'alternate', 'enum']
531     check_type(expr_info, "'returns' for command '%s'" % name,
532                expr.get('returns'), allow_array=True,
533                allow_optional=True, allow_metas=returns_meta)
534
535
536 def check_event(expr, expr_info):
537     global events
538     name = expr['event']
539
540     events.append(name)
541     check_type(expr_info, "'data' for event '%s'" % name,
542                expr.get('data'), allow_dict=True, allow_optional=True,
543                allow_metas=['struct'])
544
545
546 def check_union(expr, expr_info):
547     name = expr['union']
548     base = expr.get('base')
549     discriminator = expr.get('discriminator')
550     members = expr['data']
551     values = {}
552
553     # Two types of unions, determined by discriminator.
554
555     # With no discriminator it is a simple union.
556     if discriminator is None:
557         enum_define = None
558         allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
559         if base is not None:
560             raise QAPIExprError(expr_info,
561                                 "Simple union '%s' must not have a base"
562                                 % name)
563
564     # Else, it's a flat union.
565     else:
566         # The object must have a string member 'base'.
567         check_type(expr_info, "'base' for union '%s'" % name,
568                    base, allow_metas=['struct'])
569         if not base:
570             raise QAPIExprError(expr_info,
571                                 "Flat union '%s' must have a base"
572                                 % name)
573         base_fields = find_base_fields(base)
574         assert base_fields
575
576         # The value of member 'discriminator' must name a non-optional
577         # member of the base struct.
578         check_name(expr_info, "Discriminator of flat union '%s'" % name,
579                    discriminator)
580         discriminator_type = base_fields.get(discriminator)
581         if not discriminator_type:
582             raise QAPIExprError(expr_info,
583                                 "Discriminator '%s' is not a member of base "
584                                 "struct '%s'"
585                                 % (discriminator, base))
586         enum_define = find_enum(discriminator_type)
587         allow_metas = ['struct']
588         # Do not allow string discriminator
589         if not enum_define:
590             raise QAPIExprError(expr_info,
591                                 "Discriminator '%s' must be of enumeration "
592                                 "type" % discriminator)
593
594     # Check every branch
595     for (key, value) in members.items():
596         check_name(expr_info, "Member of union '%s'" % name, key)
597
598         # Each value must name a known type; furthermore, in flat unions,
599         # branches must be a struct with no overlapping member names
600         check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
601                    value, allow_array=not base, allow_metas=allow_metas)
602         if base:
603             branch_struct = find_struct(value)
604             assert branch_struct
605             check_member_clash(expr_info, base, branch_struct['data'],
606                                " of branch '%s'" % key)
607
608         # If the discriminator names an enum type, then all members
609         # of 'data' must also be members of the enum type.
610         if enum_define:
611             if key not in enum_define['enum_values']:
612                 raise QAPIExprError(expr_info,
613                                     "Discriminator value '%s' is not found in "
614                                     "enum '%s'" %
615                                     (key, 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 = {}
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 = {}
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.endswith('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         # struct has local_members, optional base, and no variants
954         # flat union has base, variants, and no local_members
955         # simple union has local_members, variants, and no base
956         QAPISchemaType.__init__(self, name, info)
957         assert base is None or isinstance(base, str)
958         for m in local_members:
959             assert isinstance(m, QAPISchemaObjectTypeMember)
960             m.set_owner(name)
961         if variants is not None:
962             assert isinstance(variants, QAPISchemaObjectTypeVariants)
963             variants.set_owner(name)
964         self._base_name = base
965         self.base = None
966         self.local_members = local_members
967         self.variants = variants
968         self.members = None
969
970     def check(self, schema):
971         assert self.members is not False        # not running in cycles
972         if self.members:
973             return
974         self.members = False                    # mark as being checked
975         seen = OrderedDict()
976         if self._base_name:
977             self.base = schema.lookup_type(self._base_name)
978             assert isinstance(self.base, QAPISchemaObjectType)
979             self.base.check(schema)
980             self.base.check_clash(schema, self.info, seen)
981         for m in self.local_members:
982             m.check(schema)
983             m.check_clash(self.info, seen)
984         self.members = seen.values()
985         if self.variants:
986             self.variants.check(schema, seen)
987             assert self.variants.tag_member in self.members
988             self.variants.check_clash(schema, self.info, seen)
989
990     # Check that the members of this type do not cause duplicate JSON fields,
991     # and update seen to track the members seen so far. Report any errors
992     # on behalf of info, which is not necessarily self.info
993     def check_clash(self, schema, info, seen):
994         assert not self.variants       # not implemented
995         for m in self.members:
996             m.check_clash(info, seen)
997
998     def is_implicit(self):
999         # See QAPISchema._make_implicit_object_type()
1000         return self.name[0] == ':'
1001
1002     def c_name(self):
1003         assert not self.is_implicit()
1004         return QAPISchemaType.c_name(self)
1005
1006     def c_type(self, is_param=False):
1007         assert not self.is_implicit()
1008         return QAPISchemaType.c_type(self)
1009
1010     def json_type(self):
1011         return 'object'
1012
1013     def visit(self, visitor):
1014         visitor.visit_object_type(self.name, self.info,
1015                                   self.base, self.local_members, self.variants)
1016         visitor.visit_object_type_flat(self.name, self.info,
1017                                        self.members, self.variants)
1018
1019
1020 class QAPISchemaObjectTypeMember(object):
1021     role = 'member'
1022
1023     def __init__(self, name, typ, optional):
1024         assert isinstance(name, str)
1025         assert isinstance(typ, str)
1026         assert isinstance(optional, bool)
1027         self.name = name
1028         self._type_name = typ
1029         self.type = None
1030         self.optional = optional
1031         self.owner = None
1032
1033     def set_owner(self, name):
1034         assert not self.owner
1035         self.owner = name
1036
1037     def check(self, schema):
1038         assert self.owner
1039         self.type = schema.lookup_type(self._type_name)
1040         assert self.type
1041
1042     def check_clash(self, info, seen):
1043         cname = c_name(self.name)
1044         if cname in seen:
1045             raise QAPIExprError(info,
1046                                 "%s collides with %s"
1047                                 % (self.describe(), seen[cname].describe()))
1048         seen[cname] = self
1049
1050     def _pretty_owner(self):
1051         owner = self.owner
1052         if owner.startswith(':obj-'):
1053             # See QAPISchema._make_implicit_object_type() - reverse the
1054             # mapping there to create a nice human-readable description
1055             owner = owner[5:]
1056             if owner.endswith('-arg'):
1057                 return '(parameter of %s)' % owner[:-4]
1058             else:
1059                 assert owner.endswith('-wrapper')
1060                 # Unreachable and not implemented
1061                 assert False
1062         return '(%s of %s)' % (self.role, owner)
1063
1064     def describe(self):
1065         return "'%s' %s" % (self.name, self._pretty_owner())
1066
1067
1068 class QAPISchemaObjectTypeVariants(object):
1069     def __init__(self, tag_name, tag_member, variants):
1070         # Flat unions pass tag_name but not tag_member.
1071         # Simple unions and alternates pass tag_member but not tag_name.
1072         # After check(), tag_member is always set, and tag_name remains
1073         # a reliable witness of being used by a flat union.
1074         assert bool(tag_member) != bool(tag_name)
1075         assert (isinstance(tag_name, str) or
1076                 isinstance(tag_member, QAPISchemaObjectTypeMember))
1077         for v in variants:
1078             assert isinstance(v, QAPISchemaObjectTypeVariant)
1079         self.tag_name = tag_name
1080         self.tag_member = tag_member
1081         self.variants = variants
1082
1083     def set_owner(self, name):
1084         for v in self.variants:
1085             v.set_owner(name)
1086
1087     def check(self, schema, seen):
1088         if not self.tag_member:    # flat union
1089             self.tag_member = seen[c_name(self.tag_name)]
1090             assert self.tag_name == self.tag_member.name
1091         assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1092         for v in self.variants:
1093             v.check(schema)
1094             assert v.name in self.tag_member.type.values
1095             if isinstance(v.type, QAPISchemaObjectType):
1096                 v.type.check(schema)
1097
1098     def check_clash(self, schema, info, seen):
1099         for v in self.variants:
1100             # Reset seen map for each variant, since qapi names from one
1101             # branch do not affect another branch
1102             assert isinstance(v.type, QAPISchemaObjectType)
1103             v.type.check_clash(schema, info, dict(seen))
1104
1105
1106 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1107     role = 'branch'
1108
1109     def __init__(self, name, typ):
1110         QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1111
1112     # This function exists to support ugly simple union special cases
1113     # TODO get rid of them, and drop the function
1114     def simple_union_type(self):
1115         if (self.type.is_implicit() and
1116                 isinstance(self.type, QAPISchemaObjectType)):
1117             assert len(self.type.members) == 1
1118             assert not self.type.variants
1119             return self.type.members[0].type
1120         return None
1121
1122
1123 class QAPISchemaAlternateType(QAPISchemaType):
1124     def __init__(self, name, info, variants):
1125         QAPISchemaType.__init__(self, name, info)
1126         assert isinstance(variants, QAPISchemaObjectTypeVariants)
1127         assert not variants.tag_name
1128         variants.set_owner(name)
1129         variants.tag_member.set_owner(self.name)
1130         self.variants = variants
1131
1132     def check(self, schema):
1133         self.variants.tag_member.check(schema)
1134         # Not calling self.variants.check_clash(), because there's nothing
1135         # to clash with
1136         self.variants.check(schema, {})
1137
1138     def json_type(self):
1139         return 'value'
1140
1141     def visit(self, visitor):
1142         visitor.visit_alternate_type(self.name, self.info, self.variants)
1143
1144
1145 class QAPISchemaCommand(QAPISchemaEntity):
1146     def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1147         QAPISchemaEntity.__init__(self, name, info)
1148         assert not arg_type or isinstance(arg_type, str)
1149         assert not ret_type or isinstance(ret_type, str)
1150         self._arg_type_name = arg_type
1151         self.arg_type = None
1152         self._ret_type_name = ret_type
1153         self.ret_type = None
1154         self.gen = gen
1155         self.success_response = success_response
1156
1157     def check(self, schema):
1158         if self._arg_type_name:
1159             self.arg_type = schema.lookup_type(self._arg_type_name)
1160             assert isinstance(self.arg_type, QAPISchemaObjectType)
1161             assert not self.arg_type.variants   # not implemented
1162         if self._ret_type_name:
1163             self.ret_type = schema.lookup_type(self._ret_type_name)
1164             assert isinstance(self.ret_type, QAPISchemaType)
1165
1166     def visit(self, visitor):
1167         visitor.visit_command(self.name, self.info,
1168                               self.arg_type, self.ret_type,
1169                               self.gen, self.success_response)
1170
1171
1172 class QAPISchemaEvent(QAPISchemaEntity):
1173     def __init__(self, name, info, arg_type):
1174         QAPISchemaEntity.__init__(self, name, info)
1175         assert not arg_type or isinstance(arg_type, str)
1176         self._arg_type_name = arg_type
1177         self.arg_type = None
1178
1179     def check(self, schema):
1180         if self._arg_type_name:
1181             self.arg_type = schema.lookup_type(self._arg_type_name)
1182             assert isinstance(self.arg_type, QAPISchemaObjectType)
1183             assert not self.arg_type.variants   # not implemented
1184
1185     def visit(self, visitor):
1186         visitor.visit_event(self.name, self.info, self.arg_type)
1187
1188
1189 class QAPISchema(object):
1190     def __init__(self, fname):
1191         try:
1192             self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1193             self._entity_dict = {}
1194             self._predefining = True
1195             self._def_predefineds()
1196             self._predefining = False
1197             self._def_exprs()
1198             self.check()
1199         except (QAPISchemaError, QAPIExprError), err:
1200             print >>sys.stderr, err
1201             exit(1)
1202
1203     def _def_entity(self, ent):
1204         # Only the predefined types are allowed to not have info
1205         assert ent.info or self._predefining
1206         assert ent.name not in self._entity_dict
1207         self._entity_dict[ent.name] = ent
1208
1209     def lookup_entity(self, name, typ=None):
1210         ent = self._entity_dict.get(name)
1211         if typ and not isinstance(ent, typ):
1212             return None
1213         return ent
1214
1215     def lookup_type(self, name):
1216         return self.lookup_entity(name, QAPISchemaType)
1217
1218     def _def_builtin_type(self, name, json_type, c_type, c_null):
1219         self._def_entity(QAPISchemaBuiltinType(name, json_type,
1220                                                c_type, c_null))
1221         # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1222         # qapi-types.h from a single .c, all arrays of builtins must be
1223         # declared in the first file whether or not they are used.  Nicer
1224         # would be to use lazy instantiation, while figuring out how to
1225         # avoid compilation issues with multiple qapi-types.h.
1226         self._make_array_type(name, None)
1227
1228     def _def_predefineds(self):
1229         for t in [('str',    'string',  'char' + pointer_suffix, 'NULL'),
1230                   ('number', 'number',  'double',   '0'),
1231                   ('int',    'int',     'int64_t',  '0'),
1232                   ('int8',   'int',     'int8_t',   '0'),
1233                   ('int16',  'int',     'int16_t',  '0'),
1234                   ('int32',  'int',     'int32_t',  '0'),
1235                   ('int64',  'int',     'int64_t',  '0'),
1236                   ('uint8',  'int',     'uint8_t',  '0'),
1237                   ('uint16', 'int',     'uint16_t', '0'),
1238                   ('uint32', 'int',     'uint32_t', '0'),
1239                   ('uint64', 'int',     'uint64_t', '0'),
1240                   ('size',   'int',     'uint64_t', '0'),
1241                   ('bool',   'boolean', 'bool',     'false'),
1242                   ('any',    'value',   'QObject' + pointer_suffix, 'NULL')]:
1243             self._def_builtin_type(*t)
1244         self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1245                                                           [], None)
1246         self._def_entity(self.the_empty_object_type)
1247
1248     def _make_implicit_enum_type(self, name, info, values):
1249         name = name + 'Kind'   # Use namespace reserved by add_name()
1250         self._def_entity(QAPISchemaEnumType(name, info, values, None))
1251         return name
1252
1253     def _make_array_type(self, element_type, info):
1254         name = element_type + 'List'   # Use namespace reserved by add_name()
1255         if not self.lookup_type(name):
1256             self._def_entity(QAPISchemaArrayType(name, info, element_type))
1257         return name
1258
1259     def _make_implicit_object_type(self, name, info, role, members):
1260         if not members:
1261             return None
1262         # See also QAPISchemaObjectTypeMember._pretty_owner()
1263         name = ':obj-%s-%s' % (name, role)
1264         if not self.lookup_entity(name, QAPISchemaObjectType):
1265             self._def_entity(QAPISchemaObjectType(name, info, None,
1266                                                   members, None))
1267         return name
1268
1269     def _def_enum_type(self, expr, info):
1270         name = expr['enum']
1271         data = expr['data']
1272         prefix = expr.get('prefix')
1273         self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1274
1275     def _make_member(self, name, typ, info):
1276         optional = False
1277         if name.startswith('*'):
1278             name = name[1:]
1279             optional = True
1280         if isinstance(typ, list):
1281             assert len(typ) == 1
1282             typ = self._make_array_type(typ[0], info)
1283         return QAPISchemaObjectTypeMember(name, typ, optional)
1284
1285     def _make_members(self, data, info):
1286         return [self._make_member(key, value, info)
1287                 for (key, value) in data.iteritems()]
1288
1289     def _def_struct_type(self, expr, info):
1290         name = expr['struct']
1291         base = expr.get('base')
1292         data = expr['data']
1293         self._def_entity(QAPISchemaObjectType(name, info, base,
1294                                               self._make_members(data, info),
1295                                               None))
1296
1297     def _make_variant(self, case, typ):
1298         return QAPISchemaObjectTypeVariant(case, typ)
1299
1300     def _make_simple_variant(self, case, typ, info):
1301         if isinstance(typ, list):
1302             assert len(typ) == 1
1303             typ = self._make_array_type(typ[0], info)
1304         typ = self._make_implicit_object_type(
1305             typ, info, 'wrapper', [self._make_member('data', typ, info)])
1306         return QAPISchemaObjectTypeVariant(case, typ)
1307
1308     def _make_implicit_tag(self, type_name, info, variants):
1309         typ = self._make_implicit_enum_type(type_name, info,
1310                                             [v.name for v in variants])
1311         return QAPISchemaObjectTypeMember('type', typ, False)
1312
1313     def _def_union_type(self, expr, info):
1314         name = expr['union']
1315         data = expr['data']
1316         base = expr.get('base')
1317         tag_name = expr.get('discriminator')
1318         tag_member = None
1319         if tag_name:
1320             variants = [self._make_variant(key, value)
1321                         for (key, value) in data.iteritems()]
1322             members = []
1323         else:
1324             variants = [self._make_simple_variant(key, value, info)
1325                         for (key, value) in data.iteritems()]
1326             tag_member = self._make_implicit_tag(name, info, variants)
1327             members = [tag_member]
1328         self._def_entity(
1329             QAPISchemaObjectType(name, info, base, members,
1330                                  QAPISchemaObjectTypeVariants(tag_name,
1331                                                               tag_member,
1332                                                               variants)))
1333
1334     def _def_alternate_type(self, expr, info):
1335         name = expr['alternate']
1336         data = expr['data']
1337         variants = [self._make_variant(key, value)
1338                     for (key, value) in data.iteritems()]
1339         tag_member = self._make_implicit_tag(name, info, variants)
1340         self._def_entity(
1341             QAPISchemaAlternateType(name, info,
1342                                     QAPISchemaObjectTypeVariants(None,
1343                                                                  tag_member,
1344                                                                  variants)))
1345
1346     def _def_command(self, expr, info):
1347         name = expr['command']
1348         data = expr.get('data')
1349         rets = expr.get('returns')
1350         gen = expr.get('gen', True)
1351         success_response = expr.get('success-response', True)
1352         if isinstance(data, OrderedDict):
1353             data = self._make_implicit_object_type(
1354                 name, info, 'arg', self._make_members(data, info))
1355         if isinstance(rets, list):
1356             assert len(rets) == 1
1357             rets = self._make_array_type(rets[0], info)
1358         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1359                                            success_response))
1360
1361     def _def_event(self, expr, info):
1362         name = expr['event']
1363         data = expr.get('data')
1364         if isinstance(data, OrderedDict):
1365             data = self._make_implicit_object_type(
1366                 name, info, 'arg', self._make_members(data, info))
1367         self._def_entity(QAPISchemaEvent(name, info, data))
1368
1369     def _def_exprs(self):
1370         for expr_elem in self.exprs:
1371             expr = expr_elem['expr']
1372             info = expr_elem['info']
1373             if 'enum' in expr:
1374                 self._def_enum_type(expr, info)
1375             elif 'struct' in expr:
1376                 self._def_struct_type(expr, info)
1377             elif 'union' in expr:
1378                 self._def_union_type(expr, info)
1379             elif 'alternate' in expr:
1380                 self._def_alternate_type(expr, info)
1381             elif 'command' in expr:
1382                 self._def_command(expr, info)
1383             elif 'event' in expr:
1384                 self._def_event(expr, info)
1385             else:
1386                 assert False
1387
1388     def check(self):
1389         for ent in self._entity_dict.values():
1390             ent.check(self)
1391
1392     def visit(self, visitor):
1393         visitor.visit_begin(self)
1394         for (name, entity) in sorted(self._entity_dict.items()):
1395             if visitor.visit_needed(entity):
1396                 entity.visit(visitor)
1397         visitor.visit_end()
1398
1399
1400 #
1401 # Code generation helpers
1402 #
1403
1404 def camel_case(name):
1405     new_name = ''
1406     first = True
1407     for ch in name:
1408         if ch in ['_', '-']:
1409             first = True
1410         elif first:
1411             new_name += ch.upper()
1412             first = False
1413         else:
1414             new_name += ch.lower()
1415     return new_name
1416
1417
1418 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1419 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1420 # ENUM24_Name -> ENUM24_NAME
1421 def camel_to_upper(value):
1422     c_fun_str = c_name(value, False)
1423     if value.isupper():
1424         return c_fun_str
1425
1426     new_name = ''
1427     l = len(c_fun_str)
1428     for i in range(l):
1429         c = c_fun_str[i]
1430         # When c is upper and no "_" appears before, do more checks
1431         if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1432             if i < l - 1 and c_fun_str[i + 1].islower():
1433                 new_name += '_'
1434             elif c_fun_str[i - 1].isdigit():
1435                 new_name += '_'
1436         new_name += c
1437     return new_name.lstrip('_').upper()
1438
1439
1440 def c_enum_const(type_name, const_name, prefix=None):
1441     if prefix is not None:
1442         type_name = prefix
1443     return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1444
1445 c_name_trans = string.maketrans('.-', '__')
1446
1447
1448 # Map @name to a valid C identifier.
1449 # If @protect, avoid returning certain ticklish identifiers (like
1450 # C keywords) by prepending "q_".
1451 #
1452 # Used for converting 'name' from a 'name':'type' qapi definition
1453 # into a generated struct member, as well as converting type names
1454 # into substrings of a generated C function name.
1455 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1456 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1457 def c_name(name, protect=True):
1458     # ANSI X3J11/88-090, 3.1.1
1459     c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1460                      'default', 'do', 'double', 'else', 'enum', 'extern',
1461                      'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1462                      'return', 'short', 'signed', 'sizeof', 'static',
1463                      'struct', 'switch', 'typedef', 'union', 'unsigned',
1464                      'void', 'volatile', 'while'])
1465     # ISO/IEC 9899:1999, 6.4.1
1466     c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1467     # ISO/IEC 9899:2011, 6.4.1
1468     c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1469                      '_Noreturn', '_Static_assert', '_Thread_local'])
1470     # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1471     # excluding _.*
1472     gcc_words = set(['asm', 'typeof'])
1473     # C++ ISO/IEC 14882:2003 2.11
1474     cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1475                      'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1476                      'namespace', 'new', 'operator', 'private', 'protected',
1477                      'public', 'reinterpret_cast', 'static_cast', 'template',
1478                      'this', 'throw', 'true', 'try', 'typeid', 'typename',
1479                      'using', 'virtual', 'wchar_t',
1480                      # alternative representations
1481                      'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1482                      'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1483     # namespace pollution:
1484     polluted_words = set(['unix', 'errno'])
1485     name = name.translate(c_name_trans)
1486     if protect and (name in c89_words | c99_words | c11_words | gcc_words
1487                     | cpp_words | polluted_words):
1488         return "q_" + name
1489     return name
1490
1491 eatspace = '\033EATSPACE.'
1492 pointer_suffix = ' *' + eatspace
1493
1494
1495 def genindent(count):
1496     ret = ""
1497     for _ in range(count):
1498         ret += " "
1499     return ret
1500
1501 indent_level = 0
1502
1503
1504 def push_indent(indent_amount=4):
1505     global indent_level
1506     indent_level += indent_amount
1507
1508
1509 def pop_indent(indent_amount=4):
1510     global indent_level
1511     indent_level -= indent_amount
1512
1513
1514 # Generate @code with @kwds interpolated.
1515 # Obey indent_level, and strip eatspace.
1516 def cgen(code, **kwds):
1517     raw = code % kwds
1518     if indent_level:
1519         indent = genindent(indent_level)
1520         # re.subn() lacks flags support before Python 2.7, use re.compile()
1521         raw = re.subn(re.compile("^.", re.MULTILINE),
1522                       indent + r'\g<0>', raw)
1523         raw = raw[0]
1524     return re.sub(re.escape(eatspace) + ' *', '', raw)
1525
1526
1527 def mcgen(code, **kwds):
1528     if code[0] == '\n':
1529         code = code[1:]
1530     return cgen(code, **kwds)
1531
1532
1533 def guardname(filename):
1534     return c_name(filename, protect=False).upper()
1535
1536
1537 def guardstart(name):
1538     return mcgen('''
1539
1540 #ifndef %(name)s
1541 #define %(name)s
1542
1543 ''',
1544                  name=guardname(name))
1545
1546
1547 def guardend(name):
1548     return mcgen('''
1549
1550 #endif /* %(name)s */
1551
1552 ''',
1553                  name=guardname(name))
1554
1555
1556 def gen_enum_lookup(name, values, prefix=None):
1557     ret = mcgen('''
1558
1559 const char *const %(c_name)s_lookup[] = {
1560 ''',
1561                 c_name=c_name(name))
1562     for value in values:
1563         index = c_enum_const(name, value, prefix)
1564         ret += mcgen('''
1565     [%(index)s] = "%(value)s",
1566 ''',
1567                      index=index, value=value)
1568
1569     max_index = c_enum_const(name, '_MAX', prefix)
1570     ret += mcgen('''
1571     [%(max_index)s] = NULL,
1572 };
1573 ''',
1574                  max_index=max_index)
1575     return ret
1576
1577
1578 def gen_enum(name, values, prefix=None):
1579     # append automatically generated _MAX value
1580     enum_values = values + ['_MAX']
1581
1582     ret = mcgen('''
1583
1584 typedef enum %(c_name)s {
1585 ''',
1586                 c_name=c_name(name))
1587
1588     i = 0
1589     for value in enum_values:
1590         ret += mcgen('''
1591     %(c_enum)s = %(i)d,
1592 ''',
1593                      c_enum=c_enum_const(name, value, prefix),
1594                      i=i)
1595         i += 1
1596
1597     ret += mcgen('''
1598 } %(c_name)s;
1599 ''',
1600                  c_name=c_name(name))
1601
1602     ret += mcgen('''
1603
1604 extern const char *const %(c_name)s_lookup[];
1605 ''',
1606                  c_name=c_name(name))
1607     return ret
1608
1609
1610 def gen_params(arg_type, extra):
1611     if not arg_type:
1612         return extra
1613     assert not arg_type.variants
1614     ret = ''
1615     sep = ''
1616     for memb in arg_type.members:
1617         ret += sep
1618         sep = ', '
1619         if memb.optional:
1620             ret += 'bool has_%s, ' % c_name(memb.name)
1621         ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1622     if extra:
1623         ret += sep + extra
1624     return ret
1625
1626
1627 def gen_err_check(label='out', skiperr=False):
1628     if skiperr:
1629         return ''
1630     return mcgen('''
1631     if (err) {
1632         goto %(label)s;
1633     }
1634 ''',
1635                  label=label)
1636
1637
1638 def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
1639     ret = ''
1640     if skiperr:
1641         errparg = 'NULL'
1642     else:
1643         errparg = '&err'
1644
1645     for memb in members:
1646         if memb.optional:
1647             ret += mcgen('''
1648     visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1649 ''',
1650                          prefix=prefix, c_name=c_name(memb.name),
1651                          name=memb.name, errp=errparg)
1652             ret += gen_err_check(skiperr=skiperr)
1653             ret += mcgen('''
1654     if (%(prefix)shas_%(c_name)s) {
1655 ''',
1656                          prefix=prefix, c_name=c_name(memb.name))
1657             push_indent()
1658
1659         # Ugly: sometimes we need to cast away const
1660         if need_cast and memb.type.name == 'str':
1661             cast = '(char **)'
1662         else:
1663             cast = ''
1664
1665         ret += mcgen('''
1666     visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1667 ''',
1668                      c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1669                      c_name=c_name(memb.name), name=memb.name,
1670                      errp=errparg)
1671         ret += gen_err_check(skiperr=skiperr)
1672
1673         if memb.optional:
1674             pop_indent()
1675             ret += mcgen('''
1676     }
1677 ''')
1678     return ret
1679
1680
1681 #
1682 # Common command line parsing
1683 #
1684
1685
1686 def parse_command_line(extra_options="", extra_long_options=[]):
1687
1688     try:
1689         opts, args = getopt.gnu_getopt(sys.argv[1:],
1690                                        "chp:o:" + extra_options,
1691                                        ["source", "header", "prefix=",
1692                                         "output-dir="] + extra_long_options)
1693     except getopt.GetoptError, err:
1694         print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1695         sys.exit(1)
1696
1697     output_dir = ""
1698     prefix = ""
1699     do_c = False
1700     do_h = False
1701     extra_opts = []
1702
1703     for oa in opts:
1704         o, a = oa
1705         if o in ("-p", "--prefix"):
1706             match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1707             if match.end() != len(a):
1708                 print >>sys.stderr, \
1709                     "%s: 'funny character '%s' in argument of --prefix" \
1710                     % (sys.argv[0], a[match.end()])
1711                 sys.exit(1)
1712             prefix = a
1713         elif o in ("-o", "--output-dir"):
1714             output_dir = a + "/"
1715         elif o in ("-c", "--source"):
1716             do_c = True
1717         elif o in ("-h", "--header"):
1718             do_h = True
1719         else:
1720             extra_opts.append(oa)
1721
1722     if not do_c and not do_h:
1723         do_c = True
1724         do_h = True
1725
1726     if len(args) != 1:
1727         print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1728         sys.exit(1)
1729     fname = args[0]
1730
1731     return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1732
1733 #
1734 # Generate output files with boilerplate
1735 #
1736
1737
1738 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1739                 c_comment, h_comment):
1740     guard = guardname(prefix + h_file)
1741     c_file = output_dir + prefix + c_file
1742     h_file = output_dir + prefix + h_file
1743
1744     if output_dir:
1745         try:
1746             os.makedirs(output_dir)
1747         except os.error, e:
1748             if e.errno != errno.EEXIST:
1749                 raise
1750
1751     def maybe_open(really, name, opt):
1752         if really:
1753             return open(name, opt)
1754         else:
1755             import StringIO
1756             return StringIO.StringIO()
1757
1758     fdef = maybe_open(do_c, c_file, 'w')
1759     fdecl = maybe_open(do_h, h_file, 'w')
1760
1761     fdef.write(mcgen('''
1762 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1763 %(comment)s
1764 ''',
1765                      comment=c_comment))
1766
1767     fdecl.write(mcgen('''
1768 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1769 %(comment)s
1770 #ifndef %(guard)s
1771 #define %(guard)s
1772
1773 ''',
1774                       comment=h_comment, guard=guard))
1775
1776     return (fdef, fdecl)
1777
1778
1779 def close_output(fdef, fdecl):
1780     fdecl.write('''
1781 #endif
1782 ''')
1783     fdecl.close()
1784     fdef.close()
This page took 0.118989 seconds and 4 git commands to generate.