[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions
From: |
Marc-André Lureau |
Subject: |
[Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions |
Date: |
Mon, 11 Sep 2017 13:05:37 +0200 |
Accept 'if' key in top-level elements, accepted as string or list of
string type. The following patches will modify the test visitor to
check the value is correctly saved, and generate #if/#endif code (as a
single #if/endif line or a series for a list).
Example of 'if' key:
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
'if': 'defined(TEST_IF_STRUCT)' }
The generated code is for now *unconditional*. Later patches generate
the conditionals.
A following patch for qapi-code-gen.txt will provide more complete
documentation for 'if' usage.
Signed-off-by: Marc-André Lureau <address@hidden>
---
scripts/qapi.py | 35 +++++++++++++++++++++++++++------
tests/test-qmp-commands.c | 6 ++++++
tests/qapi-schema/qapi-schema-test.json | 20 +++++++++++++++++++
tests/qapi-schema/qapi-schema-test.out | 22 +++++++++++++++++++++
4 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 62dc52ed6e..20c1abf915 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -639,6 +639,26 @@ def add_name(name, info, meta, implicit=False):
all_names[name] = meta
+def check_if(expr, info):
+
+ def check_if_str(ifcond, info):
+ if ifcond == '':
+ raise QAPISemError(info, "'if' condition '' makes no sense")
+
+ ifcond = expr['if']
+ if isinstance(ifcond, str):
+ check_if_str(ifcond, info)
+ elif (isinstance(ifcond, list)
+ and all(isinstance(elt, str) for elt in ifcond)):
+ if ifcond == []:
+ raise QAPISemError(info, "'if' condition [] is useless")
+ for elt in ifcond:
+ check_if_str(elt, info)
+ else:
+ raise QAPISemError(
+ info, "'if' condition must be a string or a list of strings")
+
+
def check_type(info, source, value, allow_array=False,
allow_dict=False, allow_optional=False,
allow_metas=[]):
@@ -878,6 +898,8 @@ def check_keys(expr_elem, meta, required, optional=[]):
raise QAPISemError(info,
"'%s' of %s '%s' should only use true value"
% (key, meta, name))
+ if key == 'if':
+ check_if(expr, info)
for key in required:
if key not in expr:
raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
@@ -903,27 +925,28 @@ def check_exprs(exprs):
if 'enum' in expr:
meta = 'enum'
- check_keys(expr_elem, 'enum', ['data'], ['prefix'])
+ check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
enum_types[expr[meta]] = expr
elif 'union' in expr:
meta = 'union'
check_keys(expr_elem, 'union', ['data'],
- ['base', 'discriminator'])
+ ['base', 'discriminator', 'if'])
union_types[expr[meta]] = expr
elif 'alternate' in expr:
meta = 'alternate'
- check_keys(expr_elem, 'alternate', ['data'])
+ check_keys(expr_elem, 'alternate', ['data'], ['if'])
elif 'struct' in expr:
meta = 'struct'
- check_keys(expr_elem, 'struct', ['data'], ['base'])
+ check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
struct_types[expr[meta]] = expr
elif 'command' in expr:
meta = 'command'
check_keys(expr_elem, 'command', [],
- ['data', 'returns', 'gen', 'success-response', 'boxed'])
+ ['data', 'returns', 'gen', 'success-response', 'boxed',
+ 'if'])
elif 'event' in expr:
meta = 'event'
- check_keys(expr_elem, 'event', [], ['data', 'boxed'])
+ check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
else:
raise QAPISemError(expr_elem['info'],
"Expression is missing metatype")
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 904c89d4d4..9b9a7ffee7 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -10,6 +10,12 @@
static QmpCommandList qmp_commands;
+/* #if defined(TEST_IF_CMD) */
+void qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
+{
+}
+/* #endif */
+
void qmp_user_def_cmd(Error **errp)
{
}
diff --git a/tests/qapi-schema/qapi-schema-test.json
b/tests/qapi-schema/qapi-schema-test.json
index c72dbd8050..dc2c444fc1 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -188,3 +188,23 @@
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
'returns': '__org.qemu_x-Union1' }
+
+# test 'if' condition handling
+
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': 'defined(TEST_IF_STRUCT)' }
+
+{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
+ 'if': 'defined(TEST_IF_ENUM)' }
+
+{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
+ 'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
+
+{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct'
},
+ 'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
+
+{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+ 'if': 'defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)' }
+
+{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
+ 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
diff --git a/tests/qapi-schema/qapi-schema-test.out
b/tests/qapi-schema/qapi-schema-test.out
index 3b1e9082d3..7fbaea19bc 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -52,6 +52,22 @@ enum QEnumTwo ['value1', 'value2']
prefix QENUM_TWO
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
prefix QTYPE
+alternate TestIfAlternate
+ tag type
+ case foo: int
+ case bar: TestStruct
+command TestIfCmd q_obj_TestIfCmd-arg -> None
+ gen=True success_response=True boxed=False
+enum TestIfEnum ['foo', 'bar']
+event TestIfEvent q_obj_TestIfEvent-arg
+ boxed=False
+object TestIfStruct
+ member foo: int optional=False
+object TestIfUnion
+ member type: TestIfUnionKind optional=False
+ tag type
+ case foo: q_obj_TestStruct-wrapper
+enum TestIfUnionKind ['foo']
object TestStruct
member integer: int optional=False
member boolean: bool optional=False
@@ -172,6 +188,12 @@ object q_obj_EVENT_D-arg
member b: str optional=False
member c: str optional=True
member enum3: EnumOne optional=True
+object q_obj_TestIfCmd-arg
+ member foo: TestIfStruct optional=False
+object q_obj_TestIfEvent-arg
+ member foo: TestIfStruct optional=False
+object q_obj_TestStruct-wrapper
+ member data: TestStruct optional=False
object q_obj_UserDefFlatUnion2-base
member integer: int optional=True
member string: str optional=False
--
2.14.1.146.gd35faa819
- [Qemu-devel] [PATCH v3 00/50] Hi,, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 03/50] qapi2texi: minor python code simplification, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 02/50] qapi: generate a literal qobject for introspection, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit(), Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions,
Marc-André Lureau <=
- [Qemu-devel] [PATCH v3 05/50] qapi: add tests for invalid 'if', Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 07/50] qapi: add 'ifcond' to visitor methods, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 06/50] qapi: pass 'if' condition into QAPISchemaEntity objects, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 08/50] qapi: mcgen() shouldn't indent # lines, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 10/50] qapi-introspect: modify to_qlit() to append ', ' on level > 0, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 11/50] qapi-introspect: modify to_qlit() to generate #if code, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 12/50] qapi-introspect: add preprocessor conditions to generated QLit, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 13/50] qapi-commands: add #if conditions to commands, Marc-André Lureau, 2017/09/11
- [Qemu-devel] [PATCH v3 14/50] qapi-event: add #if conditions to events, Marc-André Lureau, 2017/09/11