[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions
From: |
Marc-André Lureau |
Subject: |
[Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions |
Date: |
Thu, 11 Jan 2018 22:32:04 +0100 |
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>
Reviewed-by: Markus Armbruster <address@hidden>
---
scripts/qapi.py | 36 ++++++++++++++++++++++++++------
tests/test-qmp-commands.c | 6 ++++++
tests/Makefile.include | 4 ++++
tests/qapi-schema/bad-if-empty-list.err | 1 +
tests/qapi-schema/bad-if-empty-list.exit | 1 +
tests/qapi-schema/bad-if-empty-list.json | 3 +++
tests/qapi-schema/bad-if-empty-list.out | 0
tests/qapi-schema/bad-if-empty.err | 1 +
tests/qapi-schema/bad-if-empty.exit | 1 +
tests/qapi-schema/bad-if-empty.json | 3 +++
tests/qapi-schema/bad-if-empty.out | 0
tests/qapi-schema/bad-if-list.err | 1 +
tests/qapi-schema/bad-if-list.exit | 1 +
tests/qapi-schema/bad-if-list.json | 3 +++
tests/qapi-schema/bad-if-list.out | 0
tests/qapi-schema/bad-if.err | 1 +
tests/qapi-schema/bad-if.exit | 1 +
tests/qapi-schema/bad-if.json | 3 +++
tests/qapi-schema/bad-if.out | 0
tests/qapi-schema/qapi-schema-test.json | 20 ++++++++++++++++++
tests/qapi-schema/qapi-schema-test.out | 22 +++++++++++++++++++
21 files changed, 102 insertions(+), 6 deletions(-)
create mode 100644 tests/qapi-schema/bad-if-empty-list.err
create mode 100644 tests/qapi-schema/bad-if-empty-list.exit
create mode 100644 tests/qapi-schema/bad-if-empty-list.json
create mode 100644 tests/qapi-schema/bad-if-empty-list.out
create mode 100644 tests/qapi-schema/bad-if-empty.err
create mode 100644 tests/qapi-schema/bad-if-empty.exit
create mode 100644 tests/qapi-schema/bad-if-empty.json
create mode 100644 tests/qapi-schema/bad-if-empty.out
create mode 100644 tests/qapi-schema/bad-if-list.err
create mode 100644 tests/qapi-schema/bad-if-list.exit
create mode 100644 tests/qapi-schema/bad-if-list.json
create mode 100644 tests/qapi-schema/bad-if-list.out
create mode 100644 tests/qapi-schema/bad-if.err
create mode 100644 tests/qapi-schema/bad-if.exit
create mode 100644 tests/qapi-schema/bad-if.json
create mode 100644 tests/qapi-schema/bad-if.out
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 43a54bf40f..27df0fcf48 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -630,6 +630,27 @@ def add_name(name, info, meta, implicit=False):
all_names[name] = meta
+def check_if(expr, info):
+
+ def check_if_str(ifcond, info):
+ if not isinstance(ifcond, str):
+ raise QAPISemError(
+ info, "'if' condition must be a string or a list of strings")
+ if ifcond == '':
+ raise QAPISemError(info, "'if' condition '' makes no sense")
+
+ ifcond = expr.get('if')
+ if ifcond is None:
+ return
+ elif isinstance(ifcond, list):
+ if ifcond == []:
+ raise QAPISemError(info, "'if' condition [] is useless")
+ for elt in ifcond:
+ check_if_str(elt, info)
+ else:
+ check_if_str(ifcond, info)
+
+
def check_type(info, source, value, allow_array=False,
allow_dict=False, allow_optional=False,
allow_metas=[]):
@@ -869,6 +890,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'"
@@ -894,27 +917,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/Makefile.include b/tests/Makefile.include
index 39a4b5359d..501a5713b5 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -410,6 +410,10 @@ qapi-schema += args-unknown.json
qapi-schema += bad-base.json
qapi-schema += bad-data.json
qapi-schema += bad-ident.json
+qapi-schema += bad-if.json
+qapi-schema += bad-if-empty.json
+qapi-schema += bad-if-empty-list.json
+qapi-schema += bad-if-list.json
qapi-schema += bad-type-bool.json
qapi-schema += bad-type-dict.json
qapi-schema += bad-type-int.json
diff --git a/tests/qapi-schema/bad-if-empty-list.err
b/tests/qapi-schema/bad-if-empty-list.err
new file mode 100644
index 0000000000..75fe6497bc
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
diff --git a/tests/qapi-schema/bad-if-empty-list.exit
b/tests/qapi-schema/bad-if-empty-list.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-empty-list.json
b/tests/qapi-schema/bad-if-empty-list.json
new file mode 100644
index 0000000000..94f2eb8670
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.json
@@ -0,0 +1,3 @@
+# check empty 'if' list
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': [] }
diff --git a/tests/qapi-schema/bad-if-empty-list.out
b/tests/qapi-schema/bad-if-empty-list.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/bad-if-empty.err
b/tests/qapi-schema/bad-if-empty.err
new file mode 100644
index 0000000000..358bdc3e51
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
diff --git a/tests/qapi-schema/bad-if-empty.exit
b/tests/qapi-schema/bad-if-empty.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-empty.json
b/tests/qapi-schema/bad-if-empty.json
new file mode 100644
index 0000000000..fe1dd4eca6
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.json
@@ -0,0 +1,3 @@
+# check empty 'if'
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': '' }
diff --git a/tests/qapi-schema/bad-if-empty.out
b/tests/qapi-schema/bad-if-empty.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/bad-if-list.err
b/tests/qapi-schema/bad-if-list.err
new file mode 100644
index 0000000000..0af6316f78
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-list.json:2: 'if' condition '' makes no sense
diff --git a/tests/qapi-schema/bad-if-list.exit
b/tests/qapi-schema/bad-if-list.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-list.json
b/tests/qapi-schema/bad-if-list.json
new file mode 100644
index 0000000000..49ced9b9ca
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.json
@@ -0,0 +1,3 @@
+# check invalid 'if' content
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': ['foo', ''] }
diff --git a/tests/qapi-schema/bad-if-list.out
b/tests/qapi-schema/bad-if-list.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/bad-if.err b/tests/qapi-schema/bad-if.err
new file mode 100644
index 0000000000..c2e3f5f44c
--- /dev/null
+++ b/tests/qapi-schema/bad-if.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of
strings
diff --git a/tests/qapi-schema/bad-if.exit b/tests/qapi-schema/bad-if.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if.json b/tests/qapi-schema/bad-if.json
new file mode 100644
index 0000000000..3edd1a0bf2
--- /dev/null
+++ b/tests/qapi-schema/bad-if.json
@@ -0,0 +1,3 @@
+# check invalid 'if' type
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': { 'value': 'defined(TEST_IF_STRUCT)' } }
diff --git a/tests/qapi-schema/bad-if.out b/tests/qapi-schema/bad-if.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 c72dbd8050..b997b2d43d 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.16.0.rc1.1.gef27df75a1
- [Qemu-devel] [PATCH v4 00/51] Hi,, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 02/51] qlit: add qobject_from_qlit(), Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 04/51] qapi2texi: minor python code simplification, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions,
Marc-André Lureau <=
- [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check(), Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 08/51] qapi: add 'ifcond' to visitor methods, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 09/51] qapi: mcgen() shouldn't indent # lines, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 10/51] qapi: add #if/#endif helpers, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 11/51] qapi-introspect: modify to_qlit() to append ', ' on level > 0, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 12/51] qapi-introspect: add preprocessor conditions to generated QLit, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 13/51] qapi-commands: add #if conditions to commands, Marc-André Lureau, 2018/01/11
- [Qemu-devel] [PATCH v4 14/51] qapi-event: add #if conditions to events, Marc-André Lureau, 2018/01/11