mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-10-20 14:58:16 +02:00
qapi: Segregate anonymous unions into alternates in generator
Special-casing 'discriminator == {}' for handling anonymous unions is getting awkward; since this particular type is not always a dictionary on the wire, it is easier to treat it as a completely different class of type, "alternate", so that if a type is listed in the union_types array, we know it is not an anonymous union. This patch just further segregates union handling, to make sure that anonymous unions are not stored in union_types, and splitting up check_union() into separate functions. A future patch will change the qapi grammar, and having the segregation already in place will make it easier to deal with the distinct meta-type. Backports commit 811d04fd0cff1229480d3f5b2e349f646ab6e3c1 from qemu
This commit is contained in:
parent
9e87ec4b54
commit
8a6303f9cd
@ -159,7 +159,7 @@ typedef enum %(name)s
|
|||||||
|
|
||||||
return lookup_decl + enum_decl
|
return lookup_decl + enum_decl
|
||||||
|
|
||||||
def generate_anon_union_qtypes(expr):
|
def generate_alternate_qtypes(expr):
|
||||||
|
|
||||||
name = expr['union']
|
name = expr['union']
|
||||||
members = expr['data']
|
members = expr['data']
|
||||||
@ -170,7 +170,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
|
|||||||
name=name)
|
name=name)
|
||||||
|
|
||||||
for key in members:
|
for key in members:
|
||||||
qtype = find_anonymous_member_qtype(members[key])
|
qtype = find_alternate_member_qtype(members[key])
|
||||||
assert qtype, "Invalid anonymous union member"
|
assert qtype, "Invalid anonymous union member"
|
||||||
|
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
@ -396,7 +396,7 @@ for expr in exprs:
|
|||||||
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
|
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
|
||||||
expr['data'].keys()))
|
expr['data'].keys()))
|
||||||
if expr.get('discriminator') == {}:
|
if expr.get('discriminator') == {}:
|
||||||
fdef.write(generate_anon_union_qtypes(expr))
|
fdef.write(generate_alternate_qtypes(expr))
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
fdecl.write(ret)
|
fdecl.write(ret)
|
||||||
|
@ -237,7 +237,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er
|
|||||||
''',
|
''',
|
||||||
name=name)
|
name=name)
|
||||||
|
|
||||||
def generate_visit_anon_union(name, members):
|
def generate_visit_alternate(name, members):
|
||||||
ret = mcgen('''
|
ret = mcgen('''
|
||||||
|
|
||||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
|
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
|
||||||
@ -302,7 +302,7 @@ def generate_visit_union(expr):
|
|||||||
|
|
||||||
if discriminator == {}:
|
if discriminator == {}:
|
||||||
assert not base
|
assert not base
|
||||||
return generate_visit_anon_union(name, members)
|
return generate_visit_alternate(name, members)
|
||||||
|
|
||||||
enum_define = discriminator_find_enum_define(expr)
|
enum_define = discriminator_find_enum_define(expr)
|
||||||
if enum_define:
|
if enum_define:
|
||||||
|
@ -224,21 +224,16 @@ def find_base_fields(base):
|
|||||||
return None
|
return None
|
||||||
return base_struct_define['data']
|
return base_struct_define['data']
|
||||||
|
|
||||||
# Return the qtype of an anonymous union branch, or None on error.
|
# Return the qtype of an alternate branch, or None on error.
|
||||||
def find_anonymous_member_qtype(qapi_type):
|
def find_alternate_member_qtype(qapi_type):
|
||||||
if builtin_types.has_key(qapi_type):
|
if builtin_types.has_key(qapi_type):
|
||||||
return builtin_types[qapi_type]
|
return builtin_types[qapi_type]
|
||||||
elif find_struct(qapi_type):
|
elif find_struct(qapi_type):
|
||||||
return "QTYPE_QDICT"
|
return "QTYPE_QDICT"
|
||||||
elif find_enum(qapi_type):
|
elif find_enum(qapi_type):
|
||||||
return "QTYPE_QSTRING"
|
return "QTYPE_QSTRING"
|
||||||
else:
|
elif find_union(qapi_type):
|
||||||
union = find_union(qapi_type)
|
return "QTYPE_QDICT"
|
||||||
if union:
|
|
||||||
discriminator = union.get('discriminator')
|
|
||||||
if discriminator == {}:
|
|
||||||
return None
|
|
||||||
return "QTYPE_QDICT"
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Return the discriminator enum define if discriminator is specified as an
|
# Return the discriminator enum define if discriminator is specified as an
|
||||||
@ -276,7 +271,6 @@ def check_union(expr, expr_info):
|
|||||||
discriminator = expr.get('discriminator')
|
discriminator = expr.get('discriminator')
|
||||||
members = expr['data']
|
members = expr['data']
|
||||||
values = { 'MAX': '(automatic)' }
|
values = { 'MAX': '(automatic)' }
|
||||||
types_seen = {}
|
|
||||||
|
|
||||||
# If the object has a member 'base', its value must name a complex type,
|
# If the object has a member 'base', its value must name a complex type,
|
||||||
# and there must be a discriminator.
|
# and there must be a discriminator.
|
||||||
@ -286,13 +280,15 @@ def check_union(expr, expr_info):
|
|||||||
"Union '%s' requires a discriminator to go "
|
"Union '%s' requires a discriminator to go "
|
||||||
"along with base" %name)
|
"along with base" %name)
|
||||||
|
|
||||||
# If the union object has no member 'discriminator', it's a
|
# Two types of unions, determined by discriminator.
|
||||||
# simple union. If 'discriminator' is {}, it is an anonymous union.
|
assert discriminator != {}
|
||||||
if discriminator is None or discriminator == {}:
|
|
||||||
|
# With no discriminator it is a simple union.
|
||||||
|
if discriminator is None:
|
||||||
enum_define = None
|
enum_define = None
|
||||||
if base is not None:
|
if base is not None:
|
||||||
raise QAPIExprError(expr_info,
|
raise QAPIExprError(expr_info,
|
||||||
"Union '%s' must not have a base"
|
"Simple union '%s' must not have a base"
|
||||||
% name)
|
% name)
|
||||||
|
|
||||||
# Else, it's a flat union.
|
# Else, it's a flat union.
|
||||||
@ -346,24 +342,46 @@ def check_union(expr, expr_info):
|
|||||||
% (name, key, values[c_key]))
|
% (name, key, values[c_key]))
|
||||||
values[c_key] = key
|
values[c_key] = key
|
||||||
|
|
||||||
# Ensure anonymous unions have no type conflicts.
|
def check_alternate(expr, expr_info):
|
||||||
if discriminator == {}:
|
name = expr['union']
|
||||||
if isinstance(value, list):
|
base = expr.get('base')
|
||||||
raise QAPIExprError(expr_info,
|
discriminator = expr.get('discriminator')
|
||||||
"Anonymous union '%s' member '%s' must "
|
members = expr['data']
|
||||||
"not be array type" % (name, key))
|
values = { 'MAX': '(automatic)' }
|
||||||
qtype = find_anonymous_member_qtype(value)
|
types_seen = {}
|
||||||
if not qtype:
|
|
||||||
raise QAPIExprError(expr_info,
|
|
||||||
"Anonymous union '%s' member '%s' has "
|
|
||||||
"invalid type '%s'" % (name, key, value))
|
|
||||||
if qtype in types_seen:
|
|
||||||
raise QAPIExprError(expr_info,
|
|
||||||
"Anonymous union '%s' member '%s' can't "
|
|
||||||
"be distinguished from member '%s'"
|
|
||||||
% (name, key, types_seen[qtype]))
|
|
||||||
types_seen[qtype] = key
|
|
||||||
|
|
||||||
|
assert discriminator == {}
|
||||||
|
if base is not None:
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Anonymous union '%s' must not have a base"
|
||||||
|
% name)
|
||||||
|
|
||||||
|
# Check every branch
|
||||||
|
for (key, value) in members.items():
|
||||||
|
# Check for conflicts in the generated enum
|
||||||
|
c_key = _generate_enum_string(key)
|
||||||
|
if c_key in values:
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Anonymous union '%s' member '%s' clashes "
|
||||||
|
"with '%s'" % (name, key, values[c_key]))
|
||||||
|
values[c_key] = key
|
||||||
|
|
||||||
|
# Ensure alternates have no type conflicts.
|
||||||
|
if isinstance(value, list):
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Anonymous union '%s' member '%s' must "
|
||||||
|
"not be array type" % (name, key))
|
||||||
|
qtype = find_alternate_member_qtype(value)
|
||||||
|
if not qtype:
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Anonymous union '%s' member '%s' has "
|
||||||
|
"invalid type '%s'" % (name, key, value))
|
||||||
|
if qtype in types_seen:
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Anonymous union '%s' member '%s' can't "
|
||||||
|
"be distinguished from member '%s'"
|
||||||
|
% (name, key, types_seen[qtype]))
|
||||||
|
types_seen[qtype] = key
|
||||||
|
|
||||||
def check_enum(expr, expr_info):
|
def check_enum(expr, expr_info):
|
||||||
name = expr['enum']
|
name = expr['enum']
|
||||||
@ -393,7 +411,10 @@ def check_exprs(schema):
|
|||||||
if expr.has_key('enum'):
|
if expr.has_key('enum'):
|
||||||
check_enum(expr, info)
|
check_enum(expr, info)
|
||||||
elif expr.has_key('union'):
|
elif expr.has_key('union'):
|
||||||
check_union(expr, info)
|
if expr.get('discriminator') == {}:
|
||||||
|
check_alternate(expr, info)
|
||||||
|
else:
|
||||||
|
check_union(expr, info)
|
||||||
elif expr.has_key('event'):
|
elif expr.has_key('event'):
|
||||||
check_event(expr, info)
|
check_event(expr, info)
|
||||||
|
|
||||||
@ -535,7 +556,8 @@ def find_struct(name):
|
|||||||
|
|
||||||
def add_union(definition):
|
def add_union(definition):
|
||||||
global union_types
|
global union_types
|
||||||
union_types.append(definition)
|
if definition.get('discriminator') != {}:
|
||||||
|
union_types.append(definition)
|
||||||
|
|
||||||
def find_union(name):
|
def find_union(name):
|
||||||
global union_types
|
global union_types
|
||||||
|
Loading…
Reference in New Issue
Block a user