qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: kwolf@redhat.com, lcapitulino@redhat.com, qemu-devel@nongnu.org,
	mdroth@linux.vnet.ibm.com
Subject: Re: [Qemu-devel] [PATCH V7 07/11] qapi script: support pre-defined enum type as discriminator in union
Date: Fri, 21 Feb 2014 08:17:56 +0800	[thread overview]
Message-ID: <53069B34.2060006@linux.vnet.ibm.com> (raw)
In-Reply-To: <87a9dlwxh9.fsf@blackfin.pond.sub.org>

于 2014/2/21 0:38, Markus Armbruster 写道:
> Wenchao Xia <xiawenc@linux.vnet.ibm.com> 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 <xiawenc@linux.vnet.ibm.com>
>> ---
>>   docs/qapi-code-gen.txt |    8 ++++++--
>>   scripts/qapi-types.py  |   20 ++++++++++++++++----
>>   scripts/qapi-visit.py  |   27 ++++++++++++++++++++-------
>>   scripts/qapi.py        |   13 ++++++++++++-
>>   4 files changed, 54 insertions(+), 14 deletions(-)
>>
>> 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 656a9a0..4098c60 100644
>> --- a/scripts/qapi-types.py
>> +++ b/scripts/qapi-types.py
>> @@ -201,14 +201,22 @@ def generate_union(expr):
>>       base = expr.get('base')
>>       discriminator = expr.get('discriminator')
>>   
>> +    expr_elem = {'expr': expr}
>> +    enum_define = discriminator_find_enum_define(expr_elem)
> 
> expr_elem has no fp, line.  What if discriminator_find_enum_define
> throws a QAPIExprError?
> 
  It shouldn't happen, since all error check happens in parse_schema().

> More of the same below.
> 
>> +    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 +397,12 @@ 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()))
>> +        expr_elem = {'expr': expr}
>> +        enum_define = discriminator_find_enum_define(expr_elem)
>> +        if not enum_define:
>> +            ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
>> +            fdef.write(generate_enum_lookup('%sKind' % expr['union'],
>> +                                            expr['data'].keys()))
> 
> Generate the implicit enum only when we don't have an explicit enum
> discriminator.  Good.
> 
>>           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 87e6df7..08685a7 100644
>> --- a/scripts/qapi-visit.py
>> +++ b/scripts/qapi-visit.py
>> @@ -260,10 +260,17 @@ 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())
>> -    discriminator_type_name = '%sKind' % (name)
>> +    expr_elem = {'expr': expr}
>> +    enum_define = discriminator_find_enum_define(expr_elem)
>> +    if enum_define:
>> +        # Use the predefined enum type as discriminator
>> +        ret = ""
>> +        discriminator_type_name = 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())
>> +        discriminator_type_name = '%sKind' % (name)
> 
> Generate the visit of the discriminator only when we don't have an
> explicit enum discriminator (which gets visited elsewhere already).
> Good.
> 
>>   
>>       if base:
>>           base_fields = find_struct(base)['data']
>> @@ -303,11 +310,12 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
>>       else:
>>           desc_type = discriminator
>>       ret += mcgen('''
>> -        visit_type_%(name)sKind(m, &(*obj)->kind, "%(type)s", &err);
>> +        visit_type_%(discriminator_type_name)s(m, &(*obj)->kind, "%(type)s", &err);
> 
> Another long line due to very long identifier.
> 
  Will improve.

>>           if (!err) {
>>               switch ((*obj)->kind) {
>>   ''',
>> -                 name=name, type=desc_type)
>> +                 discriminator_type_name=discriminator_type_name,
>> +                 type=desc_type)
>>   
>>       for key in members:
>>           if not discriminator:
>> @@ -519,7 +527,12 @@ 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())
>> +        expr_elem = {'expr': expr}
>> +        enum_define = discriminator_find_enum_define(expr_elem)
>> +        ret = ""
>> +        if not enum_define:
>> +            ret = generate_decl_enum('%sKind' % expr['union'],
>> +                                     expr['data'].keys())
> 
> Generate the visitor for the implicit enum only when we don't have an
> explicit enum discriminator (which has its own visitor already).  Good.
> 
>>           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 130dced..2a5eb59 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -250,11 +250,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_elem)
>> +            except QAPIExprError, e:
>> +                print >>sys.stderr, e
>> +                exit(1)
>> +            if not enum_define:
>> +                add_enum('%sKind' % expr['union'])
>> +
>>       try:
>>           check_exprs(schema)
>>       except QAPIExprError, e:
> 
> I guess you move this into its own loop because when base types are used
> before they're defined, or an enum type is used for a discriminator
> before it's defined, then discriminator_find_enum_define() complains.
> Correct?
> 
  Exactly, which allow enum define after usage in schema.

  reply	other threads:[~2014-02-21  0:18 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-20  5:54 [Qemu-devel] [PATCH V7 00/11] qapi script: support enum as discriminator and better enum name Wenchao Xia
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 01/11] qapi script: remember enum values Wenchao Xia
2014-02-20 12:05   ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 02/11] qapi script: add check for duplicated key Wenchao Xia
2014-02-20 12:05   ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 03/11] qapi-script: remember line number in schema parsing Wenchao Xia
2014-02-20 12:22   ` Markus Armbruster
2014-02-21  0:10     ` Wenchao Xia
2014-02-21 13:04       ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 04/11] qapi script: check correctness of discriminator values in union Wenchao Xia
2014-02-20 14:43   ` Markus Armbruster
2014-02-20 15:26     ` Eric Blake
2014-02-21  8:21       ` Markus Armbruster
2014-02-21 13:49         ` Eric Blake
2014-02-21 14:08           ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 05/11] qapi script: code move for generate_enum_name() Wenchao Xia
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 06/11] qapi script: use same function to generate enum string Wenchao Xia
2014-02-20 15:20   ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 07/11] qapi script: support pre-defined enum type as discriminator in union Wenchao Xia
2014-02-20 16:38   ` Markus Armbruster
2014-02-21  0:17     ` Wenchao Xia [this message]
2014-02-21  8:13       ` Markus Armbruster
2014-02-21 13:56         ` Eric Blake
2014-02-21 14:39           ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 08/11] qapi: convert BlockdevOptions to use enum discriminator Wenchao Xia
2014-02-20 17:59   ` Eric Blake
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 09/11] qapi script: do not allow string discriminator Wenchao Xia
2014-02-20 16:50   ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 10/11] qapi script: do not add "_" for every capitalized char in enum Wenchao Xia
2014-02-20 16:54   ` Markus Armbruster
2014-02-20 17:53     ` Eric Blake
2014-02-21  8:21       ` Markus Armbruster
2014-02-20  5:54 ` [Qemu-devel] [PATCH V7 11/11] qapi test: add error path test for union Wenchao Xia

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=53069B34.2060006@linux.vnet.ibm.com \
    --to=xiawenc@linux.vnet.ibm.com \
    --cc=armbru@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=lcapitulino@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).