diff options
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 d1d27ff..229d24fc 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( |