From: Markus Armbruster <armbru@redhat.com>
To: Eric Blake <eblake@redhat.com>
Cc: qemu-devel@nongnu.org, Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH v8 13/18] qapi: Track owner of each object member
Date: Tue, 13 Oct 2015 15:14:34 +0200 [thread overview]
Message-ID: <87vbaa7vwl.fsf@blackfin.pond.sub.org> (raw)
In-Reply-To: <1444710158-8723-14-git-send-email-eblake@redhat.com> (Eric Blake's message of "Mon, 12 Oct 2015 22:22:33 -0600")
Eric Blake <eblake@redhat.com> writes:
> Future commits will migrate semantic checking away from parsing
> and over to the various QAPISchema*.check() methods. But to
> report an error message about an incorrect semantic use of a
> member of an object type, it helps to know which type, command,
> or event owns the member. In particular, when a member is
> inherited from a base type, it is desirable to associate the
> member name with the base type (and not the type calling
> member.check()).
>
> Rather than packing additional information into the seen array
> passed to each member.check() (as in seen[m.name] = {'member':m,
> 'owner':type}), it is easier to have each member track the name
> of the owner type in the first place (keeping things simpler
> with the existing seen[m.name] = m). The new member.owner field
> is set via a new set_owner() function, called when registering
method
> the members and variants arrays with an object or variant type.
> Track only a name, and not the actual type object, to avoid
> creating a circular python reference chain.
>
> The source information is intended for human consumption in
> error messages, and a new describe() method is added to access
> the resulting information. For example, given the qapi:
> { 'command': 'foo', 'data': { 'string': 'str' } }
> an implementation of visit_command() that calls
> arg_type.members[0].describe()
> will see "'string' (argument of foo)".
>
> To make the human-readable name of implicit types work without
> duplicating efforts, the describe() method has to reverse the
> name of implicit types.
>
> No change to generated code.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v8: don't munge implicit type names [except for event data], and
> instead make describe() create nicer messages. Add set_owner(), and
> use field 'role' instead of method _describe()
> v7: total rewrite: rework implicit object names, assign owner
> when initializing owner type rather than when creating member
> python object
> v6: rebase on new lazy array creation and simple union 'type'
> motion; tweak commit message
> ---
> scripts/qapi.py | 48 +++++++++++++++++++++++++++++++---
> tests/qapi-schema/qapi-schema-test.out | 8 +++---
> 2 files changed, 49 insertions(+), 7 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index c9ce9ee..8b29e11 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -952,8 +952,10 @@ class QAPISchemaObjectType(QAPISchemaType):
> assert base is None or isinstance(base, str)
> for m in local_members:
> assert isinstance(m, QAPISchemaObjectTypeMember)
> - assert (variants is None or
> - isinstance(variants, QAPISchemaObjectTypeVariants))
> + m.set_owner(name)
> + if variants is not None:
> + assert isinstance(variants, QAPISchemaObjectTypeVariants)
> + variants.set_owner(name)
> self._base_name = base
> self.base = None
> self.local_members = local_members
> @@ -1014,8 +1016,14 @@ class QAPISchemaObjectTypeMember(object):
> self._type_name = typ
> self.type = None
> self.optional = optional
> + self.owner = None
> +
> + def set_owner(self, name):
> + assert not self.owner
> + self.owner = name
>
> def check(self, schema, all_members, seen):
> + assert self.owner
> assert self.name not in seen
> self.type = schema.lookup_type(self._type_name)
> assert self.type
> @@ -1025,6 +1033,25 @@ class QAPISchemaObjectTypeMember(object):
> def c_name(self):
> return c_name(self.name)
>
> + def describe(self):
> + owner = self.owner
> + # See QAPISchema._make_implicit_object_type() - reverse the
> + # mapping there to create a nice human-readable description
> + if owner.startswith(':obj-'):
> + owner = owner[5:]
> + if owner.endswith('-arg'):
> + source = '(argument of %s)' % owner[:4]
> + elif owner.endswith('-data'):
> + source = '(data of %s)' % owner[:5]
> + else:
> + assert owner.endswith('-wrapper')
> + source = '(branch of %s)' % owner[:8]
> + else:
> + source = '(%s of %s)' % (self.role, owner)
> + return "'%s' %s" % (self.name, source)
Perhaps not exactly pretty, but it gets the job done with minimal fuss.
Sold.
> +
> + role = 'member'
> +
>
Class variables are usually defined first, before methods.
> # TODO Drop this class once we no longer have the 'type'/'kind' mismatch
> class QAPISchemaObjectTypeUnionTag(QAPISchemaObjectTypeMember):
> @@ -1034,6 +1061,11 @@ class QAPISchemaObjectTypeUnionTag(QAPISchemaObjectTypeMember):
> assert self.type.is_implicit()
> return 'kind'
>
> + def describe(self):
> + # Must override superclass describe() because self.name is 'type'
I don't find this argument convincing. I think 'kind' is exactly as
unhelpful as 'type' is. Specifically, should we report a QMP clash,
calling it 'kind' is confusing (it actually clashes with 'type').
Conversely 'type' is confusing when we report a C clash.
The helpful part...
> + assert self.owner[0] != ':'
> + return "'kind' (implicit tag of %s)" % self.owner
> +
... is (implicit tag of FOO).
Fortunately, you're working towards killing the kind vs. type confusion.
Suggest to either rephrase the comment, or simply drop it.
>
> class QAPISchemaObjectTypeVariants(object):
> def __init__(self, tag_name, tag_member, variants):
> @@ -1050,6 +1082,12 @@ class QAPISchemaObjectTypeVariants(object):
> self.tag_member = tag_member
> self.variants = variants
>
> + def set_owner(self, name):
> + if self.tag_member:
> + self.tag_member.set_owner(name)
> + for v in self.variants:
> + v.set_owner(name)
> +
> def check(self, schema, members, seen):
> if self.tag_name:
> self.tag_member = seen[self.tag_name]
> @@ -1079,12 +1117,15 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
> return self.type.members[0].type
> return None
>
> + role = 'branch'
> +
>
Define this first in the class.
> class QAPISchemaAlternateType(QAPISchemaType):
> def __init__(self, name, info, variants):
> QAPISchemaType.__init__(self, name, info)
> assert isinstance(variants, QAPISchemaObjectTypeVariants)
> assert not variants.tag_name
> + variants.set_owner(name)
> self.variants = variants
>
> def check(self, schema):
> @@ -1216,6 +1257,7 @@ class QAPISchema(object):
> def _make_implicit_object_type(self, name, info, role, members):
> if not members:
> return None
> + # See also QAPISchemaObjectTypeMember.describe()
> name = ':obj-%s-%s' % (name, role)
> if not self.lookup_entity(name, QAPISchemaObjectType):
> self._def_entity(QAPISchemaObjectType(name, info, None,
> @@ -1318,7 +1360,7 @@ class QAPISchema(object):
> data = expr.get('data')
> if isinstance(data, OrderedDict):
> data = self._make_implicit_object_type(
> - name, info, 'arg', self._make_members(data, info))
> + name, info, 'data', self._make_members(data, info))
> self._def_entity(QAPISchemaEvent(name, info, data))
>
> def _def_exprs(self):
> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
> index a6c80e0..d837475 100644
> --- a/tests/qapi-schema/qapi-schema-test.out
> +++ b/tests/qapi-schema/qapi-schema-test.out
> @@ -1,9 +1,9 @@
> object :empty
> -object :obj-EVENT_C-arg
> +object :obj-EVENT_C-data
> member a: int optional=True
> member b: UserDefOne optional=True
> member c: str optional=False
> -object :obj-EVENT_D-arg
> +object :obj-EVENT_D-data
> member a: EventStructOne optional=False
> member b: str optional=False
> member c: str optional=True
> @@ -79,8 +79,8 @@ alternate AltStrNum
> enum AltStrNumKind ['s', 'n']
> event EVENT_A None
> event EVENT_B None
> -event EVENT_C :obj-EVENT_C-arg
> -event EVENT_D :obj-EVENT_D-arg
> +event EVENT_C :obj-EVENT_C-data
> +event EVENT_D :obj-EVENT_D-data
> enum EnumOne ['value1', 'value2', 'value3']
> object EventStructOne
> member struct1: UserDefOne optional=False
next prev parent reply other threads:[~2015-10-13 13:14 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-10-13 4:22 [Qemu-devel] [PATCH v8 00/18] post-introspection cleanups, subset B Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 01/18] qapi: Use predicate callback to determine visit filtering Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 02/18] qapi: Prepare for errors during check() Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 03/18] qapi: Drop redundant alternate-good test Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 04/18] qapi: Move empty-enum to compile-time test Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 05/18] qapi: Drop redundant returns-int test Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 06/18] qapi: Drop redundant flat-union-reverse-define test Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 07/18] qapi: Don't use info as witness of implicit object type Eric Blake
2015-10-13 11:40 ` Markus Armbruster
2015-10-13 13:05 ` Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 08/18] qapi: Lazy creation of array types Eric Blake
2015-10-14 7:15 ` Markus Armbruster
2015-10-14 12:57 ` Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 09/18] qapi: Create simple union type member earlier Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 10/18] qapi: Move union tag quirks into subclass Eric Blake
2015-10-13 12:10 ` Markus Armbruster
2015-10-13 14:15 ` Eric Blake
2015-10-13 16:56 ` Markus Armbruster
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 11/18] qapi: Simplify gen_struct_field() Eric Blake
2015-10-13 12:12 ` Markus Armbruster
2015-10-13 13:11 ` Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 12/18] qapi: Track location that created an implicit type Eric Blake
2015-10-13 12:19 ` Markus Armbruster
2015-10-13 14:27 ` Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 13/18] qapi: Track owner of each object member Eric Blake
2015-10-13 13:14 ` Markus Armbruster [this message]
2015-10-13 14:38 ` Eric Blake
2015-10-13 16:30 ` Markus Armbruster
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 14/18] qapi: Detect collisions in C member names Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 15/18] qapi: Move duplicate member checks to schema check() Eric Blake
2015-10-13 15:06 ` Markus Armbruster
2015-10-13 15:35 ` Eric Blake
2015-10-13 17:13 ` Markus Armbruster
2015-10-13 17:43 ` Eric Blake
2015-10-13 18:32 ` Markus Armbruster
2015-10-13 20:17 ` Eric Blake
2015-10-13 20:20 ` Eric Blake
2015-10-14 7:11 ` Markus Armbruster
2015-10-14 7:32 ` Markus Armbruster
2015-10-14 12:59 ` Eric Blake
2015-10-14 13:23 ` Markus Armbruster
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 16/18] qapi: Move duplicate enum value " Eric Blake
2015-10-13 18:35 ` Markus Armbruster
2015-10-13 19:37 ` Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 17/18] qapi: Add test for alternate branch 'kind' clash Eric Blake
2015-10-13 18:43 ` Markus Armbruster
2015-10-13 19:42 ` Eric Blake
2015-10-13 4:22 ` [Qemu-devel] [PATCH v8 18/18] qapi: Detect base class loops Eric Blake
2015-10-13 18:26 ` [Qemu-devel] [PATCH v8 06.5/18] qapi: Drop redundant args-member-array test Eric Blake
2015-10-13 18:51 ` Markus Armbruster
2015-10-13 18:46 ` [Qemu-devel] [PATCH v8 00/18] post-introspection cleanups, subset B Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87vbaa7vwl.fsf@blackfin.pond.sub.org \
--to=armbru@redhat.com \
--cc=eblake@redhat.com \
--cc=mdroth@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.