aboutsummaryrefslogtreecommitdiff
path: root/scripts/qapi/types.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/qapi/types.py')
-rw-r--r--scripts/qapi/types.py199
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)