mirror of https://github.com/xemu-project/xemu.git
QAPI patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWH0puAAoJEDhwtADrkYZT6/cP/3EfS/0TVI6tiU1pz/qm6SMy yFYeYw1WIHw9/x7esRMGZ977QfmuL1YhZ0sD4lmpIMcXwuzTd0/tuO0AydH7ffZj daL/rKSiQjdPCbebHol6rAFWHOxRBqz1g2jDgIM9FB4dEjqzbUydV7/9Mmo5b44v Hss0/neKn6zVHognv4aB/FMmjjsbzqgvHcour7T+rVIF9qial/hA2I6ioM2kCnt4 jbkLUYYhb/rPNTlxjvT4vNsDfTiHScTeow6gRzd5LL5f1K7nTmRzqalsyZpRgpl+ mDIrbPExN4O6gDZkKDk3pmwAI+vPTVNP868tSjqNJmUeCdUmT9EQ8LagZCbt0b/e aViwkRmuDv+FNPfkmgmhXY0RTaX9QDT3vwWSjOzLGvrFj66UfbepXfBWlOZnl7DQ KJU33CnEjkbu/viiCat4HjCGt1kF11s+YPlYWGXgyo1QkF54o8OmKGTjZOaEze+R gvIdtbBKYSwnyMbPo26OrwvTDBYfZ+F5j2MCpuDEgwE0CtKbtAOCc87PMRtunDoh xloQ3F6fuItC9dPUGDcDxvN9RG3uPNcOUU4aoS0/y7CHlHqlxOJz6AIlm57vO67B T/PAd1uW6T/yFJWCub0iAHCkvmui639eIz2VyPfuJJb2YAiWivULsLplOzS1cYE4 N7J7BPGEATvaCCmmRPjd =CoJX -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2015-10-15' into staging QAPI patches # gpg: Signature made Thu 15 Oct 2015 07:40:46 BST using RSA key ID EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" * remotes/armbru/tags/pull-qapi-2015-10-15: qapi: Track location that created an implicit type qapi: Create simple union type member earlier qapi: Lazy creation of array types qapi: Don't use info as witness of implicit object type qapi: Drop redundant args-member-array test qapi: Drop redundant flat-union-reverse-define test qapi: Drop redundant returns-int test qapi: Move empty-enum to compile-time test qapi: Drop redundant alternate-good test qapi: Prepare for errors during check() qapi: Use predicate callback to determine visit filtering qapi: Fix regression with '-netdev help' Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
61f7901bb8
|
@ -3415,6 +3415,17 @@
|
||||||
'cpuid-register': 'X86CPURegister32',
|
'cpuid-register': 'X86CPURegister32',
|
||||||
'features': 'int' } }
|
'features': 'int' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @DummyForceArrays
|
||||||
|
#
|
||||||
|
# Not used by QMP; hack to let us use X86CPUFeatureWordInfoList internally
|
||||||
|
#
|
||||||
|
# Since 2.5
|
||||||
|
##
|
||||||
|
{ 'struct': 'DummyForceArrays',
|
||||||
|
'data': { 'unused': ['X86CPUFeatureWordInfo'] } }
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# @RxState:
|
# @RxState:
|
||||||
#
|
#
|
||||||
|
|
|
@ -54,7 +54,6 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
|
||||||
self._jsons = []
|
self._jsons = []
|
||||||
self._used_types = []
|
self._used_types = []
|
||||||
self._name_map = {}
|
self._name_map = {}
|
||||||
return QAPISchemaType # don't visit types for now
|
|
||||||
|
|
||||||
def visit_end(self):
|
def visit_end(self):
|
||||||
# visit the types that are actually used
|
# visit the types that are actually used
|
||||||
|
@ -82,6 +81,10 @@ const char %(c_name)s[] = %(c_string)s;
|
||||||
self._used_types = None
|
self._used_types = None
|
||||||
self._name_map = None
|
self._name_map = None
|
||||||
|
|
||||||
|
def visit_needed(self, entity):
|
||||||
|
# Ignore types on first pass; visit_end() will pick up used types
|
||||||
|
return not isinstance(entity, QAPISchemaType)
|
||||||
|
|
||||||
def _name(self, name):
|
def _name(self, name):
|
||||||
if self._unmask:
|
if self._unmask:
|
||||||
return name
|
return name
|
||||||
|
|
|
@ -233,6 +233,11 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
|
||||||
self.decl = self._btin + self.decl
|
self.decl = self._btin + self.decl
|
||||||
self._btin = None
|
self._btin = None
|
||||||
|
|
||||||
|
def visit_needed(self, entity):
|
||||||
|
# Visit everything except implicit objects
|
||||||
|
return not (entity.is_implicit() and
|
||||||
|
isinstance(entity, QAPISchemaObjectType))
|
||||||
|
|
||||||
def _gen_type_cleanup(self, name):
|
def _gen_type_cleanup(self, name):
|
||||||
self.decl += gen_type_cleanup_decl(name)
|
self.decl += gen_type_cleanup_decl(name)
|
||||||
self.defn += gen_type_cleanup(name)
|
self.defn += gen_type_cleanup(name)
|
||||||
|
@ -254,14 +259,13 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
|
||||||
self._gen_type_cleanup(name)
|
self._gen_type_cleanup(name)
|
||||||
|
|
||||||
def visit_object_type(self, name, info, base, members, variants):
|
def visit_object_type(self, name, info, base, members, variants):
|
||||||
if info:
|
self._fwdecl += gen_fwd_object_or_array(name)
|
||||||
self._fwdecl += gen_fwd_object_or_array(name)
|
if variants:
|
||||||
if variants:
|
assert not members # not implemented
|
||||||
assert not members # not implemented
|
self.decl += gen_union(name, base, variants)
|
||||||
self.decl += gen_union(name, base, variants)
|
else:
|
||||||
else:
|
self.decl += gen_struct(name, base, members)
|
||||||
self.decl += gen_struct(name, base, members)
|
self._gen_type_cleanup(name)
|
||||||
self._gen_type_cleanup(name)
|
|
||||||
|
|
||||||
def visit_alternate_type(self, name, info, variants):
|
def visit_alternate_type(self, name, info, variants):
|
||||||
self._fwdecl += gen_fwd_object_or_array(name)
|
self._fwdecl += gen_fwd_object_or_array(name)
|
||||||
|
|
|
@ -301,7 +301,9 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
|
||||||
out_obj:
|
out_obj:
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
err = NULL;
|
err = NULL;
|
||||||
visit_end_union(v, !!(*obj)->data, &err);
|
if (*obj) {
|
||||||
|
visit_end_union(v, !!(*obj)->data, &err);
|
||||||
|
}
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
err = NULL;
|
err = NULL;
|
||||||
visit_end_struct(v, &err);
|
visit_end_struct(v, &err);
|
||||||
|
@ -333,6 +335,11 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
|
||||||
self.decl = self._btin + self.decl
|
self.decl = self._btin + self.decl
|
||||||
self._btin = None
|
self._btin = None
|
||||||
|
|
||||||
|
def visit_needed(self, entity):
|
||||||
|
# Visit everything except implicit objects
|
||||||
|
return not (entity.is_implicit() and
|
||||||
|
isinstance(entity, QAPISchemaObjectType))
|
||||||
|
|
||||||
def visit_enum_type(self, name, info, values, prefix):
|
def visit_enum_type(self, name, info, values, prefix):
|
||||||
self.decl += gen_visit_decl(name, scalar=True)
|
self.decl += gen_visit_decl(name, scalar=True)
|
||||||
self.defn += gen_visit_enum(name)
|
self.defn += gen_visit_enum(name)
|
||||||
|
@ -349,13 +356,12 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
|
||||||
self.defn += defn
|
self.defn += defn
|
||||||
|
|
||||||
def visit_object_type(self, name, info, base, members, variants):
|
def visit_object_type(self, name, info, base, members, variants):
|
||||||
if info:
|
self.decl += gen_visit_decl(name)
|
||||||
self.decl += gen_visit_decl(name)
|
if variants:
|
||||||
if variants:
|
assert not members # not implemented
|
||||||
assert not members # not implemented
|
self.defn += gen_visit_union(name, base, variants)
|
||||||
self.defn += gen_visit_union(name, base, variants)
|
else:
|
||||||
else:
|
self.defn += gen_visit_struct(name, base, members)
|
||||||
self.defn += gen_visit_struct(name, base, members)
|
|
||||||
|
|
||||||
def visit_alternate_type(self, name, info, variants):
|
def visit_alternate_type(self, name, info, variants):
|
||||||
self.decl += gen_visit_decl(name)
|
self.decl += gen_visit_decl(name)
|
||||||
|
|
149
scripts/qapi.py
149
scripts/qapi.py
|
@ -56,9 +56,6 @@ returns_whitelist = [
|
||||||
'guest-set-vcpus',
|
'guest-set-vcpus',
|
||||||
'guest-sync',
|
'guest-sync',
|
||||||
'guest-sync-delimited',
|
'guest-sync-delimited',
|
||||||
|
|
||||||
# From qapi-schema-test:
|
|
||||||
'user_def_cmd3',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
enum_types = []
|
enum_types = []
|
||||||
|
@ -103,6 +100,7 @@ class QAPISchemaError(Exception):
|
||||||
class QAPIExprError(Exception):
|
class QAPIExprError(Exception):
|
||||||
def __init__(self, expr_info, msg):
|
def __init__(self, expr_info, msg):
|
||||||
Exception.__init__(self)
|
Exception.__init__(self)
|
||||||
|
assert expr_info
|
||||||
self.info = expr_info
|
self.info = expr_info
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|
||||||
|
@ -792,6 +790,11 @@ class QAPISchemaEntity(object):
|
||||||
def __init__(self, name, info):
|
def __init__(self, name, info):
|
||||||
assert isinstance(name, str)
|
assert isinstance(name, str)
|
||||||
self.name = name
|
self.name = name
|
||||||
|
# For explicitly defined entities, info points to the (explicit)
|
||||||
|
# definition. For builtins (and their arrays), info is None.
|
||||||
|
# For implicitly defined entities, info points to a place that
|
||||||
|
# triggered the implicit definition (there may be more than one
|
||||||
|
# such place).
|
||||||
self.info = info
|
self.info = info
|
||||||
|
|
||||||
def c_name(self):
|
def c_name(self):
|
||||||
|
@ -800,6 +803,9 @@ class QAPISchemaEntity(object):
|
||||||
def check(self, schema):
|
def check(self, schema):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def is_implicit(self):
|
||||||
|
return not self.info
|
||||||
|
|
||||||
def visit(self, visitor):
|
def visit(self, visitor):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -811,6 +817,10 @@ class QAPISchemaVisitor(object):
|
||||||
def visit_end(self):
|
def visit_end(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def visit_needed(self, entity):
|
||||||
|
# Default to visiting everything
|
||||||
|
return True
|
||||||
|
|
||||||
def visit_builtin_type(self, name, info, json_type):
|
def visit_builtin_type(self, name, info, json_type):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -898,6 +908,10 @@ class QAPISchemaEnumType(QAPISchemaType):
|
||||||
def check(self, schema):
|
def check(self, schema):
|
||||||
assert len(set(self.values)) == len(self.values)
|
assert len(set(self.values)) == len(self.values)
|
||||||
|
|
||||||
|
def is_implicit(self):
|
||||||
|
# See QAPISchema._make_implicit_enum_type()
|
||||||
|
return self.name[-4:] == 'Kind'
|
||||||
|
|
||||||
def c_type(self, is_param=False):
|
def c_type(self, is_param=False):
|
||||||
return c_name(self.name)
|
return c_name(self.name)
|
||||||
|
|
||||||
|
@ -924,6 +938,9 @@ class QAPISchemaArrayType(QAPISchemaType):
|
||||||
self.element_type = schema.lookup_type(self._element_type_name)
|
self.element_type = schema.lookup_type(self._element_type_name)
|
||||||
assert self.element_type
|
assert self.element_type
|
||||||
|
|
||||||
|
def is_implicit(self):
|
||||||
|
return True
|
||||||
|
|
||||||
def json_type(self):
|
def json_type(self):
|
||||||
return 'array'
|
return 'array'
|
||||||
|
|
||||||
|
@ -960,6 +977,7 @@ class QAPISchemaObjectType(QAPISchemaType):
|
||||||
members = []
|
members = []
|
||||||
seen = {}
|
seen = {}
|
||||||
for m in members:
|
for m in members:
|
||||||
|
assert c_name(m.name) not in seen
|
||||||
seen[m.name] = m
|
seen[m.name] = m
|
||||||
for m in self.local_members:
|
for m in self.local_members:
|
||||||
m.check(schema, members, seen)
|
m.check(schema, members, seen)
|
||||||
|
@ -967,12 +985,16 @@ class QAPISchemaObjectType(QAPISchemaType):
|
||||||
self.variants.check(schema, members, seen)
|
self.variants.check(schema, members, seen)
|
||||||
self.members = members
|
self.members = members
|
||||||
|
|
||||||
|
def is_implicit(self):
|
||||||
|
# See QAPISchema._make_implicit_object_type()
|
||||||
|
return self.name[0] == ':'
|
||||||
|
|
||||||
def c_name(self):
|
def c_name(self):
|
||||||
assert self.info
|
assert not self.is_implicit()
|
||||||
return QAPISchemaType.c_name(self)
|
return QAPISchemaType.c_name(self)
|
||||||
|
|
||||||
def c_type(self, is_param=False):
|
def c_type(self, is_param=False):
|
||||||
assert self.info
|
assert not self.is_implicit()
|
||||||
return QAPISchemaType.c_type(self)
|
return QAPISchemaType.c_type(self)
|
||||||
|
|
||||||
def json_type(self):
|
def json_type(self):
|
||||||
|
@ -1004,18 +1026,18 @@ class QAPISchemaObjectTypeMember(object):
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaObjectTypeVariants(object):
|
class QAPISchemaObjectTypeVariants(object):
|
||||||
def __init__(self, tag_name, tag_enum, variants):
|
def __init__(self, tag_name, tag_member, variants):
|
||||||
assert tag_name is None or isinstance(tag_name, str)
|
# Flat unions pass tag_name but not tag_member.
|
||||||
assert tag_enum is None or isinstance(tag_enum, str)
|
# Simple unions and alternates pass tag_member but not tag_name.
|
||||||
|
# After check(), tag_member is always set, and tag_name remains
|
||||||
|
# a reliable witness of being used by a flat union.
|
||||||
|
assert bool(tag_member) != bool(tag_name)
|
||||||
|
assert (isinstance(tag_name, str) or
|
||||||
|
isinstance(tag_member, QAPISchemaObjectTypeMember))
|
||||||
for v in variants:
|
for v in variants:
|
||||||
assert isinstance(v, QAPISchemaObjectTypeVariant)
|
assert isinstance(v, QAPISchemaObjectTypeVariant)
|
||||||
self.tag_name = tag_name
|
self.tag_name = tag_name
|
||||||
if tag_name:
|
self.tag_member = tag_member
|
||||||
assert not tag_enum
|
|
||||||
self.tag_member = None
|
|
||||||
else:
|
|
||||||
self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
|
|
||||||
False)
|
|
||||||
self.variants = variants
|
self.variants = variants
|
||||||
|
|
||||||
def check(self, schema, members, seen):
|
def check(self, schema, members, seen):
|
||||||
|
@ -1040,7 +1062,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
|
||||||
# This function exists to support ugly simple union special cases
|
# This function exists to support ugly simple union special cases
|
||||||
# TODO get rid of them, and drop the function
|
# TODO get rid of them, and drop the function
|
||||||
def simple_union_type(self):
|
def simple_union_type(self):
|
||||||
if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
|
if (self.type.is_implicit() and
|
||||||
|
isinstance(self.type, QAPISchemaObjectType)):
|
||||||
assert len(self.type.members) == 1
|
assert len(self.type.members) == 1
|
||||||
assert not self.type.variants
|
assert not self.type.variants
|
||||||
return self.type.members[0].type
|
return self.type.members[0].type
|
||||||
|
@ -1112,15 +1135,19 @@ class QAPISchema(object):
|
||||||
def __init__(self, fname):
|
def __init__(self, fname):
|
||||||
try:
|
try:
|
||||||
self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
|
self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
|
||||||
|
self._entity_dict = {}
|
||||||
|
self._predefining = True
|
||||||
|
self._def_predefineds()
|
||||||
|
self._predefining = False
|
||||||
|
self._def_exprs()
|
||||||
|
self.check()
|
||||||
except (QAPISchemaError, QAPIExprError), err:
|
except (QAPISchemaError, QAPIExprError), err:
|
||||||
print >>sys.stderr, err
|
print >>sys.stderr, err
|
||||||
exit(1)
|
exit(1)
|
||||||
self._entity_dict = {}
|
|
||||||
self._def_predefineds()
|
|
||||||
self._def_exprs()
|
|
||||||
self.check()
|
|
||||||
|
|
||||||
def _def_entity(self, ent):
|
def _def_entity(self, ent):
|
||||||
|
# Only the predefined types are allowed to not have info
|
||||||
|
assert ent.info or self._predefining
|
||||||
assert ent.name not in self._entity_dict
|
assert ent.name not in self._entity_dict
|
||||||
self._entity_dict[ent.name] = ent
|
self._entity_dict[ent.name] = ent
|
||||||
|
|
||||||
|
@ -1136,7 +1163,12 @@ class QAPISchema(object):
|
||||||
def _def_builtin_type(self, name, json_type, c_type, c_null):
|
def _def_builtin_type(self, name, json_type, c_type, c_null):
|
||||||
self._def_entity(QAPISchemaBuiltinType(name, json_type,
|
self._def_entity(QAPISchemaBuiltinType(name, json_type,
|
||||||
c_type, c_null))
|
c_type, c_null))
|
||||||
self._make_array_type(name) # TODO really needed?
|
# TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
|
||||||
|
# qapi-types.h from a single .c, all arrays of builtins must be
|
||||||
|
# declared in the first file whether or not they are used. Nicer
|
||||||
|
# would be to use lazy instantiation, while figuring out how to
|
||||||
|
# avoid compilation issues with multiple qapi-types.h.
|
||||||
|
self._make_array_type(name, None)
|
||||||
|
|
||||||
def _def_predefineds(self):
|
def _def_predefineds(self):
|
||||||
for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
|
for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
|
||||||
|
@ -1158,23 +1190,25 @@ class QAPISchema(object):
|
||||||
[], None)
|
[], None)
|
||||||
self._def_entity(self.the_empty_object_type)
|
self._def_entity(self.the_empty_object_type)
|
||||||
|
|
||||||
def _make_implicit_enum_type(self, name, values):
|
def _make_implicit_enum_type(self, name, info, values):
|
||||||
name = name + 'Kind'
|
name = name + 'Kind' # Use namespace reserved by add_name()
|
||||||
self._def_entity(QAPISchemaEnumType(name, None, values, None))
|
self._def_entity(QAPISchemaEnumType(name, info, values, None))
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def _make_array_type(self, element_type):
|
def _make_array_type(self, element_type, info):
|
||||||
|
# TODO fooList namespace is not reserved; user can create collisions,
|
||||||
|
# or abuse our type system with ['fooList'] for 2D array
|
||||||
name = element_type + 'List'
|
name = element_type + 'List'
|
||||||
if not self.lookup_type(name):
|
if not self.lookup_type(name):
|
||||||
self._def_entity(QAPISchemaArrayType(name, None, element_type))
|
self._def_entity(QAPISchemaArrayType(name, info, element_type))
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def _make_implicit_object_type(self, name, role, members):
|
def _make_implicit_object_type(self, name, info, role, members):
|
||||||
if not members:
|
if not members:
|
||||||
return None
|
return None
|
||||||
name = ':obj-%s-%s' % (name, role)
|
name = ':obj-%s-%s' % (name, role)
|
||||||
if not self.lookup_entity(name, QAPISchemaObjectType):
|
if not self.lookup_entity(name, QAPISchemaObjectType):
|
||||||
self._def_entity(QAPISchemaObjectType(name, None, None,
|
self._def_entity(QAPISchemaObjectType(name, info, None,
|
||||||
members, None))
|
members, None))
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
@ -1183,20 +1217,19 @@ class QAPISchema(object):
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
prefix = expr.get('prefix')
|
prefix = expr.get('prefix')
|
||||||
self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
|
self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
|
||||||
self._make_array_type(name) # TODO really needed?
|
|
||||||
|
|
||||||
def _make_member(self, name, typ):
|
def _make_member(self, name, typ, info):
|
||||||
optional = False
|
optional = False
|
||||||
if name.startswith('*'):
|
if name.startswith('*'):
|
||||||
name = name[1:]
|
name = name[1:]
|
||||||
optional = True
|
optional = True
|
||||||
if isinstance(typ, list):
|
if isinstance(typ, list):
|
||||||
assert len(typ) == 1
|
assert len(typ) == 1
|
||||||
typ = self._make_array_type(typ[0])
|
typ = self._make_array_type(typ[0], info)
|
||||||
return QAPISchemaObjectTypeMember(name, typ, optional)
|
return QAPISchemaObjectTypeMember(name, typ, optional)
|
||||||
|
|
||||||
def _make_members(self, data):
|
def _make_members(self, data, info):
|
||||||
return [self._make_member(key, value)
|
return [self._make_member(key, value, info)
|
||||||
for (key, value) in data.iteritems()]
|
for (key, value) in data.iteritems()]
|
||||||
|
|
||||||
def _def_struct_type(self, expr, info):
|
def _def_struct_type(self, expr, info):
|
||||||
|
@ -1204,58 +1237,56 @@ class QAPISchema(object):
|
||||||
base = expr.get('base')
|
base = expr.get('base')
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
self._def_entity(QAPISchemaObjectType(name, info, base,
|
self._def_entity(QAPISchemaObjectType(name, info, base,
|
||||||
self._make_members(data),
|
self._make_members(data, info),
|
||||||
None))
|
None))
|
||||||
self._make_array_type(name) # TODO really needed?
|
|
||||||
|
|
||||||
def _make_variant(self, case, typ):
|
def _make_variant(self, case, typ):
|
||||||
return QAPISchemaObjectTypeVariant(case, typ)
|
return QAPISchemaObjectTypeVariant(case, typ)
|
||||||
|
|
||||||
def _make_simple_variant(self, case, typ):
|
def _make_simple_variant(self, case, typ, info):
|
||||||
if isinstance(typ, list):
|
if isinstance(typ, list):
|
||||||
assert len(typ) == 1
|
assert len(typ) == 1
|
||||||
typ = self._make_array_type(typ[0])
|
typ = self._make_array_type(typ[0], info)
|
||||||
typ = self._make_implicit_object_type(typ, 'wrapper',
|
typ = self._make_implicit_object_type(
|
||||||
[self._make_member('data', typ)])
|
typ, info, 'wrapper', [self._make_member('data', typ, info)])
|
||||||
return QAPISchemaObjectTypeVariant(case, typ)
|
return QAPISchemaObjectTypeVariant(case, typ)
|
||||||
|
|
||||||
def _make_tag_enum(self, type_name, variants):
|
def _make_implicit_tag(self, type_name, info, variants):
|
||||||
return self._make_implicit_enum_type(type_name,
|
typ = self._make_implicit_enum_type(type_name, info,
|
||||||
[v.name for v in variants])
|
[v.name for v in variants])
|
||||||
|
return QAPISchemaObjectTypeMember('type', typ, False)
|
||||||
|
|
||||||
def _def_union_type(self, expr, info):
|
def _def_union_type(self, expr, info):
|
||||||
name = expr['union']
|
name = expr['union']
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
base = expr.get('base')
|
base = expr.get('base')
|
||||||
tag_name = expr.get('discriminator')
|
tag_name = expr.get('discriminator')
|
||||||
tag_enum = None
|
tag_member = None
|
||||||
if tag_name:
|
if tag_name:
|
||||||
variants = [self._make_variant(key, value)
|
variants = [self._make_variant(key, value)
|
||||||
for (key, value) in data.iteritems()]
|
for (key, value) in data.iteritems()]
|
||||||
else:
|
else:
|
||||||
variants = [self._make_simple_variant(key, value)
|
variants = [self._make_simple_variant(key, value, info)
|
||||||
for (key, value) in data.iteritems()]
|
for (key, value) in data.iteritems()]
|
||||||
tag_enum = self._make_tag_enum(name, variants)
|
tag_member = self._make_implicit_tag(name, info, variants)
|
||||||
self._def_entity(
|
self._def_entity(
|
||||||
QAPISchemaObjectType(name, info, base,
|
QAPISchemaObjectType(name, info, base,
|
||||||
self._make_members(OrderedDict()),
|
self._make_members(OrderedDict(), info),
|
||||||
QAPISchemaObjectTypeVariants(tag_name,
|
QAPISchemaObjectTypeVariants(tag_name,
|
||||||
tag_enum,
|
tag_member,
|
||||||
variants)))
|
variants)))
|
||||||
self._make_array_type(name) # TODO really needed?
|
|
||||||
|
|
||||||
def _def_alternate_type(self, expr, info):
|
def _def_alternate_type(self, expr, info):
|
||||||
name = expr['alternate']
|
name = expr['alternate']
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
variants = [self._make_variant(key, value)
|
variants = [self._make_variant(key, value)
|
||||||
for (key, value) in data.iteritems()]
|
for (key, value) in data.iteritems()]
|
||||||
tag_enum = self._make_tag_enum(name, variants)
|
tag_member = self._make_implicit_tag(name, info, variants)
|
||||||
self._def_entity(
|
self._def_entity(
|
||||||
QAPISchemaAlternateType(name, info,
|
QAPISchemaAlternateType(name, info,
|
||||||
QAPISchemaObjectTypeVariants(None,
|
QAPISchemaObjectTypeVariants(None,
|
||||||
tag_enum,
|
tag_member,
|
||||||
variants)))
|
variants)))
|
||||||
self._make_array_type(name) # TODO really needed?
|
|
||||||
|
|
||||||
def _def_command(self, expr, info):
|
def _def_command(self, expr, info):
|
||||||
name = expr['command']
|
name = expr['command']
|
||||||
|
@ -1264,11 +1295,11 @@ class QAPISchema(object):
|
||||||
gen = expr.get('gen', True)
|
gen = expr.get('gen', True)
|
||||||
success_response = expr.get('success-response', True)
|
success_response = expr.get('success-response', True)
|
||||||
if isinstance(data, OrderedDict):
|
if isinstance(data, OrderedDict):
|
||||||
data = self._make_implicit_object_type(name, 'arg',
|
data = self._make_implicit_object_type(
|
||||||
self._make_members(data))
|
name, info, 'arg', self._make_members(data, info))
|
||||||
if isinstance(rets, list):
|
if isinstance(rets, list):
|
||||||
assert len(rets) == 1
|
assert len(rets) == 1
|
||||||
rets = self._make_array_type(rets[0])
|
rets = self._make_array_type(rets[0], info)
|
||||||
self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
|
self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
|
||||||
success_response))
|
success_response))
|
||||||
|
|
||||||
|
@ -1276,8 +1307,8 @@ class QAPISchema(object):
|
||||||
name = expr['event']
|
name = expr['event']
|
||||||
data = expr.get('data')
|
data = expr.get('data')
|
||||||
if isinstance(data, OrderedDict):
|
if isinstance(data, OrderedDict):
|
||||||
data = self._make_implicit_object_type(name, 'arg',
|
data = self._make_implicit_object_type(
|
||||||
self._make_members(data))
|
name, info, 'arg', self._make_members(data, info))
|
||||||
self._def_entity(QAPISchemaEvent(name, info, data))
|
self._def_entity(QAPISchemaEvent(name, info, data))
|
||||||
|
|
||||||
def _def_exprs(self):
|
def _def_exprs(self):
|
||||||
|
@ -1304,10 +1335,10 @@ class QAPISchema(object):
|
||||||
ent.check(self)
|
ent.check(self)
|
||||||
|
|
||||||
def visit(self, visitor):
|
def visit(self, visitor):
|
||||||
ignore = visitor.visit_begin(self)
|
visitor.visit_begin(self)
|
||||||
for name in sorted(self._entity_dict.keys()):
|
for (name, entity) in sorted(self._entity_dict.items()):
|
||||||
if not ignore or not isinstance(self._entity_dict[name], ignore):
|
if visitor.visit_needed(entity):
|
||||||
self._entity_dict[name].visit(visitor)
|
entity.visit(visitor)
|
||||||
visitor.visit_end()
|
visitor.visit_end()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,6 @@ qapi-schema += alternate-clash.json
|
||||||
qapi-schema += alternate-conflict-dict.json
|
qapi-schema += alternate-conflict-dict.json
|
||||||
qapi-schema += alternate-conflict-string.json
|
qapi-schema += alternate-conflict-string.json
|
||||||
qapi-schema += alternate-empty.json
|
qapi-schema += alternate-empty.json
|
||||||
qapi-schema += alternate-good.json
|
|
||||||
qapi-schema += alternate-nested.json
|
qapi-schema += alternate-nested.json
|
||||||
qapi-schema += alternate-unknown.json
|
qapi-schema += alternate-unknown.json
|
||||||
qapi-schema += args-alternate.json
|
qapi-schema += args-alternate.json
|
||||||
|
@ -240,7 +239,6 @@ qapi-schema += args-array-unknown.json
|
||||||
qapi-schema += args-int.json
|
qapi-schema += args-int.json
|
||||||
qapi-schema += args-invalid.json
|
qapi-schema += args-invalid.json
|
||||||
qapi-schema += args-member-array-bad.json
|
qapi-schema += args-member-array-bad.json
|
||||||
qapi-schema += args-member-array.json
|
|
||||||
qapi-schema += args-member-unknown.json
|
qapi-schema += args-member-unknown.json
|
||||||
qapi-schema += args-name-clash.json
|
qapi-schema += args-name-clash.json
|
||||||
qapi-schema += args-union.json
|
qapi-schema += args-union.json
|
||||||
|
@ -261,7 +259,6 @@ qapi-schema += enum-bad-name.json
|
||||||
qapi-schema += enum-bad-prefix.json
|
qapi-schema += enum-bad-prefix.json
|
||||||
qapi-schema += enum-clash-member.json
|
qapi-schema += enum-clash-member.json
|
||||||
qapi-schema += enum-dict-member.json
|
qapi-schema += enum-dict-member.json
|
||||||
qapi-schema += enum-empty.json
|
|
||||||
qapi-schema += enum-int-member.json
|
qapi-schema += enum-int-member.json
|
||||||
qapi-schema += enum-max-member.json
|
qapi-schema += enum-max-member.json
|
||||||
qapi-schema += enum-missing-data.json
|
qapi-schema += enum-missing-data.json
|
||||||
|
@ -288,7 +285,6 @@ qapi-schema += flat-union-invalid-branch-key.json
|
||||||
qapi-schema += flat-union-invalid-discriminator.json
|
qapi-schema += flat-union-invalid-discriminator.json
|
||||||
qapi-schema += flat-union-no-base.json
|
qapi-schema += flat-union-no-base.json
|
||||||
qapi-schema += flat-union-optional-discriminator.json
|
qapi-schema += flat-union-optional-discriminator.json
|
||||||
qapi-schema += flat-union-reverse-define.json
|
|
||||||
qapi-schema += flat-union-string-discriminator.json
|
qapi-schema += flat-union-string-discriminator.json
|
||||||
qapi-schema += funny-char.json
|
qapi-schema += funny-char.json
|
||||||
qapi-schema += ident-with-escape.json
|
qapi-schema += ident-with-escape.json
|
||||||
|
@ -320,7 +316,6 @@ qapi-schema += redefined-type.json
|
||||||
qapi-schema += returns-alternate.json
|
qapi-schema += returns-alternate.json
|
||||||
qapi-schema += returns-array-bad.json
|
qapi-schema += returns-array-bad.json
|
||||||
qapi-schema += returns-dict.json
|
qapi-schema += returns-dict.json
|
||||||
qapi-schema += returns-int.json
|
|
||||||
qapi-schema += returns-unknown.json
|
qapi-schema += returns-unknown.json
|
||||||
qapi-schema += returns-whitelist.json
|
qapi-schema += returns-whitelist.json
|
||||||
qapi-schema += struct-base-clash-base.json
|
qapi-schema += struct-base-clash-base.json
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
0
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Working example of alternate
|
|
||||||
{ 'struct': 'Data',
|
|
||||||
'data': { '*number': 'int', '*name': 'str' } }
|
|
||||||
{ 'enum': 'Enum',
|
|
||||||
'data': [ 'hello', 'world' ] }
|
|
||||||
{ 'alternate': 'Alt',
|
|
||||||
'data': { 'value': 'int',
|
|
||||||
'string': 'Enum',
|
|
||||||
'struct': 'Data' } }
|
|
|
@ -1,10 +0,0 @@
|
||||||
object :empty
|
|
||||||
alternate Alt
|
|
||||||
case value: int
|
|
||||||
case string: Enum
|
|
||||||
case struct: Data
|
|
||||||
enum AltKind ['value', 'string', 'struct']
|
|
||||||
object Data
|
|
||||||
member number: int optional=True
|
|
||||||
member name: str optional=True
|
|
||||||
enum Enum ['hello', 'world']
|
|
|
@ -1 +0,0 @@
|
||||||
0
|
|
|
@ -1,4 +0,0 @@
|
||||||
# valid array members
|
|
||||||
{ 'enum': 'abc', 'data': [ 'a', 'b', 'c' ] }
|
|
||||||
{ 'struct': 'def', 'data': { 'array': [ 'abc' ] } }
|
|
||||||
{ 'command': 'okay', 'data': { 'member1': [ 'int' ], 'member2': [ 'def' ] } }
|
|
|
@ -1,9 +0,0 @@
|
||||||
object :empty
|
|
||||||
object :obj-okay-arg
|
|
||||||
member member1: intList optional=False
|
|
||||||
member member2: defList optional=False
|
|
||||||
enum abc ['a', 'b', 'c']
|
|
||||||
object def
|
|
||||||
member array: abcList optional=False
|
|
||||||
command okay :obj-okay-arg -> None
|
|
||||||
gen=True success_response=True
|
|
|
@ -1 +0,0 @@
|
||||||
0
|
|
|
@ -1,2 +0,0 @@
|
||||||
# An empty enum, although unusual, is currently acceptable
|
|
||||||
{ 'enum': 'MyEnum', 'data': [ ] }
|
|
|
@ -1,2 +0,0 @@
|
||||||
object :empty
|
|
||||||
enum MyEnum []
|
|
|
@ -1 +0,0 @@
|
||||||
0
|
|
|
@ -1,17 +0,0 @@
|
||||||
{ 'union': 'TestUnion',
|
|
||||||
'base': 'TestBase',
|
|
||||||
'discriminator': 'enum1',
|
|
||||||
'data': { 'value1': 'TestTypeA',
|
|
||||||
'value2': 'TestTypeB' } }
|
|
||||||
|
|
||||||
{ 'struct': 'TestBase',
|
|
||||||
'data': { 'enum1': 'TestEnum' } }
|
|
||||||
|
|
||||||
{ 'enum': 'TestEnum',
|
|
||||||
'data': [ 'value1', 'value2' ] }
|
|
||||||
|
|
||||||
{ 'struct': 'TestTypeA',
|
|
||||||
'data': { 'string': 'str' } }
|
|
||||||
|
|
||||||
{ 'struct': 'TestTypeB',
|
|
||||||
'data': { 'integer': 'int' } }
|
|
|
@ -1,13 +0,0 @@
|
||||||
object :empty
|
|
||||||
object TestBase
|
|
||||||
member enum1: TestEnum optional=False
|
|
||||||
enum TestEnum ['value1', 'value2']
|
|
||||||
object TestTypeA
|
|
||||||
member string: str optional=False
|
|
||||||
object TestTypeB
|
|
||||||
member integer: int optional=False
|
|
||||||
object TestUnion
|
|
||||||
base TestBase
|
|
||||||
tag enum1
|
|
||||||
case value1: TestTypeA
|
|
||||||
case value2: TestTypeB
|
|
|
@ -1,10 +1,15 @@
|
||||||
# *-*- Mode: Python -*-*
|
# *-*- Mode: Python -*-*
|
||||||
|
|
||||||
|
# This file is a stress test of supported qapi constructs that must
|
||||||
|
# parse and compile correctly.
|
||||||
|
|
||||||
# for testing enums
|
# for testing enums
|
||||||
{ 'enum': 'EnumOne',
|
|
||||||
'data': [ 'value1', 'value2', 'value3' ] }
|
|
||||||
{ 'struct': 'NestedEnumsOne',
|
{ 'struct': 'NestedEnumsOne',
|
||||||
'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
|
'data': { 'enum1': 'EnumOne', # Intentional forward reference
|
||||||
|
'*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
|
||||||
|
|
||||||
|
# An empty enum, although unusual, is currently acceptable
|
||||||
|
{ 'enum': 'MyEnum', 'data': [ ] }
|
||||||
|
|
||||||
# for testing override of default naming heuristic
|
# for testing override of default naming heuristic
|
||||||
{ 'enum': 'QEnumTwo',
|
{ 'enum': 'QEnumTwo',
|
||||||
|
@ -14,7 +19,11 @@
|
||||||
# for testing nested structs
|
# for testing nested structs
|
||||||
{ 'struct': 'UserDefOne',
|
{ 'struct': 'UserDefOne',
|
||||||
'base': 'UserDefZero', # intentional forward reference
|
'base': 'UserDefZero', # intentional forward reference
|
||||||
'data': { 'string': 'str', '*enum1': 'EnumOne' } }
|
'data': { 'string': 'str',
|
||||||
|
'*enum1': 'EnumOne' } } # intentional forward reference
|
||||||
|
|
||||||
|
{ 'enum': 'EnumOne',
|
||||||
|
'data': [ 'value1', 'value2', 'value3' ] }
|
||||||
|
|
||||||
{ 'struct': 'UserDefZero',
|
{ 'struct': 'UserDefZero',
|
||||||
'data': { 'integer': 'int' } }
|
'data': { 'integer': 'int' } }
|
||||||
|
@ -31,6 +40,10 @@
|
||||||
'data': { 'string0': 'str',
|
'data': { 'string0': 'str',
|
||||||
'dict1': 'UserDefTwoDict' } }
|
'dict1': 'UserDefTwoDict' } }
|
||||||
|
|
||||||
|
# dummy struct to force generation of array types not otherwise mentioned
|
||||||
|
{ 'struct': 'ForceArrays',
|
||||||
|
'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'] } }
|
||||||
|
|
||||||
# for testing unions
|
# for testing unions
|
||||||
# Among other things, test that a name collision between branches does
|
# Among other things, test that a name collision between branches does
|
||||||
# not cause any problems (since only one branch can be in use at a time),
|
# not cause any problems (since only one branch can be in use at a time),
|
||||||
|
@ -98,9 +111,10 @@
|
||||||
{ 'command': 'user_def_cmd2',
|
{ 'command': 'user_def_cmd2',
|
||||||
'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
|
'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
|
||||||
'returns': 'UserDefTwo' }
|
'returns': 'UserDefTwo' }
|
||||||
{ 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' },
|
|
||||||
|
# Returning a non-dictionary requires a name from the whitelist
|
||||||
|
{ 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' },
|
||||||
'returns': 'int' }
|
'returns': 'int' }
|
||||||
# note: command name 'guest-sync' chosen to avoid "cannot use built-in" error
|
|
||||||
{ 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
|
{ 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
|
||||||
|
|
||||||
# For testing integer range flattening in opts-visitor. The following schema
|
# For testing integer range flattening in opts-visitor. The following schema
|
||||||
|
|
|
@ -17,6 +17,9 @@ object :obj-anyList-wrapper
|
||||||
member data: anyList optional=False
|
member data: anyList optional=False
|
||||||
object :obj-boolList-wrapper
|
object :obj-boolList-wrapper
|
||||||
member data: boolList optional=False
|
member data: boolList optional=False
|
||||||
|
object :obj-guest-get-time-arg
|
||||||
|
member a: int optional=False
|
||||||
|
member b: int optional=True
|
||||||
object :obj-guest-sync-arg
|
object :obj-guest-sync-arg
|
||||||
member arg: any optional=False
|
member arg: any optional=False
|
||||||
object :obj-int16List-wrapper
|
object :obj-int16List-wrapper
|
||||||
|
@ -50,9 +53,6 @@ object :obj-user_def_cmd1-arg
|
||||||
object :obj-user_def_cmd2-arg
|
object :obj-user_def_cmd2-arg
|
||||||
member ud1a: UserDefOne optional=False
|
member ud1a: UserDefOne optional=False
|
||||||
member ud1b: UserDefOne optional=True
|
member ud1b: UserDefOne optional=True
|
||||||
object :obj-user_def_cmd3-arg
|
|
||||||
member a: int optional=False
|
|
||||||
member b: int optional=True
|
|
||||||
alternate AltIntNum
|
alternate AltIntNum
|
||||||
case i: int
|
case i: int
|
||||||
case n: number
|
case n: number
|
||||||
|
@ -86,6 +86,10 @@ object EventStructOne
|
||||||
member struct1: UserDefOne optional=False
|
member struct1: UserDefOne optional=False
|
||||||
member string: str optional=False
|
member string: str optional=False
|
||||||
member enum2: EnumOne optional=True
|
member enum2: EnumOne optional=True
|
||||||
|
object ForceArrays
|
||||||
|
member unused1: UserDefOneList optional=False
|
||||||
|
member unused2: UserDefTwoList optional=False
|
||||||
|
enum MyEnum []
|
||||||
object NestedEnumsOne
|
object NestedEnumsOne
|
||||||
member enum1: EnumOne optional=False
|
member enum1: EnumOne optional=False
|
||||||
member enum2: EnumOne optional=True
|
member enum2: EnumOne optional=True
|
||||||
|
@ -183,6 +187,8 @@ object __org.qemu_x-Union2
|
||||||
case __org.qemu_x-value: __org.qemu_x-Struct2
|
case __org.qemu_x-value: __org.qemu_x-Struct2
|
||||||
command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
|
command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
|
||||||
gen=True success_response=True
|
gen=True success_response=True
|
||||||
|
command guest-get-time :obj-guest-get-time-arg -> int
|
||||||
|
gen=True success_response=True
|
||||||
command guest-sync :obj-guest-sync-arg -> any
|
command guest-sync :obj-guest-sync-arg -> any
|
||||||
gen=True success_response=True
|
gen=True success_response=True
|
||||||
command user_def_cmd None -> None
|
command user_def_cmd None -> None
|
||||||
|
@ -191,5 +197,3 @@ command user_def_cmd1 :obj-user_def_cmd1-arg -> None
|
||||||
gen=True success_response=True
|
gen=True success_response=True
|
||||||
command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
|
command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
|
||||||
gen=True success_response=True
|
gen=True success_response=True
|
||||||
command user_def_cmd3 :obj-user_def_cmd3-arg -> int
|
|
||||||
gen=True success_response=True
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
0
|
|
|
@ -1,3 +0,0 @@
|
||||||
# It is okay (although not extensible) to return a non-dictionary
|
|
||||||
# But to make it work, the name must be in a whitelist
|
|
||||||
{ 'command': 'guest-get-time', 'returns': 'int' }
|
|
|
@ -1,3 +0,0 @@
|
||||||
object :empty
|
|
||||||
command guest-get-time None -> int
|
|
||||||
gen=True success_response=True
|
|
|
@ -46,7 +46,7 @@ UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp)
|
int64_t qmp_guest_get_time(int64_t a, bool has_b, int64_t b, Error **errp)
|
||||||
{
|
{
|
||||||
return a + (has_b ? b : 0);
|
return a + (has_b ? b : 0);
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ static void test_dispatch_cmd_io(void)
|
||||||
|
|
||||||
qdict_put(args3, "a", qint_from_int(66));
|
qdict_put(args3, "a", qint_from_int(66));
|
||||||
qdict_put(req, "arguments", args3);
|
qdict_put(req, "arguments", args3);
|
||||||
qdict_put(req, "execute", qstring_from_str("user_def_cmd3"));
|
qdict_put(req, "execute", qstring_from_str("guest-get-time"));
|
||||||
|
|
||||||
ret3 = qobject_to_qint(test_qmp_dispatch(req));
|
ret3 = qobject_to_qint(test_qmp_dispatch(req));
|
||||||
assert(qint_get_int(ret3) == 66);
|
assert(qint_get_int(ret3) == 66);
|
||||||
|
|
Loading…
Reference in New Issue