@ -321,8 +321,8 @@ class QAPISchemaEnumType(QAPISchemaType):
m . connect_doc ( doc )
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 ) :
return c_name ( self . name )
@ -393,8 +393,7 @@ class QAPISchemaObjectType(QAPISchemaType):
def __init__ ( self , name , info , doc , ifcond , features ,
base , local_members , 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 )
self . meta = ' union ' if variants else ' struct '
assert base is None or isinstance ( base , str )
@ -465,15 +464,6 @@ class QAPISchemaObjectType(QAPISchemaType):
for m in self . local_members :
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 ) :
# See QAPISchema._make_implicit_object_type(), as well as
# _def_predefineds()
@ -576,10 +566,9 @@ class QAPISchemaAlternateType(QAPISchemaType):
class QAPISchemaVariants :
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 ( isinstance ( tag_name , str ) or
isinstance ( tag_member , QAPISchemaObjectTypeMember ) )
@ -595,7 +584,7 @@ class QAPISchemaVariants:
v . set_defined_in ( name )
def check ( self , schema , seen ) :
if not self . tag_member : # flat union
if self . _ tag_na me: # union
self . tag_member = seen . get ( c_name ( self . _tag_name ) )
base = " ' base ' "
# Pointing to the base type when not implicit would be
@ -625,11 +614,11 @@ class QAPISchemaVariants:
self . info ,
" discriminator member ' %s ' of %s must not be conditional "
% ( self . _tag_name , base ) )
else : # simple union
else : # alternate
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 : # flat union
if self . _tag_name : # union
# branches that are not explicitly covered get an empty type
cases = { v . name for v in self . variants }
for m in self . tag_member . type . members :
@ -707,18 +696,10 @@ class QAPISchemaMember:
assert role == ' member '
role = ' parameter '
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
else :
# Implicit type created for a simple union's branch
assert defined_in . endswith ( ' -wrapper ' )
# Unreachable and not implemented
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 :
return " %s ' %s ' of type ' %s ' " % ( role , self . name , defined_in )
return " %s ' %s ' " % ( role , self . name )
@ -1004,15 +985,6 @@ class QAPISchema:
QAPISchemaIfCond ( v . get ( ' if ' ) ) )
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 ) :
name = element_type + ' List ' # reserved by check_defn_name_str()
if not self . lookup_type ( name ) :
@ -1026,17 +998,9 @@ 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 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
else :
self . _def_entity ( QAPISchemaObjectType (
@ -1084,49 +1048,28 @@ class QAPISchema:
def _make_variant ( self , case , typ , ifcond , info ) :
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 ) :
name = expr [ ' union ' ]
base = expr [ ' base ' ]
tag_name = expr [ ' discriminator ' ]
data = expr [ ' data ' ]
base = expr . get ( ' base ' )
ifcond = QAPISchemaIfCond ( expr . get ( ' if ' ) )
features = self . _make_features ( expr . get ( ' features ' ) , info )
tag_name = expr . get ( ' discriminator ' )
tag_member = None
if isinstance ( base , dict ) :
base = self . _make_implicit_object_type (
name , info , ifcond ,
' 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 (
QAPISchemaObjectType ( name , info , doc , ifcond , features ,
base , members ,
QAPISchemaVariants (
tag_name , info , tag_member , variants ) ) )
tag_name , info , None , variants ) ) )
def _def_alternate_type ( self , expr , info , doc ) :
name = expr [ ' alternate ' ]