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 check_type(expr_info, "'base' for union '%s'" % name,
564 base, allow_metas=['struct'])
566 raise QAPIExprError(expr_info,
567 "Flat union '%s' must have a base"
569 base_fields = find_base_fields(base)
572 # The value of member 'discriminator' must name a non-optional
573 # member of the base struct.
574 check_name(expr_info, "Discriminator of flat union '%s'" % name,
576 discriminator_type = base_fields.get(discriminator)
577 if not discriminator_type:
578 raise QAPIExprError(expr_info,
579 "Discriminator '%s' is not a member of base "
581 % (discriminator, base))
582 enum_define = find_enum(discriminator_type)
583 allow_metas = ['struct']
584 # Do not allow string discriminator
586 raise QAPIExprError(expr_info,
587 "Discriminator '%s' must be of enumeration "
588 "type" % discriminator)
591 for (key, value) in members.items():
592 check_name(expr_info, "Member of union '%s'" % name, key)
594 # Each value must name a known type; furthermore, in flat unions,
595 # branches must be a struct with no overlapping member names
596 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
597 value, allow_array=not base, allow_metas=allow_metas)
599 branch_struct = find_struct(value)
601 check_member_clash(expr_info, base, branch_struct['data'],
602 " of branch '%s'" % key)
604 # If the discriminator names an enum type, then all members
605 # of 'data' must also be members of the enum type, which in turn
606 # must not collide with the discriminator name.
608 if key not in enum_define['enum_values']:
609 raise QAPIExprError(expr_info,
610 "Discriminator value '%s' is not found in "
612 (key, enum_define["enum_name"]))
613 if discriminator in enum_define['enum_values']:
614 raise QAPIExprError(expr_info,
615 "Discriminator name '%s' collides with "
616 "enum value in '%s'" %
617 (discriminator, enum_define["enum_name"]))
619 # Otherwise, check for conflicts in the generated enum
621 c_key = camel_to_upper(key)
623 raise QAPIExprError(expr_info,
624 "Union '%s' member '%s' clashes with '%s'"
625 % (name, key, values[c_key]))
629 def check_alternate(expr, expr_info):
630 name = expr['alternate']
631 members = expr['data']
632 values = {'MAX': '(automatic)'}
636 for (key, value) in members.items():
637 check_name(expr_info, "Member of alternate '%s'" % name, key)
639 # Check for conflicts in the generated enum
640 c_key = camel_to_upper(key)
642 raise QAPIExprError(expr_info,
643 "Alternate '%s' member '%s' clashes with '%s'"
644 % (name, key, values[c_key]))
647 # Ensure alternates have no type conflicts.
648 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
650 allow_metas=['built-in', 'union', 'struct', 'enum'])
651 qtype = find_alternate_member_qtype(value)
653 if qtype in types_seen:
654 raise QAPIExprError(expr_info,
655 "Alternate '%s' member '%s' can't "
656 "be distinguished from member '%s'"
657 % (name, key, types_seen[qtype]))
658 types_seen[qtype] = key
661 def check_enum(expr, expr_info):
663 members = expr.get('data')
664 prefix = expr.get('prefix')
665 values = {'MAX': '(automatic)'}
667 if not isinstance(members, list):
668 raise QAPIExprError(expr_info,
669 "Enum '%s' requires an array for 'data'" % name)
670 if prefix is not None and not isinstance(prefix, str):
671 raise QAPIExprError(expr_info,
672 "Enum '%s' requires a string for 'prefix'" % name)
673 for member in members:
674 check_name(expr_info, "Member of enum '%s'" % name, member,
676 key = camel_to_upper(member)
678 raise QAPIExprError(expr_info,
679 "Enum '%s' member '%s' clashes with '%s'"
680 % (name, member, values[key]))
684 def check_struct(expr, expr_info):
685 name = expr['struct']
686 members = expr['data']
688 check_type(expr_info, "'data' for struct '%s'" % name, members,
689 allow_dict=True, allow_optional=True)
690 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
691 allow_metas=['struct'])
693 check_member_clash(expr_info, expr['base'], expr['data'])
696 def check_keys(expr_elem, meta, required, optional=[]):
697 expr = expr_elem['expr']
698 info = expr_elem['info']
700 if not isinstance(name, str):
701 raise QAPIExprError(info,
702 "'%s' key must have a string value" % meta)
703 required = required + [meta]
704 for (key, value) in expr.items():
705 if key not in required and key not in optional:
706 raise QAPIExprError(info,
707 "Unknown key '%s' in %s '%s'"
709 if (key == 'gen' or key == 'success-response') and value is not False:
710 raise QAPIExprError(info,
711 "'%s' of %s '%s' should only use false value"
715 raise QAPIExprError(info,
716 "Key '%s' is missing from %s '%s'"
720 def check_exprs(exprs):
723 # Learn the types and check for valid expression keys
724 for builtin in builtin_types.keys():
725 all_names[builtin] = 'built-in'
726 for expr_elem in exprs:
727 expr = expr_elem['expr']
728 info = expr_elem['info']
730 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
731 add_enum(expr['enum'], info, expr['data'])
732 elif 'union' in expr:
733 check_keys(expr_elem, 'union', ['data'],
734 ['base', 'discriminator'])
735 add_union(expr, info)
736 elif 'alternate' in expr:
737 check_keys(expr_elem, 'alternate', ['data'])
738 add_name(expr['alternate'], info, 'alternate')
739 elif 'struct' in expr:
740 check_keys(expr_elem, 'struct', ['data'], ['base'])
741 add_struct(expr, info)
742 elif 'command' in expr:
743 check_keys(expr_elem, 'command', [],
744 ['data', 'returns', 'gen', 'success-response'])
745 add_name(expr['command'], info, 'command')
746 elif 'event' in expr:
747 check_keys(expr_elem, 'event', [], ['data'])
748 add_name(expr['event'], info, 'event')
750 raise QAPIExprError(expr_elem['info'],
751 "Expression is missing metatype")
753 # Try again for hidden UnionKind enum
754 for expr_elem in exprs:
755 expr = expr_elem['expr']
757 if not discriminator_find_enum_define(expr):
758 add_enum('%sKind' % expr['union'], expr_elem['info'],
760 elif 'alternate' in expr:
761 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
764 # Validate that exprs make sense
765 for expr_elem in exprs:
766 expr = expr_elem['expr']
767 info = expr_elem['info']
770 check_enum(expr, info)
771 elif 'union' in expr:
772 check_union(expr, info)
773 elif 'alternate' in expr:
774 check_alternate(expr, info)
775 elif 'struct' in expr:
776 check_struct(expr, info)
777 elif 'command' in expr:
778 check_command(expr, info)
779 elif 'event' in expr:
780 check_event(expr, info)
782 assert False, 'unexpected meta type'
788 # Schema compiler frontend
791 class QAPISchemaEntity(object):
792 def __init__(self, name, info):
793 assert isinstance(name, str)
798 return c_name(self.name)
800 def check(self, schema):
803 def visit(self, visitor):
807 class QAPISchemaVisitor(object):
808 def visit_begin(self, schema):
814 def visit_builtin_type(self, name, info, json_type):
817 def visit_enum_type(self, name, info, values, prefix):
820 def visit_array_type(self, name, info, element_type):
823 def visit_object_type(self, name, info, base, members, variants):
826 def visit_object_type_flat(self, name, info, members, variants):
829 def visit_alternate_type(self, name, info, variants):
832 def visit_command(self, name, info, arg_type, ret_type,
833 gen, success_response):
836 def visit_event(self, name, info, arg_type):
840 class QAPISchemaType(QAPISchemaEntity):
841 def c_type(self, is_param=False):
842 return c_name(self.name) + pointer_suffix
850 def alternate_qtype(self):
852 'string': 'QTYPE_QSTRING',
853 'number': 'QTYPE_QFLOAT',
855 'boolean': 'QTYPE_QBOOL',
856 'object': 'QTYPE_QDICT'
858 return json2qtype.get(self.json_type())
861 class QAPISchemaBuiltinType(QAPISchemaType):
862 def __init__(self, name, json_type, c_type, c_null):
863 QAPISchemaType.__init__(self, name, None)
864 assert not c_type or isinstance(c_type, str)
865 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
867 self._json_type_name = json_type
868 self._c_type_name = c_type
869 self._c_null_val = c_null
874 def c_type(self, is_param=False):
875 if is_param and self.name == 'str':
876 return 'const ' + self._c_type_name
877 return self._c_type_name
880 return self._c_null_val
883 return self._json_type_name
885 def visit(self, visitor):
886 visitor.visit_builtin_type(self.name, self.info, self.json_type())
889 class QAPISchemaEnumType(QAPISchemaType):
890 def __init__(self, name, info, values, prefix):
891 QAPISchemaType.__init__(self, name, info)
893 assert isinstance(v, str)
894 assert prefix is None or isinstance(prefix, str)
898 def check(self, schema):
899 assert len(set(self.values)) == len(self.values)
901 def c_type(self, is_param=False):
902 return c_name(self.name)
905 return c_enum_const(self.name, (self.values + ['MAX'])[0],
911 def visit(self, visitor):
912 visitor.visit_enum_type(self.name, self.info,
913 self.values, self.prefix)
916 class QAPISchemaArrayType(QAPISchemaType):
917 def __init__(self, name, info, element_type):
918 QAPISchemaType.__init__(self, name, info)
919 assert isinstance(element_type, str)
920 self._element_type_name = element_type
921 self.element_type = None
923 def check(self, schema):
924 self.element_type = schema.lookup_type(self._element_type_name)
925 assert self.element_type
930 def visit(self, visitor):
931 visitor.visit_array_type(self.name, self.info, self.element_type)
934 class QAPISchemaObjectType(QAPISchemaType):
935 def __init__(self, name, info, base, local_members, variants):
936 QAPISchemaType.__init__(self, name, info)
937 assert base is None or isinstance(base, str)
938 for m in local_members:
939 assert isinstance(m, QAPISchemaObjectTypeMember)
940 assert (variants is None or
941 isinstance(variants, QAPISchemaObjectTypeVariants))
942 self._base_name = base
944 self.local_members = local_members
945 self.variants = variants
948 def check(self, schema):
949 assert self.members is not False # not running in cycles
952 self.members = False # mark as being checked
954 self.base = schema.lookup_type(self._base_name)
955 assert isinstance(self.base, QAPISchemaObjectType)
956 assert not self.base.variants # not implemented
957 self.base.check(schema)
958 members = list(self.base.members)
964 for m in self.local_members:
965 m.check(schema, members, seen)
967 self.variants.check(schema, members, seen)
968 self.members = members
972 return QAPISchemaType.c_name(self)
974 def c_type(self, is_param=False):
976 return QAPISchemaType.c_type(self)
981 def visit(self, visitor):
982 visitor.visit_object_type(self.name, self.info,
983 self.base, self.local_members, self.variants)
984 visitor.visit_object_type_flat(self.name, self.info,
985 self.members, self.variants)
988 class QAPISchemaObjectTypeMember(object):
989 def __init__(self, name, typ, optional):
990 assert isinstance(name, str)
991 assert isinstance(typ, str)
992 assert isinstance(optional, bool)
994 self._type_name = typ
996 self.optional = optional
998 def check(self, schema, all_members, seen):
999 assert self.name not in seen
1000 self.type = schema.lookup_type(self._type_name)
1002 all_members.append(self)
1003 seen[self.name] = self
1006 class QAPISchemaObjectTypeVariants(object):
1007 def __init__(self, tag_name, tag_enum, variants):
1008 assert tag_name is None or isinstance(tag_name, str)
1009 assert tag_enum is None or isinstance(tag_enum, str)
1011 assert isinstance(v, QAPISchemaObjectTypeVariant)
1012 self.tag_name = tag_name
1015 self.tag_member = None
1017 self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
1019 self.variants = variants
1021 def check(self, schema, members, seen):
1023 self.tag_member = seen[self.tag_name]
1025 self.tag_member.check(schema, members, seen)
1026 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1027 for v in self.variants:
1029 v.check(schema, self.tag_member.type, vseen)
1032 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1033 def __init__(self, name, typ):
1034 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1036 def check(self, schema, tag_type, seen):
1037 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1038 assert self.name in tag_type.values
1040 # This function exists to support ugly simple union special cases
1041 # TODO get rid of them, and drop the function
1042 def simple_union_type(self):
1043 if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
1044 assert len(self.type.members) == 1
1045 assert not self.type.variants
1046 return self.type.members[0].type
1050 class QAPISchemaAlternateType(QAPISchemaType):
1051 def __init__(self, name, info, variants):
1052 QAPISchemaType.__init__(self, name, info)
1053 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1054 assert not variants.tag_name
1055 self.variants = variants
1057 def check(self, schema):
1058 self.variants.check(schema, [], {})
1060 def json_type(self):
1063 def visit(self, visitor):
1064 visitor.visit_alternate_type(self.name, self.info, self.variants)
1067 class QAPISchemaCommand(QAPISchemaEntity):
1068 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1069 QAPISchemaEntity.__init__(self, name, info)
1070 assert not arg_type or isinstance(arg_type, str)
1071 assert not ret_type or isinstance(ret_type, str)
1072 self._arg_type_name = arg_type
1073 self.arg_type = None
1074 self._ret_type_name = ret_type
1075 self.ret_type = None
1077 self.success_response = success_response
1079 def check(self, schema):
1080 if self._arg_type_name:
1081 self.arg_type = schema.lookup_type(self._arg_type_name)
1082 assert isinstance(self.arg_type, QAPISchemaObjectType)
1083 assert not self.arg_type.variants # not implemented
1084 if self._ret_type_name:
1085 self.ret_type = schema.lookup_type(self._ret_type_name)
1086 assert isinstance(self.ret_type, QAPISchemaType)
1088 def visit(self, visitor):
1089 visitor.visit_command(self.name, self.info,
1090 self.arg_type, self.ret_type,
1091 self.gen, self.success_response)
1094 class QAPISchemaEvent(QAPISchemaEntity):
1095 def __init__(self, name, info, arg_type):
1096 QAPISchemaEntity.__init__(self, name, info)
1097 assert not arg_type or isinstance(arg_type, str)
1098 self._arg_type_name = arg_type
1099 self.arg_type = None
1101 def check(self, schema):
1102 if self._arg_type_name:
1103 self.arg_type = schema.lookup_type(self._arg_type_name)
1104 assert isinstance(self.arg_type, QAPISchemaObjectType)
1105 assert not self.arg_type.variants # not implemented
1107 def visit(self, visitor):
1108 visitor.visit_event(self.name, self.info, self.arg_type)
1111 class QAPISchema(object):
1112 def __init__(self, fname):
1114 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1115 except (QAPISchemaError, QAPIExprError), err:
1116 print >>sys.stderr, err
1118 self._entity_dict = {}
1119 self._def_predefineds()
1123 def _def_entity(self, ent):
1124 assert ent.name not in self._entity_dict
1125 self._entity_dict[ent.name] = ent
1127 def lookup_entity(self, name, typ=None):
1128 ent = self._entity_dict.get(name)
1129 if typ and not isinstance(ent, typ):
1133 def lookup_type(self, name):
1134 return self.lookup_entity(name, QAPISchemaType)
1136 def _def_builtin_type(self, name, json_type, c_type, c_null):
1137 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1139 self._make_array_type(name) # TODO really needed?
1141 def _def_predefineds(self):
1142 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1143 ('number', 'number', 'double', '0'),
1144 ('int', 'int', 'int64_t', '0'),
1145 ('int8', 'int', 'int8_t', '0'),
1146 ('int16', 'int', 'int16_t', '0'),
1147 ('int32', 'int', 'int32_t', '0'),
1148 ('int64', 'int', 'int64_t', '0'),
1149 ('uint8', 'int', 'uint8_t', '0'),
1150 ('uint16', 'int', 'uint16_t', '0'),
1151 ('uint32', 'int', 'uint32_t', '0'),
1152 ('uint64', 'int', 'uint64_t', '0'),
1153 ('size', 'int', 'uint64_t', '0'),
1154 ('bool', 'boolean', 'bool', 'false'),
1155 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
1156 self._def_builtin_type(*t)
1157 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1159 self._def_entity(self.the_empty_object_type)
1161 def _make_implicit_enum_type(self, name, values):
1162 name = name + 'Kind'
1163 self._def_entity(QAPISchemaEnumType(name, None, values, None))
1166 def _make_array_type(self, element_type):
1167 name = element_type + 'List'
1168 if not self.lookup_type(name):
1169 self._def_entity(QAPISchemaArrayType(name, None, element_type))
1172 def _make_implicit_object_type(self, name, role, members):
1175 name = ':obj-%s-%s' % (name, role)
1176 if not self.lookup_entity(name, QAPISchemaObjectType):
1177 self._def_entity(QAPISchemaObjectType(name, None, None,
1181 def _def_enum_type(self, expr, info):
1184 prefix = expr.get('prefix')
1185 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1186 self._make_array_type(name) # TODO really needed?
1188 def _make_member(self, name, typ):
1190 if name.startswith('*'):
1193 if isinstance(typ, list):
1194 assert len(typ) == 1
1195 typ = self._make_array_type(typ[0])
1196 return QAPISchemaObjectTypeMember(name, typ, optional)
1198 def _make_members(self, data):
1199 return [self._make_member(key, value)
1200 for (key, value) in data.iteritems()]
1202 def _def_struct_type(self, expr, info):
1203 name = expr['struct']
1204 base = expr.get('base')
1206 self._def_entity(QAPISchemaObjectType(name, info, base,
1207 self._make_members(data),
1209 self._make_array_type(name) # TODO really needed?
1211 def _make_variant(self, case, typ):
1212 return QAPISchemaObjectTypeVariant(case, typ)
1214 def _make_simple_variant(self, case, typ):
1215 if isinstance(typ, list):
1216 assert len(typ) == 1
1217 typ = self._make_array_type(typ[0])
1218 typ = self._make_implicit_object_type(typ, 'wrapper',
1219 [self._make_member('data', typ)])
1220 return QAPISchemaObjectTypeVariant(case, typ)
1222 def _make_tag_enum(self, type_name, variants):
1223 return self._make_implicit_enum_type(type_name,
1224 [v.name for v in variants])
1226 def _def_union_type(self, expr, info):
1227 name = expr['union']
1229 base = expr.get('base')
1230 tag_name = expr.get('discriminator')
1233 variants = [self._make_variant(key, value)
1234 for (key, value) in data.iteritems()]
1236 variants = [self._make_simple_variant(key, value)
1237 for (key, value) in data.iteritems()]
1238 tag_enum = self._make_tag_enum(name, variants)
1240 QAPISchemaObjectType(name, info, base,
1241 self._make_members(OrderedDict()),
1242 QAPISchemaObjectTypeVariants(tag_name,
1245 self._make_array_type(name) # TODO really needed?
1247 def _def_alternate_type(self, expr, info):
1248 name = expr['alternate']
1250 variants = [self._make_variant(key, value)
1251 for (key, value) in data.iteritems()]
1252 tag_enum = self._make_tag_enum(name, variants)
1254 QAPISchemaAlternateType(name, info,
1255 QAPISchemaObjectTypeVariants(None,
1258 self._make_array_type(name) # TODO really needed?
1260 def _def_command(self, expr, info):
1261 name = expr['command']
1262 data = expr.get('data')
1263 rets = expr.get('returns')
1264 gen = expr.get('gen', True)
1265 success_response = expr.get('success-response', True)
1266 if isinstance(data, OrderedDict):
1267 data = self._make_implicit_object_type(name, 'arg',
1268 self._make_members(data))
1269 if isinstance(rets, list):
1270 assert len(rets) == 1
1271 rets = self._make_array_type(rets[0])
1272 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1275 def _def_event(self, expr, info):
1276 name = expr['event']
1277 data = expr.get('data')
1278 if isinstance(data, OrderedDict):
1279 data = self._make_implicit_object_type(name, 'arg',
1280 self._make_members(data))
1281 self._def_entity(QAPISchemaEvent(name, info, data))
1283 def _def_exprs(self):
1284 for expr_elem in self.exprs:
1285 expr = expr_elem['expr']
1286 info = expr_elem['info']
1288 self._def_enum_type(expr, info)
1289 elif 'struct' in expr:
1290 self._def_struct_type(expr, info)
1291 elif 'union' in expr:
1292 self._def_union_type(expr, info)
1293 elif 'alternate' in expr:
1294 self._def_alternate_type(expr, info)
1295 elif 'command' in expr:
1296 self._def_command(expr, info)
1297 elif 'event' in expr:
1298 self._def_event(expr, info)
1303 for ent in self._entity_dict.values():
1306 def visit(self, visitor):
1307 ignore = visitor.visit_begin(self)
1308 for name in sorted(self._entity_dict.keys()):
1309 if not ignore or not isinstance(self._entity_dict[name], ignore):
1310 self._entity_dict[name].visit(visitor)
1315 # Code generation helpers
1318 def camel_case(name):
1322 if ch in ['_', '-']:
1325 new_name += ch.upper()
1328 new_name += ch.lower()
1332 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1333 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1334 # ENUM24_Name -> ENUM24_NAME
1335 def camel_to_upper(value):
1336 c_fun_str = c_name(value, False)
1344 # When c is upper and no "_" appears before, do more checks
1345 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1346 if i < l - 1 and c_fun_str[i + 1].islower():
1348 elif c_fun_str[i - 1].isdigit():
1351 return new_name.lstrip('_').upper()
1354 def c_enum_const(type_name, const_name, prefix=None):
1355 if prefix is not None:
1357 return camel_to_upper(type_name + '_' + const_name)
1359 c_name_trans = string.maketrans('.-', '__')
1362 # Map @name to a valid C identifier.
1363 # If @protect, avoid returning certain ticklish identifiers (like
1364 # C keywords) by prepending "q_".
1366 # Used for converting 'name' from a 'name':'type' qapi definition
1367 # into a generated struct member, as well as converting type names
1368 # into substrings of a generated C function name.
1369 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1370 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1371 def c_name(name, protect=True):
1372 # ANSI X3J11/88-090, 3.1.1
1373 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1374 'default', 'do', 'double', 'else', 'enum', 'extern',
1375 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1376 'return', 'short', 'signed', 'sizeof', 'static',
1377 'struct', 'switch', 'typedef', 'union', 'unsigned',
1378 'void', 'volatile', 'while'])
1379 # ISO/IEC 9899:1999, 6.4.1
1380 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1381 # ISO/IEC 9899:2011, 6.4.1
1382 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1383 '_Noreturn', '_Static_assert', '_Thread_local'])
1384 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1386 gcc_words = set(['asm', 'typeof'])
1387 # C++ ISO/IEC 14882:2003 2.11
1388 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1389 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1390 'namespace', 'new', 'operator', 'private', 'protected',
1391 'public', 'reinterpret_cast', 'static_cast', 'template',
1392 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1393 'using', 'virtual', 'wchar_t',
1394 # alternative representations
1395 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1396 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1397 # namespace pollution:
1398 polluted_words = set(['unix', 'errno'])
1399 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1400 | cpp_words | polluted_words):
1402 return name.translate(c_name_trans)
1404 eatspace = '\033EATSPACE.'
1405 pointer_suffix = ' *' + eatspace
1408 def genindent(count):
1410 for _ in range(count):
1417 def push_indent(indent_amount=4):
1419 indent_level += indent_amount
1422 def pop_indent(indent_amount=4):
1424 indent_level -= indent_amount
1427 # Generate @code with @kwds interpolated.
1428 # Obey indent_level, and strip eatspace.
1429 def cgen(code, **kwds):
1432 indent = genindent(indent_level)
1433 # re.subn() lacks flags support before Python 2.7, use re.compile()
1434 raw = re.subn(re.compile("^.", re.MULTILINE),
1435 indent + r'\g<0>', raw)
1437 return re.sub(re.escape(eatspace) + ' *', '', raw)
1440 def mcgen(code, **kwds):
1443 return cgen(code, **kwds)
1446 def guardname(filename):
1447 return c_name(filename, protect=False).upper()
1450 def guardstart(name):
1457 name=guardname(name))
1463 #endif /* %(name)s */
1466 name=guardname(name))
1469 def gen_enum_lookup(name, values, prefix=None):
1472 const char *const %(c_name)s_lookup[] = {
1474 c_name=c_name(name))
1475 for value in values:
1476 index = c_enum_const(name, value, prefix)
1478 [%(index)s] = "%(value)s",
1480 index=index, value=value)
1482 max_index = c_enum_const(name, 'MAX', prefix)
1484 [%(max_index)s] = NULL,
1487 max_index=max_index)
1491 def gen_enum(name, values, prefix=None):
1492 # append automatically generated _MAX value
1493 enum_values = values + ['MAX']
1497 typedef enum %(c_name)s {
1499 c_name=c_name(name))
1502 for value in enum_values:
1506 c_enum=c_enum_const(name, value, prefix),
1513 c_name=c_name(name))
1517 extern const char *const %(c_name)s_lookup[];
1519 c_name=c_name(name))
1523 def gen_params(arg_type, extra):
1526 assert not arg_type.variants
1529 for memb in arg_type.members:
1533 ret += 'bool has_%s, ' % c_name(memb.name)
1534 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1540 def gen_err_check(label='out', skiperr=False):
1551 def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
1558 for memb in members:
1561 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1563 prefix=prefix, c_name=c_name(memb.name),
1564 name=memb.name, errp=errparg)
1565 ret += gen_err_check(skiperr=skiperr)
1567 if (%(prefix)shas_%(c_name)s) {
1569 prefix=prefix, c_name=c_name(memb.name))
1572 # Ugly: sometimes we need to cast away const
1573 if need_cast and memb.type.name == 'str':
1579 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1581 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1582 c_name=c_name(memb.name), name=memb.name,
1584 ret += gen_err_check(skiperr=skiperr)
1595 # Common command line parsing
1599 def parse_command_line(extra_options="", extra_long_options=[]):
1602 opts, args = getopt.gnu_getopt(sys.argv[1:],
1603 "chp:o:" + extra_options,
1604 ["source", "header", "prefix=",
1605 "output-dir="] + extra_long_options)
1606 except getopt.GetoptError, err:
1607 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1618 if o in ("-p", "--prefix"):
1619 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1620 if match.end() != len(a):
1621 print >>sys.stderr, \
1622 "%s: 'funny character '%s' in argument of --prefix" \
1623 % (sys.argv[0], a[match.end()])
1626 elif o in ("-o", "--output-dir"):
1627 output_dir = a + "/"
1628 elif o in ("-c", "--source"):
1630 elif o in ("-h", "--header"):
1633 extra_opts.append(oa)
1635 if not do_c and not do_h:
1640 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1644 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1647 # Generate output files with boilerplate
1651 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1652 c_comment, h_comment):
1653 guard = guardname(prefix + h_file)
1654 c_file = output_dir + prefix + c_file
1655 h_file = output_dir + prefix + h_file
1659 os.makedirs(output_dir)
1661 if e.errno != errno.EEXIST:
1664 def maybe_open(really, name, opt):
1666 return open(name, opt)
1669 return StringIO.StringIO()
1671 fdef = maybe_open(do_c, c_file, 'w')
1672 fdecl = maybe_open(do_h, h_file, 'w')
1674 fdef.write(mcgen('''
1675 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1680 fdecl.write(mcgen('''
1681 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1687 comment=h_comment, guard=guard))
1689 return (fdef, fdecl)
1692 def close_output(fdef, fdecl):