On Thu, 06 Mar 2014 19:54:33 +0800 Wenchao Xia <wenchaoq...@gmail.com> wrote:
> δΊ 2014/3/6 16:25, Markus Armbruster ει: > > Wenchao Xia <wenchaoq...@gmail.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 <wenchaoq...@gmail.com> > >> Reviewed-by: Eric Blake <ebl...@redhat.com> > >> --- > >> 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: > > [...] >