X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/586fc27e6a2ade22e35089e8972bc678b113e1db..15c2f669e3fb2bc97f7b42d1871f595c0ac24af8:/scripts/qapi-visit.py diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 2308268a62..bdf8971440 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -15,10 +15,6 @@ from qapi import * import re -# visit_type_FOO_fields() is always emitted; track if a forward declaration -# or implementation has already been output. -struct_fields_seen = set() - def gen_visit_decl(name, scalar=False): c_type = c_name(name) + ' *' @@ -30,46 +26,49 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error ** c_name=c_name(name), c_type=c_type) -def gen_visit_fields_decl(typ): - if typ.name in struct_fields_seen: - return '' - struct_fields_seen.add(typ.name) +def gen_visit_members_decl(name): return mcgen(''' -static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **errp); +void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp); ''', - c_type=typ.c_name()) - - -def gen_visit_struct_fields(name, base, members, variants): - ret = '' + c_name=c_name(name)) - if base: - ret += gen_visit_fields_decl(base) - if variants: - for var in variants.variants: - # Ugly special case for simple union TODO get rid of it - if not var.simple_union_type(): - ret += gen_visit_fields_decl(var.type) - struct_fields_seen.add(name) - ret += mcgen(''' +def gen_visit_object_members(name, base, members, variants): + ret = mcgen(''' -static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **errp) +void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) { Error *err = NULL; ''', - c_name=c_name(name)) + c_name=c_name(name)) if base: ret += mcgen(''' - visit_type_%(c_type)s_fields(v, (%(c_type)s *)obj, &err); + visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, &err); ''', c_type=base.c_name()) ret += gen_err_check() - ret += gen_visit_fields(members, prefix='obj->') + for memb in members: + if memb.optional: + ret += mcgen(''' + if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) { +''', + name=memb.name, c_name=c_name(memb.name)) + push_indent() + ret += mcgen(''' + visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, &err); +''', + c_type=memb.type.c_name(), name=memb.name, + c_name=c_name(memb.name)) + ret += gen_err_check() + if memb.optional: + pop_indent() + ret += mcgen(''' + } +''') if variants: ret += mcgen(''' @@ -78,29 +77,15 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **er c_name=c_name(variants.tag_member.name)) for var in variants.variants: - # TODO ugly special case for simple union - simple_union_type = var.simple_union_type() ret += mcgen(''' case %(case)s: + visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err); + break; ''', case=c_enum_const(variants.tag_member.type.name, var.name, - variants.tag_member.type.prefix)) - if simple_union_type: - ret += mcgen(''' - visit_type_%(c_type)s(v, "data", &obj->u.%(c_name)s, &err); -''', - c_type=simple_union_type.c_name(), - c_name=c_name(var.name)) - else: - ret += mcgen(''' - visit_type_%(c_type)s_fields(v, &obj->u.%(c_name)s, &err); -''', - c_type=var.type.c_name(), - c_name=c_name(var.name)) - ret += mcgen(''' - break; -''') + variants.tag_member.type.prefix), + c_type=var.type.c_name(), c_name=c_name(var.name)) ret += mcgen(''' default: @@ -108,8 +93,8 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **er } ''') - # 'goto out' produced for base, by gen_visit_fields() for each member, - # and if variants were present + # 'goto out' produced for base, for each member, and if variants were + # present if base or members or variants: ret += mcgen(''' @@ -173,8 +158,6 @@ def gen_visit_alternate(name, variants): for var in variants.variants: if var.type.alternate_qtype() == 'QTYPE_QINT': promote_int = 'false' - if isinstance(var.type, QAPISchemaObjectType): - ret += gen_visit_fields_decl(var.type) ret += mcgen(''' @@ -202,10 +185,11 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (err) { break; } - visit_type_%(c_type)s_fields(v, &(*obj)->u.%(c_name)s, &err); - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); + visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, &err); + if (!err) { + visit_check_struct(v, &err); + } + visit_end_struct(v); ''', c_type=var.type.c_name(), c_name=c_name(var.name)) @@ -235,13 +219,11 @@ out: def gen_visit_object(name, base, members, variants): - ret = gen_visit_struct_fields(name, base, members, variants) - # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to - # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj + # *obj, but then visit_type_FOO_members() fails, we should clean up *obj # rather than leaving it non-NULL. As currently written, the caller must # call qapi_free_FOO() to avoid a memory leak of the partial FOO. - ret += mcgen(''' + return mcgen(''' void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { @@ -254,19 +236,19 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (!*obj) { goto out_obj; } - visit_type_%(c_name)s_fields(v, *obj, &err); - error_propagate(errp, err); - err = NULL; + visit_type_%(c_name)s_members(v, *obj, &err); + if (err) { + goto out_obj; + } + visit_check_struct(v, &err); out_obj: - visit_end_struct(v, &err); + visit_end_struct(v); out: error_propagate(errp, err); } ''', c_name=c_name(name)) - return ret - class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): def __init__(self): @@ -288,11 +270,6 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.decl = self._btin + self.decl self._btin = None - def visit_needed(self, entity): - # Visit everything except implicit objects - return not (entity.is_implicit() and - isinstance(entity, QAPISchemaObjectType)) - def visit_enum_type(self, name, info, values, prefix): # Special case for our lone builtin enum type # TODO use something cleaner than existence of info @@ -316,8 +293,17 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.defn += defn def visit_object_type(self, name, info, base, members, variants): - self.decl += gen_visit_decl(name) - self.defn += gen_visit_object(name, base, members, variants) + # Nothing to do for the special empty builtin + if name == 'q_empty': + return + self.decl += gen_visit_members_decl(name) + self.defn += gen_visit_object_members(name, base, members, variants) + # TODO Worth changing the visitor signature, so we could + # directly use rather than repeat type.is_implicit()? + if not name.startswith('q_'): + # only explicit types need an allocating visit + self.decl += gen_visit_decl(name) + self.defn += gen_visit_object(name, base, members, variants) def visit_alternate_type(self, name, info, variants): self.decl += gen_visit_decl(name) @@ -372,6 +358,7 @@ h_comment = ''' fdef.write(mcgen(''' #include "qemu/osdep.h" #include "qemu-common.h" +#include "qapi/error.h" #include "%(prefix)sqapi-visit.h" ''', prefix=prefix))