qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Wenchao Xia <wenchaoqemu@gmail.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: kwolf@redhat.com, Wenchao Xia <xiawenc@linux.vnet.ibm.com>,
	lcapitulino@redhat.com, qemu-devel@nongnu.org,
	mdroth@linux.vnet.ibm.com
Subject: Re: [Qemu-devel] [PATCH V8 04/10] qapi script: check correctness of union
Date: Tue, 04 Mar 2014 22:54:15 +0800	[thread overview]
Message-ID: <5315E917.10707@gmail.com> (raw)
In-Reply-To: <8761nuqgfo.fsf@blackfin.pond.sub.org>

于 2014/3/4 20:47, Markus Armbruster 写道:
> Wenchao Xia <wenchaoqemu@gmail.com> writes:
>
>> From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
> Commit message lost detail since v7.  Intentional?
>
I thought you don't want the message in V7, maybe I misunderstood it.


>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>> Signed-off-by: Wenchao Xia <wenchaoqemu@gmail.com>
>> ---
>>  scripts/qapi.py                                    |  106 +++++++++++++++++++-
>>  tests/Makefile                                     |    4 +-
>>  .../qapi-schema/flat-union-invalid-branch-key.err  |    1 +
>>  .../qapi-schema/flat-union-invalid-branch-key.exit |    1 +
>>  .../qapi-schema/flat-union-invalid-branch-key.json |   17 +++
>>  .../flat-union-invalid-discriminator.err           |    1 +
>>  .../flat-union-invalid-discriminator.exit          |    1 +
>>  .../flat-union-invalid-discriminator.json          |   17 +++
>>  tests/qapi-schema/flat-union-no-base.err           |    1 +
>>  tests/qapi-schema/flat-union-no-base.exit          |    1 +
>>  tests/qapi-schema/flat-union-no-base.json          |   16 +++
>>  tests/qapi-schema/union-invalid-base.err           |    1 +
>>  tests/qapi-schema/union-invalid-base.exit          |    1 +
>>  tests/qapi-schema/union-invalid-base.json          |   10 ++
>>  14 files changed, 175 insertions(+), 3 deletions(-)
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-branch-key.err
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-branch-key.exit
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-branch-key.json
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-branch-key.out
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-discriminator.err
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-discriminator.exit
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-discriminator.json
>>  create mode 100644 tests/qapi-schema/flat-union-invalid-discriminator.out
>>  create mode 100644 tests/qapi-schema/flat-union-no-base.err
>>  create mode 100644 tests/qapi-schema/flat-union-no-base.exit
>>  create mode 100644 tests/qapi-schema/flat-union-no-base.json
>>  create mode 100644 tests/qapi-schema/flat-union-no-base.out
>>  create mode 100644 tests/qapi-schema/union-invalid-base.err
>>  create mode 100644 tests/qapi-schema/union-invalid-base.exit
>>  create mode 100644 tests/qapi-schema/union-invalid-base.json
>>  create mode 100644 tests/qapi-schema/union-invalid-base.out
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index 1954292..cea346f 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -50,6 +50,15 @@ class QAPISchemaError(Exception):
>>      def __str__(self):
>>          return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
>>  
>> +class QAPIExprError(Exception):
>> +    def __init__(self, expr_info, msg):
>> +        self.fp = expr_info['fp']
>> +        self.line = expr_info['line']
>> +        self.msg = msg
>> +
>> +    def __str__(self):
>> +        return "%s:%s: %s" % (self.fp.name, self.line, self.msg)
>> +
>>  class QAPISchema:
>>  
>>      def __init__(self, fp):
>> @@ -64,7 +73,10 @@ class QAPISchema:
>>          self.accept()
>>  
>>          while self.tok != None:
>> -            self.exprs.append(self.get_expr(False))
>> +            expr_info = {'fp': fp, 'line': self.line}
>> +            expr_elem = {'expr': self.get_expr(False),
>> +                         'info': expr_info}
>> +            self.exprs.append(expr_elem)
>>  
>>      def accept(self):
>>          while True:
>> @@ -162,6 +174,89 @@ class QAPISchema:
>>              raise QAPISchemaError(self, 'Expected "{", "[" or string')
>>          return expr
>>  
>> +def find_base_fields(base):
>> +    base_struct_define = find_struct(base)
>> +    if not base_struct_define:
>> +        return None
>> +    return base_struct_define['data']
>> +
>> +# Return the discriminator enum define if discrminator is specified as an
>> +# enum type, otherwise return None.
>> +def discriminator_find_enum_define(expr):
>> +    base = expr.get('base')
>> +    discriminator = expr.get('discriminator')
> Why not expr['base'] and expr['discriminator']?
>
> More of the same below.  No need to respin just for that; we can clean
> it up on top.
>
It is possible 'base' not present in some caller, so use .get to
avoid python error.

