diff options
author | Peter Maydell | 2021-08-26 14:42:34 +0200 |
---|---|---|
committer | Peter Maydell | 2021-08-26 14:42:34 +0200 |
commit | c83fcfaf8a54d0d034bd0edf7bbb3b0d16669be9 (patch) | |
tree | c25238aa2e85e53975e34765616fb0a3976bf2f0 /scripts/qapi/schema.py | |
parent | Merge remote-tracking branch 'remotes/ehabkost-gl/tags/x86-next-pull-request'... (diff) | |
parent | qapi: make 'if' condition strings simple identifiers (diff) | |
download | qemu-c83fcfaf8a54d0d034bd0edf7bbb3b0d16669be9.tar.gz qemu-c83fcfaf8a54d0d034bd0edf7bbb3b0d16669be9.tar.xz qemu-c83fcfaf8a54d0d034bd0edf7bbb3b0d16669be9.zip |
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-08-26' into staging
QAPI patches patches for 2021-08-26
# gpg: Signature made Thu 26 Aug 2021 13:18:34 BST
# gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg: issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653
* remotes/armbru/tags/pull-qapi-2021-08-26:
qapi: make 'if' condition strings simple identifiers
qapi: add 'not' condition operation
qapi: Use 'if': { 'any': ... } where appropriate
qapi: add 'any' condition
qapi: replace if condition list with dict {'all': [...]}
qapidoc: introduce QAPISchemaIfCond.docgen()
qapi: introduce QAPISchemaIfCond.cgen()
qapi: add QAPISchemaIfCond.is_present()
qapi: wrap Sequence[str] in an object
docs: update the documentation upfront about schema configuration
qapi: Fix crash on redefinition with a different condition
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'scripts/qapi/schema.py')
-rw-r--r-- | scripts/qapi/schema.py | 98 |
1 files changed, 63 insertions, 35 deletions
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index d1d27ff7ee..229d24fce9 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -19,12 +19,31 @@ import os import re from typing import Optional -from .common import POINTER_SUFFIX, c_name +from .common import ( + POINTER_SUFFIX, + c_name, + cgen_ifcond, + docgen_ifcond, +) from .error import QAPIError, QAPISemError, QAPISourceError from .expr import check_exprs from .parser import QAPISchemaParser +class QAPISchemaIfCond: + def __init__(self, ifcond=None): + self.ifcond = ifcond or {} + + def cgen(self): + return cgen_ifcond(self.ifcond) + + def docgen(self): + return docgen_ifcond(self.ifcond) + + def is_present(self): + return bool(self.ifcond) + + class QAPISchemaEntity: meta: Optional[str] = None @@ -42,7 +61,7 @@ class QAPISchemaEntity: # such place). self.info = info self.doc = doc - self._ifcond = ifcond or [] + self._ifcond = ifcond or QAPISchemaIfCond() self.features = features or [] self._checked = False @@ -593,7 +612,7 @@ class QAPISchemaVariants: self.info, "discriminator member '%s' of %s must not be optional" % (self._tag_name, base)) - if self.tag_member.ifcond: + if self.tag_member.ifcond.is_present(): raise QAPISemError( self.info, "discriminator member '%s' of %s must not be conditional" @@ -601,7 +620,7 @@ class QAPISchemaVariants: 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.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} @@ -646,7 +665,7 @@ class QAPISchemaMember: 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): @@ -968,11 +987,13 @@ class QAPISchema: 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): @@ -997,18 +1018,18 @@ class QAPISchema: name = 'q_obj_%s-%s' % (name, role) typ = self.lookup_entity(name, QAPISchemaObjectType) if typ: - # The implicit object type has multiple users. This can - # happen only for simple unions' implicit wrapper types. - # Its ifcond should be the disjunction of its user's - # ifconds. Not implemented. Instead, we always pass the - # wrapped type's ifcond, which is trivially the same for all - # users. It's also necessary for the wrapper to compile. - # But it's not tight: the disjunction need not imply it. We - # may end up compiling useless wrapper types. + # The implicit object type has multiple users. This is + # either a duplicate definition (which will be flagged + # later), or an implicit wrapper type used for multiple + # simple unions. In the latter case, ifcond should be the + # disjunction of its user's ifconds. Not implemented. + # Instead, we always pass the wrapped type's ifcond, which + # is trivially the same for all users. It's also + # necessary for the wrapper to compile. But it's not + # tight: the disjunction need not imply it. We may end up + # compiling useless wrapper types. # TODO kill simple unions or implement the disjunction - - # pylint: disable=protected-access - assert (ifcond or []) == typ._ifcond + pass else: self._def_entity(QAPISchemaObjectType( name, info, None, ifcond, None, None, members, None)) @@ -1018,7 +1039,7 @@ class QAPISchema: 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, @@ -1036,7 +1057,8 @@ class QAPISchema: 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()] @@ -1044,7 +1066,7 @@ class QAPISchema: 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, @@ -1067,7 +1089,7 @@ class QAPISchema: 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 @@ -1076,15 +1098,19 @@ class QAPISchema: 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] @@ -1097,11 +1123,13 @@ class QAPISchema: 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, @@ -1118,7 +1146,7 @@ class QAPISchema: 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( @@ -1137,7 +1165,7 @@ class QAPISchema: 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( |