mirror of https://github.com/xemu-project/xemu.git
QAPI patches patches for 2024-05-06
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmY4uIASHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTCYoQAK8Y2SSPlRqwdyYWqQHcPuQe4ThvnT2l y1Dzcy0MGKdeDQng+lyMh9x50U6vMd33TaWEDZ4PEprSLirWnRIIL9/qgrc+obYB LfncQR7BRLEPYRA0cQwvSBNzSLgCiySoa9x98yCB1ZZGQsAMz4p1j8qDpJFAL2qa VThXFcBaUOPRKFDwp03r8n8PFsaqaBVjI/2YX13EyJksaPNLNT6Z2xfcgREXFu2I gWfFR21kJwkUAgkfc6LhmqlpKXBpKQ+bWCmV1G/+LZosid3B8jfKOfOx4s9q9g5G N7HVRSHlqPyGQeJGaiiKgPZyoRh65L0YRa3OtYoJL9ngx1P7opAGxnxSsARduNg3 yQbbFY4c99HuxgxfMLwRPWr6Xm3c5DEvdIwoVRWm1ajJynbLWNiTN/uQs+tIEFbr 4usxqAQRo2G5WkY9JGuDuBJkZTp1/6pEM0xVrRgGYH9jr8LZrS2HPrnbcsa3eqAl UqSfu8HAL8j1wiBAr83DQe+SuoyRfrnFaTNYAILFG4RUsWF2u44RvkceGroyq3s1 mgHFZGF0+m8K7TXqeJvkSgg4wr2AnavXrb79Zz2JVut0X6K6S4AbueTBIn8zT2EX uGHhm4ZW5JUq6Wz6bQtq6/IUa/k2pAlszVFHe3Yn50J3CUU5dR/nYry7Cx4Q6/KT h4vzopMBjVv1 =3Pxa -----END PGP SIGNATURE----- Merge tag 'pull-qapi-2024-05-06' of https://repo.or.cz/qemu/armbru into staging QAPI patches patches for 2024-05-06 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmY4uIASHGFybWJydUBy # ZWRoYXQuY29tAAoJEDhwtADrkYZTCYoQAK8Y2SSPlRqwdyYWqQHcPuQe4ThvnT2l # y1Dzcy0MGKdeDQng+lyMh9x50U6vMd33TaWEDZ4PEprSLirWnRIIL9/qgrc+obYB # LfncQR7BRLEPYRA0cQwvSBNzSLgCiySoa9x98yCB1ZZGQsAMz4p1j8qDpJFAL2qa # VThXFcBaUOPRKFDwp03r8n8PFsaqaBVjI/2YX13EyJksaPNLNT6Z2xfcgREXFu2I # gWfFR21kJwkUAgkfc6LhmqlpKXBpKQ+bWCmV1G/+LZosid3B8jfKOfOx4s9q9g5G # N7HVRSHlqPyGQeJGaiiKgPZyoRh65L0YRa3OtYoJL9ngx1P7opAGxnxSsARduNg3 # yQbbFY4c99HuxgxfMLwRPWr6Xm3c5DEvdIwoVRWm1ajJynbLWNiTN/uQs+tIEFbr # 4usxqAQRo2G5WkY9JGuDuBJkZTp1/6pEM0xVrRgGYH9jr8LZrS2HPrnbcsa3eqAl # UqSfu8HAL8j1wiBAr83DQe+SuoyRfrnFaTNYAILFG4RUsWF2u44RvkceGroyq3s1 # mgHFZGF0+m8K7TXqeJvkSgg4wr2AnavXrb79Zz2JVut0X6K6S4AbueTBIn8zT2EX # uGHhm4ZW5JUq6Wz6bQtq6/IUa/k2pAlszVFHe3Yn50J3CUU5dR/nYry7Cx4Q6/KT # h4vzopMBjVv1 # =3Pxa # -----END PGP SIGNATURE----- # gpg: Signature made Mon 06 May 2024 04:01:20 AM PDT # 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] * tag 'pull-qapi-2024-05-06' of https://repo.or.cz/qemu/armbru: qapi: Simplify QAPISchemaVariants @tag_member qapi: Move conditional code from QAPISchemaVariants to its subtypes qapi: Rename QAPISchemaAlternateType.variants to .alternatives qapi: Rename QAPISchemaObjectType.variants to .branches qapi: Rename visitor parameter @variants to @alternatives qapi: Rename visitor parameter @variants to @branches qapi: New QAPISchemaBranches, QAPISchemaAlternatives Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
604dc98970
|
@ -145,22 +145,22 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
|
|||
term.extend(self._nodes_for_ifcond(member.ifcond))
|
||||
return term
|
||||
|
||||
def _nodes_for_variant_when(self, variants, variant):
|
||||
def _nodes_for_variant_when(self, branches, variant):
|
||||
"""Return list of Text, literal nodes for variant 'when' clause
|
||||
|
||||
Return a list of doctree nodes which give text like
|
||||
'when tagname is variant (If: ...)' suitable for use in
|
||||
the 'variants' part of a definition list.
|
||||
the 'branches' part of a definition list.
|
||||
"""
|
||||
term = [nodes.Text(' when '),
|
||||
nodes.literal('', variants.tag_member.name),
|
||||
nodes.literal('', branches.tag_member.name),
|
||||
nodes.Text(' is '),
|
||||
nodes.literal('', '"%s"' % variant.name)]
|
||||
if variant.ifcond.is_present():
|
||||
term.extend(self._nodes_for_ifcond(variant.ifcond))
|
||||
return term
|
||||
|
||||
def _nodes_for_members(self, doc, what, base=None, variants=None):
|
||||
def _nodes_for_members(self, doc, what, base=None, branches=None):
|
||||
"""Return list of doctree nodes for the table of members"""
|
||||
dlnode = nodes.definition_list()
|
||||
for section in doc.args.values():
|
||||
|
@ -178,14 +178,14 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
|
|||
nodes.literal('', base.doc_type())],
|
||||
None)
|
||||
|
||||
if variants:
|
||||
for v in variants.variants:
|
||||
if branches:
|
||||
for v in branches.variants:
|
||||
if v.type.name == 'q_empty':
|
||||
continue
|
||||
assert not v.type.is_implicit()
|
||||
term = [nodes.Text('The members of '),
|
||||
nodes.literal('', v.type.doc_type())]
|
||||
term.extend(self._nodes_for_variant_when(variants, v))
|
||||
term.extend(self._nodes_for_variant_when(branches, v))
|
||||
dlnode += self._make_dlitem(term, None)
|
||||
|
||||
if not dlnode.children:
|
||||
|
@ -308,17 +308,18 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
|
|||
+ self._nodes_for_if_section(ifcond))
|
||||
|
||||
def visit_object_type(self, name, info, ifcond, features,
|
||||
base, members, variants):
|
||||
base, members, branches):
|
||||
doc = self._cur_doc
|
||||
if base and base.is_implicit():
|
||||
base = None
|
||||
self._add_doc('Object',
|
||||
self._nodes_for_members(doc, 'Members', base, variants)
|
||||
self._nodes_for_members(doc, 'Members', base, branches)
|
||||
+ self._nodes_for_features(doc)
|
||||
+ self._nodes_for_sections(doc)
|
||||
+ self._nodes_for_if_section(ifcond))
|
||||
|
||||
def visit_alternate_type(self, name, info, ifcond, features, variants):
|
||||
def visit_alternate_type(self, name, info, ifcond, features,
|
||||
alternatives):
|
||||
doc = self._cur_doc
|
||||
self._add_doc('Alternate',
|
||||
self._nodes_for_members(doc, 'Members')
|
||||
|
|
|
@ -64,7 +64,7 @@ def gen_call(name: str,
|
|||
assert arg_type
|
||||
argstr = '&arg, '
|
||||
elif arg_type:
|
||||
assert not arg_type.variants
|
||||
assert not arg_type.branches
|
||||
for memb in arg_type.members:
|
||||
assert not memb.ifcond.is_present()
|
||||
if memb.need_has():
|
||||
|
|
|
@ -51,7 +51,7 @@ def gen_param_var(typ: QAPISchemaObjectType) -> str:
|
|||
|
||||
Initialize it with the function arguments defined in `gen_event_send`.
|
||||
"""
|
||||
assert not typ.variants
|
||||
assert not typ.branches
|
||||
ret = mcgen('''
|
||||
%(c_name)s param = {
|
||||
''',
|
||||
|
|
|
@ -118,7 +118,7 @@ def build_params(arg_type: Optional[QAPISchemaObjectType],
|
|||
ret += '%s arg' % arg_type.c_param_type()
|
||||
sep = ', '
|
||||
elif arg_type:
|
||||
assert not arg_type.variants
|
||||
assert not arg_type.branches
|
||||
for memb in arg_type.members:
|
||||
assert not memb.ifcond.is_present()
|
||||
ret += sep
|
||||
|
|
|
@ -26,6 +26,8 @@ from .common import c_name, mcgen
|
|||
from .gen import QAPISchemaMonolithicCVisitor
|
||||
from .schema import (
|
||||
QAPISchema,
|
||||
QAPISchemaAlternatives,
|
||||
QAPISchemaBranches,
|
||||
QAPISchemaArrayType,
|
||||
QAPISchemaBuiltinType,
|
||||
QAPISchemaEntity,
|
||||
|
@ -36,7 +38,6 @@ from .schema import (
|
|||
QAPISchemaObjectTypeMember,
|
||||
QAPISchemaType,
|
||||
QAPISchemaVariant,
|
||||
QAPISchemaVariants,
|
||||
)
|
||||
from .source import QAPISourceInfo
|
||||
|
||||
|
@ -335,24 +336,24 @@ const QLitObject %(c_name)s = %(c_string)s;
|
|||
ifcond: QAPISchemaIfCond,
|
||||
features: List[QAPISchemaFeature],
|
||||
members: List[QAPISchemaObjectTypeMember],
|
||||
variants: Optional[QAPISchemaVariants]) -> None:
|
||||
branches: Optional[QAPISchemaBranches]) -> None:
|
||||
obj: SchemaInfoObject = {
|
||||
'members': [self._gen_object_member(m) for m in members]
|
||||
}
|
||||
if variants:
|
||||
obj['tag'] = variants.tag_member.name
|
||||
obj['variants'] = [self._gen_variant(v) for v in variants.variants]
|
||||
if branches:
|
||||
obj['tag'] = branches.tag_member.name
|
||||
obj['variants'] = [self._gen_variant(v) for v in branches.variants]
|
||||
self._gen_tree(name, 'object', obj, ifcond, features)
|
||||
|
||||
def visit_alternate_type(self, name: str, info: Optional[QAPISourceInfo],
|
||||
ifcond: QAPISchemaIfCond,
|
||||
features: List[QAPISchemaFeature],
|
||||
variants: QAPISchemaVariants) -> None:
|
||||
alternatives: QAPISchemaAlternatives) -> None:
|
||||
self._gen_tree(
|
||||
name, 'alternate',
|
||||
{'members': [Annotated({'type': self._use_type(m.type)},
|
||||
m.ifcond)
|
||||
for m in variants.variants]},
|
||||
for m in alternatives.variants]},
|
||||
ifcond, features
|
||||
)
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ class QAPISchemaVisitor:
|
|||
features: List[QAPISchemaFeature],
|
||||
base: Optional[QAPISchemaObjectType],
|
||||
members: List[QAPISchemaObjectTypeMember],
|
||||
variants: Optional[QAPISchemaVariants],
|
||||
branches: Optional[QAPISchemaBranches],
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
@ -226,7 +226,7 @@ class QAPISchemaVisitor:
|
|||
ifcond: QAPISchemaIfCond,
|
||||
features: List[QAPISchemaFeature],
|
||||
members: List[QAPISchemaObjectTypeMember],
|
||||
variants: Optional[QAPISchemaVariants],
|
||||
branches: Optional[QAPISchemaBranches],
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
@ -236,7 +236,7 @@ class QAPISchemaVisitor:
|
|||
info: Optional[QAPISourceInfo],
|
||||
ifcond: QAPISchemaIfCond,
|
||||
features: List[QAPISchemaFeature],
|
||||
variants: QAPISchemaVariants,
|
||||
alternatives: QAPISchemaAlternatives,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
@ -524,20 +524,20 @@ class QAPISchemaObjectType(QAPISchemaType):
|
|||
features: Optional[List[QAPISchemaFeature]],
|
||||
base: Optional[str],
|
||||
local_members: List[QAPISchemaObjectTypeMember],
|
||||
variants: Optional[QAPISchemaVariants],
|
||||
branches: Optional[QAPISchemaBranches],
|
||||
):
|
||||
# struct has local_members, optional base, and no variants
|
||||
# union has base, variants, and no local_members
|
||||
# struct has local_members, optional base, and no branches
|
||||
# union has base, branches, and no local_members
|
||||
super().__init__(name, info, doc, ifcond, features)
|
||||
self.meta = 'union' if variants else 'struct'
|
||||
self.meta = 'union' if branches else 'struct'
|
||||
for m in local_members:
|
||||
m.set_defined_in(name)
|
||||
if variants is not None:
|
||||
variants.set_defined_in(name)
|
||||
if branches is not None:
|
||||
branches.set_defined_in(name)
|
||||
self._base_name = base
|
||||
self.base = None
|
||||
self.local_members = local_members
|
||||
self.variants = variants
|
||||
self.branches = branches
|
||||
self.members: List[QAPISchemaObjectTypeMember]
|
||||
self._check_complete = False
|
||||
|
||||
|
@ -561,7 +561,7 @@ class QAPISchemaObjectType(QAPISchemaType):
|
|||
self.base = schema.resolve_type(self._base_name, self.info,
|
||||
"'base'")
|
||||
if (not isinstance(self.base, QAPISchemaObjectType)
|
||||
or self.base.variants):
|
||||
or self.base.branches):
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"'base' requires a struct type, %s isn't"
|
||||
|
@ -577,9 +577,9 @@ class QAPISchemaObjectType(QAPISchemaType):
|
|||
# Cast down to the subtype.
|
||||
members = cast(List[QAPISchemaObjectTypeMember], list(seen.values()))
|
||||
|
||||
if self.variants:
|
||||
self.variants.check(schema, seen)
|
||||
self.variants.check_clash(self.info, seen)
|
||||
if self.branches:
|
||||
self.branches.check(schema, seen)
|
||||
self.branches.check_clash(self.info, seen)
|
||||
|
||||
self.members = members
|
||||
self._check_complete = True # mark completed
|
||||
|
@ -595,8 +595,8 @@ class QAPISchemaObjectType(QAPISchemaType):
|
|||
assert self._checked
|
||||
for m in self.members:
|
||||
m.check_clash(info, seen)
|
||||
if self.variants:
|
||||
self.variants.check_clash(info, seen)
|
||||
if self.branches:
|
||||
self.branches.check_clash(info, seen)
|
||||
|
||||
def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
|
||||
super().connect_doc(doc)
|
||||
|
@ -612,7 +612,7 @@ class QAPISchemaObjectType(QAPISchemaType):
|
|||
return self.name.startswith('q_')
|
||||
|
||||
def is_empty(self) -> bool:
|
||||
return not self.members and not self.variants
|
||||
return not self.members and not self.branches
|
||||
|
||||
def has_conditional_members(self) -> bool:
|
||||
return any(m.ifcond.is_present() for m in self.members)
|
||||
|
@ -635,10 +635,10 @@ class QAPISchemaObjectType(QAPISchemaType):
|
|||
super().visit(visitor)
|
||||
visitor.visit_object_type(
|
||||
self.name, self.info, self.ifcond, self.features,
|
||||
self.base, self.local_members, self.variants)
|
||||
self.base, self.local_members, self.branches)
|
||||
visitor.visit_object_type_flat(
|
||||
self.name, self.info, self.ifcond, self.features,
|
||||
self.members, self.variants)
|
||||
self.members, self.branches)
|
||||
|
||||
|
||||
class QAPISchemaAlternateType(QAPISchemaType):
|
||||
|
@ -651,25 +651,25 @@ class QAPISchemaAlternateType(QAPISchemaType):
|
|||
doc: Optional[QAPIDoc],
|
||||
ifcond: Optional[QAPISchemaIfCond],
|
||||
features: List[QAPISchemaFeature],
|
||||
variants: QAPISchemaVariants,
|
||||
alternatives: QAPISchemaAlternatives,
|
||||
):
|
||||
super().__init__(name, info, doc, ifcond, features)
|
||||
assert variants.tag_member
|
||||
variants.set_defined_in(name)
|
||||
variants.tag_member.set_defined_in(self.name)
|
||||
self.variants = variants
|
||||
assert alternatives.tag_member
|
||||
alternatives.set_defined_in(name)
|
||||
alternatives.tag_member.set_defined_in(self.name)
|
||||
self.alternatives = alternatives
|
||||
|
||||
def check(self, schema: QAPISchema) -> None:
|
||||
super().check(schema)
|
||||
self.variants.tag_member.check(schema)
|
||||
# Not calling self.variants.check_clash(), because there's nothing
|
||||
# to clash with
|
||||
self.variants.check(schema, {})
|
||||
self.alternatives.tag_member.check(schema)
|
||||
# Not calling self.alternatives.check_clash(), because there's
|
||||
# nothing to clash with
|
||||
self.alternatives.check(schema, {})
|
||||
# Alternate branch names have no relation to the tag enum values;
|
||||
# so we have to check for potential name collisions ourselves.
|
||||
seen: Dict[str, QAPISchemaMember] = {}
|
||||
types_seen: Dict[str, str] = {}
|
||||
for v in self.variants.variants:
|
||||
for v in self.alternatives.variants:
|
||||
v.check_clash(self.info, seen)
|
||||
qtype = v.type.alternate_qtype()
|
||||
if not qtype:
|
||||
|
@ -700,7 +700,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
|
|||
def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
|
||||
super().connect_doc(doc)
|
||||
doc = doc or self.doc
|
||||
for v in self.variants.variants:
|
||||
for v in self.alternatives.variants:
|
||||
v.connect_doc(doc)
|
||||
|
||||
def c_type(self) -> str:
|
||||
|
@ -712,94 +712,86 @@ class QAPISchemaAlternateType(QAPISchemaType):
|
|||
def visit(self, visitor: QAPISchemaVisitor) -> None:
|
||||
super().visit(visitor)
|
||||
visitor.visit_alternate_type(
|
||||
self.name, self.info, self.ifcond, self.features, self.variants)
|
||||
self.name, self.info, self.ifcond, self.features,
|
||||
self.alternatives)
|
||||
|
||||
|
||||
class QAPISchemaVariants:
|
||||
def __init__(
|
||||
self,
|
||||
tag_name: Optional[str],
|
||||
info: QAPISourceInfo,
|
||||
tag_member: Optional[QAPISchemaObjectTypeMember],
|
||||
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._tag_member = tag_member
|
||||
self.tag_member: QAPISchemaObjectTypeMember
|
||||
self.variants = variants
|
||||
|
||||
@property
|
||||
def tag_member(self) -> QAPISchemaObjectTypeMember:
|
||||
if self._tag_member is None:
|
||||
raise RuntimeError(
|
||||
"QAPISchemaVariants has no tag_member property until "
|
||||
"after check() has been run."
|
||||
)
|
||||
return self._tag_member
|
||||
|
||||
def set_defined_in(self, name: str) -> None:
|
||||
for v in self.variants:
|
||||
v.set_defined_in(name)
|
||||
|
||||
def check(
|
||||
self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
|
||||
self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
|
||||
) -> None:
|
||||
if self._tag_name: # union
|
||||
# We need to narrow the member type:
|
||||
tmp = seen.get(c_name(self._tag_name))
|
||||
assert tmp is None or isinstance(tmp, QAPISchemaObjectTypeMember)
|
||||
self._tag_member = tmp
|
||||
for v in self.variants:
|
||||
v.check(schema)
|
||||
|
||||
base = "'base'"
|
||||
# Pointing to the base type when not implicit would be
|
||||
# nice, but we don't know it here
|
||||
if not self._tag_member or self._tag_name != self._tag_member.name:
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"discriminator '%s' is not a member of %s"
|
||||
% (self._tag_name, base))
|
||||
# Here we do:
|
||||
assert self.tag_member.defined_in
|
||||
base_type = schema.lookup_type(self.tag_member.defined_in)
|
||||
assert base_type
|
||||
if not base_type.is_implicit():
|
||||
base = "base type '%s'" % self.tag_member.defined_in
|
||||
if not isinstance(self.tag_member.type, QAPISchemaEnumType):
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"discriminator member '%s' of %s must be of enum type"
|
||||
% (self._tag_name, base))
|
||||
if self.tag_member.optional:
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"discriminator member '%s' of %s must not be optional"
|
||||
% (self._tag_name, base))
|
||||
if self.tag_member.ifcond.is_present():
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"discriminator member '%s' of %s must not be conditional"
|
||||
% (self._tag_name, base))
|
||||
else: # alternate
|
||||
assert self._tag_member
|
||||
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
|
||||
assert not self.tag_member.optional
|
||||
assert not self.tag_member.ifcond.is_present()
|
||||
if self._tag_name: # union
|
||||
# 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)
|
||||
|
||||
class QAPISchemaBranches(QAPISchemaVariants):
|
||||
def __init__(self,
|
||||
info: QAPISourceInfo,
|
||||
variants: List[QAPISchemaVariant],
|
||||
tag_name: str):
|
||||
super().__init__(info, variants)
|
||||
self._tag_name = tag_name
|
||||
|
||||
def check(
|
||||
self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
|
||||
) -> None:
|
||||
# We need to narrow the member type:
|
||||
tag_member = seen.get(c_name(self._tag_name))
|
||||
assert (tag_member is None
|
||||
or isinstance(tag_member, QAPISchemaObjectTypeMember))
|
||||
|
||||
base = "'base'"
|
||||
# Pointing to the base type when not implicit would be
|
||||
# nice, but we don't know it here
|
||||
if not tag_member or self._tag_name != tag_member.name:
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"discriminator '%s' is not a member of %s"
|
||||
% (self._tag_name, base))
|
||||
self.tag_member = tag_member
|
||||
# Here we do:
|
||||
assert tag_member.defined_in
|
||||
base_type = schema.lookup_type(tag_member.defined_in)
|
||||
assert base_type
|
||||
if not base_type.is_implicit():
|
||||
base = "base type '%s'" % tag_member.defined_in
|
||||
if not isinstance(tag_member.type, QAPISchemaEnumType):
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"discriminator member '%s' of %s must be of enum type"
|
||||
% (self._tag_name, base))
|
||||
if tag_member.optional:
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"discriminator member '%s' of %s must not be optional"
|
||||
% (self._tag_name, base))
|
||||
if tag_member.ifcond.is_present():
|
||||
raise QAPISemError(
|
||||
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 tag_member.defined_in
|
||||
cases = {v.name for v in self.variants}
|
||||
for m in tag_member.type.members:
|
||||
if m.name not in cases:
|
||||
v = QAPISchemaVariant(m.name, self.info,
|
||||
'q_empty', m.ifcond)
|
||||
v.set_defined_in(tag_member.defined_in)
|
||||
self.variants.append(v)
|
||||
if not self.variants:
|
||||
raise QAPISemError(self.info, "union has no branches")
|
||||
for v in self.variants:
|
||||
|
@ -807,11 +799,11 @@ class QAPISchemaVariants:
|
|||
# Union names must match enum values; alternate names are
|
||||
# checked separately. Use 'seen' to tell the two apart.
|
||||
if seen:
|
||||
if v.name not in self.tag_member.type.member_names():
|
||||
if v.name not in tag_member.type.member_names():
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"branch '%s' is not a value of %s"
|
||||
% (v.name, self.tag_member.type.describe()))
|
||||
% (v.name, tag_member.type.describe()))
|
||||
if not isinstance(v.type, QAPISchemaObjectType):
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
|
@ -833,6 +825,23 @@ class QAPISchemaVariants:
|
|||
v.type.check_clash(info, dict(seen))
|
||||
|
||||
|
||||
class QAPISchemaAlternatives(QAPISchemaVariants):
|
||||
def __init__(self,
|
||||
info: QAPISourceInfo,
|
||||
variants: List[QAPISchemaVariant],
|
||||
tag_member: QAPISchemaObjectTypeMember):
|
||||
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:
|
||||
""" Represents object members, enum members and features """
|
||||
role = 'member'
|
||||
|
@ -1019,7 +1028,7 @@ class QAPISchemaCommand(QAPISchemaDefinition):
|
|||
"command's 'data' cannot take %s"
|
||||
% arg_type.describe())
|
||||
self.arg_type = arg_type
|
||||
if self.arg_type.variants and not self.boxed:
|
||||
if self.arg_type.branches and not self.boxed:
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"command's 'data' can take %s only with 'boxed': true"
|
||||
|
@ -1087,7 +1096,7 @@ class QAPISchemaEvent(QAPISchemaDefinition):
|
|||
"event's 'data' cannot take %s"
|
||||
% typ.describe())
|
||||
self.arg_type = typ
|
||||
if self.arg_type.variants and not self.boxed:
|
||||
if self.arg_type.branches and not self.boxed:
|
||||
raise QAPISemError(
|
||||
self.info,
|
||||
"event's 'data' can take %s only with 'boxed': true"
|
||||
|
@ -1388,8 +1397,8 @@ class QAPISchema:
|
|||
self._def_definition(
|
||||
QAPISchemaObjectType(name, info, expr.doc, ifcond, features,
|
||||
base, members,
|
||||
QAPISchemaVariants(
|
||||
tag_name, info, None, variants)))
|
||||
QAPISchemaBranches(
|
||||
info, variants, tag_name)))
|
||||
|
||||
def _def_alternate_type(self, expr: QAPIExpression) -> None:
|
||||
name = expr['alternate']
|
||||
|
@ -1407,7 +1416,7 @@ class QAPISchema:
|
|||
self._def_definition(
|
||||
QAPISchemaAlternateType(
|
||||
name, info, expr.doc, ifcond, features,
|
||||
QAPISchemaVariants(None, info, tag_member, variants)))
|
||||
QAPISchemaAlternatives(info, variants, tag_member)))
|
||||
|
||||
def _def_command(self, expr: QAPIExpression) -> None:
|
||||
name = expr['command']
|
||||
|
|
|
@ -23,6 +23,8 @@ from .gen import (
|
|||
)
|
||||
from .schema import (
|
||||
QAPISchema,
|
||||
QAPISchemaAlternatives,
|
||||
QAPISchemaBranches,
|
||||
QAPISchemaEnumMember,
|
||||
QAPISchemaFeature,
|
||||
QAPISchemaIfCond,
|
||||
|
@ -169,7 +171,7 @@ def gen_object(name: str, ifcond: QAPISchemaIfCond,
|
|||
if not isinstance(obj, QAPISchemaObjectType):
|
||||
continue
|
||||
ret += gen_object(obj.name, obj.ifcond, obj.base,
|
||||
obj.local_members, obj.variants)
|
||||
obj.local_members, obj.branches)
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
|
@ -348,13 +350,13 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
|
|||
features: List[QAPISchemaFeature],
|
||||
base: Optional[QAPISchemaObjectType],
|
||||
members: List[QAPISchemaObjectTypeMember],
|
||||
variants: Optional[QAPISchemaVariants]) -> None:
|
||||
branches: Optional[QAPISchemaBranches]) -> None:
|
||||
# Nothing to do for the special empty builtin
|
||||
if name == 'q_empty':
|
||||
return
|
||||
with ifcontext(ifcond, self._genh):
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_object(name, ifcond, base, members, variants))
|
||||
self._genh.add(gen_object(name, ifcond, base, members, branches))
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
if base and not base.is_implicit():
|
||||
self._genh.add(gen_upcast(name, base))
|
||||
|
@ -369,11 +371,11 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
|
|||
info: Optional[QAPISourceInfo],
|
||||
ifcond: QAPISchemaIfCond,
|
||||
features: List[QAPISchemaFeature],
|
||||
variants: QAPISchemaVariants) -> None:
|
||||
alternatives: QAPISchemaAlternatives) -> None:
|
||||
with ifcontext(ifcond, self._genh):
|
||||
self._genh.preamble_add(gen_fwd_object_or_array(name))
|
||||
self._genh.add(gen_object(name, ifcond, None,
|
||||
[variants.tag_member], variants))
|
||||
[alternatives.tag_member], alternatives))
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._gen_type_cleanup(name)
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ from .gen import (
|
|||
)
|
||||
from .schema import (
|
||||
QAPISchema,
|
||||
QAPISchemaAlternatives,
|
||||
QAPISchemaBranches,
|
||||
QAPISchemaEnumMember,
|
||||
QAPISchemaEnumType,
|
||||
QAPISchemaFeature,
|
||||
|
@ -35,7 +37,6 @@ from .schema import (
|
|||
QAPISchemaObjectType,
|
||||
QAPISchemaObjectTypeMember,
|
||||
QAPISchemaType,
|
||||
QAPISchemaVariants,
|
||||
)
|
||||
from .source import QAPISourceInfo
|
||||
|
||||
|
@ -63,7 +64,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp);
|
|||
def gen_visit_object_members(name: str,
|
||||
base: Optional[QAPISchemaObjectType],
|
||||
members: List[QAPISchemaObjectTypeMember],
|
||||
variants: Optional[QAPISchemaVariants]) -> str:
|
||||
branches: Optional[QAPISchemaBranches]) -> str:
|
||||
ret = mcgen('''
|
||||
|
||||
bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
|
||||
|
@ -131,8 +132,8 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
|
|||
''')
|
||||
ret += memb.ifcond.gen_endif()
|
||||
|
||||
if variants:
|
||||
tag_member = variants.tag_member
|
||||
if branches:
|
||||
tag_member = branches.tag_member
|
||||
assert isinstance(tag_member.type, QAPISchemaEnumType)
|
||||
|
||||
ret += mcgen('''
|
||||
|
@ -140,7 +141,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
|
|||
''',
|
||||
c_name=c_name(tag_member.name))
|
||||
|
||||
for var in variants.variants:
|
||||
for var in branches.variants:
|
||||
case_str = c_enum_const(tag_member.type.name, var.name,
|
||||
tag_member.type.prefix)
|
||||
ret += var.ifcond.gen_if()
|
||||
|
@ -222,7 +223,8 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name,
|
|||
c_name=c_name(name))
|
||||
|
||||
|
||||
def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
|
||||
def gen_visit_alternate(name: str,
|
||||
alternatives: QAPISchemaAlternatives) -> str:
|
||||
ret = mcgen('''
|
||||
|
||||
bool visit_type_%(c_name)s(Visitor *v, const char *name,
|
||||
|
@ -244,7 +246,7 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name,
|
|||
''',
|
||||
c_name=c_name(name))
|
||||
|
||||
for var in variants.variants:
|
||||
for var in alternatives.variants:
|
||||
ret += var.ifcond.gen_if()
|
||||
ret += mcgen('''
|
||||
case %(case)s:
|
||||
|
@ -393,14 +395,14 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
|
|||
features: List[QAPISchemaFeature],
|
||||
base: Optional[QAPISchemaObjectType],
|
||||
members: List[QAPISchemaObjectTypeMember],
|
||||
variants: Optional[QAPISchemaVariants]) -> None:
|
||||
branches: Optional[QAPISchemaBranches]) -> None:
|
||||
# Nothing to do for the special empty builtin
|
||||
if name == 'q_empty':
|
||||
return
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_visit_members_decl(name))
|
||||
self._genc.add(gen_visit_object_members(name, base,
|
||||
members, variants))
|
||||
members, branches))
|
||||
# TODO Worth changing the visitor signature, so we could
|
||||
# directly use rather than repeat type.is_implicit()?
|
||||
if not name.startswith('q_'):
|
||||
|
@ -413,10 +415,10 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
|
|||
info: Optional[QAPISourceInfo],
|
||||
ifcond: QAPISchemaIfCond,
|
||||
features: List[QAPISchemaFeature],
|
||||
variants: QAPISchemaVariants) -> None:
|
||||
alternatives: QAPISchemaAlternatives) -> None:
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_visit_decl(name))
|
||||
self._genc.add(gen_visit_alternate(name, variants))
|
||||
self._genc.add(gen_visit_alternate(name, alternatives))
|
||||
|
||||
|
||||
def gen_visit(schema: QAPISchema,
|
||||
|
|
|
@ -48,7 +48,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
|||
self._print_if(ifcond)
|
||||
|
||||
def visit_object_type(self, name, info, ifcond, features,
|
||||
base, members, variants):
|
||||
base, members, branches):
|
||||
print('object %s' % name)
|
||||
if base:
|
||||
print(' base %s' % base.name)
|
||||
|
@ -57,13 +57,14 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
|||
% (m.name, m.type.name, m.optional))
|
||||
self._print_if(m.ifcond, 8)
|
||||
self._print_features(m.features, indent=8)
|
||||
self._print_variants(variants)
|
||||
self._print_variants(branches)
|
||||
self._print_if(ifcond)
|
||||
self._print_features(features)
|
||||
|
||||
def visit_alternate_type(self, name, info, ifcond, features, variants):
|
||||
def visit_alternate_type(self, name, info, ifcond, features,
|
||||
alternatives):
|
||||
print('alternate %s' % name)
|
||||
self._print_variants(variants)
|
||||
self._print_variants(alternatives)
|
||||
self._print_if(ifcond)
|
||||
self._print_features(features)
|
||||
|
||||
|
|
Loading…
Reference in New Issue