* [PATCH v4 1/9] qapi: replace List[str] by QAPISchemaIfCond
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-06-07 14:18 ` Eric Blake
2021-05-17 16:30 ` [PATCH v4 2/9] qapi: make gen_if/gen_endif take a simple string marcandre.lureau
` (8 subsequent siblings)
9 siblings, 1 reply; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Wrap the 'if' condition in a higher-level object. Not only this allows
more type safety but also further refactoring without too much churn.
The following patches will change the syntax of the schema 'if'
conditions to be predicate expressions, and will generate code for
different target languages (C, and Rust in another series).
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
docs/sphinx/qapidoc.py | 2 +-
scripts/qapi/commands.py | 4 +-
scripts/qapi/events.py | 5 ++-
scripts/qapi/gen.py | 14 +++----
scripts/qapi/introspect.py | 26 ++++++------
scripts/qapi/schema.py | 74 +++++++++++++++++++++++-----------
scripts/qapi/types.py | 33 +++++++--------
scripts/qapi/visit.py | 23 ++++++-----
tests/qapi-schema/test-qapi.py | 2 +-
9 files changed, 106 insertions(+), 77 deletions(-)
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index 87c67ab23f..b737949007 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -116,7 +116,7 @@ def _nodes_for_ifcond(self, ifcond, with_if=True):
the conditions are in literal-text and the commas are not.
If with_if is False, we don't return the "(If: " and ")".
"""
- condlist = intersperse([nodes.literal('', c) for c in ifcond],
+ condlist = intersperse([nodes.literal('', c) for c in ifcond.ifcond],
nodes.Text(', '))
if not with_if:
return condlist
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 0e13d51054..3654825968 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -17,7 +17,6 @@
Dict,
List,
Optional,
- Sequence,
Set,
)
@@ -31,6 +30,7 @@
from .schema import (
QAPISchema,
QAPISchemaFeature,
+ QAPISchemaIfCond,
QAPISchemaObjectType,
QAPISchemaType,
)
@@ -301,7 +301,7 @@ def visit_end(self) -> None:
def visit_command(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
arg_type: Optional[QAPISchemaObjectType],
ret_type: Optional[QAPISchemaType],
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index fee8c671e7..82475e84ec 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -12,7 +12,7 @@
See the COPYING file in the top-level directory.
"""
-from typing import List, Optional, Sequence
+from typing import List, Optional
from .common import c_enum_const, c_name, mcgen
from .gen import QAPISchemaModularCVisitor, build_params, ifcontext
@@ -20,6 +20,7 @@
QAPISchema,
QAPISchemaEnumMember,
QAPISchemaFeature,
+ QAPISchemaIfCond,
QAPISchemaObjectType,
)
from .source import QAPISourceInfo
@@ -227,7 +228,7 @@ def visit_end(self) -> None:
def visit_event(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> None:
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
index 1fa503bdbd..1c5b190276 100644
--- a/scripts/qapi/gen.py
+++ b/scripts/qapi/gen.py
@@ -18,7 +18,6 @@
Dict,
Iterator,
Optional,
- Sequence,
Tuple,
)
@@ -32,6 +31,7 @@
mcgen,
)
from .schema import (
+ QAPISchemaIfCond,
QAPISchemaModule,
QAPISchemaObjectType,
QAPISchemaVisitor,
@@ -85,7 +85,7 @@ def write(self, output_dir: str) -> None:
fp.write(text)
-def _wrap_ifcond(ifcond: Sequence[str], before: str, after: str) -> str:
+def _wrap_ifcond(ifcond: QAPISchemaIfCond, before: str, after: str) -> str:
if before == after:
return after # suppress empty #if ... #endif
@@ -95,9 +95,9 @@ def _wrap_ifcond(ifcond: Sequence[str], before: str, after: str) -> str:
if added[0] == '\n':
out += '\n'
added = added[1:]
- out += gen_if(ifcond)
+ out += gen_if(ifcond.ifcond)
out += added
- out += gen_endif(ifcond)
+ out += gen_endif(ifcond.ifcond)
return out
@@ -127,9 +127,9 @@ def build_params(arg_type: Optional[QAPISchemaObjectType],
class QAPIGenCCode(QAPIGen):
def __init__(self, fname: str):
super().__init__(fname)
- self._start_if: Optional[Tuple[Sequence[str], str, str]] = None
+ self._start_if: Optional[Tuple[QAPISchemaIfCond, str, str]] = None
- def start_if(self, ifcond: Sequence[str]) -> None:
+ def start_if(self, ifcond: QAPISchemaIfCond) -> None:
assert self._start_if is None
self._start_if = (ifcond, self._body, self._preamble)
@@ -187,7 +187,7 @@ def _bottom(self) -> str:
@contextmanager
-def ifcontext(ifcond: Sequence[str], *args: QAPIGenCCode) -> Iterator[None]:
+def ifcontext(ifcond: QAPISchemaIfCond, *args: QAPIGenCCode) -> Iterator[None]:
"""
A with-statement context manager that wraps with `start_if()` / `end_if()`.
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 9a348ca2e5..77a8c33ad4 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -15,11 +15,9 @@
Any,
Dict,
Generic,
- Iterable,
List,
Optional,
Sequence,
- Tuple,
TypeVar,
Union,
)
@@ -38,6 +36,7 @@
QAPISchemaEntity,
QAPISchemaEnumMember,
QAPISchemaFeature,
+ QAPISchemaIfCond,
QAPISchemaObjectType,
QAPISchemaObjectTypeMember,
QAPISchemaType,
@@ -91,11 +90,11 @@ class Annotated(Generic[_ValueT]):
"""
# TODO: Remove after Python 3.7 adds @dataclass:
# pylint: disable=too-few-public-methods
- def __init__(self, value: _ValueT, ifcond: Iterable[str],
+ def __init__(self, value: _ValueT, ifcond: QAPISchemaIfCond,
comment: Optional[str] = None):
self.value = value
self.comment: Optional[str] = comment
- self.ifcond: Tuple[str, ...] = tuple(ifcond)
+ self.ifcond = ifcond
def _tree_to_qlit(obj: JSONValue,
@@ -125,10 +124,10 @@ def indent(level: int) -> str:
if obj.comment:
ret += indent(level) + f"/* {obj.comment} */\n"
if obj.ifcond:
- ret += gen_if(obj.ifcond)
+ ret += gen_if(obj.ifcond.ifcond)
ret += _tree_to_qlit(obj.value, level)
if obj.ifcond:
- ret += '\n' + gen_endif(obj.ifcond)
+ ret += '\n' + gen_endif(obj.ifcond.ifcond)
return ret
ret = ''
@@ -254,7 +253,7 @@ def _gen_features(features: Sequence[QAPISchemaFeature]
return [Annotated(f.name, f.ifcond) for f in features]
def _gen_tree(self, name: str, mtype: str, obj: Dict[str, object],
- ifcond: Sequence[str] = (),
+ ifcond: QAPISchemaIfCond = QAPISchemaIfCond(),
features: Sequence[QAPISchemaFeature] = ()) -> None:
"""
Build and append a SchemaInfo object to self._trees.
@@ -305,7 +304,7 @@ def visit_builtin_type(self, name: str, info: Optional[QAPISourceInfo],
self._gen_tree(name, 'builtin', {'json-type': json_type})
def visit_enum_type(self, name: str, info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
members: List[QAPISchemaEnumMember],
prefix: Optional[str]) -> None:
@@ -316,14 +315,14 @@ def visit_enum_type(self, name: str, info: Optional[QAPISourceInfo],
)
def visit_array_type(self, name: str, info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
element_type: QAPISchemaType) -> None:
element = self._use_type(element_type)
self._gen_tree('[' + element + ']', 'array', {'element-type': element},
ifcond)
def visit_object_type_flat(self, name: str, info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
members: List[QAPISchemaObjectTypeMember],
variants: Optional[QAPISchemaVariants]) -> None:
@@ -336,7 +335,7 @@ def visit_object_type_flat(self, name: str, info: Optional[QAPISourceInfo],
self._gen_tree(name, 'object', obj, ifcond, features)
def visit_alternate_type(self, name: str, info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
variants: QAPISchemaVariants) -> None:
self._gen_tree(
@@ -348,7 +347,7 @@ def visit_alternate_type(self, name: str, info: Optional[QAPISourceInfo],
)
def visit_command(self, name: str, info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
arg_type: Optional[QAPISchemaObjectType],
ret_type: Optional[QAPISchemaType], gen: bool,
@@ -367,7 +366,8 @@ def visit_command(self, name: str, info: Optional[QAPISourceInfo],
self._gen_tree(name, 'command', obj, ifcond, features)
def visit_event(self, name: str, info: Optional[QAPISourceInfo],
- ifcond: Sequence[str], features: List[QAPISchemaFeature],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> None:
assert self._schema is not None
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 3a4172fb74..6d55add190 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -25,6 +25,20 @@
from .parser import QAPISchemaParser
+class QAPISchemaIfCond:
+ def __init__(self, ifcond=None):
+ self.ifcond = ifcond or []
+
+ # Returns true if the condition is not void
+ def __bool__(self):
+ return bool(self.ifcond)
+
+ def __eq__(self, other):
+ if not isinstance(other, QAPISchemaIfCond):
+ return NotImplemented
+ return self.ifcond == other.ifcond
+
+
class QAPISchemaEntity:
meta: Optional[str] = None
@@ -42,7 +56,7 @@ def __init__(self, name: str, info, doc, ifcond=None, features=None):
# such place).
self.info = info
self.doc = doc
- self._ifcond = ifcond or []
+ self._ifcond = ifcond or QAPISchemaIfCond()
self.features = features or []
self._checked = False
@@ -77,7 +91,7 @@ def set_module(self, schema):
@property
def ifcond(self):
- assert self._checked
+ assert self._checked and isinstance(self._ifcond, QAPISchemaIfCond)
return self._ifcond
def is_implicit(self):
@@ -601,7 +615,7 @@ def check(self, schema, seen):
else: # simple union
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
assert not self.tag_member.optional
- assert self.tag_member.ifcond == []
+ assert not self.tag_member.ifcond
if self._tag_name: # flat union
# branches that are not explicitly covered get an empty type
cases = {v.name for v in self.variants}
@@ -646,7 +660,7 @@ def __init__(self, name, info, ifcond=None):
assert isinstance(name, str)
self.name = name
self.info = info
- self.ifcond = ifcond or []
+ self.ifcond = ifcond or QAPISchemaIfCond()
self.defined_in = None
def set_defined_in(self, name):
@@ -961,11 +975,13 @@ def _def_predefineds(self):
def _make_features(self, features, info):
if features is None:
return []
- return [QAPISchemaFeature(f['name'], info, f.get('if'))
+ return [QAPISchemaFeature(f['name'], info,
+ QAPISchemaIfCond(f.get('if')))
for f in features]
def _make_enum_members(self, values, info):
- return [QAPISchemaEnumMember(v['name'], info, v.get('if'))
+ return [QAPISchemaEnumMember(v['name'], info,
+ QAPISchemaIfCond(v.get('if')))
for v in values]
def _make_implicit_enum_type(self, name, info, ifcond, values):
@@ -1001,7 +1017,7 @@ def _make_implicit_object_type(self, name, info, ifcond, role, members):
# TODO kill simple unions or implement the disjunction
# pylint: disable=protected-access
- assert (ifcond or []) == typ._ifcond
+ assert ifcond == typ._ifcond
else:
self._def_entity(QAPISchemaObjectType(
name, info, None, ifcond, None, None, members, None))
@@ -1011,7 +1027,7 @@ def _def_enum_type(self, expr, info, doc):
name = expr['enum']
data = expr['data']
prefix = expr.get('prefix')
- ifcond = expr.get('if')
+ ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaEnumType(
name, info, doc, ifcond, features,
@@ -1029,7 +1045,8 @@ def _make_member(self, name, typ, ifcond, features, info):
self._make_features(features, info))
def _make_members(self, data, info):
- return [self._make_member(key, value['type'], value.get('if'),
+ return [self._make_member(key, value['type'],
+ QAPISchemaIfCond(value.get('if')),
value.get('features'), info)
for (key, value) in data.items()]
@@ -1037,7 +1054,7 @@ def _def_struct_type(self, expr, info, doc):
name = expr['struct']
base = expr.get('base')
data = expr['data']
- ifcond = expr.get('if')
+ ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaObjectType(
name, info, doc, ifcond, features, base,
@@ -1060,7 +1077,7 @@ def _def_union_type(self, expr, info, doc):
name = expr['union']
data = expr['data']
base = expr.get('base')
- ifcond = expr.get('if')
+ ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
tag_name = expr.get('discriminator')
tag_member = None
@@ -1069,15 +1086,21 @@ def _def_union_type(self, expr, info, doc):
name, info, ifcond,
'base', self._make_members(base, info))
if tag_name:
- variants = [self._make_variant(key, value['type'],
- value.get('if'), info)
- for (key, value) in data.items()]
+ variants = [
+ self._make_variant(key, value['type'],
+ QAPISchemaIfCond(value.get('if')),
+ info)
+ for (key, value) in data.items()
+ ]
members = []
else:
- variants = [self._make_simple_variant(key, value['type'],
- value.get('if'), info)
- for (key, value) in data.items()]
- enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
+ variants = [
+ self._make_simple_variant(key, value['type'],
+ QAPISchemaIfCond(value.get('if')),
+ info)
+ for (key, value) in data.items()
+ ]
+ enum = [{'name': v.name, 'if': v.ifcond.ifcond} for v in variants]
typ = self._make_implicit_enum_type(name, info, ifcond, enum)
tag_member = QAPISchemaObjectTypeMember('type', info, typ, False)
members = [tag_member]
@@ -1090,11 +1113,14 @@ def _def_union_type(self, expr, info, doc):
def _def_alternate_type(self, expr, info, doc):
name = expr['alternate']
data = expr['data']
- ifcond = expr.get('if')
+ ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
- variants = [self._make_variant(key, value['type'], value.get('if'),
- info)
- for (key, value) in data.items()]
+ variants = [
+ self._make_variant(key, value['type'],
+ QAPISchemaIfCond(value.get('if')),
+ info)
+ for (key, value) in data.items()
+ ]
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
self._def_entity(
QAPISchemaAlternateType(name, info, doc, ifcond, features,
@@ -1111,7 +1137,7 @@ def _def_command(self, expr, info, doc):
allow_oob = expr.get('allow-oob', False)
allow_preconfig = expr.get('allow-preconfig', False)
coroutine = expr.get('coroutine', False)
- ifcond = expr.get('if')
+ ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
@@ -1130,7 +1156,7 @@ def _def_event(self, expr, info, doc):
name = expr['event']
data = expr.get('data')
boxed = expr.get('boxed', False)
- ifcond = expr.get('if')
+ ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 20d572a23a..3673cf0f49 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -13,7 +13,7 @@
# See the COPYING file in the top-level directory.
"""
-from typing import List, Optional, Sequence
+from typing import List, Optional
from .common import (
c_enum_const,
@@ -27,6 +27,7 @@
QAPISchema,
QAPISchemaEnumMember,
QAPISchemaFeature,
+ QAPISchemaIfCond,
QAPISchemaObjectType,
QAPISchemaObjectTypeMember,
QAPISchemaType,
@@ -50,13 +51,13 @@ def gen_enum_lookup(name: str,
''',
c_name=c_name(name))
for memb in members:
- ret += gen_if(memb.ifcond)
+ ret += gen_if(memb.ifcond.ifcond)
index = c_enum_const(name, memb.name, prefix)
ret += mcgen('''
[%(index)s] = "%(name)s",
''',
index=index, name=memb.name)
- ret += gen_endif(memb.ifcond)
+ ret += gen_endif(memb.ifcond.ifcond)
ret += mcgen('''
},
@@ -80,12 +81,12 @@ def gen_enum(name: str,
c_name=c_name(name))
for memb in enum_members:
- ret += gen_if(memb.ifcond)
+ ret += gen_if(memb.ifcond.ifcond)
ret += mcgen('''
%(c_enum)s,
''',
c_enum=c_enum_const(name, memb.name, prefix))
- ret += gen_endif(memb.ifcond)
+ ret += gen_endif(memb.ifcond.ifcond)
ret += mcgen('''
} %(c_name)s;
@@ -125,7 +126,7 @@ def gen_array(name: str, element_type: QAPISchemaType) -> str:
def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
ret = ''
for memb in members:
- ret += gen_if(memb.ifcond)
+ ret += gen_if(memb.ifcond.ifcond)
if memb.optional:
ret += mcgen('''
bool has_%(c_name)s;
@@ -135,11 +136,11 @@ def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
%(c_type)s %(c_name)s;
''',
c_type=memb.type.c_type(), c_name=c_name(memb.name))
- ret += gen_endif(memb.ifcond)
+ ret += gen_endif(memb.ifcond.ifcond)
return ret
-def gen_object(name: str, ifcond: Sequence[str],
+def gen_object(name: str, ifcond: QAPISchemaIfCond,
base: Optional[QAPISchemaObjectType],
members: List[QAPISchemaObjectTypeMember],
variants: Optional[QAPISchemaVariants]) -> str:
@@ -158,7 +159,7 @@ def gen_object(name: str, ifcond: Sequence[str],
ret += mcgen('''
''')
- ret += gen_if(ifcond)
+ ret += gen_if(ifcond.ifcond)
ret += mcgen('''
struct %(c_name)s {
''',
@@ -192,7 +193,7 @@ def gen_object(name: str, ifcond: Sequence[str],
ret += mcgen('''
};
''')
- ret += gen_endif(ifcond)
+ ret += gen_endif(ifcond.ifcond)
return ret
@@ -219,13 +220,13 @@ def gen_variants(variants: QAPISchemaVariants) -> str:
for var in variants.variants:
if var.type.name == 'q_empty':
continue
- ret += gen_if(var.ifcond)
+ ret += gen_if(var.ifcond.ifcond)
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
c_type=var.type.c_unboxed_type(),
c_name=c_name(var.name))
- ret += gen_endif(var.ifcond)
+ ret += gen_endif(var.ifcond.ifcond)
ret += mcgen('''
} u;
@@ -307,7 +308,7 @@ def _gen_type_cleanup(self, name: str) -> None:
def visit_enum_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
members: List[QAPISchemaEnumMember],
prefix: Optional[str]) -> None:
@@ -318,7 +319,7 @@ def visit_enum_type(self,
def visit_array_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
element_type: QAPISchemaType) -> None:
with ifcontext(ifcond, self._genh, self._genc):
self._genh.preamble_add(gen_fwd_object_or_array(name))
@@ -328,7 +329,7 @@ def visit_array_type(self,
def visit_object_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
base: Optional[QAPISchemaObjectType],
members: List[QAPISchemaObjectTypeMember],
@@ -351,7 +352,7 @@ def visit_object_type(self,
def visit_alternate_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
variants: QAPISchemaVariants) -> None:
with ifcontext(ifcond, self._genh):
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 9e96f3c566..67721b2470 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -13,7 +13,7 @@
See the COPYING file in the top-level directory.
"""
-from typing import List, Optional, Sequence
+from typing import List, Optional
from .common import (
c_enum_const,
@@ -29,6 +29,7 @@
QAPISchemaEnumMember,
QAPISchemaEnumType,
QAPISchemaFeature,
+ QAPISchemaIfCond,
QAPISchemaObjectType,
QAPISchemaObjectTypeMember,
QAPISchemaType,
@@ -78,7 +79,7 @@ def gen_visit_object_members(name: str,
for memb in members:
deprecated = 'deprecated' in [f.name for f in memb.features]
- ret += gen_if(memb.ifcond)
+ ret += gen_if(memb.ifcond.ifcond)
if memb.optional:
ret += mcgen('''
if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
@@ -111,7 +112,7 @@ def gen_visit_object_members(name: str,
ret += mcgen('''
}
''')
- ret += gen_endif(memb.ifcond)
+ ret += gen_endif(memb.ifcond.ifcond)
if variants:
tag_member = variants.tag_member
@@ -125,7 +126,7 @@ def gen_visit_object_members(name: str,
for var in variants.variants:
case_str = c_enum_const(tag_member.type.name, var.name,
tag_member.type.prefix)
- ret += gen_if(var.ifcond)
+ ret += gen_if(var.ifcond.ifcond)
if var.type.name == 'q_empty':
# valid variant and nothing to do
ret += mcgen('''
@@ -141,7 +142,7 @@ def gen_visit_object_members(name: str,
case=case_str,
c_type=var.type.c_name(), c_name=c_name(var.name))
- ret += gen_endif(var.ifcond)
+ ret += gen_endif(var.ifcond.ifcond)
ret += mcgen('''
default:
abort();
@@ -227,7 +228,7 @@ def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
c_name=c_name(name))
for var in variants.variants:
- ret += gen_if(var.ifcond)
+ ret += gen_if(var.ifcond.ifcond)
ret += mcgen('''
case %(case)s:
''',
@@ -253,7 +254,7 @@ def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
ret += mcgen('''
break;
''')
- ret += gen_endif(var.ifcond)
+ ret += gen_endif(var.ifcond.ifcond)
ret += mcgen('''
case QTYPE_NONE:
@@ -352,7 +353,7 @@ def _begin_user_module(self, name: str) -> None:
def visit_enum_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
members: List[QAPISchemaEnumMember],
prefix: Optional[str]) -> None:
@@ -363,7 +364,7 @@ def visit_enum_type(self,
def visit_array_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
element_type: QAPISchemaType) -> None:
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name))
@@ -372,7 +373,7 @@ def visit_array_type(self,
def visit_object_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
base: Optional[QAPISchemaObjectType],
members: List[QAPISchemaObjectTypeMember],
@@ -394,7 +395,7 @@ def visit_object_type(self,
def visit_alternate_type(self,
name: str,
info: Optional[QAPISourceInfo],
- ifcond: Sequence[str],
+ ifcond: QAPISchemaIfCond,
features: List[QAPISchemaFeature],
variants: QAPISchemaVariants) -> None:
with ifcontext(ifcond, self._genh, self._genc):
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index e8db9d09d9..fee37b2bc8 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -95,7 +95,7 @@ def _print_variants(variants):
@staticmethod
def _print_if(ifcond, indent=4):
if ifcond:
- print('%sif %s' % (' ' * indent, ifcond))
+ print('%sif %s' % (' ' * indent, ifcond.ifcond))
@classmethod
def _print_features(cls, features, indent=4):
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v4 1/9] qapi: replace List[str] by QAPISchemaIfCond
2021-05-17 16:30 ` [PATCH v4 1/9] qapi: replace List[str] by QAPISchemaIfCond marcandre.lureau
@ 2021-06-07 14:18 ` Eric Blake
2021-06-08 11:38 ` Marc-André Lureau
0 siblings, 1 reply; 18+ messages in thread
From: Eric Blake @ 2021-06-07 14:18 UTC (permalink / raw)
To: marcandre.lureau; +Cc: jsnow, qemu-devel, stefanha, Markus Armbruster
On Mon, May 17, 2021 at 08:30:32PM +0400, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Wrap the 'if' condition in a higher-level object. Not only this allows
> more type safety but also further refactoring without too much churn.
Grammar suggestion:
Not only does this provide more type safety, but it also enables
further refactoring without too much churn.
>
> The following patches will change the syntax of the schema 'if'
> conditions to be predicate expressions, and will generate code for
> different target languages (C, and Rust in another series).
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Tested-by: John Snow <jsnow@redhat.com>
> ---
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 1/9] qapi: replace List[str] by QAPISchemaIfCond
2021-06-07 14:18 ` Eric Blake
@ 2021-06-08 11:38 ` Marc-André Lureau
0 siblings, 0 replies; 18+ messages in thread
From: Marc-André Lureau @ 2021-06-08 11:38 UTC (permalink / raw)
To: Eric Blake; +Cc: John Snow, QEMU, Stefan Hajnoczi, Markus Armbruster
[-- Attachment #1: Type: text/plain, Size: 1110 bytes --]
Hi
On Mon, Jun 7, 2021 at 6:19 PM Eric Blake <eblake@redhat.com> wrote:
> On Mon, May 17, 2021 at 08:30:32PM +0400, marcandre.lureau@redhat.com
> wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > Wrap the 'if' condition in a higher-level object. Not only this allows
> > more type safety but also further refactoring without too much churn.
>
> Grammar suggestion:
>
> Not only does this provide more type safety, but it also enables
> further refactoring without too much churn.
>
>
done, thanks
>
> > The following patches will change the syntax of the schema 'if'
> > conditions to be predicate expressions, and will generate code for
> > different target languages (C, and Rust in another series).
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> > Tested-by: John Snow <jsnow@redhat.com>
> > ---
>
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc. +1-919-301-3266
> Virtualization: qemu.org | libvirt.org
>
>
>
--
Marc-André Lureau
[-- Attachment #2: Type: text/html, Size: 2215 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 2/9] qapi: make gen_if/gen_endif take a simple string
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 1/9] qapi: replace List[str] by QAPISchemaIfCond marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 3/9] qapi: start building an 'if' predicate tree marcandre.lureau
` (7 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Instead of building prepocessor conditions from a list of string, use
the result generated from QAPISchemaIfCond.cgen().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
scripts/qapi/common.py | 22 ++++++++++------------
scripts/qapi/gen.py | 4 ++--
scripts/qapi/introspect.py | 4 ++--
scripts/qapi/schema.py | 3 +++
scripts/qapi/types.py | 20 ++++++++++----------
scripts/qapi/visit.py | 12 ++++++------
6 files changed, 33 insertions(+), 32 deletions(-)
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index cbd3fd81d3..9ab1c9ca55 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -194,19 +194,17 @@ def guardend(name: str) -> str:
name=c_fname(name).upper())
-def gen_if(ifcond: Sequence[str]) -> str:
- ret = ''
- for ifc in ifcond:
- ret += mcgen('''
+def gen_if(cond: str) -> str:
+ if not cond:
+ return ''
+ return mcgen('''
#if %(cond)s
-''', cond=ifc)
- return ret
+''', cond=cond)
-def gen_endif(ifcond: Sequence[str]) -> str:
- ret = ''
- for ifc in reversed(ifcond):
- ret += mcgen('''
+def gen_endif(cond: str) -> str:
+ if not cond:
+ return ''
+ return mcgen('''
#endif /* %(cond)s */
-''', cond=ifc)
- return ret
+''', cond=cond)
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
index 1c5b190276..51a597a025 100644
--- a/scripts/qapi/gen.py
+++ b/scripts/qapi/gen.py
@@ -95,9 +95,9 @@ def _wrap_ifcond(ifcond: QAPISchemaIfCond, before: str, after: str) -> str:
if added[0] == '\n':
out += '\n'
added = added[1:]
- out += gen_if(ifcond.ifcond)
+ out += gen_if(ifcond.cgen())
out += added
- out += gen_endif(ifcond.ifcond)
+ out += gen_endif(ifcond.cgen())
return out
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 77a8c33ad4..474b08fd4d 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -124,10 +124,10 @@ def indent(level: int) -> str:
if obj.comment:
ret += indent(level) + f"/* {obj.comment} */\n"
if obj.ifcond:
- ret += gen_if(obj.ifcond.ifcond)
+ ret += gen_if(obj.ifcond.cgen())
ret += _tree_to_qlit(obj.value, level)
if obj.ifcond:
- ret += '\n' + gen_endif(obj.ifcond.ifcond)
+ ret += '\n' + gen_endif(obj.ifcond.cgen())
return ret
ret = ''
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 6d55add190..0a187ba3f0 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -29,6 +29,9 @@ class QAPISchemaIfCond:
def __init__(self, ifcond=None):
self.ifcond = ifcond or []
+ def cgen(self):
+ return ' && '.join([i for i in self.ifcond])
+
# Returns true if the condition is not void
def __bool__(self):
return bool(self.ifcond)
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 3673cf0f49..db9ff95bd1 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -51,13 +51,13 @@ def gen_enum_lookup(name: str,
''',
c_name=c_name(name))
for memb in members:
- ret += gen_if(memb.ifcond.ifcond)
+ ret += gen_if(memb.ifcond.cgen())
index = c_enum_const(name, memb.name, prefix)
ret += mcgen('''
[%(index)s] = "%(name)s",
''',
index=index, name=memb.name)
- ret += gen_endif(memb.ifcond.ifcond)
+ ret += gen_endif(memb.ifcond.cgen())
ret += mcgen('''
},
@@ -81,12 +81,12 @@ def gen_enum(name: str,
c_name=c_name(name))
for memb in enum_members:
- ret += gen_if(memb.ifcond.ifcond)
+ ret += gen_if(memb.ifcond.cgen())
ret += mcgen('''
%(c_enum)s,
''',
c_enum=c_enum_const(name, memb.name, prefix))
- ret += gen_endif(memb.ifcond.ifcond)
+ ret += gen_endif(memb.ifcond.cgen())
ret += mcgen('''
} %(c_name)s;
@@ -126,7 +126,7 @@ def gen_array(name: str, element_type: QAPISchemaType) -> str:
def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
ret = ''
for memb in members:
- ret += gen_if(memb.ifcond.ifcond)
+ ret += gen_if(memb.ifcond.cgen())
if memb.optional:
ret += mcgen('''
bool has_%(c_name)s;
@@ -136,7 +136,7 @@ def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
%(c_type)s %(c_name)s;
''',
c_type=memb.type.c_type(), c_name=c_name(memb.name))
- ret += gen_endif(memb.ifcond.ifcond)
+ ret += gen_endif(memb.ifcond.cgen())
return ret
@@ -159,7 +159,7 @@ def gen_object(name: str, ifcond: QAPISchemaIfCond,
ret += mcgen('''
''')
- ret += gen_if(ifcond.ifcond)
+ ret += gen_if(ifcond.cgen())
ret += mcgen('''
struct %(c_name)s {
''',
@@ -193,7 +193,7 @@ def gen_object(name: str, ifcond: QAPISchemaIfCond,
ret += mcgen('''
};
''')
- ret += gen_endif(ifcond.ifcond)
+ ret += gen_endif(ifcond.cgen())
return ret
@@ -220,13 +220,13 @@ def gen_variants(variants: QAPISchemaVariants) -> str:
for var in variants.variants:
if var.type.name == 'q_empty':
continue
- ret += gen_if(var.ifcond.ifcond)
+ ret += gen_if(var.ifcond.cgen())
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
c_type=var.type.c_unboxed_type(),
c_name=c_name(var.name))
- ret += gen_endif(var.ifcond.ifcond)
+ ret += gen_endif(var.ifcond.cgen())
ret += mcgen('''
} u;
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 67721b2470..56ea516399 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -79,7 +79,7 @@ def gen_visit_object_members(name: str,
for memb in members:
deprecated = 'deprecated' in [f.name for f in memb.features]
- ret += gen_if(memb.ifcond.ifcond)
+ ret += gen_if(memb.ifcond.cgen())
if memb.optional:
ret += mcgen('''
if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
@@ -112,7 +112,7 @@ def gen_visit_object_members(name: str,
ret += mcgen('''
}
''')
- ret += gen_endif(memb.ifcond.ifcond)
+ ret += gen_endif(memb.ifcond.cgen())
if variants:
tag_member = variants.tag_member
@@ -126,7 +126,7 @@ def gen_visit_object_members(name: str,
for var in variants.variants:
case_str = c_enum_const(tag_member.type.name, var.name,
tag_member.type.prefix)
- ret += gen_if(var.ifcond.ifcond)
+ ret += gen_if(var.ifcond.cgen())
if var.type.name == 'q_empty':
# valid variant and nothing to do
ret += mcgen('''
@@ -142,7 +142,7 @@ def gen_visit_object_members(name: str,
case=case_str,
c_type=var.type.c_name(), c_name=c_name(var.name))
- ret += gen_endif(var.ifcond.ifcond)
+ ret += gen_endif(var.ifcond.cgen())
ret += mcgen('''
default:
abort();
@@ -228,7 +228,7 @@ def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
c_name=c_name(name))
for var in variants.variants:
- ret += gen_if(var.ifcond.ifcond)
+ ret += gen_if(var.ifcond.cgen())
ret += mcgen('''
case %(case)s:
''',
@@ -254,7 +254,7 @@ def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
ret += mcgen('''
break;
''')
- ret += gen_endif(var.ifcond.ifcond)
+ ret += gen_endif(var.ifcond.cgen())
ret += mcgen('''
case QTYPE_NONE:
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 3/9] qapi: start building an 'if' predicate tree
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 1/9] qapi: replace List[str] by QAPISchemaIfCond marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 2/9] qapi: make gen_if/gen_endif take a simple string marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 4/9] qapi: introduce IfPredicateList and IfAny marcandre.lureau
` (6 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
The following patches are going to express schema 'if' conditions in a
target language agnostic way. For that, let's start building a predicate
tree of the configuration options.
This intermediary steps still uses C-preprocessor expressions as
the predicates:
"if: [STR, ..]" is translated to a "IfCond -> IfAll ->
[IfOption, ..]" tree, which will generate "#if STR && .." C code.
Once the boolean operation tree nodes are introduced, the 'if'
expressions will be converted to replace the C syntax (no more
!defined(), &&, ...) and based only on option identifiers.
For now, the condition tree will be less expressive than a full C macro
expression as it will only support these operations: 'all', 'any' and
'not', the only ones needed so far.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
docs/sphinx/qapidoc.py | 6 +--
scripts/qapi/common.py | 51 ++++++++++++++++++++++
scripts/qapi/schema.py | 17 ++++++--
tests/qapi-schema/doc-good.out | 12 +++---
tests/qapi-schema/qapi-schema-test.out | 58 +++++++++++++-------------
tests/qapi-schema/test-qapi.py | 2 +-
6 files changed, 102 insertions(+), 44 deletions(-)
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index b737949007..0f87fb16ce 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -112,12 +112,10 @@ def _make_section(self, title):
def _nodes_for_ifcond(self, ifcond, with_if=True):
"""Return list of Text, literal nodes for the ifcond
- Return a list which gives text like ' (If: cond1, cond2, cond3)', where
- the conditions are in literal-text and the commas are not.
+ Return a list which gives text like ' (If: condition)'.
If with_if is False, we don't return the "(If: " and ")".
"""
- condlist = intersperse([nodes.literal('', c) for c in ifcond.ifcond],
- nodes.Text(', '))
+ condlist = [nodes.literal('', ifcond.docgen())]
if not with_if:
return condlist
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 9ab1c9ca55..86dc2b228b 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -208,3 +208,54 @@ def gen_endif(cond: str) -> str:
return mcgen('''
#endif /* %(cond)s */
''', cond=cond)
+
+
+class IfPredicate:
+ """An 'if' condition predicate"""
+
+ def cgen(self) -> str:
+ raise NotImplementedError()
+
+ def docgen(self) -> str:
+ raise NotImplementedError()
+
+
+class IfOption(IfPredicate):
+ def __init__(self, option: str):
+ self.option = option
+
+ def cgen(self) -> str:
+ return self.option
+
+ def docgen(self) -> str:
+ return self.option
+
+ def __repr__(self) -> str:
+ return f"{type(self).__name__}({self.option!r})"
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, IfOption):
+ return NotImplemented
+ return self.option == other.option
+
+
+class IfAll(IfPredicate):
+ def __init__(self, pred_list: Sequence[IfPredicate]):
+ self.pred_list = pred_list
+
+ def cgen(self) -> str:
+ return " && ".join([p.cgen() for p in self.pred_list])
+
+ def docgen(self) -> str:
+ return " and ".join([p.docgen() for p in self.pred_list])
+
+ def __bool__(self) -> bool:
+ return bool(self.pred_list)
+
+ def __repr__(self) -> str:
+ return f"{type(self).__name__}({self.pred_list!r})"
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, IfAll):
+ return NotImplemented
+ return self.pred_list == other.pred_list
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 0a187ba3f0..0c9675f3a2 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -19,7 +19,12 @@
import re
from typing import Optional
-from .common import POINTER_SUFFIX, c_name
+from .common import (
+ POINTER_SUFFIX,
+ IfAll,
+ IfOption,
+ c_name,
+)
from .error import QAPISemError, QAPISourceError
from .expr import check_exprs
from .parser import QAPISchemaParser
@@ -28,18 +33,22 @@
class QAPISchemaIfCond:
def __init__(self, ifcond=None):
self.ifcond = ifcond or []
+ self.pred = IfAll([IfOption(opt) for opt in self.ifcond])
+
+ def docgen(self):
+ return self.pred.docgen()
def cgen(self):
- return ' && '.join([i for i in self.ifcond])
+ return self.pred.cgen()
# Returns true if the condition is not void
def __bool__(self):
- return bool(self.ifcond)
+ return bool(self.pred)
def __eq__(self, other):
if not isinstance(other, QAPISchemaIfCond):
return NotImplemented
- return self.ifcond == other.ifcond
+ return self.pred == other.pred
class QAPISchemaEntity:
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 8f54ceff2e..db1d23c6bf 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -12,15 +12,15 @@ enum QType
module doc-good.json
enum Enum
member one
- if ['defined(IFONE)']
+ if IfAll([IfOption('defined(IFONE)')])
member two
- if ['defined(IFCOND)']
+ if IfAll([IfOption('defined(IFCOND)')])
feature enum-feat
object Base
member base1: Enum optional=False
object Variant1
member var1: str optional=False
- if ['defined(IFSTR)']
+ if IfAll([IfOption('defined(IFSTR)')])
feature member-feat
feature variant1-feat
object Variant2
@@ -29,7 +29,7 @@ object Object
tag base1
case one: Variant1
case two: Variant2
- if ['IFTWO']
+ if IfAll([IfOption('IFTWO')])
feature union-feat1
object q_obj_Variant1-wrapper
member data: Variant1 optional=False
@@ -38,13 +38,13 @@ object q_obj_Variant2-wrapper
enum SugaredUnionKind
member one
member two
- if ['IFTWO']
+ if IfAll([IfOption('IFTWO')])
object SugaredUnion
member type: SugaredUnionKind optional=False
tag type
case one: q_obj_Variant1-wrapper
case two: q_obj_Variant2-wrapper
- if ['IFTWO']
+ if IfAll([IfOption('IFTWO')])
feature union-feat2
alternate Alternate
tag type
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index e0b8a5f0b6..e4e0fb173a 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -298,65 +298,65 @@ command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Unio
object TestIfStruct
member foo: int optional=False
member bar: int optional=False
- if ['defined(TEST_IF_STRUCT_BAR)']
- if ['defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_STRUCT_BAR)')])
+ if IfAll([IfOption('defined(TEST_IF_STRUCT)')])
enum TestIfEnum
member foo
member bar
- if ['defined(TEST_IF_ENUM_BAR)']
- if ['defined(TEST_IF_ENUM)']
+ if IfAll([IfOption('defined(TEST_IF_ENUM_BAR)')])
+ if IfAll([IfOption('defined(TEST_IF_ENUM)')])
object q_obj_TestStruct-wrapper
member data: TestStruct optional=False
enum TestIfUnionKind
member foo
member bar
- if ['defined(TEST_IF_UNION_BAR)']
- if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_UNION_BAR)')])
+ if IfAll([IfOption('defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)')])
object TestIfUnion
member type: TestIfUnionKind optional=False
tag type
case foo: q_obj_TestStruct-wrapper
case bar: q_obj_str-wrapper
- if ['defined(TEST_IF_UNION_BAR)']
- if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_UNION_BAR)')])
+ if IfAll([IfOption('defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)')])
object q_obj_test-if-union-cmd-arg
member union-cmd-arg: TestIfUnion optional=False
- if ['defined(TEST_IF_UNION)']
+ if IfAll([IfOption('defined(TEST_IF_UNION)')])
command test-if-union-cmd q_obj_test-if-union-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- if ['defined(TEST_IF_UNION)']
+ if IfAll([IfOption('defined(TEST_IF_UNION)')])
alternate TestIfAlternate
tag type
case foo: int
case bar: TestStruct
- if ['defined(TEST_IF_ALT_BAR)']
- if ['defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_ALT_BAR)')])
+ if IfAll([IfOption('defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)')])
object q_obj_test-if-alternate-cmd-arg
member alt-cmd-arg: TestIfAlternate optional=False
- if ['defined(TEST_IF_ALT)']
+ if IfAll([IfOption('defined(TEST_IF_ALT)')])
command test-if-alternate-cmd q_obj_test-if-alternate-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- if ['defined(TEST_IF_ALT)']
+ if IfAll([IfOption('defined(TEST_IF_ALT)')])
object q_obj_test-if-cmd-arg
member foo: TestIfStruct optional=False
member bar: TestIfEnum optional=False
- if ['defined(TEST_IF_CMD_BAR)']
- if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_CMD_BAR)')])
+ if IfAll([IfOption('defined(TEST_IF_CMD)'), IfOption('defined(TEST_IF_STRUCT)')])
command test-if-cmd q_obj_test-if-cmd-arg -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
- if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_CMD)'), IfOption('defined(TEST_IF_STRUCT)')])
command test-cmd-return-def-three None -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
array TestIfEnumList TestIfEnum
- if ['defined(TEST_IF_ENUM)']
+ if IfAll([IfOption('defined(TEST_IF_ENUM)')])
object q_obj_TEST_IF_EVENT-arg
member foo: TestIfStruct optional=False
member bar: TestIfEnumList optional=False
- if ['defined(TEST_IF_EVT_BAR)']
- if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_EVT_BAR)')])
+ if IfAll([IfOption('defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)')])
event TEST_IF_EVENT q_obj_TEST_IF_EVENT-arg
boxed=False
- if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
+ if IfAll([IfOption('defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)')])
object FeatureStruct0
member foo: int optional=False
object FeatureStruct1
@@ -379,17 +379,17 @@ object FeatureStruct4
object CondFeatureStruct1
member foo: int optional=False
feature feature1
- if ['defined(TEST_IF_FEATURE_1)']
+ if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
object CondFeatureStruct2
member foo: int optional=False
feature feature1
- if ['defined(TEST_IF_FEATURE_1)']
+ if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
feature feature2
- if ['defined(TEST_IF_FEATURE_2)']
+ if IfAll([IfOption('defined(TEST_IF_FEATURE_2)')])
object CondFeatureStruct3
member foo: int optional=False
feature feature1
- if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
+ if IfAll([IfOption('defined(TEST_IF_COND_1)'), IfOption('defined(TEST_IF_COND_2)')])
enum FeatureEnum1
member eins
member zwei
@@ -429,17 +429,17 @@ command test-command-features3 None -> None
command test-command-cond-features1 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if ['defined(TEST_IF_FEATURE_1)']
+ if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
command test-command-cond-features2 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if ['defined(TEST_IF_FEATURE_1)']
+ if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
feature feature2
- if ['defined(TEST_IF_FEATURE_2)']
+ if IfAll([IfOption('defined(TEST_IF_FEATURE_2)')])
command test-command-cond-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
+ if IfAll([IfOption('defined(TEST_IF_COND_1)'), IfOption('defined(TEST_IF_COND_2)')])
event TEST_EVENT_FEATURES0 FeatureStruct1
boxed=False
event TEST_EVENT_FEATURES1 None
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index fee37b2bc8..9a652822bd 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -95,7 +95,7 @@ def _print_variants(variants):
@staticmethod
def _print_if(ifcond, indent=4):
if ifcond:
- print('%sif %s' % (' ' * indent, ifcond.ifcond))
+ print('%sif %s' % (' ' * indent, ifcond.pred))
@classmethod
def _print_features(cls, features, indent=4):
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 4/9] qapi: introduce IfPredicateList and IfAny
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
` (2 preceding siblings ...)
2021-05-17 16:30 ` [PATCH v4 3/9] qapi: start building an 'if' predicate tree marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 5/9] qapi: add IfNot marcandre.lureau
` (5 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Refactor IfAll class, to introduce a base class IfPredicateList and add
IfAny for the 'any' conditions.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
scripts/qapi/common.py | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 86dc2b228b..4e5c3ebaae 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -239,15 +239,26 @@ def __eq__(self, other: object) -> bool:
return self.option == other.option
-class IfAll(IfPredicate):
+class IfPredicateList(IfPredicate):
+ C_SEP = ""
+ DOC_SEP = ""
+
def __init__(self, pred_list: Sequence[IfPredicate]):
self.pred_list = pred_list
def cgen(self) -> str:
- return " && ".join([p.cgen() for p in self.pred_list])
+ sep = " " + self.C_SEP + " "
+ gen = sep.join([p.cgen() for p in self.pred_list])
+ if len(self.pred_list) <= 1:
+ return gen
+ return "(%s)" % gen
def docgen(self) -> str:
- return " and ".join([p.docgen() for p in self.pred_list])
+ sep = " " + self.DOC_SEP + " "
+ gen = sep.join([p.docgen() for p in self.pred_list])
+ if len(self.pred_list) <= 1:
+ return gen
+ return "(%s)" % gen
def __bool__(self) -> bool:
return bool(self.pred_list)
@@ -256,6 +267,16 @@ def __repr__(self) -> str:
return f"{type(self).__name__}({self.pred_list!r})"
def __eq__(self, other: object) -> bool:
- if not isinstance(other, IfAll):
+ if not isinstance(other, type(self)):
return NotImplemented
return self.pred_list == other.pred_list
+
+
+class IfAll(IfPredicateList):
+ C_SEP = "&&"
+ DOC_SEP = "and"
+
+
+class IfAny(IfPredicateList):
+ C_SEP = "||"
+ DOC_SEP = "or"
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 5/9] qapi: add IfNot
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
` (3 preceding siblings ...)
2021-05-17 16:30 ` [PATCH v4 4/9] qapi: introduce IfPredicateList and IfAny marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 6/9] qapi: normalize 'if' condition to IfPredicate tree marcandre.lureau
` (4 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Introduce IfNot predicate class, for 'not' condition expressions.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
scripts/qapi/common.py | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 4e5c3ebaae..8a23c1d4ef 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -239,6 +239,28 @@ def __eq__(self, other: object) -> bool:
return self.option == other.option
+class IfNot(IfPredicate):
+ def __init__(self, pred: IfPredicate):
+ self.pred = pred
+
+ def cgen(self) -> str:
+ return "!" + self.pred.cgen()
+
+ def docgen(self) -> str:
+ return "not " + self.pred.docgen()
+
+ def __bool__(self) -> bool:
+ return bool(self.pred)
+
+ def __repr__(self) -> str:
+ return f"IfNot({self.pred!r})"
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, type(self)):
+ return False
+ return self.pred == other.pred
+
+
class IfPredicateList(IfPredicate):
C_SEP = ""
DOC_SEP = ""
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 6/9] qapi: normalize 'if' condition to IfPredicate tree
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
` (4 preceding siblings ...)
2021-05-17 16:30 ` [PATCH v4 5/9] qapi: add IfNot marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 7/9] qapi: convert 'if' C-expressions to the new syntax tree marcandre.lureau
` (3 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Modify check_if() to build an IfPredicate tree (the schema
documentation is updated in a following patch).
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
tests/unit/test-qmp-cmds.c | 1 +
scripts/qapi/expr.py | 53 ++++++++++------
scripts/qapi/schema.py | 62 +++++++++++++------
tests/qapi-schema/bad-if.err | 3 +-
tests/qapi-schema/doc-good.out | 12 ++--
tests/qapi-schema/enum-if-invalid.err | 3 +-
tests/qapi-schema/features-if-invalid.err | 2 +-
tests/qapi-schema/qapi-schema-test.json | 20 +++---
tests/qapi-schema/qapi-schema-test.out | 59 ++++++++++--------
.../qapi-schema/struct-member-if-invalid.err | 2 +-
10 files changed, 136 insertions(+), 81 deletions(-)
diff --git a/tests/unit/test-qmp-cmds.c b/tests/unit/test-qmp-cmds.c
index 1b0b7d99df..83efa39720 100644
--- a/tests/unit/test-qmp-cmds.c
+++ b/tests/unit/test-qmp-cmds.c
@@ -51,6 +51,7 @@ FeatureStruct1 *qmp_test_features0(bool has_fs0, FeatureStruct0 *fs0,
bool has_cfs1, CondFeatureStruct1 *cfs1,
bool has_cfs2, CondFeatureStruct2 *cfs2,
bool has_cfs3, CondFeatureStruct3 *cfs3,
+ bool has_cfs4, CondFeatureStruct4 *cfs4,
Error **errp)
{
return g_new0(FeatureStruct1, 1);
diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py
index 496f7e0333..0a0ff73203 100644
--- a/scripts/qapi/expr.py
+++ b/scripts/qapi/expr.py
@@ -261,12 +261,13 @@ def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
"""
Normalize and validate the ``if`` member of an object.
- The ``if`` member may be either a ``str`` or a ``List[str]``.
- A ``str`` value will be normalized to ``List[str]``.
+ The ``if`` field may be either a ``str``, a ``List[str]`` or a dict.
+ A ``str`` element or a ``List[str]`` will be normalized to
+ ``{'all': List[str]}``.
:forms:
:sugared: ``Union[str, List[str]]``
- :canonical: ``List[str]``
+ :canonical: ``Union[str, dict]``
:param expr: The expression containing the ``if`` member to validate.
:param info: QAPI schema source file information.
@@ -281,25 +282,41 @@ def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
if ifcond is None:
return
- if isinstance(ifcond, list):
- if not ifcond:
- raise QAPISemError(
- info, "'if' condition [] of %s is useless" % source)
- else:
- # Normalize to a list
- ifcond = expr['if'] = [ifcond]
-
- for elt in ifcond:
- if not isinstance(elt, str):
+ def normalize(cond: Union[str, List[str], object]) -> Union[str, object]:
+ if isinstance(cond, str):
+ if not cond.strip():
+ raise QAPISemError(
+ info,
+ "'if' condition '%s' of %s makes no sense"
+ % (cond, source))
+ return cond
+ if isinstance(cond, list):
+ cond = {"all": cond}
+ if not isinstance(cond, dict):
raise QAPISemError(
info,
- "'if' condition of %s must be a string or a list of strings"
- % source)
- if not elt.strip():
+ "'if' condition of %s must be a string, "
+ "a list of strings or a dict" % source)
+ if len(cond) != 1:
raise QAPISemError(
info,
- "'if' condition '%s' of %s makes no sense"
- % (elt, source))
+ "'if' condition dict of %s must have one key: "
+ "'all', 'any' or 'not'" % source)
+ check_keys(cond, info, "'if' condition", [],
+ ["all", "any", "not"])
+ oper, operands = next(iter(cond.items()))
+ if not operands:
+ raise QAPISemError(
+ info, "'if' condition [] of %s is useless" % source)
+ if oper == "not":
+ return {oper: normalize(operands)}
+ if oper in ("all", "any") and not isinstance(operands, list):
+ raise QAPISemError(
+ info, "'%s' condition of %s must be a list" % (oper, source))
+ operands = [normalize(o) for o in operands]
+ return {oper: operands}
+
+ expr['if'] = normalize(ifcond)
def normalize_members(members: object) -> None:
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 0c9675f3a2..07fb33834a 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -22,6 +22,8 @@
from .common import (
POINTER_SUFFIX,
IfAll,
+ IfAny,
+ IfNot,
IfOption,
c_name,
)
@@ -31,15 +33,14 @@
class QAPISchemaIfCond:
- def __init__(self, ifcond=None):
- self.ifcond = ifcond or []
- self.pred = IfAll([IfOption(opt) for opt in self.ifcond])
+ def __init__(self, pred=None):
+ self.pred = pred
def docgen(self):
- return self.pred.docgen()
+ return self and self.pred.docgen()
def cgen(self):
- return self.pred.cgen()
+ return self and self.pred.cgen()
# Returns true if the condition is not void
def __bool__(self):
@@ -984,16 +985,41 @@ def _def_predefineds(self):
self._def_entity(QAPISchemaEnumType('QType', None, None, None, None,
qtype_values, 'QTYPE'))
+ def _make_if(self, cond):
+ if isinstance(cond, QAPISchemaIfCond):
+ return cond
+ if cond is None:
+ return QAPISchemaIfCond()
+
+ def make_pred(node):
+ if isinstance(node, str):
+ return IfOption(node)
+ oper, operands = next(iter(node.items()))
+ op2cls = {
+ 'all': IfAll,
+ 'any': IfAny,
+ 'not': IfNot,
+ }
+
+ if isinstance(operands, list):
+ operands = [make_pred(o) for o in operands]
+ else:
+ operands = make_pred(operands)
+
+ return op2cls[oper](operands)
+
+ return QAPISchemaIfCond(make_pred(cond))
+
def _make_features(self, features, info):
if features is None:
return []
return [QAPISchemaFeature(f['name'], info,
- QAPISchemaIfCond(f.get('if')))
+ self._make_if(f.get('if')))
for f in features]
def _make_enum_members(self, values, info):
return [QAPISchemaEnumMember(v['name'], info,
- QAPISchemaIfCond(v.get('if')))
+ self._make_if(v.get('if')))
for v in values]
def _make_implicit_enum_type(self, name, info, ifcond, values):
@@ -1039,7 +1065,7 @@ def _def_enum_type(self, expr, info, doc):
name = expr['enum']
data = expr['data']
prefix = expr.get('prefix')
- ifcond = QAPISchemaIfCond(expr.get('if'))
+ ifcond = self._make_if(expr.get('if'))
features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaEnumType(
name, info, doc, ifcond, features,
@@ -1058,7 +1084,7 @@ def _make_member(self, name, typ, ifcond, features, info):
def _make_members(self, data, info):
return [self._make_member(key, value['type'],
- QAPISchemaIfCond(value.get('if')),
+ self._make_if(value.get('if')),
value.get('features'), info)
for (key, value) in data.items()]
@@ -1066,7 +1092,7 @@ def _def_struct_type(self, expr, info, doc):
name = expr['struct']
base = expr.get('base')
data = expr['data']
- ifcond = QAPISchemaIfCond(expr.get('if'))
+ ifcond = self._make_if(expr.get('if'))
features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaObjectType(
name, info, doc, ifcond, features, base,
@@ -1089,7 +1115,7 @@ def _def_union_type(self, expr, info, doc):
name = expr['union']
data = expr['data']
base = expr.get('base')
- ifcond = QAPISchemaIfCond(expr.get('if'))
+ ifcond = self._make_if(expr.get('if'))
features = self._make_features(expr.get('features'), info)
tag_name = expr.get('discriminator')
tag_member = None
@@ -1100,7 +1126,7 @@ def _def_union_type(self, expr, info, doc):
if tag_name:
variants = [
self._make_variant(key, value['type'],
- QAPISchemaIfCond(value.get('if')),
+ self._make_if(value.get('if')),
info)
for (key, value) in data.items()
]
@@ -1108,11 +1134,11 @@ def _def_union_type(self, expr, info, doc):
else:
variants = [
self._make_simple_variant(key, value['type'],
- QAPISchemaIfCond(value.get('if')),
+ self._make_if(value.get('if')),
info)
for (key, value) in data.items()
]
- enum = [{'name': v.name, 'if': v.ifcond.ifcond} for v in variants]
+ enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
typ = self._make_implicit_enum_type(name, info, ifcond, enum)
tag_member = QAPISchemaObjectTypeMember('type', info, typ, False)
members = [tag_member]
@@ -1125,11 +1151,11 @@ def _def_union_type(self, expr, info, doc):
def _def_alternate_type(self, expr, info, doc):
name = expr['alternate']
data = expr['data']
- ifcond = QAPISchemaIfCond(expr.get('if'))
+ ifcond = self._make_if(expr.get('if'))
features = self._make_features(expr.get('features'), info)
variants = [
self._make_variant(key, value['type'],
- QAPISchemaIfCond(value.get('if')),
+ self._make_if(value.get('if')),
info)
for (key, value) in data.items()
]
@@ -1149,7 +1175,7 @@ def _def_command(self, expr, info, doc):
allow_oob = expr.get('allow-oob', False)
allow_preconfig = expr.get('allow-preconfig', False)
coroutine = expr.get('coroutine', False)
- ifcond = QAPISchemaIfCond(expr.get('if'))
+ ifcond = self._make_if(expr.get('if'))
features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
@@ -1168,7 +1194,7 @@ def _def_event(self, expr, info, doc):
name = expr['event']
data = expr.get('data')
boxed = expr.get('boxed', False)
- ifcond = QAPISchemaIfCond(expr.get('if'))
+ ifcond = self._make_if(expr.get('if'))
features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
diff --git a/tests/qapi-schema/bad-if.err b/tests/qapi-schema/bad-if.err
index f83dee65da..454fbae387 100644
--- a/tests/qapi-schema/bad-if.err
+++ b/tests/qapi-schema/bad-if.err
@@ -1,2 +1,3 @@
bad-if.json: In struct 'TestIfStruct':
-bad-if.json:2: 'if' condition of struct must be a string or a list of strings
+bad-if.json:2: 'if' condition has unknown key 'value'
+Valid keys are 'all', 'any', 'not'.
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index db1d23c6bf..4d951f97ee 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -12,15 +12,15 @@ enum QType
module doc-good.json
enum Enum
member one
- if IfAll([IfOption('defined(IFONE)')])
+ if IfOption('defined(IFONE)')
member two
- if IfAll([IfOption('defined(IFCOND)')])
+ if IfOption('defined(IFCOND)')
feature enum-feat
object Base
member base1: Enum optional=False
object Variant1
member var1: str optional=False
- if IfAll([IfOption('defined(IFSTR)')])
+ if IfOption('defined(IFSTR)')
feature member-feat
feature variant1-feat
object Variant2
@@ -29,7 +29,7 @@ object Object
tag base1
case one: Variant1
case two: Variant2
- if IfAll([IfOption('IFTWO')])
+ if IfOption('IFTWO')
feature union-feat1
object q_obj_Variant1-wrapper
member data: Variant1 optional=False
@@ -38,13 +38,13 @@ object q_obj_Variant2-wrapper
enum SugaredUnionKind
member one
member two
- if IfAll([IfOption('IFTWO')])
+ if IfOption('IFTWO')
object SugaredUnion
member type: SugaredUnionKind optional=False
tag type
case one: q_obj_Variant1-wrapper
case two: q_obj_Variant2-wrapper
- if IfAll([IfOption('IFTWO')])
+ if IfOption('IFTWO')
feature union-feat2
alternate Alternate
tag type
diff --git a/tests/qapi-schema/enum-if-invalid.err b/tests/qapi-schema/enum-if-invalid.err
index 0556dc967b..3bb84075a9 100644
--- a/tests/qapi-schema/enum-if-invalid.err
+++ b/tests/qapi-schema/enum-if-invalid.err
@@ -1,2 +1,3 @@
enum-if-invalid.json: In enum 'TestIfEnum':
-enum-if-invalid.json:2: 'if' condition of 'data' member 'bar' must be a string or a list of strings
+enum-if-invalid.json:2: 'if' condition has unknown key 'val'
+Valid keys are 'all', 'any', 'not'.
diff --git a/tests/qapi-schema/features-if-invalid.err b/tests/qapi-schema/features-if-invalid.err
index f63b89535e..724a810086 100644
--- a/tests/qapi-schema/features-if-invalid.err
+++ b/tests/qapi-schema/features-if-invalid.err
@@ -1,2 +1,2 @@
features-if-invalid.json: In struct 'Stru':
-features-if-invalid.json:2: 'if' condition of 'features' member 'f' must be a string or a list of strings
+features-if-invalid.json:2: 'if' condition of 'features' member 'f' must be a string, a list of strings or a dict
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 84b9d41f15..2d5e480b44 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -231,8 +231,8 @@
{ 'union': 'TestIfUnion', 'data':
{ 'foo': 'TestStruct',
- 'bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
- 'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
+ 'union-bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
+ 'if': ['defined(TEST_IF_UNION)', 'defined(TEST_IF_STRUCT)'] }
{ 'command': 'test-if-union-cmd',
'data': { 'union-cmd-arg': 'TestIfUnion' },
@@ -241,11 +241,10 @@
{ 'alternate': 'TestIfAlternate', 'data':
{ 'foo': 'int',
'bar': { 'type': 'TestStruct', 'if': 'defined(TEST_IF_ALT_BAR)'} },
- 'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
+ 'if': {'all': ['defined(TEST_IF_ALT)', 'defined(TEST_IF_STRUCT)'] } }
-{ 'command': 'test-if-alternate-cmd',
- 'data': { 'alt-cmd-arg': 'TestIfAlternate' },
- 'if': 'defined(TEST_IF_ALT)' }
+{ 'command': 'test-if-alternate-cmd', 'data': { 'alt-cmd-arg': 'TestIfAlternate' },
+ 'if': {'all': ['defined(TEST_IF_ALT)', {'not': 'defined(TEST_IF_NOT_ALT)'}] } }
{ 'command': 'test-if-cmd',
'data': {
@@ -259,7 +258,7 @@
{ 'event': 'TEST_IF_EVENT', 'data':
{ 'foo': 'TestIfStruct',
'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } },
- 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
+ 'if': ['defined(TEST_IF_EVT)', 'defined(TEST_IF_STRUCT)'] }
# test 'features'
@@ -290,6 +289,10 @@
'data': { 'foo': 'int' },
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
'defined(TEST_IF_COND_2)'] } ] }
+{ 'struct': 'CondFeatureStruct4',
+ 'data': { 'foo': 'int' },
+ 'features': [ { 'name': 'feature1', 'if': {'any': ['defined(TEST_IF_COND_1)',
+ 'defined(TEST_IF_COND_2)'] } } ] }
{ 'enum': 'FeatureEnum1',
'data': [ 'eins', 'zwei', 'drei' ],
@@ -313,7 +316,8 @@
'*fs4': 'FeatureStruct4',
'*cfs1': 'CondFeatureStruct1',
'*cfs2': 'CondFeatureStruct2',
- '*cfs3': 'CondFeatureStruct3' },
+ '*cfs3': 'CondFeatureStruct3',
+ '*cfs4': 'CondFeatureStruct4' },
'returns': 'FeatureStruct1',
'features': [] }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index e4e0fb173a..dd2f83fbae 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -298,49 +298,49 @@ command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Unio
object TestIfStruct
member foo: int optional=False
member bar: int optional=False
- if IfAll([IfOption('defined(TEST_IF_STRUCT_BAR)')])
- if IfAll([IfOption('defined(TEST_IF_STRUCT)')])
+ if IfOption('defined(TEST_IF_STRUCT_BAR)')
+ if IfOption('defined(TEST_IF_STRUCT)')
enum TestIfEnum
member foo
member bar
- if IfAll([IfOption('defined(TEST_IF_ENUM_BAR)')])
- if IfAll([IfOption('defined(TEST_IF_ENUM)')])
+ if IfOption('defined(TEST_IF_ENUM_BAR)')
+ if IfOption('defined(TEST_IF_ENUM)')
object q_obj_TestStruct-wrapper
member data: TestStruct optional=False
enum TestIfUnionKind
member foo
- member bar
- if IfAll([IfOption('defined(TEST_IF_UNION_BAR)')])
- if IfAll([IfOption('defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)')])
+ member union-bar
+ if IfOption('defined(TEST_IF_UNION_BAR)')
+ if IfAll([IfOption('defined(TEST_IF_UNION)'), IfOption('defined(TEST_IF_STRUCT)')])
object TestIfUnion
member type: TestIfUnionKind optional=False
tag type
case foo: q_obj_TestStruct-wrapper
- case bar: q_obj_str-wrapper
- if IfAll([IfOption('defined(TEST_IF_UNION_BAR)')])
- if IfAll([IfOption('defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)')])
+ case union-bar: q_obj_str-wrapper
+ if IfOption('defined(TEST_IF_UNION_BAR)')
+ if IfAll([IfOption('defined(TEST_IF_UNION)'), IfOption('defined(TEST_IF_STRUCT)')])
object q_obj_test-if-union-cmd-arg
member union-cmd-arg: TestIfUnion optional=False
- if IfAll([IfOption('defined(TEST_IF_UNION)')])
+ if IfOption('defined(TEST_IF_UNION)')
command test-if-union-cmd q_obj_test-if-union-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- if IfAll([IfOption('defined(TEST_IF_UNION)')])
+ if IfOption('defined(TEST_IF_UNION)')
alternate TestIfAlternate
tag type
case foo: int
case bar: TestStruct
- if IfAll([IfOption('defined(TEST_IF_ALT_BAR)')])
- if IfAll([IfOption('defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)')])
+ if IfOption('defined(TEST_IF_ALT_BAR)')
+ if IfAll([IfOption('defined(TEST_IF_ALT)'), IfOption('defined(TEST_IF_STRUCT)')])
object q_obj_test-if-alternate-cmd-arg
member alt-cmd-arg: TestIfAlternate optional=False
- if IfAll([IfOption('defined(TEST_IF_ALT)')])
+ if IfAll([IfOption('defined(TEST_IF_ALT)'), IfNot(IfOption('defined(TEST_IF_NOT_ALT)'))])
command test-if-alternate-cmd q_obj_test-if-alternate-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- if IfAll([IfOption('defined(TEST_IF_ALT)')])
+ if IfAll([IfOption('defined(TEST_IF_ALT)'), IfNot(IfOption('defined(TEST_IF_NOT_ALT)'))])
object q_obj_test-if-cmd-arg
member foo: TestIfStruct optional=False
member bar: TestIfEnum optional=False
- if IfAll([IfOption('defined(TEST_IF_CMD_BAR)')])
+ if IfOption('defined(TEST_IF_CMD_BAR)')
if IfAll([IfOption('defined(TEST_IF_CMD)'), IfOption('defined(TEST_IF_STRUCT)')])
command test-if-cmd q_obj_test-if-cmd-arg -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
@@ -348,15 +348,15 @@ command test-if-cmd q_obj_test-if-cmd-arg -> UserDefThree
command test-cmd-return-def-three None -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
array TestIfEnumList TestIfEnum
- if IfAll([IfOption('defined(TEST_IF_ENUM)')])
+ if IfOption('defined(TEST_IF_ENUM)')
object q_obj_TEST_IF_EVENT-arg
member foo: TestIfStruct optional=False
member bar: TestIfEnumList optional=False
- if IfAll([IfOption('defined(TEST_IF_EVT_BAR)')])
- if IfAll([IfOption('defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)')])
+ if IfOption('defined(TEST_IF_EVT_BAR)')
+ if IfAll([IfOption('defined(TEST_IF_EVT)'), IfOption('defined(TEST_IF_STRUCT)')])
event TEST_IF_EVENT q_obj_TEST_IF_EVENT-arg
boxed=False
- if IfAll([IfOption('defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)')])
+ if IfAll([IfOption('defined(TEST_IF_EVT)'), IfOption('defined(TEST_IF_STRUCT)')])
object FeatureStruct0
member foo: int optional=False
object FeatureStruct1
@@ -379,17 +379,21 @@ object FeatureStruct4
object CondFeatureStruct1
member foo: int optional=False
feature feature1
- if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
+ if IfOption('defined(TEST_IF_FEATURE_1)')
object CondFeatureStruct2
member foo: int optional=False
feature feature1
- if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
+ if IfOption('defined(TEST_IF_FEATURE_1)')
feature feature2
- if IfAll([IfOption('defined(TEST_IF_FEATURE_2)')])
+ if IfOption('defined(TEST_IF_FEATURE_2)')
object CondFeatureStruct3
member foo: int optional=False
feature feature1
if IfAll([IfOption('defined(TEST_IF_COND_1)'), IfOption('defined(TEST_IF_COND_2)')])
+object CondFeatureStruct4
+ member foo: int optional=False
+ feature feature1
+ if IfAny([IfOption('defined(TEST_IF_COND_1)'), IfOption('defined(TEST_IF_COND_2)')])
enum FeatureEnum1
member eins
member zwei
@@ -417,6 +421,7 @@ object q_obj_test-features0-arg
member cfs1: CondFeatureStruct1 optional=True
member cfs2: CondFeatureStruct2 optional=True
member cfs3: CondFeatureStruct3 optional=True
+ member cfs4: CondFeatureStruct4 optional=True
command test-features0 q_obj_test-features0-arg -> FeatureStruct1
gen=True success_response=True boxed=False oob=False preconfig=False
command test-command-features1 None -> None
@@ -429,13 +434,13 @@ command test-command-features3 None -> None
command test-command-cond-features1 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
+ if IfOption('defined(TEST_IF_FEATURE_1)')
command test-command-cond-features2 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if IfAll([IfOption('defined(TEST_IF_FEATURE_1)')])
+ if IfOption('defined(TEST_IF_FEATURE_1)')
feature feature2
- if IfAll([IfOption('defined(TEST_IF_FEATURE_2)')])
+ if IfOption('defined(TEST_IF_FEATURE_2)')
command test-command-cond-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
diff --git a/tests/qapi-schema/struct-member-if-invalid.err b/tests/qapi-schema/struct-member-if-invalid.err
index 42e7fdae3c..c18157c1f9 100644
--- a/tests/qapi-schema/struct-member-if-invalid.err
+++ b/tests/qapi-schema/struct-member-if-invalid.err
@@ -1,2 +1,2 @@
struct-member-if-invalid.json: In struct 'Stru':
-struct-member-if-invalid.json:2: 'if' condition of 'data' member 'member' must be a string or a list of strings
+struct-member-if-invalid.json:2: 'if' condition of 'data' member 'member' must be a string, a list of strings or a dict
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 7/9] qapi: convert 'if' C-expressions to the new syntax tree
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
` (5 preceding siblings ...)
2021-05-17 16:30 ` [PATCH v4 6/9] qapi: normalize 'if' condition to IfPredicate tree marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-17 16:30 ` [PATCH v4 8/9] qapi: make 'if' condition strings simple identifiers marcandre.lureau
` (2 subsequent siblings)
9 siblings, 0 replies; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
qapi/machine-target.json | 20 ++++++++++++++++----
qapi/misc-target.json | 12 +++++++++++-
2 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index e7811654b7..9b56b81bea 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -213,7 +213,9 @@
##
{ 'struct': 'CpuModelExpansionInfo',
'data': { 'model': 'CpuModelInfo' },
- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' }
+ 'if': { 'any': [ 'defined(TARGET_S390X)',
+ 'defined(TARGET_I386)',
+ 'defined(TARGET_ARM)'] } }
##
# @query-cpu-model-expansion:
@@ -252,7 +254,9 @@
'data': { 'type': 'CpuModelExpansionType',
'model': 'CpuModelInfo' },
'returns': 'CpuModelExpansionInfo',
- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' }
+ 'if': { 'any': [ 'defined(TARGET_S390X)',
+ 'defined(TARGET_I386)',
+ 'defined(TARGET_ARM)' ] } }
##
# @CpuDefinitionInfo:
@@ -316,7 +320,11 @@
'typename': 'str',
'*alias-of' : 'str',
'deprecated' : 'bool' },
- 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' }
+ 'if': { 'any': [ 'defined(TARGET_PPC)',
+ 'defined(TARGET_ARM)',
+ 'defined(TARGET_I386)',
+ 'defined(TARGET_S390X)',
+ 'defined(TARGET_MIPS)' ] } }
##
# @query-cpu-definitions:
@@ -328,4 +336,8 @@
# Since: 1.2
##
{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'],
- 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' }
+ 'if': { 'any': [ 'defined(TARGET_PPC)',
+ 'defined(TARGET_ARM)',
+ 'defined(TARGET_I386)',
+ 'defined(TARGET_S390X)',
+ 'defined(TARGET_MIPS)' ] } }
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 6200c671be..835a74a072 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -23,7 +23,17 @@
##
{ 'event': 'RTC_CHANGE',
'data': { 'offset': 'int' },
- 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' }
+ 'if': { 'any': [ 'defined(TARGET_ALPHA)',
+ 'defined(TARGET_ARM)',
+ 'defined(TARGET_HPPA)',
+ 'defined(TARGET_I386)',
+ 'defined(TARGET_MIPS)',
+ 'defined(TARGET_MIPS64)',
+ 'defined(TARGET_PPC)',
+ 'defined(TARGET_PPC64)',
+ 'defined(TARGET_S390X)',
+ 'defined(TARGET_SH4)',
+ 'defined(TARGET_SPARC)' ] } }
##
# @rtc-reset-reinjection:
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 8/9] qapi: make 'if' condition strings simple identifiers
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
` (6 preceding siblings ...)
2021-05-17 16:30 ` [PATCH v4 7/9] qapi: convert 'if' C-expressions to the new syntax tree marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-21 12:02 ` Markus Armbruster
2021-05-17 16:30 ` [PATCH v4 9/9] docs: update the documentation about schema configuration marcandre.lureau
2021-05-21 15:24 ` [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor Markus Armbruster
9 siblings, 1 reply; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Change the 'if' condition strings to be C-agnostic and be simple
identifiers.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
docs/devel/qapi-code-gen.txt | 8 +--
qapi/block-core.json | 16 ++---
qapi/block-export.json | 6 +-
qapi/char.json | 8 +--
qapi/machine-target.json | 40 ++++++-------
qapi/migration.json | 10 ++--
qapi/misc-target.json | 46 +++++++-------
qapi/qom.json | 10 ++--
qapi/sockets.json | 4 +-
qapi/ui.json | 48 +++++++--------
qga/qapi-schema.json | 8 +--
scripts/qapi/common.py | 2 +-
scripts/qapi/expr.py | 4 +-
.../alternate-branch-if-invalid.err | 2 +-
tests/qapi-schema/bad-if-empty.err | 2 +-
tests/qapi-schema/bad-if-list.err | 2 +-
tests/qapi-schema/bad-if.json | 2 +-
tests/qapi-schema/doc-good.json | 6 +-
tests/qapi-schema/doc-good.out | 6 +-
tests/qapi-schema/doc-good.txt | 6 +-
tests/qapi-schema/features-missing-name.json | 2 +-
tests/qapi-schema/qapi-schema-test.json | 52 ++++++++--------
tests/qapi-schema/qapi-schema-test.out | 60 +++++++++----------
tests/qapi-schema/union-branch-if-invalid.err | 2 +-
24 files changed, 176 insertions(+), 176 deletions(-)
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index c1cb6f987d..edaaf7ec40 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -791,7 +791,7 @@ will then be guarded by #if STRING for each STRING in the COND list.
Example: a conditional struct
{ 'struct': 'IfStruct', 'data': { 'foo': 'int' },
- 'if': ['defined(CONFIG_FOO)', 'defined(HAVE_BAR)'] }
+ 'if': ['CONFIG_FOO', 'HAVE_BAR'] }
gets its generated code guarded like this:
@@ -810,7 +810,7 @@ member 'bar'
{ 'struct': 'IfStruct', 'data':
{ 'foo': 'int',
- 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } }
+ 'bar': { 'type': 'int', 'if': 'IFCOND'} } }
A union's discriminator may not be conditional.
@@ -822,7 +822,7 @@ value 'bar'
{ 'enum': 'IfEnum', 'data':
[ 'foo',
- { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] }
+ { 'name' : 'bar', 'if': 'IFCOND' } ] }
Likewise, features can be conditional. This requires the longhand
form of FEATURE.
@@ -832,7 +832,7 @@ Example: a struct with conditional feature 'allow-negative-numbers'
{ 'struct': 'TestType',
'data': { 'number': 'int' },
'features': [ { 'name': 'allow-negative-numbers',
- 'if': 'defined(IFCOND)' } ] }
+ 'if': 'IFCOND' } ] }
Please note that you are responsible to ensure that the C code will
compile with an arbitrary combination of conditions, since the
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 2ea294129e..13fcdd6b91 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2779,7 +2779,7 @@
##
{ 'enum': 'BlockdevAioOptions',
'data': [ 'threads', 'native',
- { 'name': 'io_uring', 'if': 'defined(CONFIG_LINUX_IO_URING)' } ] }
+ { 'name': 'io_uring', 'if': 'CONFIG_LINUX_IO_URING' } ] }
##
# @BlockdevCacheOptions:
@@ -2817,7 +2817,7 @@
'gluster', 'host_cdrom', 'host_device', 'http', 'https', 'iscsi',
'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels',
'preallocate', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
- { 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
+ { 'name': 'replication', 'if': 'CONFIG_REPLICATION' },
'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
##
@@ -2859,10 +2859,10 @@
'*locking': 'OnOffAuto',
'*aio': 'BlockdevAioOptions',
'*drop-cache': {'type': 'bool',
- 'if': 'defined(CONFIG_LINUX)'},
+ 'if': 'CONFIG_LINUX'},
'*x-check-cache-dropped': 'bool' },
'features': [ { 'name': 'dynamic-auto-read-only',
- 'if': 'defined(CONFIG_POSIX)' } ] }
+ 'if': 'CONFIG_POSIX' } ] }
##
# @BlockdevOptionsNull:
@@ -3662,7 +3662,7 @@
# Since: 2.9
##
{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ],
- 'if': 'defined(CONFIG_REPLICATION)' }
+ 'if': 'CONFIG_REPLICATION' }
##
# @BlockdevOptionsReplication:
@@ -3681,7 +3681,7 @@
'base': 'BlockdevOptionsGenericFormat',
'data': { 'mode': 'ReplicationMode',
'*top-id': 'str' },
- 'if': 'defined(CONFIG_REPLICATION)' }
+ 'if': 'CONFIG_REPLICATION' }
##
# @NFSTransport:
@@ -4015,7 +4015,7 @@
'raw': 'BlockdevOptionsRaw',
'rbd': 'BlockdevOptionsRbd',
'replication': { 'type': 'BlockdevOptionsReplication',
- 'if': 'defined(CONFIG_REPLICATION)' },
+ 'if': 'CONFIG_REPLICATION' },
'ssh': 'BlockdevOptionsSsh',
'throttle': 'BlockdevOptionsThrottle',
'vdi': 'BlockdevOptionsGenericFormat',
@@ -4316,7 +4316,7 @@
# Since: 5.1
##
{ 'enum': 'Qcow2CompressionType',
- 'data': [ 'zlib', { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] }
+ 'data': [ 'zlib', { 'name': 'zstd', 'if': 'CONFIG_ZSTD' } ] }
##
# @BlockdevCreateOptionsQcow2:
diff --git a/qapi/block-export.json b/qapi/block-export.json
index e819e70cac..319992b1b0 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -137,7 +137,7 @@
{ 'struct': 'BlockExportOptionsFuse',
'data': { 'mountpoint': 'str',
'*growable': 'bool' },
- 'if': 'defined(CONFIG_FUSE)' }
+ 'if': 'CONFIG_FUSE' }
##
# @NbdServerAddOptions:
@@ -247,7 +247,7 @@
##
{ 'enum': 'BlockExportType',
'data': [ 'nbd', 'vhost-user-blk',
- { 'name': 'fuse', 'if': 'defined(CONFIG_FUSE)' } ] }
+ { 'name': 'fuse', 'if': 'CONFIG_FUSE' } ] }
##
# @BlockExportOptions:
@@ -290,7 +290,7 @@
'nbd': 'BlockExportOptionsNbd',
'vhost-user-blk': 'BlockExportOptionsVhostUserBlk',
'fuse': { 'type': 'BlockExportOptionsFuse',
- 'if': 'defined(CONFIG_FUSE)' }
+ 'if': 'CONFIG_FUSE' }
} }
##
diff --git a/qapi/char.json b/qapi/char.json
index 6413970fa7..bf3f8d54e5 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -342,7 +342,7 @@
{ 'struct': 'ChardevSpiceChannel',
'data': { 'type': 'str' },
'base': 'ChardevCommon',
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @ChardevSpicePort:
@@ -356,7 +356,7 @@
{ 'struct': 'ChardevSpicePort',
'data': { 'fqdn': 'str' },
'base': 'ChardevCommon',
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @ChardevVC:
@@ -414,9 +414,9 @@
'stdio': 'ChardevStdio',
'console': 'ChardevCommon',
'spicevmc': { 'type': 'ChardevSpiceChannel',
- 'if': 'defined(CONFIG_SPICE)' },
+ 'if': 'CONFIG_SPICE' },
'spiceport': { 'type': 'ChardevSpicePort',
- 'if': 'defined(CONFIG_SPICE)' },
+ 'if': 'CONFIG_SPICE' },
'vc': 'ChardevVC',
'ringbuf': 'ChardevRingbuf',
# next one is just for compatibility
diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index 9b56b81bea..f5ec4bc172 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -89,7 +89,7 @@
##
{ 'struct': 'CpuModelBaselineInfo',
'data': { 'model': 'CpuModelInfo' },
- 'if': 'defined(TARGET_S390X)' }
+ 'if': 'TARGET_S390X' }
##
# @CpuModelCompareInfo:
@@ -112,7 +112,7 @@
{ 'struct': 'CpuModelCompareInfo',
'data': { 'result': 'CpuModelCompareResult',
'responsible-properties': ['str'] },
- 'if': 'defined(TARGET_S390X)' }
+ 'if': 'TARGET_S390X' }
##
# @query-cpu-model-comparison:
@@ -156,7 +156,7 @@
{ 'command': 'query-cpu-model-comparison',
'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' },
'returns': 'CpuModelCompareInfo',
- 'if': 'defined(TARGET_S390X)' }
+ 'if': 'TARGET_S390X' }
##
# @query-cpu-model-baseline:
@@ -200,7 +200,7 @@
'data': { 'modela': 'CpuModelInfo',
'modelb': 'CpuModelInfo' },
'returns': 'CpuModelBaselineInfo',
- 'if': 'defined(TARGET_S390X)' }
+ 'if': 'TARGET_S390X' }
##
# @CpuModelExpansionInfo:
@@ -213,9 +213,9 @@
##
{ 'struct': 'CpuModelExpansionInfo',
'data': { 'model': 'CpuModelInfo' },
- 'if': { 'any': [ 'defined(TARGET_S390X)',
- 'defined(TARGET_I386)',
- 'defined(TARGET_ARM)'] } }
+ 'if': { 'any': [ 'TARGET_S390X',
+ 'TARGET_I386',
+ 'TARGET_ARM' ] } }
##
# @query-cpu-model-expansion:
@@ -254,9 +254,9 @@
'data': { 'type': 'CpuModelExpansionType',
'model': 'CpuModelInfo' },
'returns': 'CpuModelExpansionInfo',
- 'if': { 'any': [ 'defined(TARGET_S390X)',
- 'defined(TARGET_I386)',
- 'defined(TARGET_ARM)' ] } }
+ 'if': { 'any': [ 'TARGET_S390X',
+ 'TARGET_I386',
+ 'TARGET_ARM' ] } }
##
# @CpuDefinitionInfo:
@@ -320,11 +320,11 @@
'typename': 'str',
'*alias-of' : 'str',
'deprecated' : 'bool' },
- 'if': { 'any': [ 'defined(TARGET_PPC)',
- 'defined(TARGET_ARM)',
- 'defined(TARGET_I386)',
- 'defined(TARGET_S390X)',
- 'defined(TARGET_MIPS)' ] } }
+ 'if': { 'any': [ 'TARGET_PPC',
+ 'TARGET_ARM',
+ 'TARGET_I386',
+ 'TARGET_S390X',
+ 'TARGET_MIPS' ] } }
##
# @query-cpu-definitions:
@@ -336,8 +336,8 @@
# Since: 1.2
##
{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'],
- 'if': { 'any': [ 'defined(TARGET_PPC)',
- 'defined(TARGET_ARM)',
- 'defined(TARGET_I386)',
- 'defined(TARGET_S390X)',
- 'defined(TARGET_MIPS)' ] } }
+ 'if': { 'any': [ 'TARGET_PPC',
+ 'TARGET_ARM',
+ 'TARGET_I386',
+ 'TARGET_S390X',
+ 'TARGET_MIPS' ] } }
diff --git a/qapi/migration.json b/qapi/migration.json
index 7a5bdf9a0d..44d8c90405 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -533,7 +533,7 @@
##
{ 'enum': 'MultiFDCompression',
'data': [ 'none', 'zlib',
- { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] }
+ { 'name': 'zstd', 'if': 'CONFIG_ZSTD' } ] }
##
# @BitmapMigrationBitmapAliasTransform:
@@ -1562,7 +1562,7 @@
##
{ 'command': 'xen-set-replication',
'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' },
- 'if': 'defined(CONFIG_REPLICATION)' }
+ 'if': 'CONFIG_REPLICATION' }
##
# @ReplicationStatus:
@@ -1578,7 +1578,7 @@
##
{ 'struct': 'ReplicationStatus',
'data': { 'error': 'bool', '*desc': 'str' },
- 'if': 'defined(CONFIG_REPLICATION)' }
+ 'if': 'CONFIG_REPLICATION' }
##
# @query-xen-replication-status:
@@ -1596,7 +1596,7 @@
##
{ 'command': 'query-xen-replication-status',
'returns': 'ReplicationStatus',
- 'if': 'defined(CONFIG_REPLICATION)' }
+ 'if': 'CONFIG_REPLICATION' }
##
# @xen-colo-do-checkpoint:
@@ -1613,7 +1613,7 @@
# Since: 2.9
##
{ 'command': 'xen-colo-do-checkpoint',
- 'if': 'defined(CONFIG_REPLICATION)' }
+ 'if': 'CONFIG_REPLICATION' }
##
# @COLOStatus:
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 835a74a072..fc43c98c10 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -23,17 +23,17 @@
##
{ 'event': 'RTC_CHANGE',
'data': { 'offset': 'int' },
- 'if': { 'any': [ 'defined(TARGET_ALPHA)',
- 'defined(TARGET_ARM)',
- 'defined(TARGET_HPPA)',
- 'defined(TARGET_I386)',
- 'defined(TARGET_MIPS)',
- 'defined(TARGET_MIPS64)',
- 'defined(TARGET_PPC)',
- 'defined(TARGET_PPC64)',
- 'defined(TARGET_S390X)',
- 'defined(TARGET_SH4)',
- 'defined(TARGET_SPARC)' ] } }
+ 'if': { 'any': [ 'TARGET_ALPHA',
+ 'TARGET_ARM',
+ 'TARGET_HPPA',
+ 'TARGET_I386',
+ 'TARGET_MIPS',
+ 'TARGET_MIPS64',
+ 'TARGET_PPC',
+ 'TARGET_PPC64',
+ 'TARGET_S390X',
+ 'TARGET_SH4',
+ 'TARGET_SPARC' ] } }
##
# @rtc-reset-reinjection:
@@ -52,7 +52,7 @@
#
##
{ 'command': 'rtc-reset-reinjection',
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
@@ -79,7 +79,7 @@
{ 'enum': 'SevState',
'data': ['uninit', 'launch-update', 'launch-secret', 'running',
'send-update', 'receive-update' ],
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
# @SevInfo:
@@ -111,7 +111,7 @@
'state' : 'SevState',
'handle' : 'uint32'
},
- 'if': 'defined(TARGET_I386)'
+ 'if': 'TARGET_I386'
}
##
@@ -132,7 +132,7 @@
#
##
{ 'command': 'query-sev', 'returns': 'SevInfo',
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
@@ -146,7 +146,7 @@
#
##
{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'},
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
# @query-sev-launch-measure:
@@ -164,7 +164,7 @@
#
##
{ 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo',
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
@@ -189,7 +189,7 @@
'cert-chain': 'str',
'cbitpos': 'int',
'reduced-phys-bits': 'int'},
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
# @query-sev-capabilities:
@@ -209,7 +209,7 @@
#
##
{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability',
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
# @sev-inject-launch-secret:
@@ -227,7 +227,7 @@
##
{ 'command': 'sev-inject-launch-secret',
'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' },
- 'if': 'defined(TARGET_I386)' }
+ 'if': 'TARGET_I386' }
##
# @dump-skeys:
@@ -249,7 +249,7 @@
##
{ 'command': 'dump-skeys',
'data': { 'filename': 'str' },
- 'if': 'defined(TARGET_S390X)' }
+ 'if': 'TARGET_S390X' }
##
# @GICCapability:
@@ -274,7 +274,7 @@
'data': { 'version': 'int',
'emulated': 'bool',
'kernel': 'bool' },
- 'if': 'defined(TARGET_ARM)' }
+ 'if': 'TARGET_ARM' }
##
# @query-gic-capabilities:
@@ -294,4 +294,4 @@
#
##
{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
- 'if': 'defined(TARGET_ARM)' }
+ 'if': 'TARGET_ARM' }
diff --git a/qapi/qom.json b/qapi/qom.json
index cd0e76d564..6c41ec61b0 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -603,7 +603,7 @@
'data': { '*align': 'size',
'*discard-data': 'bool',
'mem-path': 'str',
- '*pmem': { 'type': 'bool', 'if': 'defined(CONFIG_LIBPMEM)' },
+ '*pmem': { 'type': 'bool', 'if': 'CONFIG_LIBPMEM' },
'*readonly': 'bool' } }
##
@@ -752,7 +752,7 @@
'cryptodev-backend',
'cryptodev-backend-builtin',
{ 'name': 'cryptodev-vhost-user',
- 'if': 'defined(CONFIG_VHOST_CRYPTO)' },
+ 'if': 'CONFIG_VHOST_CRYPTO' },
'dbus-vmstate',
'filter-buffer',
'filter-dump',
@@ -765,7 +765,7 @@
'iothread',
'memory-backend-file',
{ 'name': 'memory-backend-memfd',
- 'if': 'defined(CONFIG_LINUX)' },
+ 'if': 'CONFIG_LINUX' },
'memory-backend-ram',
'pef-guest',
'pr-manager-helper',
@@ -809,7 +809,7 @@
'cryptodev-backend': 'CryptodevBackendProperties',
'cryptodev-backend-builtin': 'CryptodevBackendProperties',
'cryptodev-vhost-user': { 'type': 'CryptodevVhostUserProperties',
- 'if': 'defined(CONFIG_VHOST_CRYPTO)' },
+ 'if': 'CONFIG_VHOST_CRYPTO' },
'dbus-vmstate': 'DBusVMStateProperties',
'filter-buffer': 'FilterBufferProperties',
'filter-dump': 'FilterDumpProperties',
@@ -822,7 +822,7 @@
'iothread': 'IothreadProperties',
'memory-backend-file': 'MemoryBackendFileProperties',
'memory-backend-memfd': { 'type': 'MemoryBackendMemfdProperties',
- 'if': 'defined(CONFIG_LINUX)' },
+ 'if': 'CONFIG_LINUX' },
'memory-backend-ram': 'MemoryBackendProperties',
'pr-manager-helper': 'PrManagerHelperProperties',
'rng-builtin': 'RngProperties',
diff --git a/qapi/sockets.json b/qapi/sockets.json
index 2e83452797..a0c08aa4ba 100644
--- a/qapi/sockets.json
+++ b/qapi/sockets.json
@@ -86,8 +86,8 @@
{ 'struct': 'UnixSocketAddress',
'data': {
'path': 'str',
- '*abstract': { 'type': 'bool', 'if': 'defined(CONFIG_LINUX)' },
- '*tight': { 'type': 'bool', 'if': 'defined(CONFIG_LINUX)' } } }
+ '*abstract': { 'type': 'bool', 'if': 'CONFIG_LINUX' },
+ '*tight': { 'type': 'bool', 'if': 'CONFIG_LINUX' } } }
##
# @VsockSocketAddress:
diff --git a/qapi/ui.json b/qapi/ui.json
index 1052ca9c38..ec29a66c9f 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -123,7 +123,7 @@
'data': { 'host': 'str',
'port': 'str',
'family': 'NetworkAddressFamily' },
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SpiceServerInfo:
@@ -137,7 +137,7 @@
{ 'struct': 'SpiceServerInfo',
'base': 'SpiceBasicInfo',
'data': { '*auth': 'str' },
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SpiceChannel:
@@ -163,7 +163,7 @@
'base': 'SpiceBasicInfo',
'data': {'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
'tls': 'bool'},
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SpiceQueryMouseMode:
@@ -183,7 +183,7 @@
##
{ 'enum': 'SpiceQueryMouseMode',
'data': [ 'client', 'server', 'unknown' ],
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SpiceInfo:
@@ -222,7 +222,7 @@
'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']},
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @query-spice:
@@ -268,7 +268,7 @@
#
##
{ 'command': 'query-spice', 'returns': 'SpiceInfo',
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SPICE_CONNECTED:
@@ -294,7 +294,7 @@
{ 'event': 'SPICE_CONNECTED',
'data': { 'server': 'SpiceBasicInfo',
'client': 'SpiceBasicInfo' },
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SPICE_INITIALIZED:
@@ -323,7 +323,7 @@
{ 'event': 'SPICE_INITIALIZED',
'data': { 'server': 'SpiceServerInfo',
'client': 'SpiceChannel' },
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SPICE_DISCONNECTED:
@@ -349,7 +349,7 @@
{ 'event': 'SPICE_DISCONNECTED',
'data': { 'server': 'SpiceBasicInfo',
'client': 'SpiceBasicInfo' },
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# @SPICE_MIGRATE_COMPLETED:
@@ -365,7 +365,7 @@
#
##
{ 'event': 'SPICE_MIGRATE_COMPLETED',
- 'if': 'defined(CONFIG_SPICE)' }
+ 'if': 'CONFIG_SPICE' }
##
# == VNC
@@ -393,7 +393,7 @@
'service': 'str',
'family': 'NetworkAddressFamily',
'websocket': 'bool' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VncServerInfo:
@@ -408,7 +408,7 @@
{ 'struct': 'VncServerInfo',
'base': 'VncBasicInfo',
'data': { '*auth': 'str' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VncClientInfo:
@@ -426,7 +426,7 @@
{ 'struct': 'VncClientInfo',
'base': 'VncBasicInfo',
'data': { '*x509_dname': 'str', '*sasl_username': 'str' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VncInfo:
@@ -469,7 +469,7 @@
'data': {'enabled': 'bool', '*host': 'str',
'*family': 'NetworkAddressFamily',
'*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']},
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VncPrimaryAuth:
@@ -481,7 +481,7 @@
{ 'enum': 'VncPrimaryAuth',
'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra',
'tls', 'vencrypt', 'sasl' ],
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VncVencryptSubAuth:
@@ -496,7 +496,7 @@
'tls-vnc', 'x509-vnc',
'tls-plain', 'x509-plain',
'tls-sasl', 'x509-sasl' ],
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VncServerInfo2:
@@ -514,7 +514,7 @@
'base': 'VncBasicInfo',
'data': { 'auth' : 'VncPrimaryAuth',
'*vencrypt' : 'VncVencryptSubAuth' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VncInfo2:
@@ -547,7 +547,7 @@
'auth' : 'VncPrimaryAuth',
'*vencrypt' : 'VncVencryptSubAuth',
'*display' : 'str' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @query-vnc:
@@ -579,7 +579,7 @@
#
##
{ 'command': 'query-vnc', 'returns': 'VncInfo',
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @query-vnc-servers:
#
@@ -590,7 +590,7 @@
# Since: 2.3
##
{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'],
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @change-vnc-password:
@@ -606,7 +606,7 @@
##
{ 'command': 'change-vnc-password',
'data': { 'password': 'str' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VNC_CONNECTED:
@@ -636,7 +636,7 @@
{ 'event': 'VNC_CONNECTED',
'data': { 'server': 'VncServerInfo',
'client': 'VncBasicInfo' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VNC_INITIALIZED:
@@ -664,7 +664,7 @@
{ 'event': 'VNC_INITIALIZED',
'data': { 'server': 'VncServerInfo',
'client': 'VncClientInfo' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# @VNC_DISCONNECTED:
@@ -691,7 +691,7 @@
{ 'event': 'VNC_DISCONNECTED',
'data': { 'server': 'VncServerInfo',
'client': 'VncClientInfo' },
- 'if': 'defined(CONFIG_VNC)' }
+ 'if': 'CONFIG_VNC' }
##
# = Input
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index fb17eebde3..c60f5e669d 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -1380,7 +1380,7 @@
'data': {
'keys': ['str']
},
- 'if': 'defined(CONFIG_POSIX)' }
+ 'if': 'CONFIG_POSIX' }
##
@@ -1398,7 +1398,7 @@
{ 'command': 'guest-ssh-get-authorized-keys',
'data': { 'username': 'str' },
'returns': 'GuestAuthorizedKeys',
- 'if': 'defined(CONFIG_POSIX)' }
+ 'if': 'CONFIG_POSIX' }
##
# @guest-ssh-add-authorized-keys:
@@ -1416,7 +1416,7 @@
##
{ 'command': 'guest-ssh-add-authorized-keys',
'data': { 'username': 'str', 'keys': ['str'], '*reset': 'bool' },
- 'if': 'defined(CONFIG_POSIX)' }
+ 'if': 'CONFIG_POSIX' }
##
# @guest-ssh-remove-authorized-keys:
@@ -1434,4 +1434,4 @@
##
{ 'command': 'guest-ssh-remove-authorized-keys',
'data': { 'username': 'str', 'keys': ['str'] },
- 'if': 'defined(CONFIG_POSIX)' }
+ 'if': 'CONFIG_POSIX' }
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 8a23c1d4ef..c2637e55e3 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -225,7 +225,7 @@ def __init__(self, option: str):
self.option = option
def cgen(self) -> str:
- return self.option
+ return f"defined({self.option})"
def docgen(self) -> str:
return self.option
diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py
index 0a0ff73203..c8f09efae8 100644
--- a/scripts/qapi/expr.py
+++ b/scripts/qapi/expr.py
@@ -284,10 +284,10 @@ def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
def normalize(cond: Union[str, List[str], object]) -> Union[str, object]:
if isinstance(cond, str):
- if not cond.strip():
+ if not cond.isidentifier():
raise QAPISemError(
info,
- "'if' condition '%s' of %s makes no sense"
+ "'if' condition '%s' of %s is not a valid identifier"
% (cond, source))
return cond
if isinstance(cond, list):
diff --git a/tests/qapi-schema/alternate-branch-if-invalid.err b/tests/qapi-schema/alternate-branch-if-invalid.err
index d384929c51..03bad877a3 100644
--- a/tests/qapi-schema/alternate-branch-if-invalid.err
+++ b/tests/qapi-schema/alternate-branch-if-invalid.err
@@ -1,2 +1,2 @@
alternate-branch-if-invalid.json: In alternate 'Alt':
-alternate-branch-if-invalid.json:2: 'if' condition ' ' of 'data' member 'branch' makes no sense
+alternate-branch-if-invalid.json:2: 'if' condition ' ' of 'data' member 'branch' is not a valid identifier
diff --git a/tests/qapi-schema/bad-if-empty.err b/tests/qapi-schema/bad-if-empty.err
index a0f3effefb..5208f543ce 100644
--- a/tests/qapi-schema/bad-if-empty.err
+++ b/tests/qapi-schema/bad-if-empty.err
@@ -1,2 +1,2 @@
bad-if-empty.json: In struct 'TestIfStruct':
-bad-if-empty.json:2: 'if' condition '' of struct makes no sense
+bad-if-empty.json:2: 'if' condition '' of struct is not a valid identifier
diff --git a/tests/qapi-schema/bad-if-list.err b/tests/qapi-schema/bad-if-list.err
index c462f11b90..fa01894d03 100644
--- a/tests/qapi-schema/bad-if-list.err
+++ b/tests/qapi-schema/bad-if-list.err
@@ -1,2 +1,2 @@
bad-if-list.json: In struct 'TestIfStruct':
-bad-if-list.json:2: 'if' condition ' ' of struct makes no sense
+bad-if-list.json:2: 'if' condition ' ' of struct is not a valid identifier
diff --git a/tests/qapi-schema/bad-if.json b/tests/qapi-schema/bad-if.json
index 3edd1a0bf2..67818888de 100644
--- a/tests/qapi-schema/bad-if.json
+++ b/tests/qapi-schema/bad-if.json
@@ -1,3 +1,3 @@
# check invalid 'if' type
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
- 'if': { 'value': 'defined(TEST_IF_STRUCT)' } }
+ 'if': { 'value': 'TEST_IF_STRUCT' } }
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 423ea23e07..ae531e89b5 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -61,9 +61,9 @@
# @two is undocumented
##
{ 'enum': 'Enum', 'data':
- [ { 'name': 'one', 'if': 'defined(IFONE)' }, 'two' ],
+ [ { 'name': 'one', 'if': 'IFONE' }, 'two' ],
'features': [ 'enum-feat' ],
- 'if': 'defined(IFCOND)' }
+ 'if': 'IFCOND' }
##
# @Base:
@@ -86,7 +86,7 @@
'features': [ 'variant1-feat' ],
'data': { 'var1': { 'type': 'str',
'features': [ 'member-feat' ],
- 'if': 'defined(IFSTR)' } } }
+ 'if': 'IFSTR' } } }
##
# @Variant2:
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 4d951f97ee..53e5981028 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -12,15 +12,15 @@ enum QType
module doc-good.json
enum Enum
member one
- if IfOption('defined(IFONE)')
+ if IfOption('IFONE')
member two
- if IfOption('defined(IFCOND)')
+ if IfOption('IFCOND')
feature enum-feat
object Base
member base1: Enum optional=False
object Variant1
member var1: str optional=False
- if IfOption('defined(IFSTR)')
+ if IfOption('IFSTR')
feature member-feat
feature variant1-feat
object Variant2
diff --git a/tests/qapi-schema/doc-good.txt b/tests/qapi-schema/doc-good.txt
index 726727af74..27b7ce8799 100644
--- a/tests/qapi-schema/doc-good.txt
+++ b/tests/qapi-schema/doc-good.txt
@@ -43,7 +43,7 @@ Example:
Values
~~~~~~
-"one" (**If: **"defined(IFONE)")
+"one" (**If: **"IFONE")
The _one_ {and only}
"two"
@@ -62,7 +62,7 @@ Features
If
~~
-"defined(IFCOND)"
+"IFCOND"
"Base" (Object)
@@ -87,7 +87,7 @@ Another paragraph (but no "var": line)
Members
~~~~~~~
-"var1": "string" (**If: **"defined(IFSTR)")
+"var1": "string" (**If: **"IFSTR")
Not documented
diff --git a/tests/qapi-schema/features-missing-name.json b/tests/qapi-schema/features-missing-name.json
index 2314f97c00..8772c8f7b3 100644
--- a/tests/qapi-schema/features-missing-name.json
+++ b/tests/qapi-schema/features-missing-name.json
@@ -1,3 +1,3 @@
{ 'struct': 'FeatureStruct0',
'data': { 'foo': 'int' },
- 'features': [ { 'if': 'defined(NAMELESS_FEATURES)' } ] }
+ 'features': [ { 'if': 'NAMELESS_FEATURES' } ] }
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 2d5e480b44..fad64d879f 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -222,43 +222,43 @@
{ 'struct': 'TestIfStruct', 'data':
{ 'foo': 'int',
- 'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} },
- 'if': 'defined(TEST_IF_STRUCT)' }
+ 'bar': { 'type': 'int', 'if': 'TEST_IF_STRUCT_BAR'} },
+ 'if': 'TEST_IF_STRUCT' }
{ 'enum': 'TestIfEnum', 'data':
- [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
- 'if': 'defined(TEST_IF_ENUM)' }
+ [ 'foo', { 'name' : 'bar', 'if': 'TEST_IF_ENUM_BAR' } ],
+ 'if': 'TEST_IF_ENUM' }
{ 'union': 'TestIfUnion', 'data':
{ 'foo': 'TestStruct',
- 'union-bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
- 'if': ['defined(TEST_IF_UNION)', 'defined(TEST_IF_STRUCT)'] }
+ 'union-bar': { 'type': 'str', 'if': 'TEST_IF_UNION_BAR'} },
+ 'if': ['TEST_IF_UNION', 'TEST_IF_STRUCT'] }
{ 'command': 'test-if-union-cmd',
'data': { 'union-cmd-arg': 'TestIfUnion' },
- 'if': 'defined(TEST_IF_UNION)' }
+ 'if': 'TEST_IF_UNION' }
{ 'alternate': 'TestIfAlternate', 'data':
{ 'foo': 'int',
- 'bar': { 'type': 'TestStruct', 'if': 'defined(TEST_IF_ALT_BAR)'} },
- 'if': {'all': ['defined(TEST_IF_ALT)', 'defined(TEST_IF_STRUCT)'] } }
+ 'bar': { 'type': 'TestStruct', 'if': 'TEST_IF_ALT_BAR'} },
+ 'if': {'all': ['TEST_IF_ALT', 'TEST_IF_STRUCT'] } }
{ 'command': 'test-if-alternate-cmd', 'data': { 'alt-cmd-arg': 'TestIfAlternate' },
- 'if': {'all': ['defined(TEST_IF_ALT)', {'not': 'defined(TEST_IF_NOT_ALT)'}] } }
+ 'if': {'all': ['TEST_IF_ALT', {'not': 'TEST_IF_NOT_ALT'}] } }
{ 'command': 'test-if-cmd',
'data': {
'foo': 'TestIfStruct',
- 'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } },
+ 'bar': { 'type': 'TestIfEnum', 'if': 'TEST_IF_CMD_BAR' } },
'returns': 'UserDefThree',
- 'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
+ 'if': ['TEST_IF_CMD', 'TEST_IF_STRUCT'] }
{ 'command': 'test-cmd-return-def-three', 'returns': 'UserDefThree' }
{ 'event': 'TEST_IF_EVENT', 'data':
{ 'foo': 'TestIfStruct',
- 'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } },
- 'if': ['defined(TEST_IF_EVT)', 'defined(TEST_IF_STRUCT)'] }
+ 'bar': { 'type': ['TestIfEnum'], 'if': 'TEST_IF_EVT_BAR' } },
+ 'if': ['TEST_IF_EVT', 'TEST_IF_STRUCT'] }
# test 'features'
@@ -280,19 +280,19 @@
{ 'struct': 'CondFeatureStruct1',
'data': { 'foo': 'int' },
- 'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'} ] }
+ 'features': [ { 'name': 'feature1', 'if': 'TEST_IF_FEATURE_1'} ] }
{ 'struct': 'CondFeatureStruct2',
'data': { 'foo': 'int' },
- 'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'},
- { 'name': 'feature2', 'if': 'defined(TEST_IF_FEATURE_2)'} ] }
+ 'features': [ { 'name': 'feature1', 'if': 'TEST_IF_FEATURE_1'},
+ { 'name': 'feature2', 'if': 'TEST_IF_FEATURE_2'} ] }
{ 'struct': 'CondFeatureStruct3',
'data': { 'foo': 'int' },
- 'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
- 'defined(TEST_IF_COND_2)'] } ] }
+ 'features': [ { 'name': 'feature1', 'if': [ 'TEST_IF_COND_1',
+ 'TEST_IF_COND_2'] } ] }
{ 'struct': 'CondFeatureStruct4',
'data': { 'foo': 'int' },
- 'features': [ { 'name': 'feature1', 'if': {'any': ['defined(TEST_IF_COND_1)',
- 'defined(TEST_IF_COND_2)'] } } ] }
+ 'features': [ { 'name': 'feature1', 'if': {'any': ['TEST_IF_COND_1',
+ 'TEST_IF_COND_2'] } } ] }
{ 'enum': 'FeatureEnum1',
'data': [ 'eins', 'zwei', 'drei' ],
@@ -327,13 +327,13 @@
'features': [ 'feature1', 'feature2' ] }
{ 'command': 'test-command-cond-features1',
- 'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'} ] }
+ 'features': [ { 'name': 'feature1', 'if': 'TEST_IF_FEATURE_1'} ] }
{ 'command': 'test-command-cond-features2',
- 'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'},
- { 'name': 'feature2', 'if': 'defined(TEST_IF_FEATURE_2)'} ] }
+ 'features': [ { 'name': 'feature1', 'if': 'TEST_IF_FEATURE_1'},
+ { 'name': 'feature2', 'if': 'TEST_IF_FEATURE_2'} ] }
{ 'command': 'test-command-cond-features3',
- 'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
- 'defined(TEST_IF_COND_2)'] } ] }
+ 'features': [ { 'name': 'feature1', 'if': [ 'TEST_IF_COND_1',
+ 'TEST_IF_COND_2' ] } ] }
{ 'event': 'TEST_EVENT_FEATURES0',
'data': 'FeatureStruct1' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index dd2f83fbae..52737debad 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -298,65 +298,65 @@ command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Unio
object TestIfStruct
member foo: int optional=False
member bar: int optional=False
- if IfOption('defined(TEST_IF_STRUCT_BAR)')
- if IfOption('defined(TEST_IF_STRUCT)')
+ if IfOption('TEST_IF_STRUCT_BAR')
+ if IfOption('TEST_IF_STRUCT')
enum TestIfEnum
member foo
member bar
- if IfOption('defined(TEST_IF_ENUM_BAR)')
- if IfOption('defined(TEST_IF_ENUM)')
+ if IfOption('TEST_IF_ENUM_BAR')
+ if IfOption('TEST_IF_ENUM')
object q_obj_TestStruct-wrapper
member data: TestStruct optional=False
enum TestIfUnionKind
member foo
member union-bar
- if IfOption('defined(TEST_IF_UNION_BAR)')
- if IfAll([IfOption('defined(TEST_IF_UNION)'), IfOption('defined(TEST_IF_STRUCT)')])
+ if IfOption('TEST_IF_UNION_BAR')
+ if IfAll([IfOption('TEST_IF_UNION'), IfOption('TEST_IF_STRUCT')])
object TestIfUnion
member type: TestIfUnionKind optional=False
tag type
case foo: q_obj_TestStruct-wrapper
case union-bar: q_obj_str-wrapper
- if IfOption('defined(TEST_IF_UNION_BAR)')
- if IfAll([IfOption('defined(TEST_IF_UNION)'), IfOption('defined(TEST_IF_STRUCT)')])
+ if IfOption('TEST_IF_UNION_BAR')
+ if IfAll([IfOption('TEST_IF_UNION'), IfOption('TEST_IF_STRUCT')])
object q_obj_test-if-union-cmd-arg
member union-cmd-arg: TestIfUnion optional=False
- if IfOption('defined(TEST_IF_UNION)')
+ if IfOption('TEST_IF_UNION')
command test-if-union-cmd q_obj_test-if-union-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- if IfOption('defined(TEST_IF_UNION)')
+ if IfOption('TEST_IF_UNION')
alternate TestIfAlternate
tag type
case foo: int
case bar: TestStruct
- if IfOption('defined(TEST_IF_ALT_BAR)')
- if IfAll([IfOption('defined(TEST_IF_ALT)'), IfOption('defined(TEST_IF_STRUCT)')])
+ if IfOption('TEST_IF_ALT_BAR')
+ if IfAll([IfOption('TEST_IF_ALT'), IfOption('TEST_IF_STRUCT')])
object q_obj_test-if-alternate-cmd-arg
member alt-cmd-arg: TestIfAlternate optional=False
- if IfAll([IfOption('defined(TEST_IF_ALT)'), IfNot(IfOption('defined(TEST_IF_NOT_ALT)'))])
+ if IfAll([IfOption('TEST_IF_ALT'), IfNot(IfOption('TEST_IF_NOT_ALT'))])
command test-if-alternate-cmd q_obj_test-if-alternate-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- if IfAll([IfOption('defined(TEST_IF_ALT)'), IfNot(IfOption('defined(TEST_IF_NOT_ALT)'))])
+ if IfAll([IfOption('TEST_IF_ALT'), IfNot(IfOption('TEST_IF_NOT_ALT'))])
object q_obj_test-if-cmd-arg
member foo: TestIfStruct optional=False
member bar: TestIfEnum optional=False
- if IfOption('defined(TEST_IF_CMD_BAR)')
- if IfAll([IfOption('defined(TEST_IF_CMD)'), IfOption('defined(TEST_IF_STRUCT)')])
+ if IfOption('TEST_IF_CMD_BAR')
+ if IfAll([IfOption('TEST_IF_CMD'), IfOption('TEST_IF_STRUCT')])
command test-if-cmd q_obj_test-if-cmd-arg -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
- if IfAll([IfOption('defined(TEST_IF_CMD)'), IfOption('defined(TEST_IF_STRUCT)')])
+ if IfAll([IfOption('TEST_IF_CMD'), IfOption('TEST_IF_STRUCT')])
command test-cmd-return-def-three None -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
array TestIfEnumList TestIfEnum
- if IfOption('defined(TEST_IF_ENUM)')
+ if IfOption('TEST_IF_ENUM')
object q_obj_TEST_IF_EVENT-arg
member foo: TestIfStruct optional=False
member bar: TestIfEnumList optional=False
- if IfOption('defined(TEST_IF_EVT_BAR)')
- if IfAll([IfOption('defined(TEST_IF_EVT)'), IfOption('defined(TEST_IF_STRUCT)')])
+ if IfOption('TEST_IF_EVT_BAR')
+ if IfAll([IfOption('TEST_IF_EVT'), IfOption('TEST_IF_STRUCT')])
event TEST_IF_EVENT q_obj_TEST_IF_EVENT-arg
boxed=False
- if IfAll([IfOption('defined(TEST_IF_EVT)'), IfOption('defined(TEST_IF_STRUCT)')])
+ if IfAll([IfOption('TEST_IF_EVT'), IfOption('TEST_IF_STRUCT')])
object FeatureStruct0
member foo: int optional=False
object FeatureStruct1
@@ -379,21 +379,21 @@ object FeatureStruct4
object CondFeatureStruct1
member foo: int optional=False
feature feature1
- if IfOption('defined(TEST_IF_FEATURE_1)')
+ if IfOption('TEST_IF_FEATURE_1')
object CondFeatureStruct2
member foo: int optional=False
feature feature1
- if IfOption('defined(TEST_IF_FEATURE_1)')
+ if IfOption('TEST_IF_FEATURE_1')
feature feature2
- if IfOption('defined(TEST_IF_FEATURE_2)')
+ if IfOption('TEST_IF_FEATURE_2')
object CondFeatureStruct3
member foo: int optional=False
feature feature1
- if IfAll([IfOption('defined(TEST_IF_COND_1)'), IfOption('defined(TEST_IF_COND_2)')])
+ if IfAll([IfOption('TEST_IF_COND_1'), IfOption('TEST_IF_COND_2')])
object CondFeatureStruct4
member foo: int optional=False
feature feature1
- if IfAny([IfOption('defined(TEST_IF_COND_1)'), IfOption('defined(TEST_IF_COND_2)')])
+ if IfAny([IfOption('TEST_IF_COND_1'), IfOption('TEST_IF_COND_2')])
enum FeatureEnum1
member eins
member zwei
@@ -434,17 +434,17 @@ command test-command-features3 None -> None
command test-command-cond-features1 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if IfOption('defined(TEST_IF_FEATURE_1)')
+ if IfOption('TEST_IF_FEATURE_1')
command test-command-cond-features2 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if IfOption('defined(TEST_IF_FEATURE_1)')
+ if IfOption('TEST_IF_FEATURE_1')
feature feature2
- if IfOption('defined(TEST_IF_FEATURE_2)')
+ if IfOption('TEST_IF_FEATURE_2')
command test-command-cond-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
- if IfAll([IfOption('defined(TEST_IF_COND_1)'), IfOption('defined(TEST_IF_COND_2)')])
+ if IfAll([IfOption('TEST_IF_COND_1'), IfOption('TEST_IF_COND_2')])
event TEST_EVENT_FEATURES0 FeatureStruct1
boxed=False
event TEST_EVENT_FEATURES1 None
diff --git a/tests/qapi-schema/union-branch-if-invalid.err b/tests/qapi-schema/union-branch-if-invalid.err
index dd4518233e..046187a5b9 100644
--- a/tests/qapi-schema/union-branch-if-invalid.err
+++ b/tests/qapi-schema/union-branch-if-invalid.err
@@ -1,2 +1,2 @@
union-branch-if-invalid.json: In union 'Uni':
-union-branch-if-invalid.json:4: 'if' condition '' of 'data' member 'branch1' makes no sense
+union-branch-if-invalid.json:4: 'if' condition '' of 'data' member 'branch1' is not a valid identifier
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v4 8/9] qapi: make 'if' condition strings simple identifiers
2021-05-17 16:30 ` [PATCH v4 8/9] qapi: make 'if' condition strings simple identifiers marcandre.lureau
@ 2021-05-21 12:02 ` Markus Armbruster
2021-05-21 12:26 ` Marc-André Lureau
0 siblings, 1 reply; 18+ messages in thread
From: Markus Armbruster @ 2021-05-21 12:02 UTC (permalink / raw)
To: marcandre.lureau; +Cc: jsnow, qemu-devel, stefanha
marcandre.lureau@redhat.com writes:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Change the 'if' condition strings to be C-agnostic and be simple
> identifiers.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Tested-by: John Snow <jsnow@redhat.com>
> ---
[...]
> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> index c1cb6f987d..edaaf7ec40 100644
> --- a/docs/devel/qapi-code-gen.txt
> +++ b/docs/devel/qapi-code-gen.txt
> @@ -791,7 +791,7 @@ will then be guarded by #if STRING for each STRING in the COND list.
> Example: a conditional struct
>
> { 'struct': 'IfStruct', 'data': { 'foo': 'int' },
> - 'if': ['defined(CONFIG_FOO)', 'defined(HAVE_BAR)'] }
> + 'if': ['CONFIG_FOO', 'HAVE_BAR'] }
>
> gets its generated code guarded like this:
>
> @@ -810,7 +810,7 @@ member 'bar'
>
> { 'struct': 'IfStruct', 'data':
> { 'foo': 'int',
> - 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } }
> + 'bar': { 'type': 'int', 'if': 'IFCOND'} } }
>
> A union's discriminator may not be conditional.
>
> @@ -822,7 +822,7 @@ value 'bar'
>
> { 'enum': 'IfEnum', 'data':
> [ 'foo',
> - { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] }
> + { 'name' : 'bar', 'if': 'IFCOND' } ] }
>
> Likewise, features can be conditional. This requires the longhand
> form of FEATURE.
> @@ -832,7 +832,7 @@ Example: a struct with conditional feature 'allow-negative-numbers'
> { 'struct': 'TestType',
> 'data': { 'number': 'int' },
> 'features': [ { 'name': 'allow-negative-numbers',
> - 'if': 'defined(IFCOND)' } ] }
> + 'if': 'IFCOND' } ] }
>
> Please note that you are responsible to ensure that the C code will
> compile with an arbitrary combination of conditions, since the
At this point in your series, the documentation does not yet reflect the
code changes you've made. You now add another change together with a
doc update. Now the docs match *no* version of the code, past, present,
or future. I find this confusing. Swap the last two patches?
How do you feel about updating documentation before the code?
[...]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 8/9] qapi: make 'if' condition strings simple identifiers
2021-05-21 12:02 ` Markus Armbruster
@ 2021-05-21 12:26 ` Marc-André Lureau
2021-05-21 15:07 ` Markus Armbruster
0 siblings, 1 reply; 18+ messages in thread
From: Marc-André Lureau @ 2021-05-21 12:26 UTC (permalink / raw)
To: Markus Armbruster; +Cc: John Snow, QEMU, Stefan Hajnoczi
[-- Attachment #1: Type: text/plain, Size: 2634 bytes --]
On Fri, May 21, 2021 at 4:03 PM Markus Armbruster <armbru@redhat.com> wrote:
> marcandre.lureau@redhat.com writes:
>
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > Change the 'if' condition strings to be C-agnostic and be simple
> > identifiers.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> > Tested-by: John Snow <jsnow@redhat.com>
> > ---
>
> [...]
>
> > diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> > index c1cb6f987d..edaaf7ec40 100644
> > --- a/docs/devel/qapi-code-gen.txt
> > +++ b/docs/devel/qapi-code-gen.txt
> > @@ -791,7 +791,7 @@ will then be guarded by #if STRING for each STRING
> in the COND list.
> > Example: a conditional struct
> >
> > { 'struct': 'IfStruct', 'data': { 'foo': 'int' },
> > - 'if': ['defined(CONFIG_FOO)', 'defined(HAVE_BAR)'] }
> > + 'if': ['CONFIG_FOO', 'HAVE_BAR'] }
> >
> > gets its generated code guarded like this:
> >
> > @@ -810,7 +810,7 @@ member 'bar'
> >
> > { 'struct': 'IfStruct', 'data':
> > { 'foo': 'int',
> > - 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } }
> > + 'bar': { 'type': 'int', 'if': 'IFCOND'} } }
> >
> > A union's discriminator may not be conditional.
> >
> > @@ -822,7 +822,7 @@ value 'bar'
> >
> > { 'enum': 'IfEnum', 'data':
> > [ 'foo',
> > - { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] }
> > + { 'name' : 'bar', 'if': 'IFCOND' } ] }
> >
> > Likewise, features can be conditional. This requires the longhand
> > form of FEATURE.
> > @@ -832,7 +832,7 @@ Example: a struct with conditional feature
> 'allow-negative-numbers'
> > { 'struct': 'TestType',
> > 'data': { 'number': 'int' },
> > 'features': [ { 'name': 'allow-negative-numbers',
> > - 'if': 'defined(IFCOND)' } ] }
> > + 'if': 'IFCOND' } ] }
> >
> > Please note that you are responsible to ensure that the C code will
> > compile with an arbitrary combination of conditions, since the
>
> At this point in your series, the documentation does not yet reflect the
> code changes you've made. You now add another change together with a
> doc update. Now the docs match *no* version of the code, past, present,
> or future. I find this confusing. Swap the last two patches?
>
> How do you feel about updating documentation before the code?
>
I thought it would be simpler to update the doc in one go as the last patch
of this series. But if you prefer intermediary doc update, I can do that.
--
Marc-André Lureau
[-- Attachment #2: Type: text/html, Size: 4185 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 8/9] qapi: make 'if' condition strings simple identifiers
2021-05-21 12:26 ` Marc-André Lureau
@ 2021-05-21 15:07 ` Markus Armbruster
0 siblings, 0 replies; 18+ messages in thread
From: Markus Armbruster @ 2021-05-21 15:07 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: John Snow, QEMU, Stefan Hajnoczi
Marc-André Lureau <marcandre.lureau@gmail.com> writes:
> On Fri, May 21, 2021 at 4:03 PM Markus Armbruster <armbru@redhat.com> wrote:
[...]
>> At this point in your series, the documentation does not yet reflect the
>> code changes you've made. You now add another change together with a
>> doc update. Now the docs match *no* version of the code, past, present,
>> or future. I find this confusing. Swap the last two patches?
>>
>> How do you feel about updating documentation before the code?
>>
>
> I thought it would be simpler to update the doc in one go as the last patch
> of this series. But if you prefer intermediary doc update, I can do that.
Updating docs along the way (so it's consistent with the code at all
times) is nice. But sometimes updating docs just once is easier and
good enough. Whether to do it first or last is a matter of taste.
First can be nice when it serves specification for the code patches that
follow.
However, what we have here is "none of the above": you update docs last
[PATCH 9], except for one detail, which you update together with the
code in [PATCH 8].
I suggested two possible quick fixes:
1. Swap PATCH 8 and 9. Now you update docs for PATCH 1-7 last, in PATCH
8 (formerly 9), and then you update code and docs in PATCH 9
(formerly 8).
2. Move PATCH 9 to the front. Now you update docs for PATCH 2-8
(formerly 1-7) first, in PATCH 1 (formerly 9), and then you update
both code and docs in PATCH 9 (formerly 8).
If you prefer another way to clean this up, go right ahead!
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 9/9] docs: update the documentation about schema configuration
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
` (7 preceding siblings ...)
2021-05-17 16:30 ` [PATCH v4 8/9] qapi: make 'if' condition strings simple identifiers marcandre.lureau
@ 2021-05-17 16:30 ` marcandre.lureau
2021-05-21 11:56 ` Markus Armbruster
2021-05-21 15:24 ` [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor Markus Armbruster
9 siblings, 1 reply; 18+ messages in thread
From: marcandre.lureau @ 2021-05-17 16:30 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, jsnow, Markus Armbruster, stefanha
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
---
docs/devel/qapi-code-gen.txt | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index edaaf7ec40..4a3fd02723 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -780,26 +780,31 @@ downstream command __com.redhat_drive-mirror.
=== Configuring the schema ===
Syntax:
- COND = STRING
- | [ STRING, ... ]
+ COND = CFG-ID
+ | [ COND, ... ]
+ | { 'all: [ COND, ... ] }
+ | { 'any: [ COND, ... ] }
+ | { 'not': COND }
-All definitions take an optional 'if' member. Its value must be a
-string or a list of strings. A string is shorthand for a list
-containing just that string. The code generated for the definition
-will then be guarded by #if STRING for each STRING in the COND list.
+ CFG-ID = STRING
+
+All definitions take an optional 'if' member. Its value must be a string, a list
+of strings or an object with a single member 'all', 'any' or 'not'. A string is
+shorthand for a list containing just that string. A list is a shorthand for a
+'all'-member object. The C code generated for the definition will then be guarded
+by an #if precessor expression generated from that condition: 'all': [COND, ...]
+will generate '(COND && ...)', 'any': [COND, ...] '(COND || ...)', 'not': COND '!COND'.
Example: a conditional struct
{ 'struct': 'IfStruct', 'data': { 'foo': 'int' },
- 'if': ['CONFIG_FOO', 'HAVE_BAR'] }
+ 'if': { 'all': [ 'CONFIG_FOO', 'HAVE_BAR' ] } }
gets its generated code guarded like this:
- #if defined(CONFIG_FOO)
- #if defined(HAVE_BAR)
+ #if defined(CONFIG_FOO) && defined(HAVE_BAR)
... generated code ...
- #endif /* defined(HAVE_BAR) */
- #endif /* defined(CONFIG_FOO) */
+ #endif /* defined(HAVE_BAR) && defined(CONFIG_FOO) */
Individual members of complex types, commands arguments, and
event-specific data can also be made conditional. This requires the
--
2.29.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v4 9/9] docs: update the documentation about schema configuration
2021-05-17 16:30 ` [PATCH v4 9/9] docs: update the documentation about schema configuration marcandre.lureau
@ 2021-05-21 11:56 ` Markus Armbruster
2021-05-21 12:29 ` Marc-André Lureau
0 siblings, 1 reply; 18+ messages in thread
From: Markus Armbruster @ 2021-05-21 11:56 UTC (permalink / raw)
To: marcandre.lureau; +Cc: jsnow, qemu-devel, stefanha
marcandre.lureau@redhat.com writes:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Tested-by: John Snow <jsnow@redhat.com>
> ---
> docs/devel/qapi-code-gen.txt | 27 ++++++++++++++++-----------
> 1 file changed, 16 insertions(+), 11 deletions(-)
>
> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> index edaaf7ec40..4a3fd02723 100644
> --- a/docs/devel/qapi-code-gen.txt
> +++ b/docs/devel/qapi-code-gen.txt
> @@ -780,26 +780,31 @@ downstream command __com.redhat_drive-mirror.
> === Configuring the schema ===
>
> Syntax:
> - COND = STRING
> - | [ STRING, ... ]
> + COND = CFG-ID
> + | [ COND, ... ]
> + | { 'all: [ COND, ... ] }
> + | { 'any: [ COND, ... ] }
> + | { 'not': COND }
>
> -All definitions take an optional 'if' member. Its value must be a
> -string or a list of strings. A string is shorthand for a list
> -containing just that string. The code generated for the definition
> -will then be guarded by #if STRING for each STRING in the COND list.
> + CFG-ID = STRING
> +
> +All definitions take an optional 'if' member. Its value must be a string, a list
> +of strings or an object with a single member 'all', 'any' or 'not'. A string is
> +shorthand for a list containing just that string. A list is a shorthand for a
> +'all'-member object. The C code generated for the definition will then be guarded
Please try to make your changes blend into the existing text: limit line
length to 70 characters, and put two spaces between sentences.
I doubt the CFG-ID non-terminal is useful. Elsewhere, we do without,
e.g. ENUM-VALUE, ALTERNATIVE, FEATURE.
Sure the [ COND, ... ] sugar is worth the bother?
Perhaps
COND = STRING
| { 'all: [ COND, ... ] }
| { 'any: [ COND, ... ] }
| { 'not': COND }
All definitions take an optional 'if' member. The form STRING is
shorthand for { 'any': [ STRING ] }. The C code generated ...
> +by an #if precessor expression generated from that condition: 'all': [COND, ...]
> +will generate '(COND && ...)', 'any': [COND, ...] '(COND || ...)', 'not': COND '!COND'.
The technical term is "#if preprocessing directive". Let's use it.
I find the last part unnecessarily hard to read. What about:
... generated from that condition:
* { 'all': [COND, ...] } will generate #if (COND && ...)
* { 'any': [COND, ...] } will generate #if (COND || ...)
* { 'not': COND } will generate #if !COND
>
> Example: a conditional struct
>
> { 'struct': 'IfStruct', 'data': { 'foo': 'int' },
> - 'if': ['CONFIG_FOO', 'HAVE_BAR'] }
> + 'if': { 'all': [ 'CONFIG_FOO', 'HAVE_BAR' ] } }
>
> gets its generated code guarded like this:
>
> - #if defined(CONFIG_FOO)
> - #if defined(HAVE_BAR)
> + #if defined(CONFIG_FOO) && defined(HAVE_BAR)
> ... generated code ...
> - #endif /* defined(HAVE_BAR) */
> - #endif /* defined(CONFIG_FOO) */
> + #endif /* defined(HAVE_BAR) && defined(CONFIG_FOO) */
>
> Individual members of complex types, commands arguments, and
> event-specific data can also be made conditional. This requires the
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 9/9] docs: update the documentation about schema configuration
2021-05-21 11:56 ` Markus Armbruster
@ 2021-05-21 12:29 ` Marc-André Lureau
0 siblings, 0 replies; 18+ messages in thread
From: Marc-André Lureau @ 2021-05-21 12:29 UTC (permalink / raw)
To: Markus Armbruster; +Cc: John Snow, QEMU, Stefan Hajnoczi
[-- Attachment #1: Type: text/plain, Size: 3708 bytes --]
Hi
On Fri, May 21, 2021 at 3:58 PM Markus Armbruster <armbru@redhat.com> wrote:
> marcandre.lureau@redhat.com writes:
>
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> > Tested-by: John Snow <jsnow@redhat.com>
> > ---
> > docs/devel/qapi-code-gen.txt | 27 ++++++++++++++++-----------
> > 1 file changed, 16 insertions(+), 11 deletions(-)
> >
> > diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> > index edaaf7ec40..4a3fd02723 100644
> > --- a/docs/devel/qapi-code-gen.txt
> > +++ b/docs/devel/qapi-code-gen.txt
> > @@ -780,26 +780,31 @@ downstream command __com.redhat_drive-mirror.
> > === Configuring the schema ===
> >
> > Syntax:
> > - COND = STRING
> > - | [ STRING, ... ]
> > + COND = CFG-ID
> > + | [ COND, ... ]
> > + | { 'all: [ COND, ... ] }
> > + | { 'any: [ COND, ... ] }
> > + | { 'not': COND }
> >
> > -All definitions take an optional 'if' member. Its value must be a
> > -string or a list of strings. A string is shorthand for a list
> > -containing just that string. The code generated for the definition
> > -will then be guarded by #if STRING for each STRING in the COND list.
> > + CFG-ID = STRING
> > +
> > +All definitions take an optional 'if' member. Its value must be a
> string, a list
> > +of strings or an object with a single member 'all', 'any' or 'not'. A
> string is
> > +shorthand for a list containing just that string. A list is a shorthand
> for a
> > +'all'-member object. The C code generated for the definition will then
> be guarded
>
> Please try to make your changes blend into the existing text: limit line
> length to 70 characters, and put two spaces between sentences.
>
ok
> I doubt the CFG-ID non-terminal is useful. Elsewhere, we do without,
> e.g. ENUM-VALUE, ALTERNATIVE, FEATURE.
>
> Sure the [ COND, ... ] sugar is worth the bother?
>
Maybe not
> Perhaps
>
> COND = STRING
> | { 'all: [ COND, ... ] }
> | { 'any: [ COND, ... ] }
> | { 'not': COND }
>
> All definitions take an optional 'if' member. The form STRING is
> shorthand for { 'any': [ STRING ] }. The C code generated ...
>
ok
> > +by an #if precessor expression generated from that condition: 'all':
> [COND, ...]
> > +will generate '(COND && ...)', 'any': [COND, ...] '(COND || ...)',
> 'not': COND '!COND'.
>
> The technical term is "#if preprocessing directive". Let's use it.
>
ok
> I find the last part unnecessarily hard to read. What about:
>
> ... generated from that condition:
>
> * { 'all': [COND, ...] } will generate #if (COND && ...)
> * { 'any': [COND, ...] } will generate #if (COND || ...)
> * { 'not': COND } will generate #if !COND
>
>
Yes!
>
> > Example: a conditional struct
> >
> > { 'struct': 'IfStruct', 'data': { 'foo': 'int' },
> > - 'if': ['CONFIG_FOO', 'HAVE_BAR'] }
> > + 'if': { 'all': [ 'CONFIG_FOO', 'HAVE_BAR' ] } }
> >
> > gets its generated code guarded like this:
> >
> > - #if defined(CONFIG_FOO)
> > - #if defined(HAVE_BAR)
> > + #if defined(CONFIG_FOO) && defined(HAVE_BAR)
> > ... generated code ...
> > - #endif /* defined(HAVE_BAR) */
> > - #endif /* defined(CONFIG_FOO) */
> > + #endif /* defined(HAVE_BAR) && defined(CONFIG_FOO) */
> >
> > Individual members of complex types, commands arguments, and
> > event-specific data can also be made conditional. This requires the
>
>
>
thanks
--
Marc-André Lureau
[-- Attachment #2: Type: text/html, Size: 6051 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor
2021-05-17 16:30 [PATCH v4 0/9] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
` (8 preceding siblings ...)
2021-05-17 16:30 ` [PATCH v4 9/9] docs: update the documentation about schema configuration marcandre.lureau
@ 2021-05-21 15:24 ` Markus Armbruster
9 siblings, 0 replies; 18+ messages in thread
From: Markus Armbruster @ 2021-05-21 15:24 UTC (permalink / raw)
To: marcandre.lureau; +Cc: jsnow, qemu-devel, stefanha
Since I won't be able to complete my review before my vaction, let me at
least give you some high-level feedback.
I admit I'm rather fond of the the radically simple, stupid way 'if'
works. It's tied to C, which is just fine as long as all we need is C.
Since we're going to need more than C, it's no longer fine. You replace
the stupid C preprocessor expression string by a little language. The
little language is less expressive than C preprocessor expressions. I
agree with that choice. Simplicity is more important than
expressiveness we may well never need.
I'm a bit concerned about excessive OO boilerplate on the one hand, and
keeping stuff factored cleanly on the other hand. Balancing act. We'll
figure it out.
^ permalink raw reply [flat|nested] 18+ messages in thread