mirror of https://github.com/xemu-project/xemu.git
qapi: Add feature flags to struct members
Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200317115459.31821-21-armbru@redhat.com>
This commit is contained in:
parent
645178c069
commit
84ab008687
|
@ -234,7 +234,9 @@ Syntax:
|
||||||
'*features': FEATURES }
|
'*features': FEATURES }
|
||||||
MEMBERS = { MEMBER, ... }
|
MEMBERS = { MEMBER, ... }
|
||||||
MEMBER = STRING : TYPE-REF
|
MEMBER = STRING : TYPE-REF
|
||||||
| STRING : { 'type': TYPE-REF, '*if': COND }
|
| STRING : { 'type': TYPE-REF,
|
||||||
|
'*if': COND,
|
||||||
|
'*features': FEATURES }
|
||||||
|
|
||||||
Member 'struct' names the struct type.
|
Member 'struct' names the struct type.
|
||||||
|
|
||||||
|
|
|
@ -206,11 +206,15 @@
|
||||||
# Future extension: if present and non-null, the parameter
|
# Future extension: if present and non-null, the parameter
|
||||||
# is optional, and defaults to this value.
|
# is optional, and defaults to this value.
|
||||||
#
|
#
|
||||||
|
# @features: names of features associated with the member, in no
|
||||||
|
# particular order. (since 5.0)
|
||||||
|
#
|
||||||
# Since: 2.5
|
# Since: 2.5
|
||||||
##
|
##
|
||||||
{ 'struct': 'SchemaInfoObjectMember',
|
{ 'struct': 'SchemaInfoObjectMember',
|
||||||
'data': { 'name': 'str', 'type': 'str', '*default': 'any' } }
|
'data': { 'name': 'str', 'type': 'str', '*default': 'any',
|
||||||
# @default's type must be null or match @type
|
# @default's type must be null or match @type
|
||||||
|
'*features': [ 'str' ] } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @SchemaInfoObjectVariant:
|
# @SchemaInfoObjectVariant:
|
||||||
|
|
|
@ -167,8 +167,9 @@ def check_type(value, info, source,
|
||||||
allow_optional=True, permit_upper=permit_upper)
|
allow_optional=True, permit_upper=permit_upper)
|
||||||
if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
|
if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
|
||||||
raise QAPISemError(info, "%s uses reserved name" % key_source)
|
raise QAPISemError(info, "%s uses reserved name" % key_source)
|
||||||
check_keys(arg, info, key_source, ['type'], ['if'])
|
check_keys(arg, info, key_source, ['type'], ['if', 'features'])
|
||||||
check_if(arg, info, key_source)
|
check_if(arg, info, key_source)
|
||||||
|
check_features(arg.get('features'), info)
|
||||||
check_type(arg['type'], info, key_source, allow_array=True)
|
check_type(arg['type'], info, key_source, allow_array=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ const QLitObject %(c_name)s = %(c_string)s;
|
||||||
obj = {'name': member.name, 'type': self._use_type(member.type)}
|
obj = {'name': member.name, 'type': self._use_type(member.type)}
|
||||||
if member.optional:
|
if member.optional:
|
||||||
obj['default'] = None
|
obj['default'] = None
|
||||||
return _make_tree(obj, member.ifcond, None)
|
return _make_tree(obj, member.ifcond, member.features)
|
||||||
|
|
||||||
def _gen_variants(self, tag_name, variants):
|
def _gen_variants(self, tag_name, variants):
|
||||||
return {'tag': tag_name,
|
return {'tag': tag_name,
|
||||||
|
|
|
@ -668,18 +668,31 @@ class QAPISchemaFeature(QAPISchemaMember):
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaObjectTypeMember(QAPISchemaMember):
|
class QAPISchemaObjectTypeMember(QAPISchemaMember):
|
||||||
def __init__(self, name, info, typ, optional, ifcond=None):
|
def __init__(self, name, info, typ, optional, ifcond=None, features=None):
|
||||||
super().__init__(name, info, ifcond)
|
super().__init__(name, info, ifcond)
|
||||||
assert isinstance(typ, str)
|
assert isinstance(typ, str)
|
||||||
assert isinstance(optional, bool)
|
assert isinstance(optional, bool)
|
||||||
|
for f in features or []:
|
||||||
|
assert isinstance(f, QAPISchemaFeature)
|
||||||
|
f.set_defined_in(name)
|
||||||
self._type_name = typ
|
self._type_name = typ
|
||||||
self.type = None
|
self.type = None
|
||||||
self.optional = optional
|
self.optional = optional
|
||||||
|
self.features = features or []
|
||||||
|
|
||||||
def check(self, schema):
|
def check(self, schema):
|
||||||
assert self.defined_in
|
assert self.defined_in
|
||||||
self.type = schema.resolve_type(self._type_name, self.info,
|
self.type = schema.resolve_type(self._type_name, self.info,
|
||||||
self.describe)
|
self.describe)
|
||||||
|
seen = {}
|
||||||
|
for f in self.features:
|
||||||
|
f.check_clash(self.info, seen)
|
||||||
|
|
||||||
|
def connect_doc(self, doc):
|
||||||
|
super().connect_doc(doc)
|
||||||
|
if doc:
|
||||||
|
for f in self.features:
|
||||||
|
doc.connect_feature(f)
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaVariant(QAPISchemaObjectTypeMember):
|
class QAPISchemaVariant(QAPISchemaObjectTypeMember):
|
||||||
|
@ -962,7 +975,7 @@ class QAPISchema:
|
||||||
name, info, doc, ifcond, features,
|
name, info, doc, ifcond, features,
|
||||||
self._make_enum_members(data, info), prefix))
|
self._make_enum_members(data, info), prefix))
|
||||||
|
|
||||||
def _make_member(self, name, typ, ifcond, info):
|
def _make_member(self, name, typ, ifcond, features, info):
|
||||||
optional = False
|
optional = False
|
||||||
if name.startswith('*'):
|
if name.startswith('*'):
|
||||||
name = name[1:]
|
name = name[1:]
|
||||||
|
@ -970,10 +983,12 @@ class QAPISchema:
|
||||||
if isinstance(typ, list):
|
if isinstance(typ, list):
|
||||||
assert len(typ) == 1
|
assert len(typ) == 1
|
||||||
typ = self._make_array_type(typ[0], info)
|
typ = self._make_array_type(typ[0], info)
|
||||||
return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond)
|
return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond,
|
||||||
|
self._make_features(features, info))
|
||||||
|
|
||||||
def _make_members(self, data, info):
|
def _make_members(self, data, info):
|
||||||
return [self._make_member(key, value['type'], value.get('if'), info)
|
return [self._make_member(key, value['type'], value.get('if'),
|
||||||
|
value.get('features'), info)
|
||||||
for (key, value) in data.items()]
|
for (key, value) in data.items()]
|
||||||
|
|
||||||
def _def_struct_type(self, expr, info, doc):
|
def _def_struct_type(self, expr, info, doc):
|
||||||
|
@ -996,7 +1011,7 @@ class QAPISchema:
|
||||||
typ = self._make_array_type(typ[0], info)
|
typ = self._make_array_type(typ[0], info)
|
||||||
typ = self._make_implicit_object_type(
|
typ = self._make_implicit_object_type(
|
||||||
typ, info, self.lookup_type(typ),
|
typ, info, self.lookup_type(typ),
|
||||||
'wrapper', [self._make_member('data', typ, None, info)])
|
'wrapper', [self._make_member('data', typ, None, None, info)])
|
||||||
return QAPISchemaVariant(case, info, typ, ifcond)
|
return QAPISchemaVariant(case, info, typ, ifcond)
|
||||||
|
|
||||||
def _def_union_type(self, expr, info, doc):
|
def _def_union_type(self, expr, info, doc):
|
||||||
|
|
|
@ -78,10 +78,13 @@
|
||||||
#
|
#
|
||||||
# Features:
|
# Features:
|
||||||
# @variant1-feat: a feature
|
# @variant1-feat: a feature
|
||||||
|
# @member-feat: a member feature
|
||||||
##
|
##
|
||||||
{ 'struct': 'Variant1',
|
{ 'struct': 'Variant1',
|
||||||
'features': [ 'variant1-feat' ],
|
'features': [ 'variant1-feat' ],
|
||||||
'data': { 'var1': { 'type': 'str', 'if': 'defined(IFSTR)' } } }
|
'data': { 'var1': { 'type': 'str',
|
||||||
|
'features': [ 'member-feat' ],
|
||||||
|
'if': 'defined(IFSTR)' } } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @Variant2:
|
# @Variant2:
|
||||||
|
|
|
@ -21,6 +21,7 @@ object Base
|
||||||
object Variant1
|
object Variant1
|
||||||
member var1: str optional=False
|
member var1: str optional=False
|
||||||
if ['defined(IFSTR)']
|
if ['defined(IFSTR)']
|
||||||
|
feature member-feat
|
||||||
feature variant1-feat
|
feature variant1-feat
|
||||||
object Variant2
|
object Variant2
|
||||||
object Object
|
object Object
|
||||||
|
@ -135,6 +136,8 @@ Another paragraph (but no @var: line)
|
||||||
|
|
||||||
feature=variant1-feat
|
feature=variant1-feat
|
||||||
a feature
|
a feature
|
||||||
|
feature=member-feat
|
||||||
|
a member feature
|
||||||
doc symbol=Variant2
|
doc symbol=Variant2
|
||||||
body=
|
body=
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,8 @@ Not documented
|
||||||
@table @asis
|
@table @asis
|
||||||
@item @code{variant1-feat}
|
@item @code{variant1-feat}
|
||||||
a feature
|
a feature
|
||||||
|
@item @code{member-feat}
|
||||||
|
a member feature
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@end deftp
|
@end deftp
|
||||||
|
|
|
@ -258,7 +258,7 @@
|
||||||
'data': { 'foo': 'int' },
|
'data': { 'foo': 'int' },
|
||||||
'features': [] }
|
'features': [] }
|
||||||
{ 'struct': 'FeatureStruct1',
|
{ 'struct': 'FeatureStruct1',
|
||||||
'data': { 'foo': 'int' },
|
'data': { 'foo': { 'type': 'int', 'features': [ 'member-feature1' ] } },
|
||||||
'features': [ 'feature1' ] }
|
'features': [ 'feature1' ] }
|
||||||
{ 'struct': 'FeatureStruct2',
|
{ 'struct': 'FeatureStruct2',
|
||||||
'data': { 'foo': 'int' },
|
'data': { 'foo': 'int' },
|
||||||
|
|
|
@ -359,6 +359,7 @@ object FeatureStruct0
|
||||||
member foo: int optional=False
|
member foo: int optional=False
|
||||||
object FeatureStruct1
|
object FeatureStruct1
|
||||||
member foo: int optional=False
|
member foo: int optional=False
|
||||||
|
feature member-feature1
|
||||||
feature feature1
|
feature feature1
|
||||||
object FeatureStruct2
|
object FeatureStruct2
|
||||||
member foo: int optional=False
|
member foo: int optional=False
|
||||||
|
|
|
@ -55,6 +55,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
||||||
print(' member %s: %s optional=%s'
|
print(' member %s: %s optional=%s'
|
||||||
% (m.name, m.type.name, m.optional))
|
% (m.name, m.type.name, m.optional))
|
||||||
self._print_if(m.ifcond, 8)
|
self._print_if(m.ifcond, 8)
|
||||||
|
self._print_features(m.features, indent=8)
|
||||||
self._print_variants(variants)
|
self._print_variants(variants)
|
||||||
self._print_if(ifcond)
|
self._print_if(ifcond)
|
||||||
self._print_features(features)
|
self._print_features(features)
|
||||||
|
@ -96,11 +97,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
||||||
print('%sif %s' % (' ' * indent, ifcond))
|
print('%sif %s' % (' ' * indent, ifcond))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _print_features(cls, features):
|
def _print_features(cls, features, indent=4):
|
||||||
if features:
|
if features:
|
||||||
for f in features:
|
for f in features:
|
||||||
print(' feature %s' % f.name)
|
print('%sfeature %s' % (' ' * indent, f.name))
|
||||||
cls._print_if(f.ifcond, 8)
|
cls._print_if(f.ifcond, indent + 4)
|
||||||
|
|
||||||
|
|
||||||
def test_frontend(fname):
|
def test_frontend(fname):
|
||||||
|
|
Loading…
Reference in New Issue