mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-07-22 10:55:31 +00:00
qapi: Move conditional code from QAPISchemaVariants to its subtypes
QAPISchemaVariants.check()'s code is almost entirely conditional on union vs. alternate type. Move the conditional code to QAPISchemaBranches.check() and QAPISchemaAlternatives.check(), where the conditions are always satisfied. Attribute QAPISchemaVariants.tag_name is now only used by QAPISchemaBranches. Move it there. Refactor the three types' .__init__() to make them a bit simpler. Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
parent
e0a28f39b4
commit
8152bc7de6
|
@ -719,20 +719,11 @@ def visit(self, visitor: QAPISchemaVisitor) -> None:
|
||||||
class QAPISchemaVariants:
|
class QAPISchemaVariants:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tag_name: Optional[str],
|
|
||||||
info: QAPISourceInfo,
|
info: QAPISourceInfo,
|
||||||
tag_member: Optional[QAPISchemaObjectTypeMember],
|
|
||||||
variants: List[QAPISchemaVariant],
|
variants: List[QAPISchemaVariant],
|
||||||
):
|
):
|
||||||
# Unions pass tag_name but not tag_member.
|
|
||||||
# Alternates pass tag_member but not tag_name.
|
|
||||||
# After check(), tag_member is always set.
|
|
||||||
assert bool(tag_member) != bool(tag_name)
|
|
||||||
assert (isinstance(tag_name, str) or
|
|
||||||
isinstance(tag_member, QAPISchemaObjectTypeMember))
|
|
||||||
self._tag_name = tag_name
|
|
||||||
self.info = info
|
self.info = info
|
||||||
self._tag_member = tag_member
|
self._tag_member: Optional[QAPISchemaObjectTypeMember] = None
|
||||||
self.variants = variants
|
self.variants = variants
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -749,58 +740,66 @@ def set_defined_in(self, name: str) -> None:
|
||||||
v.set_defined_in(name)
|
v.set_defined_in(name)
|
||||||
|
|
||||||
def check(
|
def check(
|
||||||
self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
|
self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
|
||||||
) -> None:
|
) -> None:
|
||||||
if self._tag_name: # union
|
for v in self.variants:
|
||||||
# We need to narrow the member type:
|
v.check(schema)
|
||||||
tmp = seen.get(c_name(self._tag_name))
|
|
||||||
assert tmp is None or isinstance(tmp, QAPISchemaObjectTypeMember)
|
|
||||||
self._tag_member = tmp
|
|
||||||
|
|
||||||
base = "'base'"
|
|
||||||
# Pointing to the base type when not implicit would be
|
class QAPISchemaBranches(QAPISchemaVariants):
|
||||||
# nice, but we don't know it here
|
def __init__(self,
|
||||||
if not self._tag_member or self._tag_name != self._tag_member.name:
|
info: QAPISourceInfo,
|
||||||
raise QAPISemError(
|
variants: List[QAPISchemaVariant],
|
||||||
self.info,
|
tag_name: str):
|
||||||
"discriminator '%s' is not a member of %s"
|
super().__init__(info, variants)
|
||||||
% (self._tag_name, base))
|
self._tag_name = tag_name
|
||||||
# Here we do:
|
|
||||||
assert self.tag_member.defined_in
|
def check(
|
||||||
base_type = schema.lookup_type(self.tag_member.defined_in)
|
self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
|
||||||
assert base_type
|
) -> None:
|
||||||
if not base_type.is_implicit():
|
# We need to narrow the member type:
|
||||||
base = "base type '%s'" % self.tag_member.defined_in
|
tmp = seen.get(c_name(self._tag_name))
|
||||||
if not isinstance(self.tag_member.type, QAPISchemaEnumType):
|
assert tmp is None or isinstance(tmp, QAPISchemaObjectTypeMember)
|
||||||
raise QAPISemError(
|
self._tag_member = tmp
|
||||||
self.info,
|
|
||||||
"discriminator member '%s' of %s must be of enum type"
|
base = "'base'"
|
||||||
% (self._tag_name, base))
|
# Pointing to the base type when not implicit would be
|
||||||
if self.tag_member.optional:
|
# nice, but we don't know it here
|
||||||
raise QAPISemError(
|
if not self._tag_member or self._tag_name != self._tag_member.name:
|
||||||
self.info,
|
raise QAPISemError(
|
||||||
"discriminator member '%s' of %s must not be optional"
|
self.info,
|
||||||
% (self._tag_name, base))
|
"discriminator '%s' is not a member of %s"
|
||||||
if self.tag_member.ifcond.is_present():
|
% (self._tag_name, base))
|
||||||
raise QAPISemError(
|
# Here we do:
|
||||||
self.info,
|
assert self.tag_member.defined_in
|
||||||
"discriminator member '%s' of %s must not be conditional"
|
base_type = schema.lookup_type(self.tag_member.defined_in)
|
||||||
% (self._tag_name, base))
|
assert base_type
|
||||||
else: # alternate
|
if not base_type.is_implicit():
|
||||||
assert self._tag_member
|
base = "base type '%s'" % self.tag_member.defined_in
|
||||||
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
|
if not isinstance(self.tag_member.type, QAPISchemaEnumType):
|
||||||
assert not self.tag_member.optional
|
raise QAPISemError(
|
||||||
assert not self.tag_member.ifcond.is_present()
|
self.info,
|
||||||
if self._tag_name: # union
|
"discriminator member '%s' of %s must be of enum type"
|
||||||
# branches that are not explicitly covered get an empty type
|
% (self._tag_name, base))
|
||||||
assert self.tag_member.defined_in
|
if self.tag_member.optional:
|
||||||
cases = {v.name for v in self.variants}
|
raise QAPISemError(
|
||||||
for m in self.tag_member.type.members:
|
self.info,
|
||||||
if m.name not in cases:
|
"discriminator member '%s' of %s must not be optional"
|
||||||
v = QAPISchemaVariant(m.name, self.info,
|
% (self._tag_name, base))
|
||||||
'q_empty', m.ifcond)
|
if self.tag_member.ifcond.is_present():
|
||||||
v.set_defined_in(self.tag_member.defined_in)
|
raise QAPISemError(
|
||||||
self.variants.append(v)
|
self.info,
|
||||||
|
"discriminator member '%s' of %s must not be conditional"
|
||||||
|
% (self._tag_name, base))
|
||||||
|
# branches that are not explicitly covered get an empty type
|
||||||
|
assert self.tag_member.defined_in
|
||||||
|
cases = {v.name for v in self.variants}
|
||||||
|
for m in self.tag_member.type.members:
|
||||||
|
if m.name not in cases:
|
||||||
|
v = QAPISchemaVariant(m.name, self.info,
|
||||||
|
'q_empty', m.ifcond)
|
||||||
|
v.set_defined_in(self.tag_member.defined_in)
|
||||||
|
self.variants.append(v)
|
||||||
if not self.variants:
|
if not self.variants:
|
||||||
raise QAPISemError(self.info, "union has no branches")
|
raise QAPISemError(self.info, "union has no branches")
|
||||||
for v in self.variants:
|
for v in self.variants:
|
||||||
|
@ -834,20 +833,21 @@ def check_clash(
|
||||||
v.type.check_clash(info, dict(seen))
|
v.type.check_clash(info, dict(seen))
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaBranches(QAPISchemaVariants):
|
|
||||||
def __init__(self,
|
|
||||||
info: QAPISourceInfo,
|
|
||||||
variants: List[QAPISchemaVariant],
|
|
||||||
tag_name: str):
|
|
||||||
super().__init__(tag_name, info, None, variants)
|
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaAlternatives(QAPISchemaVariants):
|
class QAPISchemaAlternatives(QAPISchemaVariants):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
info: QAPISourceInfo,
|
info: QAPISourceInfo,
|
||||||
variants: List[QAPISchemaVariant],
|
variants: List[QAPISchemaVariant],
|
||||||
tag_member: QAPISchemaObjectTypeMember):
|
tag_member: QAPISchemaObjectTypeMember):
|
||||||
super().__init__(None, info, tag_member, variants)
|
super().__init__(info, variants)
|
||||||
|
self._tag_member = tag_member
|
||||||
|
|
||||||
|
def check(
|
||||||
|
self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
|
||||||
|
) -> None:
|
||||||
|
super().check(schema, seen)
|
||||||
|
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
|
||||||
|
assert not self.tag_member.optional
|
||||||
|
assert not self.tag_member.ifcond.is_present()
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaMember:
|
class QAPISchemaMember:
|
||||||
|
|
Loading…
Reference in a new issue