>> +
>> +    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')
>> +    discriminator = expr.get('discriminator')
>> +    members = expr['data']
>> +
>> +    # If the object has a member 'base', its value must name a complex type.
>> +    if base:
>> +        base_fields = find_base_fields(base)
>> +        if not base_fields:
>> +            raise QAPIExprError(expr_info,
>> +                                "Base '%s' is not a valid type"
>> +                                % base)
>> +
>> +    # If the union object has no member 'discriminator', it's an
>> +    # ordinary union.
>> +    if not discriminator:
>> +        enum_define = None
>> +
>> +    # Else if the value of member 'discriminator' is {}, it's an
>> +    # anonymous union.
>> +    elif discriminator == {}:
>> +        enum_define = None
>> +
>> +    # Else, it's a flat union.
>> +    else:
>> +        # The object must have a member 'base'.
>> +        if not base:
>> +            raise QAPIExprError(expr_info,
>> +                                "Flat union '%s' must have a base field"
>> +                                % name)
>> +        # The value of member 'discriminator' must name a member of the
>> +        # base type.
>> +        if not base_fields.get(discriminator):
>> +            raise QAPIExprError(expr_info,
>> +                                "Discriminator '%s' is not a member of base "
>> +                                "type '%s'"
>> +                                % (discriminator, base))
>> +        enum_define = discriminator_find_enum_define(expr)
> Could this be simplified?  Like this:
>
>            # The value of member 'discriminator' must name a member of the
>            # base type.
>            discriminator_type = base_fields.get(discriminator):
>            if not discriminator_type
>                raise QAPIExprError(expr_info,
>                                    "Discriminator '%s' is not a member of base "
>                                    "type '%s'"
>                                    % (discriminator, base))
>            enum_define = find_enum(discriminator_type)
>
> It's the only use of discriminator_find_enum_define()...
>
> Hmm, later patches add more uses, so my simplification is probably not
> worthwhile.  Anyway, we can simplify on top.
>
>> +
>> +    # Check every branch
>> +    for (key, value) in members.items():
>> +        # If this named member's value names an enum type, then all members
>> +        # of 'data' must also be members of the enum type.
>> +        if enum_define and not key in enum_define['enum_values']:
>> +            raise QAPIExprError(expr_info,
>> +                                "Discriminator value '%s' is not found in "
>> +                                "enum '%s'" %
>> +                                (key, enum_define["enum_name"]))
>> +        # Todo: put more check such as whether each value is valid, but it may
>> +        # need more functions to handle array case, so leave it now.
> I'm not sure I get your comment.
>
Above only checks key, and I found it is possible to check every
branch's value,
so leaves a comments here.

