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