From f17539c80da3c0ebabbe75a04f5451995367ec91 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Wed, 4 Aug 2021 12:30:57 +0400 Subject: qapi: wrap Sequence[str] in an object Mechanical change, except for a new assertion in QAPISchemaEntity.ifcond(). Signed-off-by: Marc-André Lureau Message-Id: <20210804083105.97531-3-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster [Rebased with obvious conflicts, commit message adjusted] Signed-off-by: Markus Armbruster --- scripts/qapi/introspect.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'scripts/qapi/introspect.py') diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index 9a348ca2e5..db1ebbf53a 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -15,11 +15,9 @@ from typing import ( Any, Dict, Generic, - Iterable, List, Optional, Sequence, - Tuple, TypeVar, Union, ) @@ -38,6 +36,7 @@ from .schema import ( 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, @@ -124,11 +123,11 @@ def _tree_to_qlit(obj: JSONValue, ret = '' if obj.comment: ret += indent(level) + f"/* {obj.comment} */\n" - if obj.ifcond: - ret += gen_if(obj.ifcond) + if obj.ifcond.ifcond: + ret += gen_if(obj.ifcond.ifcond) ret += _tree_to_qlit(obj.value, level) - if obj.ifcond: - ret += '\n' + gen_endif(obj.ifcond) + if obj.ifcond.ifcond: + ret += '\n' + gen_endif(obj.ifcond.ifcond) return ret ret = '' @@ -254,7 +253,7 @@ const QLitObject %(c_name)s = %(c_string)s; 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 @@ const QLitObject %(c_name)s = %(c_string)s; 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 @@ const QLitObject %(c_name)s = %(c_string)s; ) 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 @@ const QLitObject %(c_name)s = %(c_string)s; 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 @@ const QLitObject %(c_name)s = %(c_string)s; ) 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 @@ const QLitObject %(c_name)s = %(c_string)s; 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 -- cgit v1.2.3-55-g7522 From 33aa3267bacc5a7af363c0ffa5f1bdabba54b989 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Wed, 4 Aug 2021 12:30:58 +0400 Subject: qapi: add QAPISchemaIfCond.is_present() Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20210804083105.97531-4-marcandre.lureau@redhat.com> Signed-off-by: Markus Armbruster --- docs/sphinx/qapidoc.py | 8 ++++---- scripts/qapi/introspect.py | 4 ++-- scripts/qapi/schema.py | 7 +++++-- tests/qapi-schema/test-qapi.py | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'scripts/qapi/introspect.py') diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py index 0eac3308b2..511520f33f 100644 --- a/docs/sphinx/qapidoc.py +++ b/docs/sphinx/qapidoc.py @@ -139,7 +139,7 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor): term.append(nodes.literal('', member.type.doc_type())) if member.optional: term.append(nodes.Text(' (optional)')) - if member.ifcond.ifcond: + if member.ifcond.is_present(): term.extend(self._nodes_for_ifcond(member.ifcond)) return term @@ -154,7 +154,7 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor): nodes.literal('', variants.tag_member.name), nodes.Text(' is '), nodes.literal('', '"%s"' % variant.name)] - if variant.ifcond.ifcond: + if variant.ifcond.is_present(): term.extend(self._nodes_for_ifcond(variant.ifcond)) return term @@ -209,7 +209,7 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor): dlnode = nodes.definition_list() for section in doc.args.values(): termtext = [nodes.literal('', section.member.name)] - if section.member.ifcond.ifcond: + if section.member.ifcond.is_present(): termtext.extend(self._nodes_for_ifcond(section.member.ifcond)) # TODO drop fallbacks when undocumented members are outlawed if section.text: @@ -277,7 +277,7 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor): def _nodes_for_if_section(self, ifcond): """Return list of doctree nodes for the "If" section""" nodelist = [] - if ifcond.ifcond: + if ifcond.is_present(): snode = self._make_section('If') snode += nodes.paragraph( '', '', *self._nodes_for_ifcond(ifcond, with_if=False) diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index db1ebbf53a..e23725e2f9 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -123,10 +123,10 @@ def _tree_to_qlit(obj: JSONValue, ret = '' if obj.comment: ret += indent(level) + f"/* {obj.comment} */\n" - if obj.ifcond.ifcond: + if obj.ifcond.is_present(): ret += gen_if(obj.ifcond.ifcond) ret += _tree_to_qlit(obj.value, level) - if obj.ifcond.ifcond: + if obj.ifcond.is_present(): ret += '\n' + gen_endif(obj.ifcond.ifcond) return ret diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index e3beb24500..86fcd6cbd5 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 is_present(self): + return bool(self.ifcond) + class QAPISchemaEntity: meta: Optional[str] = None @@ -598,7 +601,7 @@ class QAPISchemaVariants: self.info, "discriminator member '%s' of %s must not be optional" % (self._tag_name, base)) - if self.tag_member.ifcond.ifcond: + if self.tag_member.ifcond.is_present(): raise QAPISemError( self.info, "discriminator member '%s' of %s must not be conditional" @@ -606,7 +609,7 @@ class QAPISchemaVariants: else: # simple union assert isinstance(self.tag_member.type, QAPISchemaEnumType) assert not self.tag_member.optional - assert self.tag_member.ifcond.ifcond == [] + assert not self.tag_member.ifcond.is_present() if self._tag_name: # flat union # branches that are not explicitly covered get an empty type cases = {v.name for v in self.variants} diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index 7907b4ac3a..c92be2d086 100755 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -94,7 +94,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): @staticmethod def _print_if(ifcond, indent=4): - if ifcond.ifcond: + if ifcond.is_present(): print('%sif %s' % (' ' * indent, ifcond.ifcond)) @classmethod -- cgit v1.2.3-55-g7522 From 6cc2e4817ff5b33d6f67e0a5f27dbd1112d1ecd5 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Wed, 4 Aug 2021 12:30:59 +0400 Subject: qapi: introduce QAPISchemaIfCond.cgen() Instead of building prepocessor conditions from a list of string, use the result generated from QAPISchemaIfCond.cgen() and hide the implementation details. Note: this patch introduces a minor regression, generating a redundant pair of parenthesis. This is mostly fixed in a later patch in this series ("qapi: replace if condition list with dict [..]") Signed-off-by: Marc-André Lureau Message-Id: <20210804083105.97531-5-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster [Commit message tweaked] Signed-off-by: Markus Armbruster --- scripts/qapi/common.py | 35 ++++++++++++++++++++++------------- scripts/qapi/gen.py | 4 ++-- scripts/qapi/introspect.py | 4 ++-- scripts/qapi/schema.py | 5 ++++- scripts/qapi/types.py | 20 ++++++++++---------- scripts/qapi/visit.py | 12 ++++++------ 6 files changed, 46 insertions(+), 34 deletions(-) (limited to 'scripts/qapi/introspect.py') diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 6ad1eeb61d..ba9fe14e4b 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -12,7 +12,12 @@ # See the COPYING file in the top-level directory. import re -from typing import Match, Optional, Sequence +from typing import ( + List, + Match, + Optional, + Union, +) #: Magic string that gets removed along with all space to its right. @@ -194,22 +199,26 @@ 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 cgen_ifcond(ifcond: Union[str, List[str]]) -> str: + if not ifcond: + return '' + return '(' + ') && ('.join(ifcond) + ')' + + +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) def must_match(pattern: str, string: str) -> Match[str]: 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 e23725e2f9..bd4233ecee 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -124,10 +124,10 @@ def _tree_to_qlit(obj: JSONValue, if obj.comment: ret += indent(level) + f"/* {obj.comment} */\n" if obj.ifcond.is_present(): - ret += gen_if(obj.ifcond.ifcond) + ret += gen_if(obj.ifcond.cgen()) ret += _tree_to_qlit(obj.value, level) if obj.ifcond.is_present(): - 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 86fcd6cbd5..4ea7e88846 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -19,7 +19,7 @@ import os import re from typing import Optional -from .common import POINTER_SUFFIX, c_name +from .common import POINTER_SUFFIX, c_name, cgen_ifcond from .error import QAPIError, QAPISemError, QAPISourceError from .expr import check_exprs from .parser import QAPISchemaParser @@ -29,6 +29,9 @@ class QAPISchemaIfCond: def __init__(self, ifcond=None): self.ifcond = ifcond or [] + def cgen(self): + return cgen_ifcond(self.ifcond) + def is_present(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 @@ const QEnumLookup %(c_name)s_lookup = { ''', 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 @@ typedef enum %(c_name)s { 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 @@ struct %(c_name)s { 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 @@ struct %(c_name)s { 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 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) 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 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) 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 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) 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 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) 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 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, 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 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, ret += mcgen(''' break; ''') - ret += gen_endif(var.ifcond.ifcond) + ret += gen_endif(var.ifcond.cgen()) ret += mcgen(''' case QTYPE_NONE: -- cgit v1.2.3-55-g7522