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