mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-25 07:05:30 +00:00
03c3b81d7a
These classes encapsulate accumulating and writing output. Convert C code generation to QAPIGenC and QAPIGenH. The conversion is rather shallow: most of the output accumulation is not converted. Left for later. The indentation machinery uses a single global variable indent_level, even though we generally interleave creation of a .c and its .h. It should become instance variable of QAPIGenC. Also left for later. Documentation generation isn't converted, and QAPIGenDoc isn't used. This will change shortly. Backports commit 47a6ea9aab1d857015684cda387ffba05a036721 from qemu
209 lines
5 KiB
Python
209 lines
5 KiB
Python
"""
|
|
QAPI event generator
|
|
|
|
Copyright (c) 2014 Wenchao Xia
|
|
Copyright (c) 2015-2018 Red Hat Inc.
|
|
|
|
Authors:
|
|
Wenchao Xia <wenchaoqemu@gmail.com>
|
|
Markus Armbruster <armbru@redhat.com>
|
|
|
|
This work is licensed under the terms of the GNU GPL, version 2.
|
|
See the COPYING file in the top-level directory.
|
|
"""
|
|
|
|
from qapi import *
|
|
|
|
def build_event_send_proto(name, arg_type, boxed):
|
|
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
|
|
'c_name': c_name(name.lower()),
|
|
'param': gen_params(arg_type, boxed, 'Error **errp')}
|
|
|
|
|
|
def gen_event_send_decl(name, arg_type, boxed):
|
|
return mcgen('''
|
|
|
|
%(proto)s;
|
|
''',
|
|
proto=build_event_send_proto(name, arg_type, boxed))
|
|
|
|
|
|
# Declare and initialize an object 'qapi' using parameters from build_params()
|
|
def gen_param_var(typ):
|
|
assert not typ.variants
|
|
ret = mcgen('''
|
|
%(c_name)s param = {
|
|
''',
|
|
c_name=typ.c_name())
|
|
sep = ' '
|
|
for memb in typ.members:
|
|
ret += sep
|
|
sep = ', '
|
|
if memb.optional:
|
|
ret += 'has_' + c_name(memb.name) + sep
|
|
if memb.type.name == 'str':
|
|
# Cast away const added in build_params()
|
|
ret += '(char *)'
|
|
ret += c_name(memb.name)
|
|
ret += mcgen('''
|
|
|
|
};
|
|
''')
|
|
if not typ.is_implicit():
|
|
ret += mcgen('''
|
|
%(c_name)s *arg = ¶m;
|
|
''',
|
|
c_name=typ.c_name())
|
|
return ret
|
|
|
|
|
|
def gen_event_send(name, arg_type, boxed):
|
|
# FIXME: Our declaration of local variables (and of 'errp' in the
|
|
# parameter list) can collide with exploded members of the event's
|
|
# data type passed in as parameters. If this collision ever hits in
|
|
# practice, we can rename our local variables with a leading _ prefix,
|
|
# or split the code into a wrapper function that creates a boxed
|
|
# 'param' object then calls another to do the real work.
|
|
ret = mcgen('''
|
|
|
|
%(proto)s
|
|
{
|
|
QDict *qmp;
|
|
Error *err = NULL;
|
|
QMPEventFuncEmit emit;
|
|
''',
|
|
proto=build_event_send_proto(name, arg_type, boxed))
|
|
|
|
if arg_type and not arg_type.is_empty():
|
|
assert not arg_type.variants
|
|
ret += mcgen('''
|
|
QObject *obj;
|
|
Visitor *v;
|
|
''')
|
|
if not boxed:
|
|
ret += gen_param_var(arg_type)
|
|
else:
|
|
assert not boxed
|
|
|
|
ret += mcgen('''
|
|
|
|
emit = qmp_event_get_func_emit();
|
|
if (!emit) {
|
|
return;
|
|
}
|
|
|
|
qmp = qmp_event_build_dict("%(name)s");
|
|
|
|
''',
|
|
name=name)
|
|
|
|
if arg_type and not arg_type.is_empty():
|
|
ret += mcgen('''
|
|
v = qobject_output_visitor_new(&obj);
|
|
''')
|
|
if not arg_type.is_implicit():
|
|
ret += mcgen('''
|
|
visit_type_%(c_name)s(v, "%(name)s", &arg, &err);
|
|
''',
|
|
name=name, c_name=arg_type.c_name())
|
|
else:
|
|
ret += mcgen('''
|
|
|
|
visit_start_struct(v, "%(name)s", NULL, 0, &err);
|
|
if (err) {
|
|
goto out;
|
|
}
|
|
visit_type_%(c_name)s_members(v, ¶m, &err);
|
|
if (!err) {
|
|
visit_check_struct(v, &err);
|
|
}
|
|
visit_end_struct(v, NULL);
|
|
''',
|
|
name=name, c_name=arg_type.c_name())
|
|
ret += mcgen('''
|
|
if (err) {
|
|
goto out;
|
|
}
|
|
|
|
visit_complete(v, &obj);
|
|
qdict_put_obj(qmp, "data", obj);
|
|
''')
|
|
|
|
ret += mcgen('''
|
|
emit(%(c_enum)s, qmp, &err);
|
|
|
|
''',
|
|
c_enum=c_enum_const(event_enum_name, name))
|
|
|
|
if arg_type and not arg_type.is_empty():
|
|
ret += mcgen('''
|
|
out:
|
|
visit_free(v);
|
|
''')
|
|
ret += mcgen('''
|
|
error_propagate(errp, err);
|
|
QDECREF(qmp);
|
|
}
|
|
''')
|
|
return ret
|
|
|
|
|
|
class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
|
|
def __init__(self):
|
|
self.decl = None
|
|
self.defn = None
|
|
self._event_names = None
|
|
|
|
def visit_begin(self, schema):
|
|
self.decl = ''
|
|
self.defn = ''
|
|
self._event_names = []
|
|
|
|
def visit_end(self):
|
|
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, boxed):
|
|
self.decl += gen_event_send_decl(name, arg_type, boxed)
|
|
self.defn += gen_event_send(name, arg_type, boxed)
|
|
self._event_names.append(name)
|
|
|
|
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
|
|
|
|
blurb = ' * Schema-defined QAPI/QMP events'
|
|
|
|
genc = QAPIGenC(blurb, __doc__)
|
|
genh = QAPIGenH(blurb, __doc__)
|
|
|
|
genc.add(mcgen('''
|
|
#include "qemu-common.h"
|
|
#include "%(prefix)sqapi-event.h"
|
|
#include "%(prefix)sqapi-visit.h"
|
|
#include "qapi/error.h"
|
|
#include "qapi/qmp/qdict.h"
|
|
#include "qapi/qobject-output-visitor.h"
|
|
#include "qapi/qmp-event.h"
|
|
|
|
''',
|
|
prefix=prefix))
|
|
|
|
genh.add(mcgen('''
|
|
#include "%(prefix)sqapi-types.h"
|
|
|
|
''',
|
|
prefix=prefix))
|
|
|
|
event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
|
|
|
|
schema = QAPISchema(input_file)
|
|
vis = QAPISchemaGenEventVisitor()
|
|
schema.visit(vis)
|
|
genc.add(vis.defn)
|
|
genh.add(vis.decl)
|
|
|
|
if do_c:
|
|
genc.write(output_dir, prefix + 'qapi-event.c')
|
|
if do_h:
|
|
genh.write(output_dir, prefix + 'qapi-event.h')
|