qapi: Consistent generated code: minimize push_indent() usage

We had some pointless differences in the generated code for visit,
command marshalling, and events; unifying them makes it easier for
future patches to consolidate to common helper functions.
This is one patch of a series to clean up these differences.

This patch reduces the number of push_indent()/pop_indent() pairs
so that generated code is typically already at its natural output
indentation in the python files. It is easier to reason about
generated code if the reader does not have to track how much
spacing will be inserted alongside the code, and moreso when all
of the generators use the same patterns (qapi-type and qapi-event
were already using in-place indentation).

Arguably, the resulting python may be a bit harder to read with C
code at the same indentation as python; on the other hand, not
having to think about push_indent() is a win, and most decent
editors provide syntax highlighting that makes it easier to
visually distinguish python code from string literals that will
become C code.

There is no change to the generated output.

Backports commit 05372f708a8cb3556e4d67458de79417dadf241f from qemu
This commit is contained in:
Eric Blake 2018-02-19 18:27:47 -05:00 committed by Lioncash
parent ec89e19b30
commit 13b3a6c92f
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7
3 changed files with 80 additions and 103 deletions

View File

@ -13,68 +13,52 @@
from qapi import *
def _generate_event_api_name(event_name, params):
api_name = "void qapi_event_send_%s(" % c_name(event_name).lower();
l = len(api_name)
if params:
for m in params.members:
if m.optional:
api_name += "bool has_%s,\n" % c_name(m.name)
api_name += "".ljust(l)
api_name += "%s %s,\n" % (m.type.c_type(is_param=True),
c_name(m.name))
api_name += "".ljust(l)
api_name += "Error **errp)"
return api_name;
def gen_event_send_proto(name, arg_type):
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
'c_name': c_name(name.lower()),
'param': gen_params(arg_type, 'Error **errp')}
# Following are the core functions that generate C APIs to emit event.
def generate_event_declaration(api_name):
def gen_event_send_decl(name, arg_type):
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;
Error *err = NULL;
QMPEventFuncEmit emit;
""",
api_name = api_name)
''',
proto=gen_event_send_proto(name, arg_type))
if params and params.members:
ret += mcgen("""
if arg_type and arg_type.members:
ret += mcgen('''
QmpOutputVisitor *qov;
Visitor *v;
QObject *obj;
""")
''')
# step 2: check emit function, create a dict
ret += mcgen("""
ret += mcgen('''
emit = qmp_event_get_func_emit();
if (!emit) {
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 params and params.members:
ret += mcgen("""
if arg_type and arg_type.members:
ret += mcgen('''
qov = qmp_output_visitor_new();
g_assert(qov);
@ -82,46 +66,41 @@ def generate_event_implement(api_name, event_name, params):
g_assert(v);
/* Fake visit, as if all members are under a structure */
visit_start_struct(v, NULL, "", "%(event_name)s", 0, &err);
if (err) {
goto out;
}
visit_start_struct(v, NULL, "", "%(name)s", 0, &err);
''',
name=name)
ret += gen_err_check()
""",
event_name = event_name)
for memb in params.members:
for memb in arg_type.members:
if memb.optional:
ret += mcgen("""
if (has_%(var)s) {
""",
var=c_name(memb.name))
ret += mcgen('''
if (has_%(c_name)s) {
''',
c_name=c_name(memb.name))
push_indent()
# Ugly: need to cast away the const
if memb.type.name == "str":
var_type = "(char **)"
cast = '(char **)'
else:
var_type = ""
cast = ''
ret += mcgen("""
visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &err);
if (err) {
goto out;
}
""",
var_type = var_type,
var=c_name(memb.name),
type=memb.type.c_name(),
ret += mcgen('''
visit_type_%(c_type)s(v, %(cast)s&%(c_name)s, "%(name)s", &err);
''',
cast=cast,
c_name=c_name(memb.name),
c_type=memb.type.c_name(),
name=memb.name)
ret += gen_err_check()
if memb.optional:
pop_indent()
ret += mcgen("""
ret += mcgen('''
}
""")
ret += mcgen("""
''')
ret += mcgen('''
visit_end_struct(v, &err);
if (err) {
goto out;
@ -131,27 +110,24 @@ def generate_event_implement(api_name, event_name, params):
g_assert(obj != NULL);
qdict_put_obj(qmp, "data", obj);
""")
''')
# step 4: call qmp event api
ret += mcgen("""
emit(%(event_enum_value)s, qmp, &err);
ret += mcgen('''
emit(%(c_enum)s, qmp, &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 params and params.members:
ret += mcgen("""
out:
if arg_type and arg_type.members:
ret += mcgen('''
out:
qmp_output_visitor_cleanup(qov);
""")
ret += mcgen("""
''')
ret += mcgen('''
error_propagate(errp, err);
QDECREF(qmp);
}
""")
''')
return ret
@ -167,14 +143,13 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
self._event_names = []
def visit_end(self):
self.decl += generate_enum(event_enum_name, self._event_names)
self.defn += generate_enum_lookup(event_enum_name, self._event_names)
self._event_names = None
self.decl += gen_enum(event_enum_name, self._event_names)
self.defn += gen_enum_lookup(event_enum_name, self._event_names)
self._event_names = None;
def visit_event(self, name, info, arg_type):
api_name = _generate_event_api_name(name, arg_type)
self.decl += generate_event_declaration(api_name)
self.defn += generate_event_implement(api_name, name, arg_type)
self.decl += gen_event_send_decl(name, arg_type)
self.defn += gen_event_send(name, arg_type)
self._event_names.append(name)
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()

View File

@ -75,28 +75,25 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **e
''',
c_name=c_name(name))
push_indent()
if base:
ret += mcgen('''
visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
if (err) {
goto out;
}
visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
''',
c_type=base.c_name(), c_name=c_name('base'))
ret += gen_err_check()
for memb in members:
if memb.optional:
ret += mcgen('''
visit_optional(v, &(*obj)->has_%(c_name)s, "%(name)s", &err);
if (!err && (*obj)->has_%(c_name)s) {
visit_optional(v, &(*obj)->has_%(c_name)s, "%(name)s", &err);
if (!err && (*obj)->has_%(c_name)s) {
''',
c_name=c_name(memb.name), name=memb.name)
push_indent()
ret += mcgen('''
visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
''',
c_type=memb.type.c_name(), c_name=c_name(memb.name),
name=memb.name)
@ -104,15 +101,10 @@ visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
if memb.optional:
pop_indent()
ret += mcgen('''
}
''')
ret += mcgen('''
if (err) {
goto out;
}
}
''')
ret += gen_err_check()
pop_indent()
if re.search('^ *goto out;', ret, re.MULTILINE):
ret += mcgen('''
@ -271,11 +263,9 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
if base:
ret += mcgen('''
visit_type_%(c_name)s_fields(v, obj, &err);
if (err) {
goto out_obj;
}
''',
c_name=c_name(name))
ret += gen_err_check(label='out_obj')
tag_key = variants.tag_member.name
if not variants.tag_name:

View File

@ -1531,6 +1531,18 @@ def gen_params(arg_type, extra):
ret += sep + extra
return ret
def gen_err_check(err='err', label='out'):
if not err:
return ''
return mcgen('''
if (%(err)s) {
goto %(label)s;
}
''',
err=err, label=label)
#
# Common command line parsing
#