mirror of https://gitee.com/openkylin/qemu.git
qapi: pass 'if' condition into QAPISchemaEntity objects
Built-in objects remain unconditional. Explicitly defined objects use the condition specified in the schema. Implicitly defined objects inherit their condition from their users. For most of them, there is exactly one user, so the condition to use is obvious. The exception is wrapped types generated for simple union variants, which can be shared by any number of simple unions. The tight condition would be the disjunction of the conditions of these simple unions. For now, use the wrapped type's condition instead. Much simpler and good enough for now. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20180703155648.11933-3-marcandre.lureau@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
parent
967c885108
commit
2cbc94376e
|
@ -1001,8 +1001,16 @@ def check_exprs(exprs):
|
|||
# Schema compiler frontend
|
||||
#
|
||||
|
||||
def listify_cond(ifcond):
|
||||
if not ifcond:
|
||||
return []
|
||||
if not isinstance(ifcond, list):
|
||||
return [ifcond]
|
||||
return ifcond
|
||||
|
||||
|
||||
class QAPISchemaEntity(object):
|
||||
def __init__(self, name, info, doc):
|
||||
def __init__(self, name, info, doc, ifcond=None):
|
||||
assert name is None or isinstance(name, str)
|
||||
self.name = name
|
||||
self.module = None
|
||||
|
@ -1013,6 +1021,7 @@ def __init__(self, name, info, doc):
|
|||
# such place).
|
||||
self.info = info
|
||||
self.doc = doc
|
||||
self.ifcond = listify_cond(ifcond)
|
||||
|
||||
def c_name(self):
|
||||
return c_name(self.name)
|
||||
|
@ -1145,8 +1154,8 @@ def visit(self, visitor):
|
|||
|
||||
|
||||
class QAPISchemaEnumType(QAPISchemaType):
|
||||
def __init__(self, name, info, doc, values, prefix):
|
||||
QAPISchemaType.__init__(self, name, info, doc)
|
||||
def __init__(self, name, info, doc, ifcond, values, prefix):
|
||||
QAPISchemaType.__init__(self, name, info, doc, ifcond)
|
||||
for v in values:
|
||||
assert isinstance(v, QAPISchemaMember)
|
||||
v.set_owner(name)
|
||||
|
@ -1181,7 +1190,7 @@ def visit(self, visitor):
|
|||
|
||||
class QAPISchemaArrayType(QAPISchemaType):
|
||||
def __init__(self, name, info, element_type):
|
||||
QAPISchemaType.__init__(self, name, info, None)
|
||||
QAPISchemaType.__init__(self, name, info, None, None)
|
||||
assert isinstance(element_type, str)
|
||||
self._element_type_name = element_type
|
||||
self.element_type = None
|
||||
|
@ -1189,6 +1198,7 @@ def __init__(self, name, info, element_type):
|
|||
def check(self, schema):
|
||||
self.element_type = schema.lookup_type(self._element_type_name)
|
||||
assert self.element_type
|
||||
self.ifcond = self.element_type.ifcond
|
||||
|
||||
def is_implicit(self):
|
||||
return True
|
||||
|
@ -1210,11 +1220,12 @@ def visit(self, visitor):
|
|||
|
||||
|
||||
class QAPISchemaObjectType(QAPISchemaType):
|
||||
def __init__(self, name, info, doc, base, local_members, variants):
|
||||
def __init__(self, name, info, doc, ifcond,
|
||||
base, local_members, variants):
|
||||
# struct has local_members, optional base, and no variants
|
||||
# flat union has base, variants, and no local_members
|
||||
# simple union has local_members, variants, and no base
|
||||
QAPISchemaType.__init__(self, name, info, doc)
|
||||
QAPISchemaType.__init__(self, name, info, doc, ifcond)
|
||||
assert base is None or isinstance(base, str)
|
||||
for m in local_members:
|
||||
assert isinstance(m, QAPISchemaObjectTypeMember)
|
||||
|
@ -1410,8 +1421,8 @@ def __init__(self, name, typ):
|
|||
|
||||
|
||||
class QAPISchemaAlternateType(QAPISchemaType):
|
||||
def __init__(self, name, info, doc, variants):
|
||||
QAPISchemaType.__init__(self, name, info, doc)
|
||||
def __init__(self, name, info, doc, ifcond, variants):
|
||||
QAPISchemaType.__init__(self, name, info, doc, ifcond)
|
||||
assert isinstance(variants, QAPISchemaObjectTypeVariants)
|
||||
assert variants.tag_member
|
||||
variants.set_owner(name)
|
||||
|
@ -1447,9 +1458,9 @@ def is_empty(self):
|
|||
|
||||
|
||||
class QAPISchemaCommand(QAPISchemaEntity):
|
||||
def __init__(self, name, info, doc, arg_type, ret_type,
|
||||
def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
|
||||
gen, success_response, boxed, allow_oob, allow_preconfig):
|
||||
QAPISchemaEntity.__init__(self, name, info, doc)
|
||||
QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
|
||||
assert not arg_type or isinstance(arg_type, str)
|
||||
assert not ret_type or isinstance(ret_type, str)
|
||||
self._arg_type_name = arg_type
|
||||
|
@ -1490,8 +1501,8 @@ def visit(self, visitor):
|
|||
|
||||
|
||||
class QAPISchemaEvent(QAPISchemaEntity):
|
||||
def __init__(self, name, info, doc, arg_type, boxed):
|
||||
QAPISchemaEntity.__init__(self, name, info, doc)
|
||||
def __init__(self, name, info, doc, ifcond, arg_type, boxed):
|
||||
QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
|
||||
assert not arg_type or isinstance(arg_type, str)
|
||||
self._arg_type_name = arg_type
|
||||
self.arg_type = None
|
||||
|
@ -1590,22 +1601,22 @@ def _def_predefineds(self):
|
|||
('null', 'null', 'QNull' + pointer_suffix)]:
|
||||
self._def_builtin_type(*t)
|
||||
self.the_empty_object_type = QAPISchemaObjectType(
|
||||
'q_empty', None, None, None, [], None)
|
||||
'q_empty', None, None, None, None, [], None)
|
||||
self._def_entity(self.the_empty_object_type)
|
||||
qtype_values = self._make_enum_members(['none', 'qnull', 'qnum',
|
||||
'qstring', 'qdict', 'qlist',
|
||||
'qbool'])
|
||||
self._def_entity(QAPISchemaEnumType('QType', None, None,
|
||||
self._def_entity(QAPISchemaEnumType('QType', None, None, None,
|
||||
qtype_values, 'QTYPE'))
|
||||
|
||||
def _make_enum_members(self, values):
|
||||
return [QAPISchemaMember(v) for v in values]
|
||||
|
||||
def _make_implicit_enum_type(self, name, info, values):
|
||||
def _make_implicit_enum_type(self, name, info, ifcond, values):
|
||||
# See also QAPISchemaObjectTypeMember._pretty_owner()
|
||||
name = name + 'Kind' # Use namespace reserved by add_name()
|
||||
self._def_entity(QAPISchemaEnumType(
|
||||
name, info, None, self._make_enum_members(values), None))
|
||||
name, info, None, ifcond, self._make_enum_members(values), None))
|
||||
return name
|
||||
|
||||
def _make_array_type(self, element_type, info):
|
||||
|
@ -1614,22 +1625,37 @@ def _make_array_type(self, element_type, info):
|
|||
self._def_entity(QAPISchemaArrayType(name, info, element_type))
|
||||
return name
|
||||
|
||||
def _make_implicit_object_type(self, name, info, doc, role, members):
|
||||
def _make_implicit_object_type(self, name, info, doc, ifcond,
|
||||
role, members):
|
||||
if not members:
|
||||
return None
|
||||
# See also QAPISchemaObjectTypeMember._pretty_owner()
|
||||
name = 'q_obj_%s-%s' % (name, role)
|
||||
if not self.lookup_entity(name, QAPISchemaObjectType):
|
||||
self._def_entity(QAPISchemaObjectType(name, info, doc, None,
|
||||
members, None))
|
||||
typ = self.lookup_entity(name, QAPISchemaObjectType)
|
||||
if typ:
|
||||
# The implicit object type has multiple users. This can
|
||||
# happen only for simple unions' implicit wrapper types.
|
||||
# Its ifcond should be the disjunction of its user's
|
||||
# ifconds. Not implemented. Instead, we always pass the
|
||||
# wrapped type's ifcond, which is trivially the same for all
|
||||
# users. It's also necessary for the wrapper to compile.
|
||||
# But it's not tight: the disjunction need not imply it. We
|
||||
# may end up compiling useless wrapper types.
|
||||
# TODO kill simple unions or implement the disjunction
|
||||
assert ifcond == typ.ifcond
|
||||
else:
|
||||
self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
|
||||
None, members, None))
|
||||
return name
|
||||
|
||||
def _def_enum_type(self, expr, info, doc):
|
||||
name = expr['enum']
|
||||
data = expr['data']
|
||||
prefix = expr.get('prefix')
|
||||
ifcond = expr.get('if')
|
||||
self._def_entity(QAPISchemaEnumType(
|
||||
name, info, doc, self._make_enum_members(data), prefix))
|
||||
name, info, doc, ifcond,
|
||||
self._make_enum_members(data), prefix))
|
||||
|
||||
def _make_member(self, name, typ, info):
|
||||
optional = False
|
||||
|
@ -1649,7 +1675,8 @@ def _def_struct_type(self, expr, info, doc):
|
|||
name = expr['struct']
|
||||
base = expr.get('base')
|
||||
data = expr['data']
|
||||
self._def_entity(QAPISchemaObjectType(name, info, doc, base,
|
||||
ifcond = expr.get('if')
|
||||
self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, base,
|
||||
self._make_members(data, info),
|
||||
None))
|
||||
|
||||
|
@ -1661,18 +1688,21 @@ def _make_simple_variant(self, case, typ, info):
|
|||
assert len(typ) == 1
|
||||
typ = self._make_array_type(typ[0], info)
|
||||
typ = self._make_implicit_object_type(
|
||||
typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
|
||||
typ, info, None, self.lookup_type(typ).ifcond,
|
||||
'wrapper', [self._make_member('data', typ, info)])
|
||||
return QAPISchemaObjectTypeVariant(case, typ)
|
||||
|
||||
def _def_union_type(self, expr, info, doc):
|
||||
name = expr['union']
|
||||
data = expr['data']
|
||||
base = expr.get('base')
|
||||
ifcond = expr.get('if')
|
||||
tag_name = expr.get('discriminator')
|
||||
tag_member = None
|
||||
if isinstance(base, dict):
|
||||
base = (self._make_implicit_object_type(
|
||||
name, info, doc, 'base', self._make_members(base, info)))
|
||||
base = self._make_implicit_object_type(
|
||||
name, info, doc, ifcond,
|
||||
'base', self._make_members(base, info))
|
||||
if tag_name:
|
||||
variants = [self._make_variant(key, value)
|
||||
for (key, value) in data.items()]
|
||||
|
@ -1680,12 +1710,12 @@ def _def_union_type(self, expr, info, doc):
|
|||
else:
|
||||
variants = [self._make_simple_variant(key, value, info)
|
||||
for (key, value) in data.items()]
|
||||
typ = self._make_implicit_enum_type(name, info,
|
||||
typ = self._make_implicit_enum_type(name, info, ifcond,
|
||||
[v.name for v in variants])
|
||||
tag_member = QAPISchemaObjectTypeMember('type', typ, False)
|
||||
members = [tag_member]
|
||||
self._def_entity(
|
||||
QAPISchemaObjectType(name, info, doc, base, members,
|
||||
QAPISchemaObjectType(name, info, doc, ifcond, base, members,
|
||||
QAPISchemaObjectTypeVariants(tag_name,
|
||||
tag_member,
|
||||
variants)))
|
||||
|
@ -1693,11 +1723,12 @@ def _def_union_type(self, expr, info, doc):
|
|||
def _def_alternate_type(self, expr, info, doc):
|
||||
name = expr['alternate']
|
||||
data = expr['data']
|
||||
ifcond = expr.get('if')
|
||||
variants = [self._make_variant(key, value)
|
||||
for (key, value) in data.items()]
|
||||
tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
|
||||
self._def_entity(
|
||||
QAPISchemaAlternateType(name, info, doc,
|
||||
QAPISchemaAlternateType(name, info, doc, ifcond,
|
||||
QAPISchemaObjectTypeVariants(None,
|
||||
tag_member,
|
||||
variants)))
|
||||
|
@ -1711,13 +1742,14 @@ def _def_command(self, expr, info, doc):
|
|||
boxed = expr.get('boxed', False)
|
||||
allow_oob = expr.get('allow-oob', False)
|
||||
allow_preconfig = expr.get('allow-preconfig', False)
|
||||
ifcond = expr.get('if')
|
||||
if isinstance(data, OrderedDict):
|
||||
data = self._make_implicit_object_type(
|
||||
name, info, doc, 'arg', self._make_members(data, info))
|
||||
name, info, doc, ifcond, 'arg', self._make_members(data, info))
|
||||
if isinstance(rets, list):
|
||||
assert len(rets) == 1
|
||||
rets = self._make_array_type(rets[0], info)
|
||||
self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
|
||||
self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets,
|
||||
gen, success_response,
|
||||
boxed, allow_oob, allow_preconfig))
|
||||
|
||||
|
@ -1725,10 +1757,11 @@ def _def_event(self, expr, info, doc):
|
|||
name = expr['event']
|
||||
data = expr.get('data')
|
||||
boxed = expr.get('boxed', False)
|
||||
ifcond = expr.get('if')
|
||||
if isinstance(data, OrderedDict):
|
||||
data = self._make_implicit_object_type(
|
||||
name, info, doc, 'arg', self._make_members(data, info))
|
||||
self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
|
||||
name, info, doc, ifcond, 'arg', self._make_members(data, info))
|
||||
self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed))
|
||||
|
||||
def _def_exprs(self, exprs):
|
||||
for expr_elem in exprs:
|
||||
|
|
Loading…
Reference in New Issue