>> +
>> +def check_exprs(schema):
>> +    for expr_elem in schema.exprs:
>> +        expr = expr_elem['expr']
>> +        if expr.has_key('union'):
>> +            check_union(expr, expr_elem['info'])
>> +
>>  def parse_schema(fp):
>>      try:
>>          schema = QAPISchema(fp)
>> @@ -171,7 +266,8 @@ def parse_schema(fp):
>>  
>>      exprs = []
>>  
>> -    for expr in schema.exprs:
>> +    for expr_elem in schema.exprs:
>> +        expr = expr_elem['expr']
>>          if expr.has_key('enum'):
>>              add_enum(expr['enum'], expr['data'])
>>          elif expr.has_key('union'):
>> @@ -181,6 +277,12 @@ def parse_schema(fp):
>>              add_struct(expr)
>>          exprs.append(expr)
>>  
>> +    try:
>> +        check_exprs(schema)
>> +    except QAPIExprError, e:
>> +        print >>sys.stderr, e
>> +        exit(1)
>> +
>>      return exprs
>>  
>>  def parse_args(typeinfo):
>> diff --git a/tests/Makefile b/tests/Makefile
>> index dfe06eb..6ac9889 100644
>> --- a/tests/Makefile
>> +++ b/tests/Makefile
>> @@ -143,7 +143,9 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
>>          qapi-schema-test.json quoted-structural-chars.json \
>>          trailing-comma-list.json trailing-comma-object.json \
>>          unclosed-list.json unclosed-object.json unclosed-string.json \
>> -        duplicate-key.json)
>> +        duplicate-key.json union-invalid-base.json flat-union-no-base.json \
>> +        flat-union-invalid-discriminator.json \
>> +        flat-union-invalid-branch-key.json)
>>  
>>  GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
>>  
>> diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err
>> new file mode 100644
>> index 0000000..1125caf
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-invalid-branch-key.err
>> @@ -0,0 +1 @@
>> +<stdin>:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
>> diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.exit b/tests/qapi-schema/flat-union-invalid-branch-key.exit
>> new file mode 100644
>> index 0000000..d00491f
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-invalid-branch-key.exit
>> @@ -0,0 +1 @@
>> +1
>> diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.json b/tests/qapi-schema/flat-union-invalid-branch-key.json
>> new file mode 100644
>> index 0000000..a624282
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-invalid-branch-key.json
>> @@ -0,0 +1,17 @@
>> +{ 'enum': 'TestEnum',
>> +  'data': [ 'value1', 'value2' ] }
>> +
>> +{ 'type': 'TestBase',
>> +  'data': { 'enum1': 'TestEnum' } }
>> +
>> +{ 'type': 'TestTypeA',
>> +  'data': { 'string': 'str' } }
>> +
>> +{ 'type': 'TestTypeB',
>> +  'data': { 'integer': 'int' } }
>> +
>> +{ 'union': 'TestUnion',
>> +  'base': 'TestBase',
>> +  'discriminator': 'enum1',
>> +  'data': { 'value_wrong': 'TestTypeA',
>> +            'value2': 'TestTypeB' } }
>> diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.out b/tests/qapi-schema/flat-union-invalid-branch-key.out
>> new file mode 100644
>> index 0000000..e69de29
>> diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err
>> new file mode 100644
>> index 0000000..cad9dbf
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-invalid-discriminator.err
>> @@ -0,0 +1 @@
>> +<stdin>:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase'
>> diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.exit b/tests/qapi-schema/flat-union-invalid-discriminator.exit
>> new file mode 100644
>> index 0000000..d00491f
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-invalid-discriminator.exit
>> @@ -0,0 +1 @@
>> +1
>> diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.json b/tests/qapi-schema/flat-union-invalid-discriminator.json
>> new file mode 100644
>> index 0000000..887157e
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-invalid-discriminator.json
>> @@ -0,0 +1,17 @@
>> +{ 'enum': 'TestEnum',
>> +  'data': [ 'value1', 'value2' ] }
>> +
>> +{ 'type': 'TestBase',
>> +  'data': { 'enum1': 'TestEnum' } }
>> +
>> +{ 'type': 'TestTypeA',
>> +  'data': { 'string': 'str' } }
>> +
>> +{ 'type': 'TestTypeB',
>> +  'data': { 'integer': 'int' } }
>> +
>> +{ 'union': 'TestUnion',
>> +  'base': 'TestBase',
>> +  'discriminator': 'enum_wrong',
>> +  'data': { 'value1': 'TestTypeA',
>> +            'value2': 'TestTypeB' } }
>> diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.out b/tests/qapi-schema/flat-union-invalid-discriminator.out
>> new file mode 100644
>> index 0000000..e69de29
>> diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err
>> new file mode 100644
>> index 0000000..e695315
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-no-base.err
>> @@ -0,0 +1 @@
>> +<stdin>:13: Flat union 'TestUnion' must have a base field
>> diff --git a/tests/qapi-schema/flat-union-no-base.exit b/tests/qapi-schema/flat-union-no-base.exit
>> new file mode 100644
>> index 0000000..d00491f
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-no-base.exit
>> @@ -0,0 +1 @@
>> +1
>> diff --git a/tests/qapi-schema/flat-union-no-base.json b/tests/qapi-schema/flat-union-no-base.json
>> new file mode 100644
>> index 0000000..e0900d4
>> --- /dev/null
>> +++ b/tests/qapi-schema/flat-union-no-base.json
>> @@ -0,0 +1,16 @@
>> +{ 'enum': 'TestEnum',
>> +  'data': [ 'value1', 'value2' ] }
>> +
>> +{ 'type': 'TestBase',
>> +  'data': { 'enum1': 'TestEnum' } }
>> +
> TestEnum and TestBase aren't used.
>
will remove.

>> +{ 'type': 'TestTypeA',
>> +  'data': { 'string': 'str' } }
>> +
>> +{ 'type': 'TestTypeB',
>> +  'data': { 'integer': 'int' } }
>> +
>> +{ 'union': 'TestUnion',
>> +  'discriminator': 'enum1',
>> +  'data': { 'value1': 'TestTypeA',
>> +            'value2': 'TestTypeB' } }
>> diff --git a/tests/qapi-schema/flat-union-no-base.out b/tests/qapi-schema/flat-union-no-base.out
>> new file mode 100644
>> index 0000000..e69de29
>> diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err
>> new file mode 100644
>> index 0000000..dd8e3d1
>> --- /dev/null
>> +++ b/tests/qapi-schema/union-invalid-base.err
>> @@ -0,0 +1 @@
>> +<stdin>:7: Base 'TestBaseWrong' is not a valid type
>> diff --git a/tests/qapi-schema/union-invalid-base.exit b/tests/qapi-schema/union-invalid-base.exit
>> new file mode 100644
>> index 0000000..d00491f
>> --- /dev/null
>> +++ b/tests/qapi-schema/union-invalid-base.exit
>> @@ -0,0 +1 @@
>> +1
>> diff --git a/tests/qapi-schema/union-invalid-base.json b/tests/qapi-schema/union-invalid-base.json
>> new file mode 100644
>> index 0000000..1fa4930
>> --- /dev/null
>> +++ b/tests/qapi-schema/union-invalid-base.json
>> @@ -0,0 +1,10 @@
>> +{ 'type': 'TestTypeA',
>> +  'data': { 'string': 'str' } }
>> +
>> +{ 'type': 'TestTypeB',
>> +  'data': { 'integer': 'int' } }
>> +
>> +{ 'union': 'TestUnion',
>> +  'base': 'TestBaseWrong',
>> +  'data': { 'value1': 'TestTypeA',
>> +            'value2': 'TestTypeB' } }
>> diff --git a/tests/qapi-schema/union-invalid-base.out b/tests/qapi-schema/union-invalid-base.out
>> new file mode 100644
>> index 0000000..e69de29
> Tests cover all the new errors.  Good.

  reply	other threads:[~2014-03-04 14:54 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-27 11:09 [Qemu-devel] [PATCH V8 00/10] qapi script: support enum as discriminator and better enum name Wenchao Xia
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 01/10] qapi script: remember explicitly defined enum values Wenchao Xia
2014-02-27 13:45   ` Eric Blake
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 02/10] qapi script: add check for duplicated key Wenchao Xia
2014-02-27 15:41   ` Eric Blake
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 03/10] qapi script: remember line number in schema parsing Wenchao Xia
2014-02-27 18:03   ` Eric Blake
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 04/10] qapi script: check correctness of union Wenchao Xia
2014-02-27 19:21   ` Eric Blake
2014-02-28 23:19     ` Wenchao Xia
2014-03-04 12:47   ` Markus Armbruster
2014-03-04 14:54     ` Wenchao Xia [this message]
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 05/10] qapi script: code move for generate_enum_name() Wenchao Xia
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 06/10] qapi script: use same function to generate enum string Wenchao Xia
2014-02-27 20:12   ` Eric Blake
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 07/10] qapi script: support enum type as discriminator in union Wenchao Xia
2014-02-27 21:27   ` Eric Blake
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 08/10] qapi: convert BlockdevOptions to use enum discriminator Wenchao Xia
2014-02-27 21:54   ` Eric Blake
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 09/10] qapi script: do not allow string discriminator Wenchao Xia
2014-02-27 22:05   ` Eric Blake
2014-02-27 11:09 ` [Qemu-devel] [PATCH V8 10/10] qapi script: do not add "_" for every capitalized char in enum Wenchao Xia
2014-02-28 23:25 ` [Qemu-devel] [PATCH V8 00/10] qapi script: support enum as discriminator and better enum name Wenchao Xia
2014-03-01  7:09   ` Markus Armbruster
2014-03-04 13:03 ` Markus Armbruster
2014-03-04 13:35   ` Luiz Capitulino
2014-03-04 13:53     ` Markus Armbruster
2014-03-04 14:55       ` 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=5315E917.10707@gmail.com \
    --to=wenchaoqemu@gmail.com \
    --cc=armbru@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=xiawenc@linux.vnet.ibm.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 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).