qapi: Clean up after recent conversions to QAPISchemaVisitor

Generate just 'FOO' instead of 'struct FOO' when possible.

Drop helper functions that are now unused.

Make pep8 and pylint reasonably happy.

Rename generate_FOO() functions to gen_FOO() for consistency.

Use more consistent and sensible variable names.

Consistently use c_ for mapping keys when their value is a C
identifier or type.

Simplify gen_enum() and gen_visit_union()

Consistently use single quotes for C text string literals.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1442401589-24189-14-git-send-email-armbru@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Markus Armbruster 2015-09-16 13:06:16 +02:00
parent 5710153e73
commit e98859a9b9
6 changed files with 276 additions and 329 deletions

View File

@ -598,7 +598,7 @@ Example:
UserDefOne *value; UserDefOne *value;
uint64_t padding; uint64_t padding;
}; };
struct UserDefOneList *next; UserDefOneList *next;
}; };
void qapi_free_UserDefOneList(UserDefOneList *obj); void qapi_free_UserDefOneList(UserDefOneList *obj);

View File

@ -15,20 +15,22 @@
from qapi import * from qapi import *
import re import re
def generate_command_decl(name, args, ret_type):
arglist="" def gen_command_decl(name, arg_type, ret_type):
if args: argstr = ''
for memb in args.members: if arg_type:
argtype = memb.type.c_type(is_param=True) for memb in arg_type.members:
if memb.optional: if memb.optional:
arglist += "bool has_%s, " % c_name(memb.name) argstr += 'bool has_%s, ' % c_name(memb.name)
arglist += "%s %s, " % (argtype, c_name(memb.name)) argstr += '%s %s, ' % (memb.type.c_type(is_param=True),
c_name(memb.name))
return mcgen(''' return mcgen('''
%(ret_type)s qmp_%(name)s(%(args)sError **errp); %(c_type)s qmp_%(c_name)s(%(args)sError **errp);
''', ''',
ret_type=(ret_type and ret_type.c_type()) or 'void', c_type=(ret_type and ret_type.c_type()) or 'void',
name=c_name(name), c_name=c_name(name),
args=arglist) args=argstr)
def gen_err_check(err): def gen_err_check(err):
if not err: if not err:
@ -40,37 +42,42 @@ def gen_err_check(err):
''', ''',
err=err) err=err)
def gen_sync_call(name, args, ret_type):
ret = "" def gen_call(name, arg_type, ret_type):
arglist="" ret = ''
retval=""
if ret_type: argstr = ''
retval = "retval = " if arg_type:
if args: for memb in arg_type.members:
for memb in args.members:
if memb.optional: if memb.optional:
arglist += "has_%s, " % c_name(memb.name) argstr += 'has_%s, ' % c_name(memb.name)
arglist += "%s, " % c_name(memb.name) argstr += '%s, ' % c_name(memb.name)
lhs = ''
if ret_type:
lhs = 'retval = '
push_indent() push_indent()
ret = mcgen(''' ret = mcgen('''
%(retval)sqmp_%(name)s(%(args)s&local_err); %(lhs)sqmp_%(c_name)s(%(args)s&local_err);
''', ''',
name=c_name(name), args=arglist, retval=retval) c_name=c_name(name), args=argstr, lhs=lhs)
if ret_type: if ret_type:
ret += gen_err_check('local_err') ret += gen_err_check('local_err')
ret += mcgen(''' ret += mcgen('''
qmp_marshal_output_%(c_name)s(retval, ret, &local_err); qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
''', ''',
c_name=c_name(name)) c_name=c_name(name))
pop_indent() pop_indent()
return ret return ret
def gen_visitor_input_containers_decl(args):
ret = "" def gen_visitor_input_containers_decl(arg_type):
ret = ''
push_indent() push_indent()
if args: if arg_type:
ret += mcgen(''' ret += mcgen('''
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args)); QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
@ -80,17 +87,18 @@ def gen_visitor_input_containers_decl(args):
return ret return ret
def gen_visitor_input_vars_decl(args):
ret = "" def gen_visitor_input_vars_decl(arg_type):
ret = ''
push_indent() push_indent()
if args: if arg_type:
for memb in args.members: for memb in arg_type.members:
if memb.optional: if memb.optional:
ret += mcgen(''' ret += mcgen('''
bool has_%(argname)s = false; bool has_%(c_name)s = false;
''', ''',
argname=c_name(memb.name)) c_name=c_name(memb.name))
ret += mcgen(''' ret += mcgen('''
%(c_type)s %(c_name)s = %(c_null)s; %(c_type)s %(c_name)s = %(c_null)s;
''', ''',
@ -101,19 +109,20 @@ def gen_visitor_input_vars_decl(args):
pop_indent() pop_indent()
return ret return ret
def gen_visitor_input_block(args, dealloc=False):
ret = "" def gen_visitor_input_block(arg_type, dealloc=False):
ret = ''
errparg = '&local_err' errparg = '&local_err'
errarg = 'local_err' errarg = 'local_err'
if not args: if not arg_type:
return ret return ret
push_indent() push_indent()
if dealloc: if dealloc:
errparg = 'NULL' errparg = 'NULL'
errarg = None; errarg = None
ret += mcgen(''' ret += mcgen('''
qmp_input_visitor_cleanup(mi); qmp_input_visitor_cleanup(mi);
md = qapi_dealloc_visitor_new(); md = qapi_dealloc_visitor_new();
@ -124,7 +133,7 @@ def gen_visitor_input_block(args, dealloc=False):
v = qmp_input_get_visitor(mi); v = qmp_input_get_visitor(mi);
''') ''')
for memb in args.members: for memb in arg_type.members:
if memb.optional: if memb.optional:
ret += mcgen(''' ret += mcgen('''
visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
@ -138,10 +147,10 @@ def gen_visitor_input_block(args, dealloc=False):
c_name=c_name(memb.name)) c_name=c_name(memb.name))
push_indent() push_indent()
ret += mcgen(''' ret += mcgen('''
visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); visit_type_%(c_type)s(v, &%(c_name)s, "%(name)s", %(errp)s);
''', ''',
c_name=c_name(memb.name), name=memb.name, c_name=c_name(memb.name), name=memb.name,
visitor=memb.type.c_name(), errp=errparg) c_type=memb.type.c_name(), errp=errparg)
ret += gen_err_check(errarg) ret += gen_err_check(errarg)
if memb.optional: if memb.optional:
pop_indent() pop_indent()
@ -156,13 +165,14 @@ def gen_visitor_input_block(args, dealloc=False):
pop_indent() pop_indent()
return ret return ret
def gen_marshal_output(name, ret_type): def gen_marshal_output(name, ret_type):
if not ret_type: if not ret_type:
return "" return ''
ret = mcgen(''' ret = mcgen('''
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp) static void qmp_marshal_output_%(c_cmd_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new(); QmpOutputVisitor *mo = qmp_output_visitor_new();
@ -170,7 +180,7 @@ def gen_marshal_output(name, ret_type):
Visitor *v; Visitor *v;
v = qmp_output_get_visitor(mo); v = qmp_output_get_visitor(mo);
visit_type_%(visitor)s(v, &ret_in, "unused", &local_err); visit_type_%(c_name)s(v, &ret_in, "unused", &local_err);
if (local_err) { if (local_err) {
goto out; goto out;
} }
@ -181,23 +191,25 @@ def gen_marshal_output(name, ret_type):
qmp_output_visitor_cleanup(mo); qmp_output_visitor_cleanup(mo);
md = qapi_dealloc_visitor_new(); md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
visit_type_%(visitor)s(v, &ret_in, "unused", NULL); visit_type_%(c_name)s(v, &ret_in, "unused", NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
} }
''', ''',
c_ret_type=ret_type.c_type(), c_name=c_name(name), c_type=ret_type.c_type(), c_cmd_name=c_name(name),
visitor=ret_type.c_name()) c_name=ret_type.c_name())
return ret return ret
def gen_marshal_input_decl(name, middle_mode):
def gen_marshal_input_decl(name):
ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name) ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
if not middle_mode: if not middle_mode:
ret = "static " + ret ret = 'static ' + ret
return ret return ret
def gen_marshal_input(name, args, ret_type, middle_mode):
hdr = gen_marshal_input_decl(name, middle_mode) def gen_marshal_input(name, arg_type, ret_type):
hdr = gen_marshal_input_decl(name)
ret = mcgen(''' ret = mcgen('''
@ -213,10 +225,10 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
''', ''',
c_type=ret_type.c_type()) c_type=ret_type.c_type())
if args: if arg_type:
ret += gen_visitor_input_containers_decl(args) ret += gen_visitor_input_containers_decl(arg_type)
ret += gen_visitor_input_vars_decl(args) + '\n' ret += gen_visitor_input_vars_decl(arg_type) + '\n'
ret += gen_visitor_input_block(args) + '\n' ret += gen_visitor_input_block(arg_type) + '\n'
else: else:
ret += mcgen(''' ret += mcgen('''
@ -224,9 +236,9 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
''') ''')
ret += gen_sync_call(name, args, ret_type) ret += gen_call(name, arg_type, ret_type)
if re.search('^ *goto out\\;', ret, re.MULTILINE): if re.search('^ *goto out;', ret, re.MULTILINE):
ret += mcgen(''' ret += mcgen('''
out: out:
@ -234,12 +246,13 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
ret += mcgen(''' ret += mcgen('''
error_propagate(errp, local_err); error_propagate(errp, local_err);
''') ''')
ret += gen_visitor_input_block(args, dealloc=True) ret += gen_visitor_input_block(arg_type, dealloc=True)
ret += mcgen(''' ret += mcgen('''
} }
''') ''')
return ret return ret
def gen_register_command(name, success_response): def gen_register_command(name, success_response):
push_indent() push_indent()
options = 'QCO_NO_OPTIONS' options = 'QCO_NO_OPTIONS'
@ -249,11 +262,12 @@ def gen_register_command(name, success_response):
ret = mcgen(''' ret = mcgen('''
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s); qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
''', ''',
name=name, c_name=c_name(name), name=name, c_name=c_name(name),
opts=options) opts=options)
pop_indent() pop_indent()
return ret return ret
def gen_registry(registry): def gen_registry(registry):
ret = mcgen(''' ret = mcgen('''
@ -289,12 +303,12 @@ def visit_command(self, name, info, arg_type, ret_type,
gen, success_response): gen, success_response):
if not gen: if not gen:
return return
self.decl += generate_command_decl(name, arg_type, ret_type) self.decl += gen_command_decl(name, arg_type, ret_type)
if ret_type: if ret_type:
self.defn += gen_marshal_output(name, ret_type) self.defn += gen_marshal_output(name, ret_type)
if middle_mode: if middle_mode:
self.decl += gen_marshal_input_decl(name, middle_mode) + ';\n' self.decl += gen_marshal_input_decl(name) + ';\n'
self.defn += gen_marshal_input(name, arg_type, ret_type, middle_mode) self.defn += gen_marshal_input(name, arg_type, ret_type)
if not middle_mode: if not middle_mode:
self._regy += gen_register_command(name, success_response) self._regy += gen_register_command(name, success_response)
@ -355,7 +369,7 @@ def visit_command(self, name, info, arg_type, ret_type,
#include "%(prefix)sqmp-commands.h" #include "%(prefix)sqmp-commands.h"
''', ''',
prefix=prefix)) prefix=prefix))
fdecl.write(mcgen(''' fdecl.write(mcgen('''
#include "%(prefix)sqapi-types.h" #include "%(prefix)sqapi-types.h"

View File

@ -13,12 +13,13 @@
from qapi import * from qapi import *
def _generate_event_api_name(event_name, params):
api_name = "void qapi_event_send_%s(" % c_name(event_name).lower(); def gen_event_send_proto(name, arg_type):
api_name = "void qapi_event_send_%s(" % c_name(name).lower()
l = len(api_name) l = len(api_name)
if params: if arg_type:
for m in params.members: for m in arg_type.members:
if m.optional: if m.optional:
api_name += "bool has_%s,\n" % c_name(m.name) api_name += "bool has_%s,\n" % c_name(m.name)
api_name += "".ljust(l) api_name += "".ljust(l)
@ -28,53 +29,49 @@ def _generate_event_api_name(event_name, params):
api_name += "".ljust(l) api_name += "".ljust(l)
api_name += "Error **errp)" api_name += "Error **errp)"
return api_name; return api_name
# Following are the core functions that generate C APIs to emit event. def gen_event_send_decl(name, arg_type):
def generate_event_declaration(api_name):
return mcgen(''' return mcgen('''
%(api_name)s; %(proto)s;
''', ''',
api_name = api_name) proto=gen_event_send_proto(name, arg_type))
def generate_event_implement(api_name, event_name, params):
# step 1: declare any variables
ret = mcgen("""
%(api_name)s def gen_event_send(name, arg_type):
ret = mcgen('''
%(proto)s
{ {
QDict *qmp; QDict *qmp;
Error *local_err = NULL; Error *local_err = NULL;
QMPEventFuncEmit emit; QMPEventFuncEmit emit;
""", ''',
api_name = api_name) proto=gen_event_send_proto(name, arg_type))
if params and params.members: if arg_type and arg_type.members:
ret += mcgen(""" ret += mcgen('''
QmpOutputVisitor *qov; QmpOutputVisitor *qov;
Visitor *v; Visitor *v;
QObject *obj; QObject *obj;
""") ''')
# step 2: check emit function, create a dict ret += mcgen('''
ret += mcgen("""
emit = qmp_event_get_func_emit(); emit = qmp_event_get_func_emit();
if (!emit) { if (!emit) {
return; return;
} }
qmp = qmp_event_build_dict("%(event_name)s"); qmp = qmp_event_build_dict("%(name)s");
""", ''',
event_name = event_name) name=name)
# step 3: visit the params if params != None if arg_type and arg_type.members:
if params and params.members: ret += mcgen('''
ret += mcgen("""
qov = qmp_output_visitor_new(); qov = qmp_output_visitor_new();
g_assert(qov); g_assert(qov);
@ -82,45 +79,46 @@ def generate_event_implement(api_name, event_name, params):
g_assert(v); g_assert(v);
/* Fake visit, as if all members are under a structure */ /* Fake visit, as if all members are under a structure */
visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err); visit_start_struct(v, NULL, "", "%(name)s", 0, &local_err);
if (local_err) { if (local_err) {
goto clean; goto clean;
} }
""", ''',
event_name = event_name) name=name)
for memb in params.members: for memb in arg_type.members:
if memb.optional: if memb.optional:
ret += mcgen(""" ret += mcgen('''
if (has_%(var)s) { if (has_%(c_name)s) {
""", ''',
var=c_name(memb.name)) c_name=c_name(memb.name))
push_indent() push_indent()
# Ugly: need to cast away the const
if memb.type.name == "str": if memb.type.name == "str":
var_type = "(char **)" cast = '(char **)'
else: else:
var_type = "" cast = ''
ret += mcgen(""" ret += mcgen('''
visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err); visit_type_%(c_type)s(v, %(cast)s&%(c_name)s, "%(name)s", &local_err);
if (local_err) { if (local_err) {
goto clean; goto clean;
} }
""", ''',
var_type = var_type, cast=cast,
var=c_name(memb.name), c_name=c_name(memb.name),
type=memb.type.c_name(), c_type=memb.type.c_name(),
name=memb.name) name=memb.name)
if memb.optional: if memb.optional:
pop_indent() pop_indent()
ret += mcgen(""" ret += mcgen('''
} }
""") ''')
ret += mcgen(""" ret += mcgen('''
visit_end_struct(v, &local_err); visit_end_struct(v, &local_err);
if (local_err) { if (local_err) {
@ -131,27 +129,24 @@ def generate_event_implement(api_name, event_name, params):
g_assert(obj != NULL); g_assert(obj != NULL);
qdict_put_obj(qmp, "data", obj); qdict_put_obj(qmp, "data", obj);
""") ''')
# step 4: call qmp event api ret += mcgen('''
ret += mcgen(""" emit(%(c_enum)s, qmp, &local_err);
emit(%(event_enum_value)s, qmp, &local_err);
""", ''',
event_enum_value = c_enum_const(event_enum_name, event_name)) c_enum=c_enum_const(event_enum_name, name))
# step 5: clean up if arg_type and arg_type.members:
if params and params.members: ret += mcgen('''
ret += mcgen("""
clean: clean:
qmp_output_visitor_cleanup(qov); qmp_output_visitor_cleanup(qov);
""") ''')
ret += mcgen(""" ret += mcgen('''
error_propagate(errp, local_err); error_propagate(errp, local_err);
QDECREF(qmp); QDECREF(qmp);
} }
""") ''')
return ret return ret
@ -167,14 +162,13 @@ def visit_begin(self, schema):
self._event_names = [] self._event_names = []
def visit_end(self): def visit_end(self):
self.decl += generate_enum(event_enum_name, self._event_names) self.decl += gen_enum(event_enum_name, self._event_names)
self.defn += generate_enum_lookup(event_enum_name, self._event_names) self.defn += gen_enum_lookup(event_enum_name, self._event_names)
self._event_names = None self._event_names = None
def visit_event(self, name, info, arg_type): def visit_event(self, name, info, arg_type):
api_name = _generate_event_api_name(name, arg_type) self.decl += gen_event_send_decl(name, arg_type)
self.decl += generate_event_declaration(api_name) self.defn += gen_event_send(name, arg_type)
self.defn += generate_event_implement(api_name, name, arg_type)
self._event_names.append(name) self._event_names.append(name)

View File

@ -13,25 +13,28 @@
from qapi import * from qapi import *
def gen_fwd_object_or_array(name): def gen_fwd_object_or_array(name):
return mcgen(''' return mcgen('''
typedef struct %(name)s %(name)s; typedef struct %(c_name)s %(c_name)s;
''', ''',
name=c_name(name)) c_name=c_name(name))
def gen_array(name, element_type): def gen_array(name, element_type):
return mcgen(''' return mcgen('''
struct %(name)s { struct %(c_name)s {
union { union {
%(c_type)s value; %(c_type)s value;
uint64_t padding; uint64_t padding;
}; };
struct %(name)s *next; %(c_name)s *next;
}; };
''', ''',
name=c_name(name), c_type=element_type.c_type()) c_name=c_name(name), c_type=element_type.c_type())
def gen_struct_field(name, typ, optional): def gen_struct_field(name, typ, optional):
ret = '' ret = ''
@ -47,30 +50,33 @@ def gen_struct_field(name, typ, optional):
c_type=typ.c_type(), c_name=c_name(name)) c_type=typ.c_type(), c_name=c_name(name))
return ret return ret
def generate_struct_fields(members):
def gen_struct_fields(members):
ret = '' ret = ''
for memb in members: for memb in members:
ret += gen_struct_field(memb.name, memb.type, memb.optional) ret += gen_struct_field(memb.name, memb.type, memb.optional)
return ret return ret
def gen_struct(name, base, members): def gen_struct(name, base, members):
ret = mcgen(''' ret = mcgen('''
struct %(name)s { struct %(c_name)s {
''', ''',
name=c_name(name)) c_name=c_name(name))
if base: if base:
ret += gen_struct_field('base', base, False) ret += gen_struct_field('base', base, False)
ret += generate_struct_fields(members) ret += gen_struct_fields(members)
# Make sure that all structs have at least one field; this avoids # Make sure that all structs have at least one field; this avoids
# potential issues with attempting to malloc space for zero-length structs # potential issues with attempting to malloc space for zero-length
# in C, and also incompatibility with C++ (where an empty struct is size 1). # structs in C, and also incompatibility with C++ (where an empty
# struct is size 1).
if not base and not members: if not base and not members:
ret += mcgen(''' ret += mcgen('''
char qapi_dummy_field_for_empty_struct; char qapi_dummy_field_for_empty_struct;
''') ''')
@ -80,6 +86,7 @@ def gen_struct(name, base, members):
return ret return ret
def gen_alternate_qtypes_decl(name): def gen_alternate_qtypes_decl(name):
return mcgen(''' return mcgen('''
@ -87,12 +94,13 @@ def gen_alternate_qtypes_decl(name):
''', ''',
c_name=c_name(name)) c_name=c_name(name))
def gen_alternate_qtypes(name, variants): def gen_alternate_qtypes(name, variants):
ret = mcgen(''' ret = mcgen('''
const int %(name)s_qtypes[QTYPE_MAX] = { const int %(c_name)s_qtypes[QTYPE_MAX] = {
''', ''',
name=c_name(name)) c_name=c_name(name))
for var in variants.variants: for var in variants.variants:
qtype = var.type.alternate_qtype() qtype = var.type.alternate_qtype()
@ -101,7 +109,7 @@ def gen_alternate_qtypes(name, variants):
ret += mcgen(''' ret += mcgen('''
[%(qtype)s] = %(enum_const)s, [%(qtype)s] = %(enum_const)s,
''', ''',
qtype = qtype, qtype=qtype,
enum_const=c_enum_const(variants.tag_member.type.name, enum_const=c_enum_const(variants.tag_member.type.name,
var.name)) var.name))
@ -110,28 +118,27 @@ def gen_alternate_qtypes(name, variants):
''') ''')
return ret return ret
def gen_union(name, base, variants):
name = c_name(name)
def gen_union(name, base, variants):
ret = mcgen(''' ret = mcgen('''
struct %(name)s { struct %(c_name)s {
''', ''',
name=name) c_name=c_name(name))
if base: if base:
ret += mcgen(''' ret += mcgen('''
/* Members inherited from %(c_name)s: */ /* Members inherited from %(c_name)s: */
''', ''',
c_name=c_name(base.name)) c_name=c_name(base.name))
ret += generate_struct_fields(base.members) ret += gen_struct_fields(base.members)
ret += mcgen(''' ret += mcgen('''
/* Own members: */ /* Own members: */
''') ''')
else: else:
ret += mcgen(''' ret += mcgen('''
%(discriminator_type_name)s kind; %(c_type)s kind;
''', ''',
discriminator_type_name=c_name(variants.tag_member.type.name)) c_type=c_name(variants.tag_member.type.name))
# FIXME: What purpose does data serve, besides preventing a union that # FIXME: What purpose does data serve, besides preventing a union that
# has a branch named 'data'? We use it in qapi-visit.py to decide # has a branch named 'data'? We use it in qapi-visit.py to decide
@ -166,18 +173,20 @@ def gen_union(name, base, variants):
return ret return ret
def generate_type_cleanup_decl(name):
def gen_type_cleanup_decl(name):
ret = mcgen(''' ret = mcgen('''
void qapi_free_%(name)s(%(name)s *obj); void qapi_free_%(c_name)s(%(c_name)s *obj);
''', ''',
name=c_name(name)) c_name=c_name(name))
return ret return ret
def generate_type_cleanup(name):
def gen_type_cleanup(name):
ret = mcgen(''' ret = mcgen('''
void qapi_free_%(name)s(%(name)s *obj) void qapi_free_%(c_name)s(%(c_name)s *obj)
{ {
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
@ -188,11 +197,11 @@ def generate_type_cleanup(name):
md = qapi_dealloc_visitor_new(); md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
visit_type_%(name)s(v, &obj, NULL, NULL); visit_type_%(c_name)s(v, &obj, NULL, NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
} }
''', ''',
name=c_name(name)) c_name=c_name(name))
return ret return ret
@ -225,20 +234,20 @@ def visit_end(self):
self._btin = None self._btin = None
def _gen_type_cleanup(self, name): def _gen_type_cleanup(self, name):
self.decl += generate_type_cleanup_decl(name) self.decl += gen_type_cleanup_decl(name)
self.defn += generate_type_cleanup(name) self.defn += gen_type_cleanup(name)
def visit_enum_type(self, name, info, values, prefix): def visit_enum_type(self, name, info, values, prefix):
self._fwdecl += generate_enum(name, values, prefix) self._fwdecl += gen_enum(name, values, prefix)
self._fwdefn += generate_enum_lookup(name, values, prefix) self._fwdefn += gen_enum_lookup(name, values, prefix)
def visit_array_type(self, name, info, element_type): def visit_array_type(self, name, info, element_type):
if isinstance(element_type, QAPISchemaBuiltinType): if isinstance(element_type, QAPISchemaBuiltinType):
self._btin += gen_fwd_object_or_array(name) self._btin += gen_fwd_object_or_array(name)
self._btin += gen_array(name, element_type) self._btin += gen_array(name, element_type)
self._btin += generate_type_cleanup_decl(name) self._btin += gen_type_cleanup_decl(name)
if do_builtins: if do_builtins:
self.defn += generate_type_cleanup(name) self.defn += gen_type_cleanup(name)
else: else:
self._fwdecl += gen_fwd_object_or_array(name) self._fwdecl += gen_fwd_object_or_array(name)
self.decl += gen_array(name, element_type) self.decl += gen_array(name, element_type)

View File

@ -18,18 +18,20 @@
implicit_structs_seen = set() implicit_structs_seen = set()
struct_fields_seen = set() struct_fields_seen = set()
def generate_visit_implicit_struct(type):
if type in implicit_structs_seen: def gen_visit_implicit_struct(typ):
if typ in implicit_structs_seen:
return '' return ''
implicit_structs_seen.add(type) implicit_structs_seen.add(typ)
ret = '' ret = ''
if type.name not in struct_fields_seen: if typ.name not in struct_fields_seen:
# Need a forward declaration # Need a forward declaration
ret += mcgen(''' ret += mcgen('''
static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp); static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
''', ''',
c_type=type.c_name()) c_type=typ.c_name())
ret += mcgen(''' ret += mcgen('''
@ -45,35 +47,36 @@ def generate_visit_implicit_struct(type):
error_propagate(errp, err); error_propagate(errp, err);
} }
''', ''',
c_type=type.c_name()) c_type=typ.c_name())
return ret return ret
def generate_visit_struct_fields(name, members, base = None):
def gen_visit_struct_fields(name, base, members):
struct_fields_seen.add(name) struct_fields_seen.add(name)
ret = '' ret = ''
if base: if base:
ret += generate_visit_implicit_struct(base) ret += gen_visit_implicit_struct(base)
ret += mcgen(''' ret += mcgen('''
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp) static void visit_type_%(c_name)s_fields(Visitor *m, %(c_name)s **obj, Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
''', ''',
name=c_name(name)) c_name=c_name(name))
push_indent() push_indent()
if base: if base:
ret += mcgen(''' ret += mcgen('''
visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err); visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);
if (err) { if (err) {
goto out; goto out;
} }
''', ''',
type=base.c_name(), c_name=c_name('base')) c_type=base.c_name(), c_name=c_name('base'))
for memb in members: for memb in members:
if memb.optional: if memb.optional:
@ -85,9 +88,9 @@ def generate_visit_struct_fields(name, members, base = None):
push_indent() push_indent()
ret += mcgen(''' ret += mcgen('''
visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err); visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
''', ''',
type=memb.type.c_name(), c_name=c_name(memb.name), c_type=memb.type.c_name(), c_name=c_name(memb.name),
name=memb.name) name=memb.name)
if memb.optional: if memb.optional:
@ -102,7 +105,7 @@ def generate_visit_struct_fields(name, members, base = None):
''') ''')
pop_indent() pop_indent()
if re.search('^ *goto out\\;', ret, re.MULTILINE): if re.search('^ *goto out;', ret, re.MULTILINE):
ret += mcgen(''' ret += mcgen('''
out: out:
@ -114,7 +117,7 @@ def generate_visit_struct_fields(name, members, base = None):
return ret return ret
def generate_visit_struct_body(name): def gen_visit_struct_body(name):
# FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to # 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_fields() fails, we should clean up *obj
# rather than leaving it non-NULL. As currently written, the caller must # rather than leaving it non-NULL. As currently written, the caller must
@ -132,30 +135,30 @@ def generate_visit_struct_body(name):
error_propagate(errp, err); error_propagate(errp, err);
''', ''',
name=name, c_name=c_name(name)) name=name, c_name=c_name(name))
return ret return ret
def gen_visit_struct(name, base, members):
ret = generate_visit_struct_fields(name, members, base)
def gen_visit_struct(name, base, members):
ret = gen_visit_struct_fields(name, base, members)
ret += mcgen(''' ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{ {
''', ''',
name=c_name(name)) c_name=c_name(name))
ret += generate_visit_struct_body(name) ret += gen_visit_struct_body(name)
ret += mcgen(''' ret += mcgen('''
} }
''') ''')
return ret return ret
def gen_visit_list(name, element_type): def gen_visit_list(name, element_type):
return mcgen(''' return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
GenericList *i, **prev; GenericList *i, **prev;
@ -168,7 +171,7 @@ def gen_visit_list(name, element_type):
for (prev = (GenericList **)obj; for (prev = (GenericList **)obj;
!err && (i = visit_next_list(m, prev, &err)) != NULL; !err && (i = visit_next_list(m, prev, &err)) != NULL;
prev = &i) { prev = &i) {
%(name)s *native_i = (%(name)s *)i; %(c_name)s *native_i = (%(c_name)s *)i;
visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err); visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err);
} }
@ -179,10 +182,10 @@ def gen_visit_list(name, element_type):
error_propagate(errp, err); error_propagate(errp, err);
} }
''', ''',
name=c_name(name), c_name=c_name(name), c_elt_type=element_type.c_name())
c_elt_type=element_type.c_name())
def generate_visit_enum(name):
def gen_visit_enum(name):
return mcgen(''' return mcgen('''
void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp) void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp)
@ -192,36 +195,36 @@ def generate_visit_enum(name):
''', ''',
c_name=c_name(name), name=name) c_name=c_name(name), name=name)
def gen_visit_alternate(name, variants): def gen_visit_alternate(name, variants):
ret = mcgen(''' ret = mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); visit_start_implicit_struct(m, (void**) obj, sizeof(%(c_name)s), &err);
if (err) { if (err) {
goto out; goto out;
} }
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); visit_get_next_type(m, (int*) &(*obj)->kind, %(c_name)s_qtypes, name, &err);
if (err) { if (err) {
goto out_end; goto out_end;
} }
switch ((*obj)->kind) { switch ((*obj)->kind) {
''', ''',
name=c_name(name)) c_name=c_name(name))
for var in variants.variants: for var in variants.variants:
enum_full_value = c_enum_const(variants.tag_member.type.name,
var.name)
ret += mcgen(''' ret += mcgen('''
case %(enum_full_value)s: case %(case)s:
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
break; break;
''', ''',
enum_full_value = enum_full_value, case=c_enum_const(variants.tag_member.type.name,
c_type=var.type.c_name(), var.name),
c_name=c_name(var.name)) c_type=var.type.c_name(),
c_name=c_name(var.name))
ret += mcgen(''' ret += mcgen('''
default: default:
@ -238,17 +241,18 @@ def gen_visit_alternate(name, variants):
return ret return ret
def gen_visit_union(name, base, variants): def gen_visit_union(name, base, variants):
ret = '' ret = ''
if base: if base:
members = [m for m in base.members if m != variants.tag_member] members = [m for m in base.members if m != variants.tag_member]
ret += generate_visit_struct_fields(name, members) ret += gen_visit_struct_fields(name, None, members)
for var in variants.variants: for var in variants.variants:
# Ugly special case for simple union TODO get rid of it # Ugly special case for simple union TODO get rid of it
if not var.simple_union_type(): if not var.simple_union_type():
ret += generate_visit_implicit_struct(var.type) ret += gen_visit_implicit_struct(var.type)
ret += mcgen(''' ret += mcgen('''
@ -266,19 +270,19 @@ def gen_visit_union(name, base, variants):
if base: if base:
ret += mcgen(''' ret += mcgen('''
visit_type_%(name)s_fields(m, obj, &err); visit_type_%(c_name)s_fields(m, obj, &err);
if (err) { if (err) {
goto out_obj; goto out_obj;
} }
''', ''',
name=c_name(name)) c_name=c_name(name))
disc_key = variants.tag_member.name tag_key = variants.tag_member.name
if not variants.tag_name: if not variants.tag_name:
# we pointlessly use a different key for simple unions # we pointlessly use a different key for simple unions
disc_key = 'type' tag_key = 'type'
ret += mcgen(''' ret += mcgen('''
visit_type_%(disc_type)s(m, &(*obj)->%(c_name)s, "%(disc_key)s", &err); visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
if (err) { if (err) {
goto out_obj; goto out_obj;
} }
@ -287,30 +291,36 @@ def gen_visit_union(name, base, variants):
} }
switch ((*obj)->%(c_name)s) { switch ((*obj)->%(c_name)s) {
''', ''',
disc_type=variants.tag_member.type.c_name(), c_type=variants.tag_member.type.c_name(),
# TODO ugly special case for simple union # TODO ugly special case for simple union
# Use same tag name in C as on the wire to get rid of # Use same tag name in C as on the wire to get rid of
# it, then: c_name=c_name(variants.tag_member.name) # it, then: c_name=c_name(variants.tag_member.name)
c_name=c_name(variants.tag_name or 'kind'), c_name=c_name(variants.tag_name or 'kind'),
disc_key = disc_key) name=tag_key)
for var in variants.variants: for var in variants.variants:
# TODO ugly special case for simple union # TODO ugly special case for simple union
simple_union_type = var.simple_union_type() simple_union_type = var.simple_union_type()
if simple_union_type:
fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
else:
fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
enum_full_value = c_enum_const(variants.tag_member.type.name, var.name)
ret += mcgen(''' ret += mcgen('''
case %(enum_full_value)s: case %(case)s:
''' + fmt + '''
break;
''', ''',
enum_full_value = enum_full_value, case=c_enum_const(variants.tag_member.type.name,
c_type=(simple_union_type or var.type).c_name(), var.name))
c_name=c_name(var.name)) if simple_union_type:
ret += mcgen('''
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
''',
c_type=simple_union_type.c_name(),
c_name=c_name(var.name))
else:
ret += mcgen('''
visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);
''',
c_type=var.type.c_name(),
c_name=c_name(var.name))
ret += mcgen('''
break;
''')
ret += mcgen(''' ret += mcgen('''
default: default:
@ -331,6 +341,7 @@ def gen_visit_union(name, base, variants):
return ret return ret
def gen_visit_decl(name, scalar=False): def gen_visit_decl(name, scalar=False):
c_type = c_name(name) + ' *' c_type = c_name(name) + ' *'
if not scalar: if not scalar:
@ -363,7 +374,7 @@ def visit_end(self):
def visit_enum_type(self, name, info, values, prefix): def visit_enum_type(self, name, info, values, prefix):
self.decl += gen_visit_decl(name, scalar=True) self.decl += gen_visit_decl(name, scalar=True)
self.defn += generate_visit_enum(name) self.defn += gen_visit_enum(name)
def visit_array_type(self, name, info, element_type): def visit_array_type(self, name, info, element_type):
decl = gen_visit_decl(name) decl = gen_visit_decl(name)
@ -439,7 +450,7 @@ def visit_alternate_type(self, name, info, variants):
#include "qemu-common.h" #include "qemu-common.h"
#include "%(prefix)sqapi-visit.h" #include "%(prefix)sqapi-visit.h"
''', ''',
prefix = prefix)) prefix=prefix))
fdecl.write(mcgen(''' fdecl.write(mcgen('''
#include "qapi/visitor.h" #include "qapi/visitor.h"

View File

@ -1086,9 +1086,6 @@ def __init__(self, fname):
self._def_exprs() self._def_exprs()
self.check() self.check()
def get_exprs(self):
return [expr_elem['expr'] for expr_elem in self.exprs]
def _def_entity(self, ent): def _def_entity(self, ent):
assert ent.name not in self._entity_dict assert ent.name not in self._entity_dict
self._entity_dict[ent.name] = ent self._entity_dict[ent.name] = ent
@ -1281,23 +1278,6 @@ def visit(self, visitor):
# Code generation helpers # Code generation helpers
# #
def parse_args(typeinfo):
if isinstance(typeinfo, str):
struct = find_struct(typeinfo)
assert struct != None
typeinfo = struct['data']
for member in typeinfo:
argname = member
argentry = typeinfo[member]
optional = False
if member.startswith('*'):
argname = member[1:]
optional = True
# Todo: allow argentry to be OrderedDict, for providing the
# value of an optional argument.
yield (argname, argentry, optional)
def camel_case(name): def camel_case(name):
new_name = '' new_name = ''
first = True first = True
@ -1380,67 +1360,9 @@ def c_name(name, protect=True):
return "q_" + name return "q_" + name
return name.translate(c_name_trans) return name.translate(c_name_trans)
# Map type @name to the C typedef name for the list form.
#
# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList'
def c_list_type(name):
return type_name(name) + 'List'
# Map type @value to the C typedef form.
#
# Used for converting 'type' from a 'member':'type' qapi definition
# into the alphanumeric portion of the type for a generated C parameter,
# as well as generated C function names. See c_type() for the rest of
# the conversion such as adding '*' on pointer types.
# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c'
def type_name(value):
if type(value) == list:
return c_list_type(value[0])
if value in builtin_types.keys():
return value
return c_name(value)
eatspace = '\033EATSPACE.' eatspace = '\033EATSPACE.'
pointer_suffix = ' *' + eatspace pointer_suffix = ' *' + eatspace
# Map type @name to its C type expression.
# If @is_param, const-qualify the string type.
#
# This function is used for computing the full C type of 'member':'name'.
# A special suffix is added in c_type() for pointer types, and it's
# stripped in mcgen(). So please notice this when you check the return
# value of c_type() outside mcgen().
def c_type(value, is_param=False):
if value == 'str':
if is_param:
return 'const char' + pointer_suffix
return 'char' + pointer_suffix
elif value == 'int':
return 'int64_t'
elif (value == 'int8' or value == 'int16' or value == 'int32' or
value == 'int64' or value == 'uint8' or value == 'uint16' or
value == 'uint32' or value == 'uint64'):
return value + '_t'
elif value == 'size':
return 'uint64_t'
elif value == 'bool':
return 'bool'
elif value == 'number':
return 'double'
elif type(value) == list:
return c_list_type(value[0]) + pointer_suffix
elif is_enum(value):
return c_name(value)
elif value == None:
return 'void'
elif value in events:
return camel_case(value) + 'Event' + pointer_suffix
else:
# complex type name
assert isinstance(value, str) and value != ""
return c_name(value) + pointer_suffix
def genindent(count): def genindent(count):
ret = "" ret = ""
for i in range(count): for i in range(count):
@ -1495,60 +1417,57 @@ def guardend(name):
''', ''',
name=guardname(name)) name=guardname(name))
def generate_enum_lookup(name, values, prefix=None): def gen_enum_lookup(name, values, prefix=None):
ret = mcgen(''' ret = mcgen('''
const char *const %(name)s_lookup[] = { const char *const %(c_name)s_lookup[] = {
''', ''',
name=c_name(name)) c_name=c_name(name))
for value in values: for value in values:
index = c_enum_const(name, value, prefix) index = c_enum_const(name, value, prefix)
ret += mcgen(''' ret += mcgen('''
[%(index)s] = "%(value)s", [%(index)s] = "%(value)s",
''', ''',
index = index, value = value) index=index, value=value)
max_index = c_enum_const(name, 'MAX', prefix) max_index = c_enum_const(name, 'MAX', prefix)
ret += mcgen(''' ret += mcgen('''
[%(max_index)s] = NULL, [%(max_index)s] = NULL,
}; };
''', ''',
max_index=max_index) max_index=max_index)
return ret return ret
def generate_enum(name, values, prefix=None): def gen_enum(name, values, prefix=None):
name = c_name(name)
lookup_decl = mcgen('''
extern const char *const %(name)s_lookup[];
''',
name=name)
enum_decl = mcgen('''
typedef enum %(name)s {
''',
name=name)
# append automatically generated _MAX value # append automatically generated _MAX value
enum_values = values + [ 'MAX' ] enum_values = values + ['MAX']
ret = mcgen('''
typedef enum %(c_name)s {
''',
c_name=c_name(name))
i = 0 i = 0
for value in enum_values: for value in enum_values:
enum_full_value = c_enum_const(name, value, prefix) ret += mcgen('''
enum_decl += mcgen(''' %(c_enum)s = %(i)d,
%(enum_full_value)s = %(i)d,
''', ''',
enum_full_value = enum_full_value, c_enum=c_enum_const(name, value, prefix),
i=i) i=i)
i += 1 i += 1
enum_decl += mcgen(''' ret += mcgen('''
} %(name)s; } %(c_name)s;
''', ''',
name=name) c_name=c_name(name))
return enum_decl + lookup_decl ret += mcgen('''
extern const char *const %(c_name)s_lookup[];
''',
c_name=c_name(name))
return ret
# #
# Common command line parsing # Common command line parsing