diff options
Diffstat (limited to 'scripts/qapi/types.py')
-rw-r--r-- | scripts/qapi/types.py | 199 |
1 files changed, 166 insertions, 33 deletions
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index fd7808103c..c39d054d2c 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -13,7 +13,25 @@ This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. """ -from qapi.common import * +from typing import List, Optional + +from .common import c_enum_const, c_name, mcgen +from .gen import ( + QAPISchemaModularCVisitor, + gen_special_features, + ifcontext, +) +from .schema import ( + QAPISchema, + QAPISchemaEnumMember, + QAPISchemaFeature, + QAPISchemaIfCond, + QAPISchemaObjectType, + QAPISchemaObjectTypeMember, + QAPISchemaType, + QAPISchemaVariants, +) +from .source import QAPISourceInfo # variants must be emitted before their container; track what has already @@ -21,7 +39,87 @@ from qapi.common import * objects_seen = set() -def gen_fwd_object_or_array(name): +def gen_enum_lookup(name: str, + members: List[QAPISchemaEnumMember], + prefix: Optional[str] = None) -> str: + max_index = c_enum_const(name, '_MAX', prefix) + feats = '' + ret = mcgen(''' + +const QEnumLookup %(c_name)s_lookup = { + .array = (const char *const[]) { +''', + c_name=c_name(name)) + for memb in members: + ret += memb.ifcond.gen_if() + index = c_enum_const(name, memb.name, prefix) + ret += mcgen(''' + [%(index)s] = "%(name)s", +''', + index=index, name=memb.name) + ret += memb.ifcond.gen_endif() + + special_features = gen_special_features(memb.features) + if special_features != '0': + feats += mcgen(''' + [%(index)s] = %(special_features)s, +''', + index=index, special_features=special_features) + + if feats: + ret += mcgen(''' + }, + .special_features = (const unsigned char[%(max_index)s]) { +''', + max_index=max_index) + ret += feats + + ret += mcgen(''' + }, + .size = %(max_index)s +}; +''', + max_index=max_index) + return ret + + +def gen_enum(name: str, + members: List[QAPISchemaEnumMember], + prefix: Optional[str] = None) -> str: + # append automatically generated _MAX value + enum_members = members + [QAPISchemaEnumMember('_MAX', None)] + + ret = mcgen(''' + +typedef enum %(c_name)s { +''', + c_name=c_name(name)) + + for memb in enum_members: + ret += memb.ifcond.gen_if() + ret += mcgen(''' + %(c_enum)s, +''', + c_enum=c_enum_const(name, memb.name, prefix)) + ret += memb.ifcond.gen_endif() + + ret += mcgen(''' +} %(c_name)s; +''', + c_name=c_name(name)) + + ret += mcgen(''' + +#define %(c_name)s_str(val) \\ + qapi_enum_lookup(&%(c_name)s_lookup, (val)) + +extern const QEnumLookup %(c_name)s_lookup; +''', + c_name=c_name(name)) + return ret + + +def gen_fwd_object_or_array(name: str) -> str: return mcgen(''' typedef struct %(c_name)s %(c_name)s; @@ -29,7 +127,7 @@ typedef struct %(c_name)s %(c_name)s; c_name=c_name(name)) -def gen_array(name, element_type): +def gen_array(name: str, element_type: QAPISchemaType) -> str: return mcgen(''' struct %(c_name)s { @@ -40,10 +138,11 @@ struct %(c_name)s { c_name=c_name(name), c_type=element_type.c_type()) -def gen_struct_members(members): +def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str: ret = '' for memb in members: - if memb.optional: + ret += memb.ifcond.gen_if() + if memb.need_has(): ret += mcgen(''' bool has_%(c_name)s; ''', @@ -52,25 +151,30 @@ def gen_struct_members(members): %(c_type)s %(c_name)s; ''', c_type=memb.type.c_type(), c_name=c_name(memb.name)) + ret += memb.ifcond.gen_endif() return ret -def gen_object(name, ifcond, base, members, variants): +def gen_object(name: str, ifcond: QAPISchemaIfCond, + base: Optional[QAPISchemaObjectType], + members: List[QAPISchemaObjectTypeMember], + variants: Optional[QAPISchemaVariants]) -> str: if name in objects_seen: return '' objects_seen.add(name) ret = '' - if variants: - for v in variants.variants: - if isinstance(v.type, QAPISchemaObjectType): - ret += gen_object(v.type.name, v.type.ifcond, v.type.base, - v.type.local_members, v.type.variants) + for var in variants.variants if variants else (): + obj = var.type + if not isinstance(obj, QAPISchemaObjectType): + continue + ret += gen_object(obj.name, obj.ifcond, obj.base, + obj.local_members, obj.variants) ret += mcgen(''' ''') - ret += gen_if(ifcond) + ret += ifcond.gen_if() ret += mcgen(''' struct %(c_name)s { ''', @@ -104,12 +208,12 @@ struct %(c_name)s { ret += mcgen(''' }; ''') - ret += gen_endif(ifcond) + ret += ifcond.gen_endif() return ret -def gen_upcast(name, base): +def gen_upcast(name: str, base: QAPISchemaObjectType) -> str: # C makes const-correctness ugly. We have to cast away const to let # this function work for both const and non-const obj. return mcgen(''' @@ -122,7 +226,7 @@ static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj) c_name=c_name(name), base=base.c_name()) -def gen_variants(variants): +def gen_variants(variants: QAPISchemaVariants) -> str: ret = mcgen(''' union { /* union tag is @%(c_name)s */ ''', @@ -131,11 +235,13 @@ def gen_variants(variants): for var in variants.variants: if var.type.name == 'q_empty': continue + ret += var.ifcond.gen_if() ret += mcgen(''' %(c_type)s %(c_name)s; ''', c_type=var.type.c_unboxed_type(), c_name=c_name(var.name)) + ret += var.ifcond.gen_endif() ret += mcgen(''' } u; @@ -144,16 +250,17 @@ def gen_variants(variants): return ret -def gen_type_cleanup_decl(name): +def gen_type_cleanup_decl(name: str) -> str: ret = mcgen(''' void qapi_free_%(c_name)s(%(c_name)s *obj); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(%(c_name)s, qapi_free_%(c_name)s) ''', c_name=c_name(name)) return ret -def gen_type_cleanup(name): +def gen_type_cleanup(name: str) -> str: ret = mcgen(''' void qapi_free_%(c_name)s(%(c_name)s *obj) @@ -175,11 +282,12 @@ void qapi_free_%(c_name)s(%(c_name)s *obj) class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): - def __init__(self, prefix): - QAPISchemaModularCVisitor.__init__( - self, prefix, 'qapi-types', ' * Schema-defined QAPI types', - __doc__) - self._add_module(None, ' * Built-in QAPI types') + def __init__(self, prefix: str): + super().__init__( + prefix, 'qapi-types', ' * Schema-defined QAPI types', + ' * Built-in QAPI types', __doc__) + + def _begin_builtin_module(self) -> None: self._genc.preamble_add(mcgen(''' #include "qemu/osdep.h" #include "qapi/dealloc-visitor.h" @@ -190,7 +298,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): #include "qapi/util.h" ''')) - def _begin_module(self, name): + def _begin_user_module(self, name: str) -> None: types = self._module_basename('qapi-types', name) visit = self._module_basename('qapi-visit', name) self._genc.preamble_add(mcgen(''' @@ -204,26 +312,43 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): #include "qapi/qapi-builtin-types.h" ''')) - def visit_begin(self, schema): + def visit_begin(self, schema: QAPISchema) -> None: # gen_object() is recursive, ensure it doesn't visit the empty type objects_seen.add(schema.the_empty_object_type.name) - def _gen_type_cleanup(self, name): + def _gen_type_cleanup(self, name: str) -> None: self._genh.add(gen_type_cleanup_decl(name)) self._genc.add(gen_type_cleanup(name)) - def visit_enum_type(self, name, info, ifcond, values, prefix): + def visit_enum_type(self, + name: str, + info: Optional[QAPISourceInfo], + ifcond: QAPISchemaIfCond, + features: List[QAPISchemaFeature], + members: List[QAPISchemaEnumMember], + prefix: Optional[str]) -> None: with ifcontext(ifcond, self._genh, self._genc): - self._genh.preamble_add(gen_enum(name, values, prefix)) - self._genc.add(gen_enum_lookup(name, values, prefix)) - - def visit_array_type(self, name, info, ifcond, element_type): + self._genh.preamble_add(gen_enum(name, members, prefix)) + self._genc.add(gen_enum_lookup(name, members, prefix)) + + def visit_array_type(self, + name: str, + info: Optional[QAPISourceInfo], + ifcond: QAPISchemaIfCond, + element_type: QAPISchemaType) -> None: with ifcontext(ifcond, self._genh, self._genc): self._genh.preamble_add(gen_fwd_object_or_array(name)) self._genh.add(gen_array(name, element_type)) self._gen_type_cleanup(name) - def visit_object_type(self, name, info, ifcond, base, members, variants): + def visit_object_type(self, + name: str, + info: Optional[QAPISourceInfo], + ifcond: QAPISchemaIfCond, + features: List[QAPISchemaFeature], + base: Optional[QAPISchemaObjectType], + members: List[QAPISchemaObjectTypeMember], + variants: Optional[QAPISchemaVariants]) -> None: # Nothing to do for the special empty builtin if name == 'q_empty': return @@ -239,7 +364,12 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): # implicit types won't be directly allocated/freed self._gen_type_cleanup(name) - def visit_alternate_type(self, name, info, ifcond, variants): + def visit_alternate_type(self, + name: str, + info: Optional[QAPISourceInfo], + ifcond: QAPISchemaIfCond, + features: List[QAPISchemaFeature], + variants: QAPISchemaVariants) -> None: with ifcontext(ifcond, self._genh): self._genh.preamble_add(gen_fwd_object_or_array(name)) self._genh.add(gen_object(name, ifcond, None, @@ -248,7 +378,10 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): self._gen_type_cleanup(name) -def gen_types(schema, output_dir, prefix, opt_builtins): +def gen_types(schema: QAPISchema, + output_dir: str, + prefix: str, + opt_builtins: bool) -> None: vis = QAPISchemaGenTypeVisitor(prefix) schema.visit(vis) vis.write(output_dir, opt_builtins) |