[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 02/14] qapi: pass 'if' condition into QAPISchemaEntit
From: |
Markus Armbruster |
Subject: |
[Qemu-devel] [PULL 02/14] qapi: pass 'if' condition into QAPISchemaEntity objects |
Date: |
Tue, 3 Jul 2018 23:06:01 +0200 |
From: Marc-André Lureau <address@hidden>
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 <address@hidden>
Reviewed-by: Markus Armbruster <address@hidden>
Message-Id: <address@hidden>
Signed-off-by: Markus Armbruster <address@hidden>
---
scripts/qapi/common.py | 97 ++++++++++++++++++++++++++++--------------
1 file changed, 65 insertions(+), 32 deletions(-)
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 991045a478..4f4014b387 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -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 @@ class QAPISchemaEntity(object):
# 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 @@ class QAPISchemaBuiltinType(QAPISchemaType):
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 @@ class QAPISchemaEnumType(QAPISchemaType):
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 @@ class QAPISchemaArrayType(QAPISchemaType):
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 @@ class QAPISchemaArrayType(QAPISchemaType):
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 @@ class
QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
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 @@ class QAPISchemaAlternateType(QAPISchemaType):
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 @@ class QAPISchemaCommand(QAPISchemaEntity):
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 @@ class QAPISchema(object):
('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 @@ class QAPISchema(object):
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 @@ class QAPISchema(object):
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 @@ class QAPISchema(object):
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 @@ class QAPISchema(object):
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 @@ class QAPISchema(object):
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 @@ class QAPISchema(object):
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 @@ class QAPISchema(object):
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:
--
2.17.1
- [Qemu-devel] [PULL 09/14] qapi/commands: add #if conditions to commands, (continued)
- [Qemu-devel] [PULL 09/14] qapi/commands: add #if conditions to commands, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 04/14] qapi: add 'ifcond' to visitor methods, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 13/14] qapi: add conditions to VNC type/commands/events on the schema, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 06/14] qapi: add #if/#endif helpers, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 10/14] qapi/events: add #if conditions to events, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 14/14] qapi: add conditions to SPICE type/commands/events on the schema, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 05/14] qapi: mcgen() shouldn't indent # lines, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 01/14] qapi: add 'if' to top-level expressions, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 07/14] qapi-introspect: modify to_qlit() to append ', ' on level > 0, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 12/14] qapi: add 'If:' section to generated documentation, Markus Armbruster, 2018/07/03
- [Qemu-devel] [PULL 02/14] qapi: pass 'if' condition into QAPISchemaEntity objects,
Markus Armbruster <=
- [Qemu-devel] [PULL 08/14] qapi-introspect: add preprocessor conditions to generated QLit, Markus Armbruster, 2018/07/03
- Re: [Qemu-devel] [PULL 00/14] QAPI patches for 2018-07-03, Peter Maydell, 2018/07/05