Sfoglia il codice sorgente

qapi: add 'if' to enum members

QAPISchemaMember gains .ifcond for enum members: inherited classes,
such as QAPISchemaObjectTypeMember, will thus have an ifcond member
after this (those different types will also use the .ifcond to store
the condition and generate conditional code in the following patches).

The generated code remains unconditional for now. Later patches
generate the conditionals.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20181213123724.4866-10-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Marc-André Lureau 6 anni fa
parent
commit
6cc32b0e14

+ 9 - 0
docs/devel/qapi-code-gen.txt

@@ -752,6 +752,15 @@ gets its generated code guarded like this:
  #endif /* defined(HAVE_BAR) */
  #endif /* defined(HAVE_BAR) */
  #endif /* defined(CONFIG_FOO) */
  #endif /* defined(CONFIG_FOO) */
 
 
+An enum value can be replaced by a dictionary with a 'name' and a 'if'
+key.
+
+Example: a conditional 'bar' enum member.
+
+{ 'enum': 'IfEnum', 'data':
+  [ 'foo',
+    { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] }
+
 Please note that you are responsible to ensure that the C code will
 Please note that you are responsible to ensure that the C code will
 compile with an arbitrary combination of conditions, since the
 compile with an arbitrary combination of conditions, since the
 generators are unable to check it at this point.
 generators are unable to check it at this point.

+ 5 - 3
scripts/qapi/common.py

@@ -871,7 +871,8 @@ def check_enum(expr, info):
 
 
     for member in members:
     for member in members:
         source = "dictionary member of enum '%s'" % name
         source = "dictionary member of enum '%s'" % name
-        check_known_keys(info, source, member, ['name'], [])
+        check_known_keys(info, source, member, ['name'], ['if'])
+        check_if(member, info)
         check_name(info, "Member of enum '%s'" % name, member['name'],
         check_name(info, "Member of enum '%s'" % name, member['name'],
                    enum_member=True)
                    enum_member=True)
 
 
@@ -1345,9 +1346,10 @@ def visit(self, visitor):
 class QAPISchemaMember(object):
 class QAPISchemaMember(object):
     role = 'member'
     role = 'member'
 
 
-    def __init__(self, name):
+    def __init__(self, name, ifcond=None):
         assert isinstance(name, str)
         assert isinstance(name, str)
         self.name = name
         self.name = name
+        self.ifcond = listify_cond(ifcond)
         self.owner = None
         self.owner = None
 
 
     def set_owner(self, name):
     def set_owner(self, name):
@@ -1656,7 +1658,7 @@ def _def_predefineds(self):
                                             qtype_values, 'QTYPE'))
                                             qtype_values, 'QTYPE'))
 
 
     def _make_enum_members(self, values):
     def _make_enum_members(self, values):
-        return [QAPISchemaMember(v['name']) for v in values]
+        return [QAPISchemaMember(v['name'], v.get('if')) for v in values]
 
 
     def _make_implicit_enum_type(self, name, info, ifcond, values):
     def _make_implicit_enum_type(self, name, info, ifcond, values):
         # See also QAPISchemaObjectTypeMember._pretty_owner()
         # See also QAPISchemaObjectTypeMember._pretty_owner()

+ 1 - 0
tests/Makefile.include

@@ -384,6 +384,7 @@ qapi-schema += enum-bad-name.json
 qapi-schema += enum-bad-prefix.json
 qapi-schema += enum-bad-prefix.json
 qapi-schema += enum-clash-member.json
 qapi-schema += enum-clash-member.json
 qapi-schema += enum-dict-member-unknown.json
 qapi-schema += enum-dict-member-unknown.json
+qapi-schema += enum-if-invalid.json
 qapi-schema += enum-int-member.json
 qapi-schema += enum-int-member.json
 qapi-schema += enum-member-case.json
 qapi-schema += enum-member-case.json
 qapi-schema += enum-missing-data.json
 qapi-schema += enum-missing-data.json

+ 1 - 1
tests/qapi-schema/enum-dict-member-unknown.err

@@ -1,2 +1,2 @@
 tests/qapi-schema/enum-dict-member-unknown.json:2: Unknown key 'bad-key' in dictionary member of enum 'MyEnum'
 tests/qapi-schema/enum-dict-member-unknown.json:2: Unknown key 'bad-key' in dictionary member of enum 'MyEnum'
-Valid keys are 'name'.
+Valid keys are 'if', 'name'.

+ 1 - 0
tests/qapi-schema/enum-if-invalid.err

@@ -0,0 +1 @@
+tests/qapi-schema/enum-if-invalid.json:2: 'if' condition must be a string or a list of strings

+ 1 - 0
tests/qapi-schema/enum-if-invalid.exit

@@ -0,0 +1 @@
+1

+ 3 - 0
tests/qapi-schema/enum-if-invalid.json

@@ -0,0 +1,3 @@
+# check invalid 'if' type
+{ 'enum': 'TestIfEnum', 'data':
+  [ 'foo', { 'name' : 'bar', 'if': { 'val': 'foo' } } ] }

+ 0 - 0
tests/qapi-schema/enum-if-invalid.out


+ 3 - 2
tests/qapi-schema/qapi-schema-test.json

@@ -204,7 +204,8 @@
 { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
 { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
   'if': 'defined(TEST_IF_STRUCT)' }
   '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)' }
   'if': 'defined(TEST_IF_ENUM)' }
 
 
 { 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
 { 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
@@ -219,7 +220,7 @@
 { 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' },
 { 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' },
   'if': 'defined(TEST_IF_ALT)' }
   'if': 'defined(TEST_IF_ALT)' }
 
 
-{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' },
   'returns': 'UserDefThree',
   'returns': 'UserDefThree',
   'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
   'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
 
 

+ 2 - 0
tests/qapi-schema/qapi-schema-test.out

@@ -272,6 +272,7 @@ object TestIfStruct
 enum TestIfEnum
 enum TestIfEnum
     member foo
     member foo
     member bar
     member bar
+        if ['defined(TEST_IF_ENUM_BAR)']
     if ['defined(TEST_IF_ENUM)']
     if ['defined(TEST_IF_ENUM)']
 object q_obj_TestStruct-wrapper
 object q_obj_TestStruct-wrapper
     member data: TestStruct optional=False
     member data: TestStruct optional=False
@@ -302,6 +303,7 @@ command TestIfAlternateCmd q_obj_TestIfAlternateCmd-arg -> None
     if ['defined(TEST_IF_ALT)']
     if ['defined(TEST_IF_ALT)']
 object q_obj_TestIfCmd-arg
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct optional=False
     member foo: TestIfStruct optional=False
+    member bar: TestIfEnum optional=False
     if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
     if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
 command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
 command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
    gen=True success_response=True boxed=False oob=False preconfig=False
    gen=True success_response=True boxed=False oob=False preconfig=False

+ 1 - 0
tests/qapi-schema/test-qapi.py

@@ -29,6 +29,7 @@ def visit_enum_type(self, name, info, ifcond, members, prefix):
             print('    prefix %s' % prefix)
             print('    prefix %s' % prefix)
         for m in members:
         for m in members:
             print('    member %s' % m.name)
             print('    member %s' % m.name)
+            self._print_if(m.ifcond, indent=8)
         self._print_if(ifcond)
         self._print_if(ifcond)
 
 
     def visit_object_type(self, name, info, ifcond, base, members, variants):
     def visit_object_type(self, name, info, ifcond, base, members, variants):