qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH V9 07/10] qapi script: support enum type as disc


From: Markus Armbruster
Subject: Re: [Qemu-devel] [PATCH V9 07/10] qapi script: support enum type as discriminator in union
Date: Thu, 06 Mar 2014 09:25:23 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.2 (gnu/linux)

Wenchao Xia <address@hidden> writes:

> By default, any union will automatically generate a enum type as
> "[UnionName]Kind" in C code, and it is duplicated when the discriminator
> is specified as a pre-defined enum type in schema. After this patch,
> the pre-defined enum type will be really used as the switch case
> condition in generated C code, if discriminator is an enum field.
>
> Signed-off-by: Wenchao Xia <address@hidden>
> Reviewed-by: Eric Blake <address@hidden>
> ---
>  docs/qapi-code-gen.txt                           |    8 ++++-
>  scripts/qapi-types.py                            |   18 +++++++++---
>  scripts/qapi-visit.py                            |   29 +++++++++++++------
>  scripts/qapi.py                                  |   32 
> +++++++++++++++++++++-
>  tests/Makefile                                   |    2 +-
>  tests/qapi-schema/flat-union-reverse-define.exit |    1 +
>  tests/qapi-schema/flat-union-reverse-define.json |   17 +++++++++++
>  tests/qapi-schema/flat-union-reverse-define.out  |    9 ++++++
>  8 files changed, 99 insertions(+), 17 deletions(-)
>  create mode 100644 tests/qapi-schema/flat-union-reverse-define.err
>  create mode 100644 tests/qapi-schema/flat-union-reverse-define.exit
>  create mode 100644 tests/qapi-schema/flat-union-reverse-define.json
>  create mode 100644 tests/qapi-schema/flat-union-reverse-define.out
>
> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> index 0728f36..a2e7921 100644
> --- a/docs/qapi-code-gen.txt
> +++ b/docs/qapi-code-gen.txt
> @@ -123,11 +123,15 @@ And it looks like this on the wire:
>  
>  Flat union types avoid the nesting on the wire. They are used whenever a
>  specific field of the base type is declared as the discriminator ('type' is
> -then no longer generated). The discriminator must always be a string field.
> +then no longer generated). The discriminator can be a string field or a
> +predefined enum field. If it is a string field, a hidden enum type will be
> +generated as "[UNION_NAME]Kind". If it is an enum field, a compile time check
> +will be done to verify the correctness. It is recommended to use an enum 
> field.
>  The above example can then be modified as follows:
>  
> + { 'enum': 'BlockdevDriver', 'data': [ 'raw', 'qcow2' ] }
>   { 'type': 'BlockdevCommonOptions',
> -   'data': { 'driver': 'str', 'readonly': 'bool' } }
> +   'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
>   { 'union': 'BlockdevOptions',
>     'base': 'BlockdevCommonOptions',
>     'discriminator': 'driver',
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> index 5885bac..10864ef 100644
> --- a/scripts/qapi-types.py
> +++ b/scripts/qapi-types.py
> @@ -201,14 +201,21 @@ def generate_union(expr):
>      base = expr.get('base')
>      discriminator = expr.get('discriminator')
>  
> +    enum_define = discriminator_find_enum_define(expr)
> +    if enum_define:
> +        discriminator_type_name = enum_define['enum_name']
> +    else:
> +        discriminator_type_name = '%sKind' % (name)
> +
>      ret = mcgen('''
>  struct %(name)s
>  {
> -    %(name)sKind kind;
> +    %(discriminator_type_name)s kind;
>      union {
>          void *data;
>  ''',
> -                name=name)
> +                name=name,
> +                discriminator_type_name=discriminator_type_name)
>  
>      for key in typeinfo:
>          ret += mcgen('''
> @@ -389,8 +396,11 @@ for expr in exprs:
>          fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
>      elif expr.has_key('union'):
>          ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
> -        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
> -        fdef.write(generate_enum_lookup('%sKind' % expr['union'], 
> expr['data'].keys()))
> +        enum_define = discriminator_find_enum_define(expr)
> +        if not enum_define:
> +            ret += generate_enum('%sKind' % expr['union'], 
> expr['data'].keys())
> +            fdef.write(generate_enum_lookup('%sKind' % expr['union'],
> +                                            expr['data'].keys()))
>          if expr.get('discriminator') == {}:
>              fdef.write(generate_anon_union_qtypes(expr))
>      else:
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 0baaf60..45ce3a9 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -259,10 +259,16 @@ def generate_visit_union(expr):
>          assert not base
>          return generate_visit_anon_union(name, members)
>  
> -    # There will always be a discriminator in the C switch code, by default 
> it
> -    # is an enum type generated silently as "'%sKind' % (name)"
> -    ret = generate_visit_enum('%sKind' % name, members.keys())
> -    disc_type = '%sKind' % (name)
> +    enum_define = discriminator_find_enum_define(expr)
> +    if enum_define:
> +        # Use the enum type as discriminator
> +        ret = ""
> +        disc_type = enum_define['enum_name']
> +    else:
> +        # There will always be a discriminator in the C switch code, by 
> default it
> +        # is an enum type generated silently as "'%sKind' % (name)"
> +        ret = generate_visit_enum('%sKind' % name, members.keys())
> +        disc_type = '%sKind' % (name)
>  
>      if base:
>          base_fields = find_struct(base)['data']
> @@ -298,15 +304,16 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, 
> const char *name, Error **
>      pop_indent()
>  
>      if not discriminator:
> -        desc_type = "type"
> +        disc_key = "type"
>      else:
> -        desc_type = discriminator
> +        disc_key = discriminator
>      ret += mcgen('''
> -        visit_type_%(name)sKind(m, &(*obj)->kind, "%(type)s", &err);
> +        visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
>          if (!err) {
>              switch ((*obj)->kind) {
>  ''',
> -                 name=name, type=desc_type)
> +                 disc_type = disc_type,
> +                 disc_key = disc_key)
>  
>      for key in members:
>          if not discriminator:
> @@ -517,7 +524,11 @@ for expr in exprs:
>          ret += generate_visit_list(expr['union'], expr['data'])
>          fdef.write(ret)
>  
> -        ret = generate_decl_enum('%sKind' % expr['union'], 
> expr['data'].keys())
> +        enum_define = discriminator_find_enum_define(expr)
> +        ret = ""
> +        if not enum_define:
> +            ret = generate_decl_enum('%sKind' % expr['union'],
> +                                     expr['data'].keys())
>          ret += generate_declaration(expr['union'], expr['data'])
>          fdecl.write(ret)
>      elif expr.has_key('enum'):
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index eebc8a7..0a504c4 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -180,6 +180,25 @@ def find_base_fields(base):
>          return None
>      return base_struct_define['data']
>  
> +# Return the discriminator enum define if discriminator is specified as an
> +# enum type, otherwise return None.
> +def discriminator_find_enum_define(expr):
> +    base = expr.get('base')
> +    discriminator = expr.get('discriminator')
> +
> +    if not (discriminator and base):
> +        return None
> +
> +    base_fields = find_base_fields(base)
> +    if not base_fields:
> +        return None
> +
> +    discriminator_type = base_fields.get(discriminator)
> +    if not discriminator_type:
> +        return None
> +
> +    return find_enum(discriminator_type)
> +
>  def check_union(expr, expr_info):
>      name = expr['union']
>      base = expr.get('base')
> @@ -254,11 +273,22 @@ def parse_schema(fp):
>              add_enum(expr['enum'], expr['data'])
>          elif expr.has_key('union'):
>              add_union(expr)
> -            add_enum('%sKind' % expr['union'])
>          elif expr.has_key('type'):
>              add_struct(expr)
>          exprs.append(expr)
>  
> +    # Try again for hidden UnionKind enum
> +    for expr_elem in schema.exprs:
> +        expr = expr_elem['expr']
> +        if expr.has_key('union'):
> +            try:
> +                enum_define = discriminator_find_enum_define(expr)
> +            except QAPIExprError, e:
> +                print >>sys.stderr, e
> +                exit(1)

How can we get QAPIExprError here?

> +            if not enum_define:
> +                add_enum('%sKind' % expr['union'])
> +
>      try:
>          check_exprs(schema)
>      except QAPIExprError, e:
[...]



reply via email to

[Prev in Thread] Current Thread [Next in Thread]