|
@@ -321,8 +321,8 @@ def connect_doc(self, doc=None):
|
|
m.connect_doc(doc)
|
|
m.connect_doc(doc)
|
|
|
|
|
|
def is_implicit(self):
|
|
def is_implicit(self):
|
|
- # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
|
|
|
|
- return self.name.endswith('Kind') or self.name == 'QType'
|
|
|
|
|
|
+ # See QAPISchema._def_predefineds()
|
|
|
|
+ return self.name == 'QType'
|
|
|
|
|
|
def c_type(self):
|
|
def c_type(self):
|
|
return c_name(self.name)
|
|
return c_name(self.name)
|
|
@@ -393,8 +393,7 @@ class QAPISchemaObjectType(QAPISchemaType):
|
|
def __init__(self, name, info, doc, ifcond, features,
|
|
def __init__(self, name, info, doc, ifcond, features,
|
|
base, local_members, variants):
|
|
base, local_members, variants):
|
|
# struct has local_members, optional base, and no variants
|
|
# struct has local_members, optional base, and no variants
|
|
- # flat union has base, variants, and no local_members
|
|
|
|
- # simple union has local_members, variants, and no base
|
|
|
|
|
|
+ # union has base, variants, and no local_members
|
|
super().__init__(name, info, doc, ifcond, features)
|
|
super().__init__(name, info, doc, ifcond, features)
|
|
self.meta = 'union' if variants else 'struct'
|
|
self.meta = 'union' if variants else 'struct'
|
|
assert base is None or isinstance(base, str)
|
|
assert base is None or isinstance(base, str)
|
|
@@ -465,15 +464,6 @@ def connect_doc(self, doc=None):
|
|
for m in self.local_members:
|
|
for m in self.local_members:
|
|
m.connect_doc(doc)
|
|
m.connect_doc(doc)
|
|
|
|
|
|
- @property
|
|
|
|
- def ifcond(self):
|
|
|
|
- assert self._checked
|
|
|
|
- if isinstance(self._ifcond, QAPISchemaType):
|
|
|
|
- # Simple union wrapper type inherits from wrapped type;
|
|
|
|
- # see _make_implicit_object_type()
|
|
|
|
- return self._ifcond.ifcond
|
|
|
|
- return self._ifcond
|
|
|
|
-
|
|
|
|
def is_implicit(self):
|
|
def is_implicit(self):
|
|
# See QAPISchema._make_implicit_object_type(), as well as
|
|
# See QAPISchema._make_implicit_object_type(), as well as
|
|
# _def_predefineds()
|
|
# _def_predefineds()
|
|
@@ -576,10 +566,9 @@ def visit(self, visitor):
|
|
|
|
|
|
class QAPISchemaVariants:
|
|
class QAPISchemaVariants:
|
|
def __init__(self, tag_name, info, tag_member, variants):
|
|
def __init__(self, tag_name, info, tag_member, variants):
|
|
- # Flat unions pass tag_name but not tag_member.
|
|
|
|
- # Simple unions and alternates pass tag_member but not tag_name.
|
|
|
|
- # After check(), tag_member is always set, and tag_name remains
|
|
|
|
- # a reliable witness of being used by a flat union.
|
|
|
|
|
|
+ # 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 bool(tag_member) != bool(tag_name)
|
|
assert (isinstance(tag_name, str) or
|
|
assert (isinstance(tag_name, str) or
|
|
isinstance(tag_member, QAPISchemaObjectTypeMember))
|
|
isinstance(tag_member, QAPISchemaObjectTypeMember))
|
|
@@ -595,7 +584,7 @@ def set_defined_in(self, name):
|
|
v.set_defined_in(name)
|
|
v.set_defined_in(name)
|
|
|
|
|
|
def check(self, schema, seen):
|
|
def check(self, schema, seen):
|
|
- if not self.tag_member: # flat union
|
|
|
|
|
|
+ if self._tag_name: # union
|
|
self.tag_member = seen.get(c_name(self._tag_name))
|
|
self.tag_member = seen.get(c_name(self._tag_name))
|
|
base = "'base'"
|
|
base = "'base'"
|
|
# Pointing to the base type when not implicit would be
|
|
# Pointing to the base type when not implicit would be
|
|
@@ -625,11 +614,11 @@ def check(self, schema, seen):
|
|
self.info,
|
|
self.info,
|
|
"discriminator member '%s' of %s must not be conditional"
|
|
"discriminator member '%s' of %s must not be conditional"
|
|
% (self._tag_name, base))
|
|
% (self._tag_name, base))
|
|
- else: # simple union
|
|
|
|
|
|
+ else: # alternate
|
|
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
|
|
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
|
|
assert not self.tag_member.optional
|
|
assert not self.tag_member.optional
|
|
assert not self.tag_member.ifcond.is_present()
|
|
assert not self.tag_member.ifcond.is_present()
|
|
- if self._tag_name: # flat union
|
|
|
|
|
|
+ if self._tag_name: # union
|
|
# branches that are not explicitly covered get an empty type
|
|
# branches that are not explicitly covered get an empty type
|
|
cases = {v.name for v in self.variants}
|
|
cases = {v.name for v in self.variants}
|
|
for m in self.tag_member.type.members:
|
|
for m in self.tag_member.type.members:
|
|
@@ -707,18 +696,10 @@ def describe(self, info):
|
|
assert role == 'member'
|
|
assert role == 'member'
|
|
role = 'parameter'
|
|
role = 'parameter'
|
|
elif defined_in.endswith('-base'):
|
|
elif defined_in.endswith('-base'):
|
|
- # Implicit type created for a flat union's dict 'base'
|
|
|
|
|
|
+ # Implicit type created for a union's dict 'base'
|
|
role = 'base ' + role
|
|
role = 'base ' + role
|
|
else:
|
|
else:
|
|
- # Implicit type created for a simple union's branch
|
|
|
|
- assert defined_in.endswith('-wrapper')
|
|
|
|
- # Unreachable and not implemented
|
|
|
|
assert False
|
|
assert False
|
|
- elif defined_in.endswith('Kind'):
|
|
|
|
- # See QAPISchema._make_implicit_enum_type()
|
|
|
|
- # Implicit enum created for simple union's branches
|
|
|
|
- assert role == 'value'
|
|
|
|
- role = 'branch'
|
|
|
|
elif defined_in != info.defn_name:
|
|
elif defined_in != info.defn_name:
|
|
return "%s '%s' of type '%s'" % (role, self.name, defined_in)
|
|
return "%s '%s' of type '%s'" % (role, self.name, defined_in)
|
|
return "%s '%s'" % (role, self.name)
|
|
return "%s '%s'" % (role, self.name)
|
|
@@ -1004,15 +985,6 @@ def _make_enum_members(self, values, info):
|
|
QAPISchemaIfCond(v.get('if')))
|
|
QAPISchemaIfCond(v.get('if')))
|
|
for v in values]
|
|
for v in values]
|
|
|
|
|
|
- def _make_implicit_enum_type(self, name, info, ifcond, values):
|
|
|
|
- # See also QAPISchemaObjectTypeMember.describe()
|
|
|
|
- name = name + 'Kind' # reserved by check_defn_name_str()
|
|
|
|
- self._def_entity(QAPISchemaEnumType(
|
|
|
|
- name, info, None, ifcond, None,
|
|
|
|
- self._make_enum_members(values, info),
|
|
|
|
- None))
|
|
|
|
- return name
|
|
|
|
-
|
|
|
|
def _make_array_type(self, element_type, info):
|
|
def _make_array_type(self, element_type, info):
|
|
name = element_type + 'List' # reserved by check_defn_name_str()
|
|
name = element_type + 'List' # reserved by check_defn_name_str()
|
|
if not self.lookup_type(name):
|
|
if not self.lookup_type(name):
|
|
@@ -1026,17 +998,9 @@ def _make_implicit_object_type(self, name, info, ifcond, role, members):
|
|
name = 'q_obj_%s-%s' % (name, role)
|
|
name = 'q_obj_%s-%s' % (name, role)
|
|
typ = self.lookup_entity(name, QAPISchemaObjectType)
|
|
typ = self.lookup_entity(name, QAPISchemaObjectType)
|
|
if typ:
|
|
if typ:
|
|
- # 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
|
|
|
|
|
|
+ # The implicit object type has multiple users. This can
|
|
|
|
+ # only be a duplicate definition, which will be flagged
|
|
|
|
+ # later.
|
|
pass
|
|
pass
|
|
else:
|
|
else:
|
|
self._def_entity(QAPISchemaObjectType(
|
|
self._def_entity(QAPISchemaObjectType(
|
|
@@ -1084,49 +1048,28 @@ def _def_struct_type(self, expr, info, doc):
|
|
def _make_variant(self, case, typ, ifcond, info):
|
|
def _make_variant(self, case, typ, ifcond, info):
|
|
return QAPISchemaVariant(case, info, typ, ifcond)
|
|
return QAPISchemaVariant(case, info, typ, ifcond)
|
|
|
|
|
|
- def _make_simple_variant(self, case, typ, ifcond, info):
|
|
|
|
- if isinstance(typ, list):
|
|
|
|
- assert len(typ) == 1
|
|
|
|
- typ = self._make_array_type(typ[0], info)
|
|
|
|
- typ = self._make_implicit_object_type(
|
|
|
|
- typ, info, self.lookup_type(typ),
|
|
|
|
- 'wrapper', [self._make_member('data', typ, None, None, info)])
|
|
|
|
- return QAPISchemaVariant(case, info, typ, ifcond)
|
|
|
|
-
|
|
|
|
def _def_union_type(self, expr, info, doc):
|
|
def _def_union_type(self, expr, info, doc):
|
|
name = expr['union']
|
|
name = expr['union']
|
|
|
|
+ base = expr['base']
|
|
|
|
+ tag_name = expr['discriminator']
|
|
data = expr['data']
|
|
data = expr['data']
|
|
- base = expr.get('base')
|
|
|
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
|
features = self._make_features(expr.get('features'), info)
|
|
features = self._make_features(expr.get('features'), info)
|
|
- tag_name = expr.get('discriminator')
|
|
|
|
- tag_member = None
|
|
|
|
if isinstance(base, dict):
|
|
if isinstance(base, dict):
|
|
base = self._make_implicit_object_type(
|
|
base = self._make_implicit_object_type(
|
|
name, info, ifcond,
|
|
name, info, ifcond,
|
|
'base', self._make_members(base, info))
|
|
'base', self._make_members(base, info))
|
|
- if tag_name:
|
|
|
|
- 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'],
|
|
|
|
- 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]
|
|
|
|
|
|
+ variants = [
|
|
|
|
+ self._make_variant(key, value['type'],
|
|
|
|
+ QAPISchemaIfCond(value.get('if')),
|
|
|
|
+ info)
|
|
|
|
+ for (key, value) in data.items()]
|
|
|
|
+ members = []
|
|
self._def_entity(
|
|
self._def_entity(
|
|
QAPISchemaObjectType(name, info, doc, ifcond, features,
|
|
QAPISchemaObjectType(name, info, doc, ifcond, features,
|
|
base, members,
|
|
base, members,
|
|
QAPISchemaVariants(
|
|
QAPISchemaVariants(
|
|
- tag_name, info, tag_member, variants)))
|
|
|
|
|
|
+ tag_name, info, None, variants)))
|
|
|
|
|
|
def _def_alternate_type(self, expr, info, doc):
|
|
def _def_alternate_type(self, expr, info, doc):
|
|
name = expr['alternate']
|
|
name = expr['alternate']
|