All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Eric Blake <eblake@redhat.com>
Cc: kwolf@redhat.com, lcapitulino@redhat.com, famz@redhat.com,
	qemu-devel@nongnu.org, wenchaoqemu@gmail.com
Subject: Re: [Qemu-devel] [PATCH v5 10/28] qapi: Segregate anonymous unions into alternates in generator
Date: Thu, 26 Mar 2015 15:47:04 +0100	[thread overview]
Message-ID: <87d23v24uv.fsf@blackfin.pond.sub.org> (raw)
In-Reply-To: <1427227433-5030-11-git-send-email-eblake@redhat.com> (Eric Blake's message of "Tue, 24 Mar 2015 14:03:35 -0600")

Eric Blake <eblake@redhat.com> writes:

> Special-casing 'discriminator == {}' for handling anonymous unions
> is getting awkward; since this particular type is not always a
> dictionary on the wire, it is easier to treat it as a completely
> different class of type, "alternate", so that if a type is listed
> in the union_types array, we know it is not an anonymous union.
>
> This patch just further segregates union handling, to make sure that
> anonymous unions are not stored in union_types, and splitting up
> check_union() into separate functions.  A future patch will change
> the qapi grammar, and having the segregation already in place will
> make it easier to deal with the distinct meta-type.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
>  scripts/qapi-types.py |  6 ++--
>  scripts/qapi-visit.py |  4 +--
>  scripts/qapi.py       | 94 +++++++++++++++++++++++++++++----------------------
>  3 files changed, 58 insertions(+), 46 deletions(-)
>
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> index 2390887..c9e0201 100644
> --- a/scripts/qapi-types.py
> +++ b/scripts/qapi-types.py
> @@ -170,7 +170,7 @@ typedef enum %(name)s
>
>      return lookup_decl + enum_decl
>
> -def generate_anon_union_qtypes(expr):
> +def generate_alternate_qtypes(expr):
>
>      name = expr['union']
>      members = expr['data']
> @@ -181,7 +181,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
>      name=name)
>
>      for key in members:
> -        qtype = find_anonymous_member_qtype(members[key])
> +        qtype = find_alternate_member_qtype(members[key])
>          assert qtype, "Invalid anonymous union member"
>
>          ret += mcgen('''
> @@ -408,7 +408,7 @@ for expr in exprs:
>              fdef.write(generate_enum_lookup('%sKind' % expr['union'],
>                                              expr['data'].keys()))
>          if expr.get('discriminator') == {}:
> -            fdef.write(generate_anon_union_qtypes(expr))
> +            fdef.write(generate_alternate_qtypes(expr))
>      else:
>          continue
>      fdecl.write(ret)
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 3f82bd4..77b0a1f 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -237,7 +237,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er
>  ''',
>                   name=name)
>
> -def generate_visit_anon_union(name, members):
> +def generate_visit_alternate(name, members):
>      ret = mcgen('''
>
>  void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
> @@ -302,7 +302,7 @@ def generate_visit_union(expr):
>
>      if discriminator == {}:
>          assert not base
> -        return generate_visit_anon_union(name, members)
> +        return generate_visit_alternate(name, members)
>
>      enum_define = discriminator_find_enum_define(expr)
>      if enum_define:
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 39cc88b..17252e9 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -224,21 +224,16 @@ def find_base_fields(base):
>          return None
>      return base_struct_define['data']
>
> -# Return the qtype of an anonymous union branch, or None on error.
> -def find_anonymous_member_qtype(qapi_type):
> +# Return the qtype of an alternate branch, or None on error.
> +def find_alternate_member_qtype(qapi_type):
>      if builtin_types.has_key(qapi_type):
>          return builtin_types[qapi_type]
>      elif find_struct(qapi_type):
>          return "QTYPE_QDICT"
>      elif find_enum(qapi_type):
>          return "QTYPE_QSTRING"
> -    else:
> -        union = find_union(qapi_type)
> -        if union:
> -            discriminator = union.get('discriminator')
> -            if discriminator == {}:
> -                return None
> -            return "QTYPE_QDICT"
> +    elif find_union(qapi_type):
> +        return "QTYPE_QDICT"
>      return None
>
>  # Return the discriminator enum define if discriminator is specified as an
> @@ -276,22 +271,13 @@ def check_union(expr, expr_info):
>      discriminator = expr.get('discriminator')
>      members = expr['data']
>      values = { 'MAX': '(automatic)' }
> -    types_seen = {}
>
> -    # Three types of unions, determined by discriminator.
> +    # Two types of unions, determined by discriminator.
> +    assert discriminator != {}
>
> -    # If the value of member 'discriminator' is {}, it's an
> -    # anonymous union, and must not have a base.
> -    if discriminator == {}:
> -        enum_define = None
> -        if base:
> -            raise QAPIExprError(expr_info,
> -                                "Anonymous union '%s' must not have a base"
> -                                % name)
> -
> -    # Else if the union object has no member 'discriminator', it's an
> +    # If the union object has no member 'discriminator', it's an
>      # ordinary union.  For now, it must not have a base.
> -    elif not discriminator:
> +    if not discriminator:
>          enum_define = None
>          if base:
>              raise QAPIExprError(expr_info,
> @@ -346,24 +332,46 @@ def check_union(expr, expr_info):
>                                      % (name, key, values[c_key]))
>              values[c_key] = key
>
> -        # Ensure anonymous unions have no type conflicts.
> -        if discriminator == {}:
> -            if isinstance(value, list):
> -                raise QAPIExprError(expr_info,
> -                                    "Anonymous union '%s' member '%s' must "
> -                                    "not be array type" % (name, key))
> -            qtype = find_anonymous_member_qtype(value)
> -            if not qtype:
> -                raise QAPIExprError(expr_info,
> -                                    "Anonymous union '%s' member '%s' has "
> -                                    "invalid type '%s'" % (name, key, value))
> -            if qtype in types_seen:
> -                raise QAPIExprError(expr_info,
> -                                    "Anonymous union '%s' member '%s' has "
> -                                    "same QObject type as member '%s'"
> -                                    % (name, key, types_seen[qtype]))
> -            types_seen[qtype] = key
> +def check_alternate(expr, expr_info):
> +    name = expr['union']
> +    base = expr.get('base')
> +    discriminator = expr.get('discriminator')
> +    members = expr['data']
> +    values = { 'MAX': '(automatic)' }
> +    types_seen = {}
>
> +    assert discriminator == {}
> +    if base:
> +        raise QAPIExprError(expr_info,
> +                            "Anonymous union '%s' must not have a base"
> +                            % name)
> +
> +    # Check every branch
> +    for (key, value) in members.items():
> +        # Check for conflicts in the generated enum
> +        c_key = _generate_enum_string(key)
> +        if c_key in values:
> +            raise QAPIExprError(expr_info,
> +                                "Union '%s' member '%s' clashes with '%s'"
> +                                % (name, key, values[c_key]))
> +        values[c_key] = key
> +
> +        # Ensure alternates have no type conflicts.
> +        if isinstance(value, list):
> +            raise QAPIExprError(expr_info,
> +                                "Anonymous union '%s' member '%s' must "
> +                                "not be array type" % (name, key))
> +        qtype = find_alternate_member_qtype(value)
> +        if not qtype:
> +            raise QAPIExprError(expr_info,
> +                                "Anonymous union '%s' member '%s' has "
> +                                "invalid type '%s'" % (name, key, value))
> +        if qtype in types_seen:
> +            raise QAPIExprError(expr_info,
> +                                "Anonymous union '%s' member '%s' has "
> +                                "same QObject type as member '%s'"
> +                                % (name, key, types_seen[qtype]))
> +        types_seen[qtype] = key
>
>  def check_enum(expr, expr_info):
>      name = expr['enum']
> @@ -393,7 +401,10 @@ def check_exprs(schema):
>          if expr.has_key('enum'):
>              check_enum(expr, info)
>          elif expr.has_key('union'):
> -            check_union(expr, info)
> +            if expr.get('discriminator') == {}:
> +                check_alternate(expr, info)
> +            else:
> +                check_union(expr, info)
>          elif expr.has_key('event'):
>              check_event(expr, info)
>
> @@ -535,7 +546,8 @@ def find_struct(name):
>
>  def add_union(definition):
>      global union_types
> -    union_types.append(definition)
> +    if definition.get('discriminator') != {}:
> +        union_types.append(definition)
>
>  def find_union(name):
>      global union_types

This is the only unobvious hunk.

union_types is used only through find_union.  The hunk makes
find_union(N) return None when N names an anonymous union.

find_union() is used in two places:

* find_alternate_member_qtype()

  Patched further up.  It really wants only non-anonymous unions, and
  this change to find_union() renders its check for anonymous unions
  superfluous.  Good.

* generate_visit_alternate()

  Asserts that each member's type is either a built-in type, a complex
  type, a union type, or an enum type.

  The change relaxes the assertion not to trigger on anonymous union
  types.  Why is that okay?

  reply	other threads:[~2015-03-26 14:47 UTC|newest]

Thread overview: 124+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-24 20:03 [Qemu-devel] [PATCH v5 00/28] drop qapi nested structs Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 01/28] qapi: Document type-safety considerations Eric Blake
2015-03-25 18:31   ` Markus Armbruster
2015-03-25 20:11     ` Eric Blake
2015-03-25 21:15       ` Eric Blake
2015-03-26  9:09         ` Markus Armbruster
2015-03-26  7:52       ` Markus Armbruster
2015-03-30 15:23         ` Eric Blake
2015-03-26  8:09       ` Markus Armbruster
2015-03-31 15:09   ` Kevin Wolf
2015-03-31 17:07     ` Eric Blake
2015-03-31 17:15       ` Kevin Wolf
2015-04-01 15:29   ` Markus Armbruster
2015-04-01 15:36     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 02/28] qapi: Fix generation of 'size' builtin type Eric Blake
2015-03-26  9:52   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 03/28] qapi: Require ASCII in schema Eric Blake
2015-03-24 20:33   ` Eric Blake
2015-03-26  9:54     ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 04/28] qapi: Add some enum tests Eric Blake
2015-03-26 10:01   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 05/28] qapi: Better error messages for bad enums Eric Blake
2015-03-26 10:08   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 06/28] qapi: Add some union tests Eric Blake
2015-03-26 13:18   ` Markus Armbruster
2015-03-26 15:04     ` Eric Blake
2015-03-27 12:30       ` Markus Armbruster
2015-03-27 19:47         ` Eric Blake
2015-03-31 17:13       ` Kevin Wolf
2015-03-31 18:15         ` Eric Blake
2015-03-31 18:31           ` Eric Blake
2015-03-31 18:34           ` Kevin Wolf
2015-03-31 20:46         ` Markus Armbruster
2015-04-01  8:23           ` Kevin Wolf
2015-04-01  9:14             ` Markus Armbruster
2015-03-26 13:23   ` Markus Armbruster
2015-03-26 13:51     ` Eric Blake
2015-03-26 15:58       ` Markus Armbruster
2015-03-30 22:45         ` Eric Blake
2015-03-31 23:40           ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 07/28] qapi: Simplify tests of simple unions Eric Blake
2015-03-26 13:41   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 08/28] qapi: Better error messages for bad unions Eric Blake
2015-03-24 20:38   ` Eric Blake
2015-03-26 14:20   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 09/28] qapi: Prepare for catching more semantic parse errors Eric Blake
2015-03-26 14:22   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 10/28] qapi: Segregate anonymous unions into alternates in generator Eric Blake
2015-03-26 14:47   ` Markus Armbruster [this message]
2015-03-26 15:26     ` Eric Blake
2015-03-27 12:32       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 11/28] qapi: Rename anonymous union type in test Eric Blake
2015-03-26 14:55   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 12/28] qapi: Introduce 'alternate' to replace anonymous union Eric Blake
2015-03-24 20:41   ` Eric Blake
2015-03-26 15:42   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 13/28] qapi: Add some expr tests Eric Blake
2015-03-26 15:55   ` Markus Armbruster
2015-03-26 19:02     ` Eric Blake
2015-03-27 12:38       ` Markus Armbruster
2015-03-27 19:39         ` Eric Blake
2015-03-29  8:27           ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 14/28] qapi: Better error messages for bad expressions Eric Blake
2015-03-26 16:27   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 15/28] qapi: Add tests of redefined expressions Eric Blake
2015-03-26 17:05   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 16/28] qapi: Better error messages for duplicated expressions Eric Blake
2015-03-26 17:21   ` Markus Armbruster
2015-03-27  7:52   ` Markus Armbruster
2015-03-27 19:53     ` Eric Blake
2015-03-29  8:38       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 17/28] qapi: Allow true, false and null in schema json Eric Blake
2015-03-26 17:32   ` Markus Armbruster
2015-03-31 15:23   ` Kevin Wolf
2015-03-31 20:09     ` Markus Armbruster
2015-04-01  8:31       ` Kevin Wolf
2015-04-01  9:33         ` Markus Armbruster
2015-04-01  9:58           ` Kevin Wolf
2015-04-01 11:03             ` Markus Armbruster
2015-04-01 11:17               ` Kevin Wolf
2015-04-01 14:51                 ` Markus Armbruster
2015-04-01 12:17           ` Eric Blake
2015-04-01 14:55             ` Markus Armbruster
2015-04-01 15:43             ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 18/28] qapi: Unify type bypass and add tests Eric Blake
2015-03-26 17:38   ` Markus Armbruster
2015-03-26 19:05     ` Eric Blake
2015-03-27 12:40       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 19/28] qapi: Add some type check tests Eric Blake
2015-03-26 17:58   ` Markus Armbruster
2015-03-26 19:07     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 20/28] qapi: More rigourous checking of types Eric Blake
2015-03-27  8:23   ` Markus Armbruster
2015-03-27 20:03     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 21/28] qapi: Require valid names Eric Blake
2015-03-27  8:48   ` Markus Armbruster
2015-03-27 20:15     ` Eric Blake
2015-03-29 10:17       ` Markus Armbruster
2015-03-29 14:23         ` Markus Armbruster
2015-03-27 17:14   ` Markus Armbruster
2015-03-27 20:17     ` Eric Blake
2015-03-29  9:06   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 22/28] qapi: Whitelist commands that don't return dictionary Eric Blake
2015-03-27  9:11   ` Markus Armbruster
2015-03-27 20:20     ` Eric Blake
2015-03-27 16:19   ` Markus Armbruster
2015-03-27 20:29     ` Eric Blake
2015-03-29 10:22       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 23/28] qapi: More rigorous checking for type safety bypass Eric Blake
2015-03-27  9:45   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 24/28] qapi: Merge UserDefTwo and UserDefNested in tests Eric Blake
2015-03-27  9:52   ` Markus Armbruster
2015-03-27 20:30     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 25/28] qapi: Drop tests for inline nested structs Eric Blake
2015-03-27 10:30   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 26/28] qapi: Drop inline nested type in query-version Eric Blake
2015-03-27 10:34   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 27/28] qapi: Drop inline nested types in query-pci Eric Blake
2015-03-27 10:37   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 28/28] qapi: Drop support for inline nested types Eric Blake
2015-03-27 10:45   ` Markus Armbruster
2015-03-27 12:50 ` [Qemu-devel] [PATCH v5 00/28] drop qapi nested structs Markus Armbruster
2015-03-29 16:03 ` Markus Armbruster
2015-03-31  4:30   ` Eric Blake

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=87d23v24uv.fsf@blackfin.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=famz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=wenchaoqemu@gmail.com \
    /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.