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