4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2015 Red Hat Inc.
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
15 from ordereddict import OrderedDict
23 'str': 'QTYPE_QSTRING',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
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',
36 'any': None, # any qtype_code possible, actually
39 # Whitelist of commands allowed to return a non-dictionary
42 'human-monitor-command',
44 'query-migrate-cache-size',
51 'guest-fsfreeze-freeze',
52 'guest-fsfreeze-freeze-list',
53 'guest-fsfreeze-status',
54 'guest-fsfreeze-thaw',
58 'guest-sync-delimited',
60 # From qapi-schema-test:
71 # Parsing the schema into expressions
75 def error_path(parent):
78 res = ("In file included from %s:%d:\n" % (parent['file'],
79 parent['line'])) + res
80 parent = parent['parent']
84 class QAPISchemaError(Exception):
85 def __init__(self, schema, msg):
86 Exception.__init__(self)
87 self.fname = schema.fname
90 self.line = schema.line
91 for ch in schema.src[schema.line_pos:schema.pos]:
93 self.col = (self.col + 7) % 8 + 1
96 self.info = schema.incl_info
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 self.info = expr_info
110 return error_path(self.info['parent']) + \
111 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
114 class QAPISchemaParser(object):
116 def __init__(self, fp, previously_included=[], incl_info=None):
117 abs_fname = os.path.abspath(fp.name)
120 previously_included.append(abs_fname)
121 self.incl_info = incl_info
123 if self.src == '' or self.src[-1] != '\n':
131 while self.tok is not None:
132 expr_info = {'file': fname, 'line': self.line,
133 'parent': self.incl_info}
134 expr = self.get_expr(False)
135 if isinstance(expr, dict) and "include" in expr:
137 raise QAPIExprError(expr_info,
138 "Invalid 'include' directive")
139 include = expr["include"]
140 if not isinstance(include, str):
141 raise QAPIExprError(expr_info,
142 "Value of 'include' must be a string")
143 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
145 # catch inclusion cycle
148 if incl_abs_fname == os.path.abspath(inf['file']):
149 raise QAPIExprError(expr_info, "Inclusion loop for %s"
152 # skip multiple include of the same file
153 if incl_abs_fname in previously_included:
156 fobj = open(incl_abs_fname, 'r')
158 raise QAPIExprError(expr_info,
159 '%s: %s' % (e.strerror, include))
160 exprs_include = QAPISchemaParser(fobj, previously_included,
162 self.exprs.extend(exprs_include.exprs)
164 expr_elem = {'expr': expr,
166 self.exprs.append(expr_elem)
170 self.tok = self.src[self.cursor]
171 self.pos = self.cursor
176 self.cursor = self.src.find('\n', self.cursor)
177 elif self.tok in ['{', '}', ':', ',', '[', ']']:
179 elif self.tok == "'":
183 ch = self.src[self.cursor]
186 raise QAPISchemaError(self,
187 'Missing terminating "\'"')
201 for _ in range(0, 4):
202 ch = self.src[self.cursor]
204 if ch not in "0123456789abcdefABCDEF":
205 raise QAPISchemaError(self,
206 '\\u escape needs 4 '
208 value = (value << 4) + int(ch, 16)
209 # If Python 2 and 3 didn't disagree so much on
210 # how to handle Unicode, then we could allow
211 # Unicode string defaults. But most of QAPI is
212 # ASCII-only, so we aren't losing much for now.
213 if not value or value > 0x7f:
214 raise QAPISchemaError(self,
215 'For now, \\u escape '
216 'only supports non-zero '
217 'values up to \\u007f')
222 raise QAPISchemaError(self,
223 "Unknown escape \\%s" % ch)
232 elif self.src.startswith("true", self.pos):
236 elif self.src.startswith("false", self.pos):
240 elif self.src.startswith("null", self.pos):
244 elif self.tok == '\n':
245 if self.cursor == len(self.src):
249 self.line_pos = self.cursor
250 elif not self.tok.isspace():
251 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
253 def get_members(self):
259 raise QAPISchemaError(self, 'Expected string or "}"')
264 raise QAPISchemaError(self, 'Expected ":"')
267 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
268 expr[key] = self.get_expr(True)
273 raise QAPISchemaError(self, 'Expected "," or "}"')
276 raise QAPISchemaError(self, 'Expected string')
278 def get_values(self):
283 if self.tok not in "{['tfn":
284 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
287 expr.append(self.get_expr(True))
292 raise QAPISchemaError(self, 'Expected "," or "]"')
295 def get_expr(self, nested):
296 if self.tok != '{' and not nested:
297 raise QAPISchemaError(self, 'Expected "{"')
300 expr = self.get_members()
301 elif self.tok == '[':
303 expr = self.get_values()
304 elif self.tok in "'tfn":
308 raise QAPISchemaError(self, 'Expected "{", "[" or string')
312 # Semantic analysis of schema expressions
313 # TODO fold into QAPISchema
314 # TODO catching name collisions in generated code would be nice
318 def find_base_fields(base):
319 base_struct_define = find_struct(base)
320 if not base_struct_define:
322 return base_struct_define['data']
325 # Return the qtype of an alternate branch, or None on error.
326 def find_alternate_member_qtype(qapi_type):
327 if qapi_type in builtin_types:
328 return builtin_types[qapi_type]
329 elif find_struct(qapi_type):
331 elif find_enum(qapi_type):
332 return "QTYPE_QSTRING"
333 elif find_union(qapi_type):
338 # Return the discriminator enum define if discriminator is specified as an
339 # enum type, otherwise return None.
340 def discriminator_find_enum_define(expr):
341 base = expr.get('base')
342 discriminator = expr.get('discriminator')
344 if not (discriminator and base):
347 base_fields = find_base_fields(base)
351 discriminator_type = base_fields.get(discriminator)
352 if not discriminator_type:
355 return find_enum(discriminator_type)
358 # FIXME should enforce "other than downstream extensions [...], all
359 # names should begin with a letter".
360 valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
363 def check_name(expr_info, source, name, allow_optional=False,
368 if not isinstance(name, str):
369 raise QAPIExprError(expr_info,
370 "%s requires a string name" % source)
371 if name.startswith('*'):
372 membername = name[1:]
373 if not allow_optional:
374 raise QAPIExprError(expr_info,
375 "%s does not allow optional name '%s'"
377 # Enum members can start with a digit, because the generated C
378 # code always prefixes it with the enum name
380 membername = '_' + membername
381 if not valid_name.match(membername):
382 raise QAPIExprError(expr_info,
383 "%s uses invalid name '%s'" % (source, name))
386 def add_name(name, info, meta, implicit=False):
388 check_name(info, "'%s'" % meta, name)
389 # FIXME should reject names that differ only in '_' vs. '.'
390 # vs. '-', because they're liable to clash in generated C.
391 if name in all_names:
392 raise QAPIExprError(info,
393 "%s '%s' is already defined"
394 % (all_names[name], name))
395 if not implicit and name[-4:] == 'Kind':
396 raise QAPIExprError(info,
397 "%s '%s' should not end in 'Kind'"
399 all_names[name] = meta
402 def add_struct(definition, info):
404 name = definition['struct']
405 add_name(name, info, 'struct')
406 struct_types.append(definition)
409 def find_struct(name):
411 for struct in struct_types:
412 if struct['struct'] == name:
417 def add_union(definition, info):
419 name = definition['union']
420 add_name(name, info, 'union')
421 union_types.append(definition)
424 def find_union(name):
426 for union in union_types:
427 if union['union'] == name:
432 def add_enum(name, info, enum_values=None, implicit=False):
434 add_name(name, info, 'enum', implicit)
435 enum_types.append({"enum_name": name, "enum_values": enum_values})
440 for enum in enum_types:
441 if enum['enum_name'] == name:
447 return find_enum(name) is not None
450 def check_type(expr_info, source, value, allow_array=False,
451 allow_dict=False, allow_optional=False,
458 # Check if array type for value is okay
459 if isinstance(value, list):
461 raise QAPIExprError(expr_info,
462 "%s cannot be an array" % source)
463 if len(value) != 1 or not isinstance(value[0], str):
464 raise QAPIExprError(expr_info,
465 "%s: array type must contain single type name"
469 # Check if type name for value is okay
470 if isinstance(value, str):
471 if value not in all_names:
472 raise QAPIExprError(expr_info,
473 "%s uses unknown type '%s'"
475 if not all_names[value] in allow_metas:
476 raise QAPIExprError(expr_info,
477 "%s cannot use %s type '%s'"
478 % (source, all_names[value], value))
482 raise QAPIExprError(expr_info,
483 "%s should be a type name" % source)
485 if not isinstance(value, OrderedDict):
486 raise QAPIExprError(expr_info,
487 "%s should be a dictionary or type name" % source)
489 # value is a dictionary, check that each member is okay
490 for (key, arg) in value.items():
491 check_name(expr_info, "Member of %s" % source, key,
492 allow_optional=allow_optional)
493 # Todo: allow dictionaries to represent default values of
494 # an optional argument.
495 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
497 allow_metas=['built-in', 'union', 'alternate', 'struct',
501 def check_member_clash(expr_info, base_name, data, source=""):
502 base = find_struct(base_name)
504 base_members = base['data']
505 for key in data.keys():
506 if key.startswith('*'):
508 if key in base_members or "*" + key in base_members:
509 raise QAPIExprError(expr_info,
510 "Member name '%s'%s clashes with base '%s'"
511 % (key, source, base_name))
513 check_member_clash(expr_info, base['base'], data, source)
516 def check_command(expr, expr_info):
517 name = expr['command']
519 check_type(expr_info, "'data' for command '%s'" % name,
520 expr.get('data'), allow_dict=True, allow_optional=True,
521 allow_metas=['struct'])
522 returns_meta = ['union', 'struct']
523 if name in returns_whitelist:
524 returns_meta += ['built-in', 'alternate', 'enum']
525 check_type(expr_info, "'returns' for command '%s'" % name,
526 expr.get('returns'), allow_array=True,
527 allow_optional=True, allow_metas=returns_meta)
530 def check_event(expr, expr_info):
534 if name.upper() == 'MAX':
535 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
537 check_type(expr_info, "'data' for event '%s'" % name,
538 expr.get('data'), allow_dict=True, allow_optional=True,
539 allow_metas=['struct'])
542 def check_union(expr, expr_info):
544 base = expr.get('base')
545 discriminator = expr.get('discriminator')
546 members = expr['data']
547 values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
549 # Two types of unions, determined by discriminator.
551 # With no discriminator it is a simple union.
552 if discriminator is None:
554 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
556 raise QAPIExprError(expr_info,
557 "Simple union '%s' must not have a base"
560 # Else, it's a flat union.
562 # The object must have a string member 'base'.
563 if not isinstance(base, str):
564 raise QAPIExprError(expr_info,
565 "Flat union '%s' must have a string base field"
567 base_fields = find_base_fields(base)
569 raise QAPIExprError(expr_info,
570 "Base '%s' is not a valid struct"
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,
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 "
582 % (discriminator, base))
583 enum_define = find_enum(discriminator_type)
584 allow_metas = ['struct']
585 # Do not allow string discriminator
587 raise QAPIExprError(expr_info,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator)
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)
600 branch_struct = find_struct(value)
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.
609 if key not in enum_define['enum_values']:
610 raise QAPIExprError(expr_info,
611 "Discriminator value '%s' is not found in "
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
622 c_key = camel_to_upper(key)
624 raise QAPIExprError(expr_info,
625 "Union '%s' member '%s' clashes with '%s'"
626 % (name, key, values[c_key]))
630 def check_alternate(expr, expr_info):
631 name = expr['alternate']
632 members = expr['data']
633 values = {'MAX': '(automatic)'}
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)
643 raise QAPIExprError(expr_info,
644 "Alternate '%s' member '%s' clashes with '%s'"
645 % (name, key, values[c_key]))
648 # Ensure alternates have no type conflicts.
649 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
651 allow_metas=['built-in', 'union', 'struct', 'enum'])
652 qtype = find_alternate_member_qtype(value)
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):
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,
677 key = camel_to_upper(member)
679 raise QAPIExprError(expr_info,
680 "Enum '%s' member '%s' clashes with '%s'"
681 % (name, member, values[key]))
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'])
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']
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'"
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"
716 raise QAPIExprError(info,
717 "Key '%s' is missing from %s '%s'"
721 def check_exprs(exprs):
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']
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')
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']
758 if not discriminator_find_enum_define(expr):
759 add_enum('%sKind' % expr['union'], expr_elem['info'],
761 elif 'alternate' in expr:
762 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
765 # Validate that exprs make sense
766 for expr_elem in exprs:
767 expr = expr_elem['expr']
768 info = expr_elem['info']
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)
783 assert False, 'unexpected meta type'
789 # Schema compiler frontend
792 class QAPISchemaEntity(object):
793 def __init__(self, name, info):
794 assert isinstance(name, str)
799 return c_name(self.name)
801 def check(self, schema):
804 def visit(self, visitor):
808 class QAPISchemaVisitor(object):
809 def visit_begin(self, schema):
815 def visit_builtin_type(self, name, info, json_type):
818 def visit_enum_type(self, name, info, values, prefix):
821 def visit_array_type(self, name, info, element_type):
824 def visit_object_type(self, name, info, base, members, variants):
827 def visit_object_type_flat(self, name, info, members, variants):
830 def visit_alternate_type(self, name, info, variants):
833 def visit_command(self, name, info, arg_type, ret_type,
834 gen, success_response):
837 def visit_event(self, name, info, arg_type):
841 class QAPISchemaType(QAPISchemaEntity):
842 def c_type(self, is_param=False):
843 return c_name(self.name) + pointer_suffix
851 def alternate_qtype(self):
853 'string': 'QTYPE_QSTRING',
854 'number': 'QTYPE_QFLOAT',
856 'boolean': 'QTYPE_QBOOL',
857 'object': 'QTYPE_QDICT'
859 return json2qtype.get(self.json_type())
862 class QAPISchemaBuiltinType(QAPISchemaType):
863 def __init__(self, name, json_type, c_type, c_null):
864 QAPISchemaType.__init__(self, name, None)
865 assert not c_type or isinstance(c_type, str)
866 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
868 self._json_type_name = json_type
869 self._c_type_name = c_type
870 self._c_null_val = c_null
875 def c_type(self, is_param=False):
876 if is_param and self.name == 'str':
877 return 'const ' + self._c_type_name
878 return self._c_type_name
881 return self._c_null_val
884 return self._json_type_name
886 def visit(self, visitor):
887 visitor.visit_builtin_type(self.name, self.info, self.json_type())
890 class QAPISchemaEnumType(QAPISchemaType):
891 def __init__(self, name, info, values, prefix):
892 QAPISchemaType.__init__(self, name, info)
894 assert isinstance(v, str)
895 assert prefix is None or isinstance(prefix, str)
899 def check(self, schema):
900 assert len(set(self.values)) == len(self.values)
902 def c_type(self, is_param=False):
903 return c_name(self.name)
906 return c_enum_const(self.name, (self.values + ['MAX'])[0],
912 def visit(self, visitor):
913 visitor.visit_enum_type(self.name, self.info,
914 self.values, self.prefix)
917 class QAPISchemaArrayType(QAPISchemaType):
918 def __init__(self, name, info, element_type):
919 QAPISchemaType.__init__(self, name, info)
920 assert isinstance(element_type, str)
921 self._element_type_name = element_type
922 self.element_type = None
924 def check(self, schema):
925 self.element_type = schema.lookup_type(self._element_type_name)
926 assert self.element_type
931 def visit(self, visitor):
932 visitor.visit_array_type(self.name, self.info, self.element_type)
935 class QAPISchemaObjectType(QAPISchemaType):
936 def __init__(self, name, info, base, local_members, variants):
937 QAPISchemaType.__init__(self, name, info)
938 assert base is None or isinstance(base, str)
939 for m in local_members:
940 assert isinstance(m, QAPISchemaObjectTypeMember)
941 assert (variants is None or
942 isinstance(variants, QAPISchemaObjectTypeVariants))
943 self._base_name = base
945 self.local_members = local_members
946 self.variants = variants
949 def check(self, schema):
950 assert self.members is not False # not running in cycles
953 self.members = False # mark as being checked
955 self.base = schema.lookup_type(self._base_name)
956 assert isinstance(self.base, QAPISchemaObjectType)
957 assert not self.base.variants # not implemented
958 self.base.check(schema)
959 members = list(self.base.members)
965 for m in self.local_members:
966 m.check(schema, members, seen)
968 self.variants.check(schema, members, seen)
969 self.members = members
973 return QAPISchemaType.c_name(self)
975 def c_type(self, is_param=False):
977 return QAPISchemaType.c_type(self)
982 def visit(self, visitor):
983 visitor.visit_object_type(self.name, self.info,
984 self.base, self.local_members, self.variants)
985 visitor.visit_object_type_flat(self.name, self.info,
986 self.members, self.variants)
989 class QAPISchemaObjectTypeMember(object):
990 def __init__(self, name, typ, optional):
991 assert isinstance(name, str)
992 assert isinstance(typ, str)
993 assert isinstance(optional, bool)
995 self._type_name = typ
997 self.optional = optional
999 def check(self, schema, all_members, seen):
1000 assert self.name not in seen
1001 self.type = schema.lookup_type(self._type_name)
1003 all_members.append(self)
1004 seen[self.name] = self
1007 class QAPISchemaObjectTypeVariants(object):
1008 def __init__(self, tag_name, tag_enum, variants):
1009 assert tag_name is None or isinstance(tag_name, str)
1010 assert tag_enum is None or isinstance(tag_enum, str)
1012 assert isinstance(v, QAPISchemaObjectTypeVariant)
1013 self.tag_name = tag_name
1016 self.tag_member = None
1018 self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
1020 self.variants = variants
1022 def check(self, schema, members, seen):
1024 self.tag_member = seen[self.tag_name]
1026 self.tag_member.check(schema, members, seen)
1027 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1028 for v in self.variants:
1030 v.check(schema, self.tag_member.type, vseen)
1033 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1034 def __init__(self, name, typ):
1035 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1037 def check(self, schema, tag_type, seen):
1038 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1039 assert self.name in tag_type.values
1041 # This function exists to support ugly simple union special cases
1042 # TODO get rid of them, and drop the function
1043 def simple_union_type(self):
1044 if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
1045 assert len(self.type.members) == 1
1046 assert not self.type.variants
1047 return self.type.members[0].type
1051 class QAPISchemaAlternateType(QAPISchemaType):
1052 def __init__(self, name, info, variants):
1053 QAPISchemaType.__init__(self, name, info)
1054 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1055 assert not variants.tag_name
1056 self.variants = variants
1058 def check(self, schema):
1059 self.variants.check(schema, [], {})
1061 def json_type(self):
1064 def visit(self, visitor):
1065 visitor.visit_alternate_type(self.name, self.info, self.variants)
1068 class QAPISchemaCommand(QAPISchemaEntity):
1069 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1070 QAPISchemaEntity.__init__(self, name, info)
1071 assert not arg_type or isinstance(arg_type, str)
1072 assert not ret_type or isinstance(ret_type, str)
1073 self._arg_type_name = arg_type
1074 self.arg_type = None
1075 self._ret_type_name = ret_type
1076 self.ret_type = None
1078 self.success_response = success_response
1080 def check(self, schema):
1081 if self._arg_type_name:
1082 self.arg_type = schema.lookup_type(self._arg_type_name)
1083 assert isinstance(self.arg_type, QAPISchemaObjectType)
1084 assert not self.arg_type.variants # not implemented
1085 if self._ret_type_name:
1086 self.ret_type = schema.lookup_type(self._ret_type_name)
1087 assert isinstance(self.ret_type, QAPISchemaType)
1089 def visit(self, visitor):
1090 visitor.visit_command(self.name, self.info,
1091 self.arg_type, self.ret_type,
1092 self.gen, self.success_response)
1095 class QAPISchemaEvent(QAPISchemaEntity):
1096 def __init__(self, name, info, arg_type):
1097 QAPISchemaEntity.__init__(self, name, info)
1098 assert not arg_type or isinstance(arg_type, str)
1099 self._arg_type_name = arg_type
1100 self.arg_type = None
1102 def check(self, schema):
1103 if self._arg_type_name:
1104 self.arg_type = schema.lookup_type(self._arg_type_name)
1105 assert isinstance(self.arg_type, QAPISchemaObjectType)
1106 assert not self.arg_type.variants # not implemented
1108 def visit(self, visitor):
1109 visitor.visit_event(self.name, self.info, self.arg_type)
1112 class QAPISchema(object):
1113 def __init__(self, fname):
1115 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1116 except (QAPISchemaError, QAPIExprError), err:
1117 print >>sys.stderr, err
1119 self._entity_dict = {}
1120 self._def_predefineds()
1124 def _def_entity(self, ent):
1125 assert ent.name not in self._entity_dict
1126 self._entity_dict[ent.name] = ent
1128 def lookup_entity(self, name, typ=None):
1129 ent = self._entity_dict.get(name)
1130 if typ and not isinstance(ent, typ):
1134 def lookup_type(self, name):
1135 return self.lookup_entity(name, QAPISchemaType)
1137 def _def_builtin_type(self, name, json_type, c_type, c_null):
1138 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1140 self._make_array_type(name) # TODO really needed?
1142 def _def_predefineds(self):
1143 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1144 ('number', 'number', 'double', '0'),
1145 ('int', 'int', 'int64_t', '0'),
1146 ('int8', 'int', 'int8_t', '0'),
1147 ('int16', 'int', 'int16_t', '0'),
1148 ('int32', 'int', 'int32_t', '0'),
1149 ('int64', 'int', 'int64_t', '0'),
1150 ('uint8', 'int', 'uint8_t', '0'),
1151 ('uint16', 'int', 'uint16_t', '0'),
1152 ('uint32', 'int', 'uint32_t', '0'),
1153 ('uint64', 'int', 'uint64_t', '0'),
1154 ('size', 'int', 'uint64_t', '0'),
1155 ('bool', 'boolean', 'bool', 'false'),
1156 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
1157 self._def_builtin_type(*t)
1158 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1160 self._def_entity(self.the_empty_object_type)
1162 def _make_implicit_enum_type(self, name, values):
1163 name = name + 'Kind'
1164 self._def_entity(QAPISchemaEnumType(name, None, values, None))
1167 def _make_array_type(self, element_type):
1168 name = element_type + 'List'
1169 if not self.lookup_type(name):
1170 self._def_entity(QAPISchemaArrayType(name, None, element_type))
1173 def _make_implicit_object_type(self, name, role, members):
1176 name = ':obj-%s-%s' % (name, role)
1177 if not self.lookup_entity(name, QAPISchemaObjectType):
1178 self._def_entity(QAPISchemaObjectType(name, None, None,
1182 def _def_enum_type(self, expr, info):
1185 prefix = expr.get('prefix')
1186 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1187 self._make_array_type(name) # TODO really needed?
1189 def _make_member(self, name, typ):
1191 if name.startswith('*'):
1194 if isinstance(typ, list):
1195 assert len(typ) == 1
1196 typ = self._make_array_type(typ[0])
1197 return QAPISchemaObjectTypeMember(name, typ, optional)
1199 def _make_members(self, data):
1200 return [self._make_member(key, value)
1201 for (key, value) in data.iteritems()]
1203 def _def_struct_type(self, expr, info):
1204 name = expr['struct']
1205 base = expr.get('base')
1207 self._def_entity(QAPISchemaObjectType(name, info, base,
1208 self._make_members(data),
1210 self._make_array_type(name) # TODO really needed?
1212 def _make_variant(self, case, typ):
1213 return QAPISchemaObjectTypeVariant(case, typ)
1215 def _make_simple_variant(self, case, typ):
1216 if isinstance(typ, list):
1217 assert len(typ) == 1
1218 typ = self._make_array_type(typ[0])
1219 typ = self._make_implicit_object_type(typ, 'wrapper',
1220 [self._make_member('data', typ)])
1221 return QAPISchemaObjectTypeVariant(case, typ)
1223 def _make_tag_enum(self, type_name, variants):
1224 return self._make_implicit_enum_type(type_name,
1225 [v.name for v in variants])
1227 def _def_union_type(self, expr, info):
1228 name = expr['union']
1230 base = expr.get('base')
1231 tag_name = expr.get('discriminator')
1234 variants = [self._make_variant(key, value)
1235 for (key, value) in data.iteritems()]
1237 variants = [self._make_simple_variant(key, value)
1238 for (key, value) in data.iteritems()]
1239 tag_enum = self._make_tag_enum(name, variants)
1241 QAPISchemaObjectType(name, info, base,
1242 self._make_members(OrderedDict()),
1243 QAPISchemaObjectTypeVariants(tag_name,
1246 self._make_array_type(name) # TODO really needed?
1248 def _def_alternate_type(self, expr, info):
1249 name = expr['alternate']
1251 variants = [self._make_variant(key, value)
1252 for (key, value) in data.iteritems()]
1253 tag_enum = self._make_tag_enum(name, variants)
1255 QAPISchemaAlternateType(name, info,
1256 QAPISchemaObjectTypeVariants(None,
1259 self._make_array_type(name) # TODO really needed?
1261 def _def_command(self, expr, info):
1262 name = expr['command']
1263 data = expr.get('data')
1264 rets = expr.get('returns')
1265 gen = expr.get('gen', True)
1266 success_response = expr.get('success-response', True)
1267 if isinstance(data, OrderedDict):
1268 data = self._make_implicit_object_type(name, 'arg',
1269 self._make_members(data))
1270 if isinstance(rets, list):
1271 assert len(rets) == 1
1272 rets = self._make_array_type(rets[0])
1273 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1276 def _def_event(self, expr, info):
1277 name = expr['event']
1278 data = expr.get('data')
1279 if isinstance(data, OrderedDict):
1280 data = self._make_implicit_object_type(name, 'arg',
1281 self._make_members(data))
1282 self._def_entity(QAPISchemaEvent(name, info, data))
1284 def _def_exprs(self):
1285 for expr_elem in self.exprs:
1286 expr = expr_elem['expr']
1287 info = expr_elem['info']
1289 self._def_enum_type(expr, info)
1290 elif 'struct' in expr:
1291 self._def_struct_type(expr, info)
1292 elif 'union' in expr:
1293 self._def_union_type(expr, info)
1294 elif 'alternate' in expr:
1295 self._def_alternate_type(expr, info)
1296 elif 'command' in expr:
1297 self._def_command(expr, info)
1298 elif 'event' in expr:
1299 self._def_event(expr, info)
1304 for ent in self._entity_dict.values():
1307 def visit(self, visitor):
1308 ignore = visitor.visit_begin(self)
1309 for name in sorted(self._entity_dict.keys()):
1310 if not ignore or not isinstance(self._entity_dict[name], ignore):
1311 self._entity_dict[name].visit(visitor)
1316 # Code generation helpers
1319 def camel_case(name):
1323 if ch in ['_', '-']:
1326 new_name += ch.upper()
1329 new_name += ch.lower()
1333 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1334 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1335 # ENUM24_Name -> ENUM24_NAME
1336 def camel_to_upper(value):
1337 c_fun_str = c_name(value, False)
1345 # When c is upper and no "_" appears before, do more checks
1346 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1347 if i < l - 1 and c_fun_str[i + 1].islower():
1349 elif c_fun_str[i - 1].isdigit():
1352 return new_name.lstrip('_').upper()
1355 def c_enum_const(type_name, const_name, prefix=None):
1356 if prefix is not None:
1358 return camel_to_upper(type_name + '_' + const_name)
1360 c_name_trans = string.maketrans('.-', '__')
1363 # Map @name to a valid C identifier.
1364 # If @protect, avoid returning certain ticklish identifiers (like
1365 # C keywords) by prepending "q_".
1367 # Used for converting 'name' from a 'name':'type' qapi definition
1368 # into a generated struct member, as well as converting type names
1369 # into substrings of a generated C function name.
1370 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1371 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1372 def c_name(name, protect=True):
1373 # ANSI X3J11/88-090, 3.1.1
1374 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1375 'default', 'do', 'double', 'else', 'enum', 'extern',
1376 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1377 'return', 'short', 'signed', 'sizeof', 'static',
1378 'struct', 'switch', 'typedef', 'union', 'unsigned',
1379 'void', 'volatile', 'while'])
1380 # ISO/IEC 9899:1999, 6.4.1
1381 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1382 # ISO/IEC 9899:2011, 6.4.1
1383 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1384 '_Noreturn', '_Static_assert', '_Thread_local'])
1385 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1387 gcc_words = set(['asm', 'typeof'])
1388 # C++ ISO/IEC 14882:2003 2.11
1389 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1390 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1391 'namespace', 'new', 'operator', 'private', 'protected',
1392 'public', 'reinterpret_cast', 'static_cast', 'template',
1393 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1394 'using', 'virtual', 'wchar_t',
1395 # alternative representations
1396 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1397 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1398 # namespace pollution:
1399 polluted_words = set(['unix', 'errno'])
1400 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1401 | cpp_words | polluted_words):
1403 return name.translate(c_name_trans)
1405 eatspace = '\033EATSPACE.'
1406 pointer_suffix = ' *' + eatspace
1409 def genindent(count):
1411 for _ in range(count):
1418 def push_indent(indent_amount=4):
1420 indent_level += indent_amount
1423 def pop_indent(indent_amount=4):
1425 indent_level -= indent_amount
1428 # Generate @code with @kwds interpolated.
1429 # Obey indent_level, and strip eatspace.
1430 def cgen(code, **kwds):
1433 indent = genindent(indent_level)
1434 # re.subn() lacks flags support before Python 2.7, use re.compile()
1435 raw = re.subn(re.compile("^.", re.MULTILINE),
1436 indent + r'\g<0>', raw)
1438 return re.sub(re.escape(eatspace) + ' *', '', raw)
1441 def mcgen(code, **kwds):
1444 return cgen(code, **kwds)
1447 def guardname(filename):
1448 return c_name(filename, protect=False).upper()
1451 def guardstart(name):
1458 name=guardname(name))
1464 #endif /* %(name)s */
1467 name=guardname(name))
1470 def gen_enum_lookup(name, values, prefix=None):
1473 const char *const %(c_name)s_lookup[] = {
1475 c_name=c_name(name))
1476 for value in values:
1477 index = c_enum_const(name, value, prefix)
1479 [%(index)s] = "%(value)s",
1481 index=index, value=value)
1483 max_index = c_enum_const(name, 'MAX', prefix)
1485 [%(max_index)s] = NULL,
1488 max_index=max_index)
1492 def gen_enum(name, values, prefix=None):
1493 # append automatically generated _MAX value
1494 enum_values = values + ['MAX']
1498 typedef enum %(c_name)s {
1500 c_name=c_name(name))
1503 for value in enum_values:
1507 c_enum=c_enum_const(name, value, prefix),
1514 c_name=c_name(name))
1518 extern const char *const %(c_name)s_lookup[];
1520 c_name=c_name(name))
1524 def gen_params(arg_type, extra):
1527 assert not arg_type.variants
1530 for memb in arg_type.members:
1534 ret += 'bool has_%s, ' % c_name(memb.name)
1535 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1541 # Common command line parsing
1545 def parse_command_line(extra_options="", extra_long_options=[]):
1548 opts, args = getopt.gnu_getopt(sys.argv[1:],
1549 "chp:o:" + extra_options,
1550 ["source", "header", "prefix=",
1551 "output-dir="] + extra_long_options)
1552 except getopt.GetoptError, err:
1553 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1564 if o in ("-p", "--prefix"):
1565 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1566 if match.end() != len(a):
1567 print >>sys.stderr, \
1568 "%s: 'funny character '%s' in argument of --prefix" \
1569 % (sys.argv[0], a[match.end()])
1572 elif o in ("-o", "--output-dir"):
1573 output_dir = a + "/"
1574 elif o in ("-c", "--source"):
1576 elif o in ("-h", "--header"):
1579 extra_opts.append(oa)
1581 if not do_c and not do_h:
1586 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1590 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1593 # Generate output files with boilerplate
1597 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1598 c_comment, h_comment):
1599 guard = guardname(prefix + h_file)
1600 c_file = output_dir + prefix + c_file
1601 h_file = output_dir + prefix + h_file
1605 os.makedirs(output_dir)
1607 if e.errno != errno.EEXIST:
1610 def maybe_open(really, name, opt):
1612 return open(name, opt)
1615 return StringIO.StringIO()
1617 fdef = maybe_open(do_c, c_file, 'w')
1618 fdecl = maybe_open(do_h, h_file, 'w')
1620 fdef.write(mcgen('''
1621 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1626 fdecl.write(mcgen('''
1627 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1633 comment=h_comment, guard=guard))
1635 return (fdef, fdecl)
1638 def close_output(fdef, fdecl):