From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3003CA9EAF for ; Thu, 24 Oct 2019 13:11:26 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7BA4420663 for ; Thu, 24 Oct 2019 13:11:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="JGitjycg" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7BA4420663 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:42038 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iNctg-0005JV-Uw for qemu-devel@archiver.kernel.org; Thu, 24 Oct 2019 09:11:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47817) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iNcKo-00049l-Ty for qemu-devel@nongnu.org; Thu, 24 Oct 2019 08:35:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iNcKg-00069x-EF for qemu-devel@nongnu.org; Thu, 24 Oct 2019 08:35:22 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:26686 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iNcKg-00069B-6o for qemu-devel@nongnu.org; Thu, 24 Oct 2019 08:35:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1571920513; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DozXcw9tnlDl0LzdgpzU6hGrU59c21CuoJOKOZbwanc=; b=JGitjycg7sVTh13fUMzTkfhDfizTIb4RkYSQzzeVxEMl5r71/a3IfNs7AbkqDKdSJJ9K0X Rhkyxx/is8UYETVEHjegpuk6GjNrRvBoz84hB62uf5kFVlWtshRedV0ynYfpd/lCUTnjkf 6+b6m8IAxESWU3ZXFiMlJz6/711+7Jc= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-326-hmWGS2j4OeqxlZPMVETOCw-1; Thu, 24 Oct 2019 08:35:11 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id EEA901005500; Thu, 24 Oct 2019 12:35:10 +0000 (UTC) Received: from blackfin.pond.sub.org (unknown [10.36.118.123]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A87125C222; Thu, 24 Oct 2019 12:35:06 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 114AA1132986; Thu, 24 Oct 2019 14:34:59 +0200 (CEST) From: Markus Armbruster To: qemu-devel@nongnu.org Subject: [RFC PATCH 07/19] qapi: Add feature flags to remaining definitions Date: Thu, 24 Oct 2019 14:34:46 +0200 Message-Id: <20191024123458.13505-8-armbru@redhat.com> In-Reply-To: <20191024123458.13505-1-armbru@redhat.com> References: <20191024123458.13505-1-armbru@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-MC-Unique: hmWGS2j4OeqxlZPMVETOCw-1 X-Mimecast-Spam-Score: 0 Content-Type: text/plain; charset=WINDOWS-1252 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: libvir-list@redhat.com, mdroth@linux.vnet.ibm.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" In v4.1.0, we added feature flags just to struct types (commit 6a8c0b5102^..f3ed93d545), to satisfy an immediate need (commit c9d4070991 "file-posix: Add dynamic-auto-read-only QAPI feature"). We just added them to commands (commit 23394b4c39 "qapi: Add feature flags to commands") to satisfy another immediate need (commit d76744e65e "qapi: Allow introspecting fix for savevm's cooperation with blockdev"). Add them to the remaining definitions: enumeration types, union types, alternate types, and events. Signed-off-by: Markus Armbruster --- docs/devel/qapi-code-gen.txt | 15 ++-- tests/qapi-schema/doc-good.texi | 32 ++++++++- qapi/introspect.json | 28 +++++--- tests/test-qmp-cmds.c | 6 +- scripts/qapi/doc.py | 6 +- scripts/qapi/events.py | 2 +- scripts/qapi/expr.py | 11 ++- scripts/qapi/introspect.py | 31 ++++---- scripts/qapi/schema.py | 96 ++++++++++++++----------- scripts/qapi/types.py | 4 +- scripts/qapi/visit.py | 4 +- tests/qapi-schema/alternate-base.err | 2 +- tests/qapi-schema/doc-good.json | 18 ++++- tests/qapi-schema/doc-good.out | 20 +++++- tests/qapi-schema/qapi-schema-test.json | 29 ++++++-- tests/qapi-schema/qapi-schema-test.out | 27 +++++-- tests/qapi-schema/test-qapi.py | 9 ++- 17 files changed, 226 insertions(+), 114 deletions(-) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 45c93a43cc..eaeedc7bd3 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -172,7 +172,8 @@ Syntax: ENUM =3D { 'enum': STRING, 'data': [ ENUM-VALUE, ... ], '*prefix': STRING, - '*if': COND } + '*if': COND, + '*features': FEATURES } ENUM-VALUE =3D STRING | { 'name': STRING, '*if': COND } =20 @@ -279,12 +280,14 @@ below for more on this. Syntax: UNION =3D { 'union': STRING, 'data': BRANCHES, - '*if': COND } + '*if': COND, + '*features': FEATURES } | { 'union': STRING, 'data': BRANCHES, 'base': ( MEMBERS | STRING ), 'discriminator': STRING, - '*if': COND } + '*if': COND, + '*features': FEATURES } BRANCHES =3D { BRANCH, ... } BRANCH =3D STRING : TYPE-REF | STRING : { 'type': TYPE-REF, '*if': COND } @@ -397,7 +400,8 @@ the schema" below for more on this. Syntax: ALTERNATE =3D { 'alternate': STRING, 'data': ALTERNATIVES, - '*if': COND } + '*if': COND, + '*features': FEATURES } ALTERNATIVES =3D { ALTERNATIVE, ... } ALTERNATIVE =3D STRING : TYPE-REF | STRING : { 'type': STRING, '*if': COND } @@ -595,7 +599,8 @@ Syntax: 'data': STRING, 'boxed': true, ) - '*if': COND } + '*if': COND, + '*features': FEATURES } =20 Member 'event' names the event. This is the event name used in the Client JSON Protocol. diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.t= exi index d4b15dabf0..5ef7fea436 100644 --- a/tests/qapi-schema/doc-good.texi +++ b/tests/qapi-schema/doc-good.texi @@ -84,11 +84,17 @@ Examples: @table @asis @item @code{one} The @emph{one} @{and only@} +@code{two} is undocumented @*@b{If:} @code{defined(IFONE)} @item @code{two} Not documented @end table -@code{two} is undocumented + +@b{Features:} +@table @asis +@item @code{enum-feat} +Also @emph{one} @{and only@} +@end table =20 @b{If:} @code{defined(IFCOND)} @end deftp @@ -151,6 +157,12 @@ a feature @item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If= :} @code{IFTWO}) @end table =20 +@b{Features:} +@table @asis +@item @code{union-feat1} +a feature +@end table + @end deftp =20 =20 @@ -167,6 +179,12 @@ One of @t{"one"}, @t{"two"} @item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{I= FTWO}) @end table =20 +@b{Features:} +@table @asis +@item @code{union-feat2} +a feature +@end table + @end deftp =20 =20 @@ -184,6 +202,12 @@ an integer Not documented @end table =20 +@b{Features:} +@table @asis +@item @code{alt-feat} +a feature +@end table + @end deftp =20 =20 @@ -283,5 +307,11 @@ another feature =20 @b{Arguments:} the members of @code{Object} =20 +@b{Features:} +@table @asis +@item @code{feat3} +a feature +@end table + @end deftypefn =20 diff --git a/qapi/introspect.json b/qapi/introspect.json index 031a954fa9..7322ab3f59 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -105,6 +105,17 @@ 'command': 'SchemaInfoCommand', 'event': 'SchemaInfoEvent' } } =20 +## +# @SchemaInfoFeatures: +# +# @features: names of features associated with the entity, in no particula= r +# order. +# +# Since: 4.2 +## +{ 'struct': 'SchemaInfoFeatures', + 'data': { '*features': [ 'str' ] } } + ## # @SchemaInfoBuiltin: # @@ -142,6 +153,7 @@ # Since: 2.5 ## { 'struct': 'SchemaInfoEnum', + 'base': 'SchemaInfoFeatures', 'data': { 'values': ['str'] } } =20 ## @@ -174,18 +186,15 @@ # and may even differ from the order of the values of the # enum type of the @tag. # -# @features: names of features associated with the type, in no particular -# order. (since: 4.1) -# # Values of this type are JSON object on the wire. # # Since: 2.5 ## { 'struct': 'SchemaInfoObject', + 'base': 'SchemaInfoFeatures', 'data': { 'members': [ 'SchemaInfoObjectMember' ], '*tag': 'str', - '*variants': [ 'SchemaInfoObjectVariant' ], - '*features': [ 'str' ] } } + '*variants': [ 'SchemaInfoObjectVariant' ] } } =20 ## # @SchemaInfoObjectMember: @@ -239,6 +248,7 @@ # Since: 2.5 ## { 'struct': 'SchemaInfoAlternate', + 'base': 'SchemaInfoFeatures', 'data': { 'members': [ 'SchemaInfoAlternateMember' ] } } =20 ## @@ -266,17 +276,14 @@ # @allow-oob: whether the command allows out-of-band execution, # defaults to false (Since: 2.12) # -# @features: names of features associated with the command, in no particul= ar -# order. (since 4.2) -# # TODO: @success-response (currently irrelevant, because it's QGA, not QMP= ) # # Since: 2.5 ## { 'struct': 'SchemaInfoCommand', + 'base': 'SchemaInfoFeatures', 'data': { 'arg-type': 'str', 'ret-type': 'str', - '*allow-oob': 'bool', - '*features': [ 'str' ] } } + '*allow-oob': 'bool' } } =20 ## # @SchemaInfoEvent: @@ -289,4 +296,5 @@ # Since: 2.5 ## { 'struct': 'SchemaInfoEvent', + 'base': 'SchemaInfoFeatures', 'data': { 'arg-type': 'str' } } diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index 3798ba1b16..cf4fa1a091 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -44,7 +44,7 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp) { } =20 -void qmp_test_features(FeatureStruct0 *fs0, FeatureStruct1 *fs1, +void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1, FeatureStruct2 *fs2, FeatureStruct3 *fs3, FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1, CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3, @@ -52,10 +52,6 @@ void qmp_test_features(FeatureStruct0 *fs0, FeatureStruc= t1 *fs1, { } =20 -void qmp_test_command_features0(Error **errp) -{ -} - void qmp_test_command_features1(Error **errp) { } diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index 6f1c17f71f..53a1f8e952 100644 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -244,7 +244,7 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor): def write(self, output_dir): self._gen.write(output_dir) =20 - def visit_enum_type(self, name, info, ifcond, members, prefix): + def visit_enum_type(self, name, info, ifcond, features, members, prefi= x): doc =3D self.cur_doc self._gen.add(texi_type('Enum', doc, ifcond, texi_members(doc, 'Values', @@ -258,7 +258,7 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor): self._gen.add(texi_type('Object', doc, ifcond, texi_members(doc, 'Members', base, variant= s))) =20 - def visit_alternate_type(self, name, info, ifcond, variants): + def visit_alternate_type(self, name, info, ifcond, features, variants)= : doc =3D self.cur_doc self._gen.add(texi_type('Alternate', doc, ifcond, texi_members(doc, 'Members'))) @@ -271,7 +271,7 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor): texi_arguments(doc, arg_type if boxed else None)= )) =20 - def visit_event(self, name, info, ifcond, arg_type, boxed): + def visit_event(self, name, info, ifcond, features, arg_type, boxed): doc =3D self.cur_doc self._gen.add(texi_msg('Event', doc, ifcond, texi_arguments(doc, diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index 10fc509fa9..f64e61076e 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -189,7 +189,7 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict)= ; event_emit=3Dself._event_emit_name, event_enum=3Dself._event_enum_name)) =20 - def visit_event(self, name, info, ifcond, arg_type, boxed): + def visit_event(self, name, info, ifcond, features, arg_type, boxed): with ifcontext(ifcond, self._genh, self._genc): self._genh.add(gen_event_send_decl(name, arg_type, boxed)) self._genc.add(gen_event_send(name, arg_type, boxed, diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index d7a289eded..92b2407315 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -220,7 +220,6 @@ def check_struct(expr, info): =20 check_type(members, info, "'data'", allow_dict=3Dname) check_type(expr.get('base'), info, "'base'") - check_features(expr.get('features'), info) =20 =20 def check_union(expr, info): @@ -268,7 +267,6 @@ def check_command(expr, info): raise QAPISemError(info, "'boxed': true requires 'data'") check_type(args, info, "'data'", allow_dict=3Dnot boxed) check_type(rets, info, "'returns'", allow_array=3DTrue) - check_features(expr.get('features'), info) =20 =20 def check_event(expr, info): @@ -320,18 +318,18 @@ def check_exprs(exprs): =20 if meta =3D=3D 'enum': check_keys(expr, info, meta, - ['enum', 'data'], ['if', 'prefix']) + ['enum', 'data'], ['if', 'features', 'prefix']) check_enum(expr, info) elif meta =3D=3D 'union': check_keys(expr, info, meta, ['union', 'data'], - ['base', 'discriminator', 'if']) + ['base', 'discriminator', 'if', 'features']) normalize_members(expr.get('base')) normalize_members(expr['data']) check_union(expr, info) elif meta =3D=3D 'alternate': check_keys(expr, info, meta, - ['alternate', 'data'], ['if']) + ['alternate', 'data'], ['if', 'features']) normalize_members(expr['data']) check_alternate(expr, info) elif meta =3D=3D 'struct': @@ -349,13 +347,14 @@ def check_exprs(exprs): check_command(expr, info) elif meta =3D=3D 'event': check_keys(expr, info, meta, - ['event'], ['data', 'boxed', 'if']) + ['event'], ['data', 'boxed', 'if', 'features']) normalize_members(expr.get('data')) check_event(expr, info) else: assert False, 'unexpected meta type' =20 check_if(expr, info, meta) + check_features(expr.get('features'), info) check_flags(expr, info) =20 return exprs diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index b3a463dd8b..ba493977cf 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -146,7 +146,7 @@ const QLitObject %(c_name)s =3D %(c_string)s; return '[' + self._use_type(typ.element_type) + ']' return self._name(typ.name) =20 - def _gen_qlit(self, name, mtype, obj, ifcond): + def _gen_qlit(self, name, mtype, obj, ifcond, features): extra =3D {} if mtype not in ('command', 'event', 'builtin', 'array'): if not self._unmask: @@ -156,6 +156,8 @@ const QLitObject %(c_name)s =3D %(c_string)s; name =3D self._name(name) obj['name'] =3D name obj['meta-type'] =3D mtype + if features: + obj['features'] =3D [(f.name, {'if': f.ifcond}) for f in featu= res] if ifcond: extra['if'] =3D ifcond if extra: @@ -180,18 +182,18 @@ const QLitObject %(c_name)s =3D %(c_string)s; {'if': variant.ifcond}) =20 def visit_builtin_type(self, name, info, json_type): - self._gen_qlit(name, 'builtin', {'json-type': json_type}, []) + self._gen_qlit(name, 'builtin', {'json-type': json_type}, [], None= ) =20 - def visit_enum_type(self, name, info, ifcond, members, prefix): + def visit_enum_type(self, name, info, ifcond, features, members, prefi= x): self._gen_qlit(name, 'enum', {'values': [(m.name, {'if': m.ifcond}) for m in members]}, - ifcond) + ifcond, features) =20 def visit_array_type(self, name, info, ifcond, element_type): element =3D self._use_type(element_type) self._gen_qlit('[' + element + ']', 'array', {'element-type': elem= ent}, - ifcond) + ifcond, None) =20 def visit_object_type_flat(self, name, info, ifcond, members, variants= , features): @@ -199,16 +201,15 @@ const QLitObject %(c_name)s =3D %(c_string)s; if variants: obj.update(self._gen_variants(variants.tag_member.name, variants.variants)) - if features: - obj['features'] =3D [(f.name, {'if': f.ifcond}) for f in featu= res] =20 - self._gen_qlit(name, 'object', obj, ifcond) + self._gen_qlit(name, 'object', obj, ifcond, features) =20 - def visit_alternate_type(self, name, info, ifcond, variants): + def visit_alternate_type(self, name, info, ifcond, features, variants)= : self._gen_qlit(name, 'alternate', {'members': [ ({'type': self._use_type(m.type)}, {'if': m.ifc= ond}) - for m in variants.variants]}, ifcond) + for m in variants.variants]}, + ifcond, features) =20 def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, @@ -219,16 +220,12 @@ const QLitObject %(c_name)s =3D %(c_string)s; 'ret-type': self._use_type(ret_type)} if allow_oob: obj['allow-oob'] =3D allow_oob + self._gen_qlit(name, 'command', obj, ifcond, features) =20 - if features: - obj['features'] =3D [(f.name, {'if': f.ifcond}) for f in featu= res] - - self._gen_qlit(name, 'command', obj, ifcond) - - def visit_event(self, name, info, ifcond, arg_type, boxed): + def visit_event(self, name, info, ifcond, features, arg_type, boxed): arg_type =3D arg_type or self._schema.the_empty_object_type self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type= )}, - ifcond) + ifcond, features) =20 =20 def gen_introspect(schema, output_dir, prefix, opt_unmask): diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index cf0045f34e..f13f442896 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -109,7 +109,7 @@ class QAPISchemaVisitor(object): def visit_builtin_type(self, name, info, json_type): pass =20 - def visit_enum_type(self, name, info, ifcond, members, prefix): + def visit_enum_type(self, name, info, ifcond, features, members, prefi= x): pass =20 def visit_array_type(self, name, info, ifcond, element_type): @@ -123,7 +123,7 @@ class QAPISchemaVisitor(object): features): pass =20 - def visit_alternate_type(self, name, info, ifcond, variants): + def visit_alternate_type(self, name, info, ifcond, features, variants)= : pass =20 def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, @@ -131,7 +131,7 @@ class QAPISchemaVisitor(object): features): pass =20 - def visit_event(self, name, info, ifcond, arg_type, boxed): + def visit_event(self, name, info, ifcond, features, arg_type, boxed): pass =20 =20 @@ -220,8 +220,8 @@ class QAPISchemaBuiltinType(QAPISchemaType): class QAPISchemaEnumType(QAPISchemaType): meta =3D 'enum' =20 - def __init__(self, name, info, doc, ifcond, members, prefix): - QAPISchemaType.__init__(self, name, info, doc, ifcond) + def __init__(self, name, info, doc, ifcond, features, members, prefix)= : + QAPISchemaType.__init__(self, name, info, doc, ifcond, features) for m in members: assert isinstance(m, QAPISchemaEnumMember) m.set_defined_in(name) @@ -256,15 +256,16 @@ class QAPISchemaEnumType(QAPISchemaType): =20 def visit(self, visitor): QAPISchemaType.visit(self, visitor) - visitor.visit_enum_type(self.name, self.info, self.ifcond, - self.members, self.prefix) + visitor.visit_enum_type( + self.name, self.info, self.ifcond, self.features, + self.members, self.prefix) =20 =20 class QAPISchemaArrayType(QAPISchemaType): meta =3D 'array' =20 def __init__(self, name, info, element_type): - QAPISchemaType.__init__(self, name, info, None, None) + QAPISchemaType.__init__(self, name, info, None) assert isinstance(element_type, str) self._element_type_name =3D element_type self.element_type =3D None @@ -312,8 +313,8 @@ class QAPISchemaArrayType(QAPISchemaType): =20 =20 class QAPISchemaObjectType(QAPISchemaType): - def __init__(self, name, info, doc, ifcond, - base, local_members, variants, features): + def __init__(self, name, info, doc, ifcond, features, + 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 @@ -609,8 +610,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeM= ember): class QAPISchemaAlternateType(QAPISchemaType): meta =3D 'alternate' =20 - def __init__(self, name, info, doc, ifcond, variants): - QAPISchemaType.__init__(self, name, info, doc, ifcond) + def __init__(self, name, info, doc, ifcond, features, variants): + QAPISchemaType.__init__(self, name, info, doc, ifcond, features) assert isinstance(variants, QAPISchemaObjectTypeVariants) assert variants.tag_member variants.set_defined_in(name) @@ -669,16 +670,16 @@ class QAPISchemaAlternateType(QAPISchemaType): =20 def visit(self, visitor): QAPISchemaType.visit(self, visitor) - visitor.visit_alternate_type(self.name, self.info, self.ifcond, - self.variants) + visitor.visit_alternate_type( + self.name, self.info, self.ifcond, self.features, self.variant= s) =20 =20 class QAPISchemaCommand(QAPISchemaEntity): meta =3D 'command' =20 - def __init__(self, name, info, doc, ifcond, arg_type, ret_type, - gen, success_response, boxed, allow_oob, allow_preconfig, - features): + def __init__(self, name, info, doc, ifcond, features, + arg_type, ret_type, + gen, success_response, boxed, allow_oob, allow_preconfig)= : QAPISchemaEntity.__init__(self, name, info, doc, ifcond, features) assert not arg_type or isinstance(arg_type, str) assert not ret_type or isinstance(ret_type, str) @@ -739,8 +740,8 @@ class QAPISchemaCommand(QAPISchemaEntity): class QAPISchemaEvent(QAPISchemaEntity): meta =3D 'event' =20 - def __init__(self, name, info, doc, ifcond, arg_type, boxed): - QAPISchemaEntity.__init__(self, name, info, doc, ifcond) + def __init__(self, name, info, doc, ifcond, features, arg_type, boxed)= : + QAPISchemaEntity.__init__(self, name, info, doc, ifcond, features) assert not arg_type or isinstance(arg_type, str) self._arg_type_name =3D arg_type self.arg_type =3D None @@ -770,8 +771,9 @@ class QAPISchemaEvent(QAPISchemaEntity): =20 def visit(self, visitor): QAPISchemaEntity.visit(self, visitor) - visitor.visit_event(self.name, self.info, self.ifcond, - self.arg_type, self.boxed) + visitor.visit_event( + self.name, self.info, self.ifcond, self.features, + self.arg_type, self.boxed) =20 =20 class QAPISchema(object): @@ -860,7 +862,7 @@ class QAPISchema(object): ('null', 'null', 'QNull' + pointer_suffix)]: self._def_builtin_type(*t) self.the_empty_object_type =3D QAPISchemaObjectType( - 'q_empty', None, None, None, None, [], None, []) + 'q_empty', None, None, None, None, None, [], None) self._def_entity(self.the_empty_object_type) =20 qtypes =3D ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', @@ -868,10 +870,11 @@ class QAPISchema(object): qtype_values =3D self._make_enum_members( [{'name': n} for n in qtypes], None) =20 - self._def_entity(QAPISchemaEnumType('QType', None, None, None, + self._def_entity(QAPISchemaEnumType('QType', None, None, None, Non= e, qtype_values, 'QTYPE')) =20 - def _make_features(self, features, info): + def _make_features(self, expr, info): + features =3D expr.get('features', []) return [QAPISchemaFeature(f['name'], info, f.get('if')) for f in features] =20 @@ -883,7 +886,8 @@ class QAPISchema(object): # See also QAPISchemaObjectTypeMember.describe() name =3D name + 'Kind' # reserved by check_defn_name_str() self._def_entity(QAPISchemaEnumType( - name, info, None, ifcond, self._make_enum_members(values, info= ), + name, info, None, ifcond, None, + self._make_enum_members(values, info), None)) return name =20 @@ -911,8 +915,8 @@ class QAPISchema(object): # TODO kill simple unions or implement the disjunction assert (ifcond or []) =3D=3D typ._ifcond # pylint: disable=3Dp= rotected-access else: - self._def_entity(QAPISchemaObjectType(name, info, None, ifcond= , - None, members, None, [])= ) + self._def_entity(QAPISchemaObjectType( + name, info, None, ifcond, None, None, members, None)) return name =20 def _def_enum_type(self, expr, info, doc): @@ -920,8 +924,9 @@ class QAPISchema(object): data =3D expr['data'] prefix =3D expr.get('prefix') ifcond =3D expr.get('if') + features =3D self._make_features(expr, info) self._def_entity(QAPISchemaEnumType( - name, info, doc, ifcond, + name, info, doc, ifcond, features, self._make_enum_members(data, info), prefix)) =20 def _make_member(self, name, typ, ifcond, info): @@ -943,12 +948,11 @@ class QAPISchema(object): base =3D expr.get('base') data =3D expr['data'] ifcond =3D expr.get('if') - features =3D expr.get('features', []) + features =3D self._make_features(expr, info) self._def_entity(QAPISchemaObjectType( - name, info, doc, ifcond, base, + name, info, doc, ifcond, features, base, self._make_members(data, info), - None, - self._make_features(features, info))) + None)) =20 def _make_variant(self, case, typ, ifcond, info): return QAPISchemaObjectTypeVariant(case, info, typ, ifcond) @@ -967,6 +971,7 @@ class QAPISchema(object): data =3D expr['data'] base =3D expr.get('base') ifcond =3D expr.get('if') + features =3D self._make_features(expr, info) tag_name =3D expr.get('discriminator') tag_member =3D None if isinstance(base, dict): @@ -987,21 +992,22 @@ class QAPISchema(object): tag_member =3D QAPISchemaObjectTypeMember('type', info, typ, F= alse) members =3D [tag_member] self._def_entity( - QAPISchemaObjectType(name, info, doc, ifcond, base, members, + QAPISchemaObjectType(name, info, doc, ifcond, features, + base, members, QAPISchemaObjectTypeVariants( - tag_name, info, tag_member, variants)= , - [])) + tag_name, info, tag_member, variants)= )) =20 def _def_alternate_type(self, expr, info, doc): name =3D expr['alternate'] data =3D expr['data'] ifcond =3D expr.get('if') + features =3D self._make_features(expr, info) variants =3D [self._make_variant(key, value['type'], value.get('if= '), info) for (key, value) in data.items()] tag_member =3D QAPISchemaObjectTypeMember('type', info, 'QType', F= alse) self._def_entity( - QAPISchemaAlternateType(name, info, doc, ifcond, + QAPISchemaAlternateType(name, info, doc, ifcond, features, QAPISchemaObjectTypeVariants( None, info, tag_member, variants))= ) =20 @@ -1015,27 +1021,31 @@ class QAPISchema(object): allow_oob =3D expr.get('allow-oob', False) allow_preconfig =3D expr.get('allow-preconfig', False) ifcond =3D expr.get('if') - features =3D expr.get('features', []) + features =3D self._make_features(expr, info) if isinstance(data, OrderedDict): data =3D self._make_implicit_object_type( - name, info, ifcond, 'arg', self._make_members(data, info)) + name, info, ifcond, + 'arg', self._make_members(data, info)) if isinstance(rets, list): assert len(rets) =3D=3D 1 rets =3D self._make_array_type(rets[0], info) - self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, = rets, + self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, featur= es, + data, rets, gen, success_response, - boxed, allow_oob, allow_preconf= ig, - self._make_features(features, i= nfo))) + boxed, allow_oob, allow_preconf= ig)) =20 def _def_event(self, expr, info, doc): name =3D expr['event'] data =3D expr.get('data') boxed =3D expr.get('boxed', False) ifcond =3D expr.get('if') + features =3D self._make_features(expr, info) if isinstance(data, OrderedDict): data =3D self._make_implicit_object_type( - name, info, ifcond, 'arg', self._make_members(data, info)) - self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, bo= xed)) + name, info, ifcond, + 'arg', self._make_members(data, info)) + self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, features= , + data, boxed)) =20 def _def_exprs(self, exprs): for expr_elem in exprs: diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index d8751daa04..2a108b6911 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -277,7 +277,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisito= r): self._genh.add(gen_type_cleanup_decl(name)) self._genc.add(gen_type_cleanup(name)) =20 - def visit_enum_type(self, name, info, ifcond, members, prefix): + def visit_enum_type(self, name, info, ifcond, features, members, prefi= x): with ifcontext(ifcond, self._genh, self._genc): self._genh.preamble_add(gen_enum(name, members, prefix)) self._genc.add(gen_enum_lookup(name, members, prefix)) @@ -305,7 +305,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisito= r): # implicit types won't be directly allocated/freed self._gen_type_cleanup(name) =20 - def visit_alternate_type(self, name, info, ifcond, variants): + def visit_alternate_type(self, name, info, ifcond, features, variants)= : with ifcontext(ifcond, self._genh): self._genh.preamble_add(gen_fwd_object_or_array(name)) self._genh.add(gen_object(name, ifcond, None, diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index c72f2bc5c0..b21e1340a2 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -316,7 +316,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisit= or): ''', types=3Dtypes)) =20 - def visit_enum_type(self, name, info, ifcond, members, prefix): + def visit_enum_type(self, name, info, ifcond, features, members, prefi= x): with ifcontext(ifcond, self._genh, self._genc): self._genh.add(gen_visit_decl(name, scalar=3DTrue)) self._genc.add(gen_visit_enum(name)) @@ -342,7 +342,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisit= or): self._genh.add(gen_visit_decl(name)) self._genc.add(gen_visit_object(name, base, members, varia= nts)) =20 - def visit_alternate_type(self, name, info, ifcond, variants): + def visit_alternate_type(self, name, info, ifcond, features, variants)= : with ifcontext(ifcond, self._genh, self._genc): self._genh.add(gen_visit_decl(name)) self._genc.add(gen_visit_alternate(name, variants)) diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alter= nate-base.err index 31ebe56bbf..970a08ab26 100644 --- a/tests/qapi-schema/alternate-base.err +++ b/tests/qapi-schema/alternate-base.err @@ -1,3 +1,3 @@ alternate-base.json: In alternate 'Alt': alternate-base.json:4: alternate has unknown key 'base' -Valid keys are 'alternate', 'data', 'if'. +Valid keys are 'alternate', 'data', 'features', 'if'. diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.j= son index d992e713d9..01c930c474 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -52,11 +52,14 @@ ## # @Enum: # @one: The _one_ {and only} -# # @two is undocumented +# +# Features: +# @enum-feat: Also _one_ {and only} ## { 'enum': 'Enum', 'data': [ { 'name': 'one', 'if': 'defined(IFONE)' }, 'two' ], + 'features': [ 'enum-feat' ], 'if': 'defined(IFCOND)' } =20 ## @@ -86,24 +89,34 @@ =20 ## # @Object: +# Features: +# @union-feat1: a feature ## { 'union': 'Object', + 'features': [ 'union-feat1' ], 'base': 'Base', 'discriminator': 'base1', 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' = } } } =20 ## # @SugaredUnion: +# Features: +# @union-feat2: a feature ## { 'union': 'SugaredUnion', + 'features': [ 'union-feat2' ], 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' = } } } =20 ## # @Alternate: # @i: an integer # @b is undocumented +# +# Features: +# @alt-feat: a feature ## { 'alternate': 'Alternate', + 'features': [ 'alt-feat' ], 'data': { 'i': 'int', 'b': 'bool' } } =20 ## @@ -160,6 +173,9 @@ =20 ## # @EVT-BOXED: +# Features: +# @feat3: a feature ## { 'event': 'EVT-BOXED', 'boxed': true, + 'features': [ 'feat3' ], 'data': 'Object' } diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.ou= t index 4c9406a464..f5d9dc969c 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -15,6 +15,7 @@ enum Enum if ['defined(IFONE)'] member two if ['defined(IFCOND)'] + feature enum-feat object Base member base1: Enum optional=3DFalse object Variant1 @@ -28,6 +29,7 @@ object Object case one: Variant1 case two: Variant2 if ['IFTWO'] + feature union-feat1 object q_obj_Variant1-wrapper member data: Variant1 optional=3DFalse object q_obj_Variant2-wrapper @@ -42,10 +44,12 @@ object SugaredUnion case one: q_obj_Variant1-wrapper case two: q_obj_Variant2-wrapper if ['IFTWO'] + feature union-feat2 alternate Alternate tag type case i: int case b: bool + feature alt-feat object q_obj_cmd-arg member arg1: int optional=3DFalse member arg2: str optional=3DTrue @@ -60,6 +64,7 @@ command cmd-boxed Object -> None feature cmd-feat2 event EVT-BOXED Object boxed=3DTrue + feature feat3 doc freeform body=3D =3D Section @@ -110,10 +115,11 @@ doc symbol=3DEnum =20 arg=3Done The _one_ {and only} - arg=3Dtwo - - section=3DNone @two is undocumented + arg=3Dtwo + + feature=3Denum-feat +Also _one_ {and only} doc symbol=3DBase body=3D =20 @@ -134,11 +140,15 @@ doc symbol=3DVariant2 doc symbol=3DObject body=3D =20 + feature=3Dunion-feat1 +a feature doc symbol=3DSugaredUnion body=3D =20 arg=3Dtype =20 + feature=3Dunion-feat2 +a feature doc symbol=3DAlternate body=3D =20 @@ -147,6 +157,8 @@ an integer @b is undocumented arg=3Db =20 + feature=3Dalt-feat +a feature doc freeform body=3D =3D=3D Another subsection @@ -197,3 +209,5 @@ another feature doc symbol=3DEVT-BOXED body=3D =20 + feature=3Dfeat3 +a feature diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qa= pi-schema-test.json index 9abf175fe0..fa4f3a15da 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -252,7 +252,7 @@ 'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } }, 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' } =20 -# test 'features' for structs +# test 'features' =20 { 'struct': 'FeatureStruct0', 'data': { 'foo': 'int' }, @@ -281,7 +281,22 @@ 'data': { 'foo': 'int' }, 'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] }= ] } -{ 'command': 'test-features', + +{ 'enum': 'FeatureEnum1', + 'data': [ 'eins', 'zwei', 'drei' ], + 'features': [ 'feature1' ] } + +{ 'union': 'FeatureUnion1', + 'base': { 'tag': 'FeatureEnum1' }, + 'discriminator': 'tag', + 'data': { 'eins': 'FeatureStruct1' }, + 'features': [ 'feature1' ] } + +{ 'alternate': 'FeatureAlternate1', + 'data': { 'eins': 'FeatureStruct1' }, + 'features': [ 'feature1' ] } + +{ 'command': 'test-features0', 'data': { 'fs0': 'FeatureStruct0', 'fs1': 'FeatureStruct1', 'fs2': 'FeatureStruct2', @@ -289,12 +304,9 @@ 'fs4': 'FeatureStruct4', 'cfs1': 'CondFeatureStruct1', 'cfs2': 'CondFeatureStruct2', - 'cfs3': 'CondFeatureStruct3' } } - -# test 'features' for command - -{ 'command': 'test-command-features0', + 'cfs3': 'CondFeatureStruct3' }, 'features': [] } + { 'command': 'test-command-features1', 'features': [ 'feature1' ] } { 'command': 'test-command-features3', @@ -308,3 +320,6 @@ { 'command': 'test-command-cond-features3', 'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] }= ] } + +{ 'event': 'TEST-EVENT-FEATURES1', + 'features': [ 'feature1' ] } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qap= i-schema-test.out index 3660e75a48..1ece836d9b 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -401,7 +401,25 @@ object CondFeatureStruct3 member foo: int optional=3DFalse feature feature1 if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] -object q_obj_test-features-arg +enum FeatureEnum1 + member eins + member zwei + member drei + feature feature1 +object q_obj_FeatureUnion1-base + member tag: FeatureEnum1 optional=3DFalse +object FeatureUnion1 + base q_obj_FeatureUnion1-base + tag tag + case eins: FeatureStruct1 + case zwei: q_empty + case drei: q_empty + feature feature1 +alternate FeatureAlternate1 + tag type + case eins: FeatureStruct1 + feature feature1 +object q_obj_test-features0-arg member fs0: FeatureStruct0 optional=3DFalse member fs1: FeatureStruct1 optional=3DFalse member fs2: FeatureStruct2 optional=3DFalse @@ -410,9 +428,7 @@ object q_obj_test-features-arg member cfs1: CondFeatureStruct1 optional=3DFalse member cfs2: CondFeatureStruct2 optional=3DFalse member cfs3: CondFeatureStruct3 optional=3DFalse -command test-features q_obj_test-features-arg -> None - gen=3DTrue success_response=3DTrue boxed=3DFalse oob=3DFalse preconfig= =3DFalse -command test-command-features0 None -> None +command test-features0 q_obj_test-features0-arg -> None gen=3DTrue success_response=3DTrue boxed=3DFalse oob=3DFalse preconfig= =3DFalse command test-command-features1 None -> None gen=3DTrue success_response=3DTrue boxed=3DFalse oob=3DFalse preconfig= =3DFalse @@ -435,3 +451,6 @@ command test-command-cond-features3 None -> None gen=3DTrue success_response=3DTrue boxed=3DFalse oob=3DFalse preconfig= =3DFalse feature feature1 if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] +event TEST-EVENT-FEATURES1 None + boxed=3DFalse + feature feature1 diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.p= y index bad14edb47..078fc63f97 100755 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -35,7 +35,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): def visit_include(self, name, info): print('include %s' % name) =20 - def visit_enum_type(self, name, info, ifcond, members, prefix): + def visit_enum_type(self, name, info, ifcond, features, members, prefi= x): print('enum %s' % name) if prefix: print(' prefix %s' % prefix) @@ -43,6 +43,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): print(' member %s' % m.name) self._print_if(m.ifcond, indent=3D8) self._print_if(ifcond) + self._print_features(features) =20 def visit_array_type(self, name, info, ifcond, element_type): if not info: @@ -63,10 +64,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): self._print_if(ifcond) self._print_features(features) =20 - def visit_alternate_type(self, name, info, ifcond, variants): + def visit_alternate_type(self, name, info, ifcond, features, variants)= : print('alternate %s' % name) self._print_variants(variants) self._print_if(ifcond) + self._print_features(features) =20 def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, @@ -79,10 +81,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): self._print_if(ifcond) self._print_features(features) =20 - def visit_event(self, name, info, ifcond, arg_type, boxed): + def visit_event(self, name, info, ifcond, features, arg_type, boxed): print('event %s %s' % (name, arg_type and arg_type.name)) print(' boxed=3D%s' % boxed) self._print_if(ifcond) + self._print_features(features) =20 @staticmethod def _print_variants(variants): --=20 2.21.0