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: Luiz Capitulino
Subject: Re: [Qemu-devel] [PATCH V9 07/10] qapi script: support enum type as discriminator in union
Date: Thu, 6 Mar 2014 08:03:58 -0500

On Thu, 06 Mar 2014 19:54:33 +0800
Wenchao Xia <address@hidden> wrote:

> 于 2014/3/6 16:25, Markus Armbruster 写道:
> > 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?
> >
> Ops, for this version Exception wouldn't happen, I forgot
> to remove the "try except". It should be simply:
> 
> +    # Try again for hidden UnionKind enum
> +    for expr_elem in schema.exprs:
> +        expr = expr_elem['expr']
> +        if expr.has_key('union'):
> +            enum_define = discriminator_find_enum_define(expr)
> 
> Luiz, do you mind apply this series and correct above directly?

I do. Please, respin 07/10 only and send it as a reply to this thread.

> >> +            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]