From patchwork Mon Feb 12 07:22:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Markus Armbruster X-Patchwork-Id: 10211917 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 177F5602CB for ; Mon, 12 Feb 2018 07:37:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EB3F11FF6A for ; Mon, 12 Feb 2018 07:37:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DDF2920182; Mon, 12 Feb 2018 07:37:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D2A961FF6A for ; Mon, 12 Feb 2018 07:37:37 +0000 (UTC) Received: from localhost ([::1]:49889 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1el8gD-0005aa-6S for patchwork-qemu-devel@patchwork.kernel.org; Mon, 12 Feb 2018 02:37:37 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38190) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1el8RN-0000jP-G8 for qemu-devel@nongnu.org; Mon, 12 Feb 2018 02:22:19 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1el8RK-0005vD-Ck for qemu-devel@nongnu.org; Mon, 12 Feb 2018 02:22:17 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:49850 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1el8RK-0005tt-23 for qemu-devel@nongnu.org; Mon, 12 Feb 2018 02:22:14 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1567F4084FE8; Mon, 12 Feb 2018 07:22:13 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-43.ams2.redhat.com [10.36.116.43]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A987D2017DD4; Mon, 12 Feb 2018 07:22:12 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id F09E81138651; Mon, 12 Feb 2018 08:22:07 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Mon, 12 Feb 2018 08:22:00 +0100 Message-Id: <20180212072207.9367-8-armbru@redhat.com> In-Reply-To: <20180212072207.9367-1-armbru@redhat.com> References: <20180212072207.9367-1-armbru@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 12 Feb 2018 07:22:13 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 12 Feb 2018 07:22:13 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'armbru@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH RFC 07/14] qapi: pass 'if' condition into QAPISchemaEntity objects X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: marcandre.lureau@redhat.com, mdroth@linux.vnet.ibm.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Marc-André Lureau 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 the wrapped type's 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 wrapped type's condition instead. Much simpler and good enough for now. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- scripts/qapi/common.py | 98 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 0254b9e1ef..789c77f11f 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -1007,8 +1007,17 @@ def check_exprs(exprs): # Schema compiler frontend # +def listify_cond(ifcond): + if not ifcond: + return [] + elif not isinstance(ifcond, list): + return [ifcond] + else: + 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 @@ -1019,6 +1028,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) @@ -1151,8 +1161,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) @@ -1187,7 +1197,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 @@ -1195,6 +1205,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 @@ -1216,11 +1227,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) @@ -1408,8 +1420,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) @@ -1445,9 +1457,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): - 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 @@ -1484,8 +1496,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 @@ -1579,22 +1591,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): @@ -1603,22 +1615,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 @@ -1638,7 +1665,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)) @@ -1650,18 +1678,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()] @@ -1669,12 +1700,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))) @@ -1682,11 +1713,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))) @@ -1698,23 +1730,25 @@ class QAPISchema(object): gen = expr.get('gen', True) success_response = expr.get('success-response', True) 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)) + 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)) 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: