qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 08/26] qapi: add 'if' condition on enum member value


From: Marc-André Lureau
Subject: [Qemu-devel] [PATCH 08/26] qapi: add 'if' condition on enum member values
Date: Thu, 27 Jul 2017 17:41:08 +0200

Signed-off-by: Marc-André Lureau <address@hidden>
---
 scripts/qapi.py                                 | 39 +++++++++++++++++++++----
 tests/Makefile.include                          |  2 ++
 tests/qapi-schema/enum-dict-member-invalid.err  |  1 +
 tests/qapi-schema/enum-dict-member-invalid.exit |  1 +
 tests/qapi-schema/enum-dict-member-invalid.json |  2 ++
 tests/qapi-schema/enum-dict-member-invalid.out  |  0
 tests/qapi-schema/enum-dict-member.err          |  1 -
 tests/qapi-schema/enum-dict-member.exit         |  2 +-
 tests/qapi-schema/enum-dict-member.json         |  3 +-
 tests/qapi-schema/enum-dict-member.out          |  4 +++
 tests/qapi-schema/enum-if-invalid.err           |  1 +
 tests/qapi-schema/enum-if-invalid.exit          |  1 +
 tests/qapi-schema/enum-if-invalid.json          |  3 ++
 tests/qapi-schema/enum-if-invalid.out           |  0
 tests/qapi-schema/qapi-schema-test.json         |  5 ++--
 tests/qapi-schema/qapi-schema-test.out          |  3 +-
 tests/qapi-schema/test-qapi.py                  |  4 ++-
 17 files changed, 58 insertions(+), 14 deletions(-)
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.err
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.exit
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.json
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.out
 create mode 100644 tests/qapi-schema/enum-if-invalid.err
 create mode 100644 tests/qapi-schema/enum-if-invalid.exit
 create mode 100644 tests/qapi-schema/enum-if-invalid.json
 create mode 100644 tests/qapi-schema/enum-if-invalid.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 79ba1e93da..93d07283e6 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -729,6 +729,10 @@ def check_event(expr, info):
                allow_metas=meta)
 
 
+def enum_get_values(expr):
+    return [e if isinstance(e, str) else e['name'] for e in expr['data']]
+
+
 def check_union(expr, info):
     name = expr['union']
     base = expr.get('base')
@@ -788,7 +792,7 @@ def check_union(expr, info):
         # If the discriminator names an enum type, then all members
         # of 'data' must also be members of the enum type.
         if enum_define:
-            if key not in enum_define['data']:
+            if key not in enum_get_values(enum_define):
                 raise QAPISemError(info,
                                    "Discriminator value '%s' is not found in "
                                    "enum '%s'"
@@ -796,7 +800,7 @@ def check_union(expr, info):
 
     # If discriminator is user-defined, ensure all values are covered
     if enum_define:
-        for value in enum_define['data']:
+        for value in enum_get_values(enum_define):
             if value not in members.keys():
                 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
                                    % (name, value))
@@ -827,7 +831,7 @@ def check_alternate(expr, info):
         if qtype == 'QTYPE_QSTRING':
             enum_expr = enum_types.get(value)
             if enum_expr:
-                for v in enum_expr['data']:
+                for v in enum_get_values(enum_expr):
                     if v in ['on', 'off']:
                         conflicting.add('QTYPE_QBOOL')
                     if re.match(r'[-+0-9.]', v): # lazy, could be tightened
@@ -857,6 +861,12 @@ def check_enum(expr, info):
         raise QAPISemError(info,
                            "Enum '%s' requires a string for 'prefix'" % name)
     for member in members:
+        if isinstance(member, dict):
+            if not 'name' in member:
+                raise QAPISemError(info, "Dictionary member of enum '%s' must "
+                                   "have a 'name' key" % name)
+            check_if(member, info)
+            member = member['name']
         check_name(info, "Member of enum '%s'" % name, member,
                    enum_member=True)
 
@@ -1148,12 +1158,15 @@ class QAPISchemaEnumType(QAPISchemaType):
     def member_names(self):
         return [v.name for v in self.values]
 
+    def members(self):
+        return [(v.name, v.ifcond) for v in self.values]
+
     def json_type(self):
         return 'string'
 
     def visit(self, visitor):
         visitor.visit_enum_type(self.name, self.info,
-                                self.member_names(), self.prefix, self.ifcond)
+                                self.members(), self.prefix, self.ifcond)
 
 
 class QAPISchemaArrayType(QAPISchemaType):
@@ -1275,9 +1288,11 @@ class QAPISchemaObjectType(QAPISchemaType):
 class QAPISchemaMember(object):
     role = 'member'
 
-    def __init__(self, name):
+    def __init__(self, name, ifcond=None):
         assert isinstance(name, str)
+        assert ifcond is None or isinstance(ifcond, str)
         self.name = name
+        self.ifcond = ifcond
         self.owner = None
 
     def set_owner(self, name):
@@ -1556,7 +1571,9 @@ class QAPISchema(object):
                                             qtype_values, 'QTYPE'))
 
     def _make_enum_members(self, values):
-        return [QAPISchemaMember(v) for v in values]
+        return [QAPISchemaMember(v['name'], v.get('if')) if isinstance(v, dict)
+                else QAPISchemaMember(v)
+                for v in values]
 
     def _make_implicit_enum_type(self, name, info, values, ifcond):
         # See also QAPISchemaObjectTypeMember._pretty_owner()
@@ -1942,11 +1959,16 @@ const char *const %(c_name)s_lookup[] = {
 ''',
                 c_name=c_name(name))
     for value in values:
+        ifcond = None
+        if isinstance(value, tuple):
+            value, ifcond = value
+        ret += gen_if(ifcond)
         index = c_enum_const(name, value, prefix)
         ret += mcgen('''
     [%(index)s] = "%(value)s",
 ''',
                      index=index, value=value)
+        ret += gen_endif(ifcond)
 
     max_index = c_enum_const(name, '_MAX', prefix)
     ret += mcgen('''
@@ -1969,12 +1991,17 @@ typedef enum %(c_name)s {
 
     i = 0
     for value in enum_values:
+        ifcond = None
+        if isinstance(value, tuple):
+            value, ifcond = value
+        ret += gen_if(ifcond)
         ret += mcgen('''
     %(c_enum)s = %(i)d,
 ''',
                      c_enum=c_enum_const(name, value, prefix),
                      i=i)
         i += 1
+        ret += gen_endif(ifcond)
 
     ret += mcgen('''
 } %(c_name)s;
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 0fc7088b2c..cb5daf0009 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -413,6 +413,8 @@ qapi-schema += enum-bad-name.json
 qapi-schema += enum-bad-prefix.json
 qapi-schema += enum-clash-member.json
 qapi-schema += enum-dict-member.json
+qapi-schema += enum-dict-member-invalid.json
+qapi-schema += enum-if-invalid.json
 qapi-schema += enum-int-member.json
 qapi-schema += enum-member-case.json
 qapi-schema += enum-missing-data.json
diff --git a/tests/qapi-schema/enum-dict-member-invalid.err 
b/tests/qapi-schema/enum-dict-member-invalid.err
new file mode 100644
index 0000000000..d12cca0df3
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-dict-member-invalid.json:2: Dictionary member of enum 
'MyEnum' must have a 'name' key
diff --git a/tests/qapi-schema/enum-dict-member-invalid.exit 
b/tests/qapi-schema/enum-dict-member-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-dict-member-invalid.json 
b/tests/qapi-schema/enum-dict-member-invalid.json
new file mode 100644
index 0000000000..9cf8406867
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid.json
@@ -0,0 +1,2 @@
+# we reject any enum member that is not a string or a dict with 'name'
+{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
diff --git a/tests/qapi-schema/enum-dict-member-invalid.out 
b/tests/qapi-schema/enum-dict-member-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/enum-dict-member.err 
b/tests/qapi-schema/enum-dict-member.err
index 8ca146ea59..e69de29bb2 100644
--- a/tests/qapi-schema/enum-dict-member.err
+++ b/tests/qapi-schema/enum-dict-member.err
@@ -1 +0,0 @@
-tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a 
string name
diff --git a/tests/qapi-schema/enum-dict-member.exit 
b/tests/qapi-schema/enum-dict-member.exit
index d00491fd7e..573541ac97 100644
--- a/tests/qapi-schema/enum-dict-member.exit
+++ b/tests/qapi-schema/enum-dict-member.exit
@@ -1 +1 @@
-1
+0
diff --git a/tests/qapi-schema/enum-dict-member.json 
b/tests/qapi-schema/enum-dict-member.json
index 79672e0f09..b09a83061c 100644
--- a/tests/qapi-schema/enum-dict-member.json
+++ b/tests/qapi-schema/enum-dict-member.json
@@ -1,2 +1 @@
-# we reject any enum member that is not a string
-{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
+{ 'enum': 'TestEnum', 'data': [ { 'name': 'foo' }, { 'name': 'bar' } ]}
diff --git a/tests/qapi-schema/enum-dict-member.out 
b/tests/qapi-schema/enum-dict-member.out
index e69de29bb2..cf8e3cce2b 100644
--- a/tests/qapi-schema/enum-dict-member.out
+++ b/tests/qapi-schema/enum-dict-member.out
@@ -0,0 +1,4 @@
+enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+    prefix QTYPE
+enum TestEnum ['foo', 'bar']
+object q_empty
diff --git a/tests/qapi-schema/enum-if-invalid.err 
b/tests/qapi-schema/enum-if-invalid.err
new file mode 100644
index 0000000000..236b703e88
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-if-invalid.json:2: 'if' condition requires a string or 
a list of string
diff --git a/tests/qapi-schema/enum-if-invalid.exit 
b/tests/qapi-schema/enum-if-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-if-invalid.json 
b/tests/qapi-schema/enum-if-invalid.json
new file mode 100644
index 0000000000..60bd0ef1d7
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.json
@@ -0,0 +1,3 @@
+# check invalid 'if' type
+{ 'enum': 'TestIfEnum', 'data':
+  [ 'foo', { 'name' : 'bar', 'if': { 'val': 'foo' } } ] }
diff --git a/tests/qapi-schema/enum-if-invalid.out 
b/tests/qapi-schema/enum-if-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/qapi-schema-test.json 
b/tests/qapi-schema/qapi-schema-test.json
index dc2c444fc1..ad2b405d83 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -194,7 +194,8 @@
 { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
   'if': 'defined(TEST_IF_STRUCT)' }
 
-{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
+{ 'enum': 'TestIfEnum', 'data':
+  [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
   'if': 'defined(TEST_IF_ENUM)' }
 
 { 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
@@ -203,7 +204,7 @@
 { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' 
},
   'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
 
-{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' 
},
   'if': 'defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)' }
 
 { 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
diff --git a/tests/qapi-schema/qapi-schema-test.out 
b/tests/qapi-schema/qapi-schema-test.out
index fc5fd25f1b..211c367632 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -60,7 +60,7 @@ alternate TestIfAlternate
 command TestIfCmd q_obj_TestIfCmd-arg -> None
    gen=True success_response=True boxed=False
     if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
-enum TestIfEnum ['foo', 'bar']
+enum TestIfEnum ['foo', ('bar', 'defined(TEST_IF_ENUM_BAR)')]
     if defined(TEST_IF_ENUM)
 event TestIfEvent q_obj_TestIfEvent-arg
    boxed=False
@@ -197,6 +197,7 @@ object q_obj_EVENT_D-arg
     member enum3: EnumOne optional=True
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct optional=False
+    member bar: TestIfEnum optional=False
     if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
 object q_obj_TestIfEvent-arg
     member foo: TestIfStruct optional=False
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 17fd975812..70054848f0 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -18,7 +18,9 @@ import sys
 
 class QAPISchemaTestVisitor(QAPISchemaVisitor):
     def visit_enum_type(self, name, info, values, prefix, ifcond):
-        print 'enum %s %s' % (name, values)
+        values = ', '.join(["'%s'" % v[0] if not v[1] else str(v)
+                            for v in values])
+        print 'enum %s [%s]' % (name, values)
         if prefix:
             print '    prefix %s' % prefix
         self._print_if(ifcond)
-- 
2.14.0.rc0.1.g40ca67566




reply via email to

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