qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).