qapi: Plumb in 'boxed' to qapi generator lower levels
The next patch will add support for passing a qapi union type as the 'data' of a command. But to do that, the user function for implementing the command, as called by the generated marshal command, must take the corresponding C struct as a single boxed pointer, rather than a breakdown into one parameter per member. Even without a union, being able to use a C struct rather than a list of parameters can make it much easier to handle coding with QAPI. This patch adds the internal plumbing of a 'boxed' flag associated with each command and event. In several cases, this means adding indentation, with one new dead branch and the remaining branch being the original code more deeply nested; this was done so that the new implementation in the next patch is easier to review without also being mixed with indentation changes. For this patch, no behavior or generated output changes, other than the testsuite outputting the value of the new flag (always False for now). Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1468468228-27827-9-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> [Identifier box renamed to boxed in two places] Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
parent
4d0b268fdb
commit
48825ca419
@ -16,20 +16,22 @@ from qapi import *
|
||||
import re
|
||||
|
||||
|
||||
def gen_command_decl(name, arg_type, ret_type):
|
||||
def gen_command_decl(name, arg_type, boxed, ret_type):
|
||||
return mcgen('''
|
||||
%(c_type)s qmp_%(c_name)s(%(params)s);
|
||||
''',
|
||||
c_type=(ret_type and ret_type.c_type()) or 'void',
|
||||
c_name=c_name(name),
|
||||
params=gen_params(arg_type, 'Error **errp'))
|
||||
params=gen_params(arg_type, boxed, 'Error **errp'))
|
||||
|
||||
|
||||
def gen_call(name, arg_type, ret_type):
|
||||
def gen_call(name, arg_type, boxed, ret_type):
|
||||
ret = ''
|
||||
|
||||
argstr = ''
|
||||
if arg_type:
|
||||
if boxed:
|
||||
assert False # not implemented
|
||||
elif arg_type:
|
||||
assert not arg_type.variants
|
||||
for memb in arg_type.members:
|
||||
if memb.optional:
|
||||
@ -94,7 +96,7 @@ def gen_marshal_decl(name):
|
||||
proto=gen_marshal_proto(name))
|
||||
|
||||
|
||||
def gen_marshal(name, arg_type, ret_type):
|
||||
def gen_marshal(name, arg_type, boxed, ret_type):
|
||||
ret = mcgen('''
|
||||
|
||||
%(proto)s
|
||||
@ -136,7 +138,7 @@ def gen_marshal(name, arg_type, ret_type):
|
||||
(void)args;
|
||||
''')
|
||||
|
||||
ret += gen_call(name, arg_type, ret_type)
|
||||
ret += gen_call(name, arg_type, boxed, ret_type)
|
||||
|
||||
# 'goto out' produced above for arg_type, and by gen_call() for ret_type
|
||||
if (arg_type and not arg_type.is_empty()) or ret_type:
|
||||
@ -212,16 +214,16 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
|
||||
self._visited_ret_types = None
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response):
|
||||
gen, success_response, boxed):
|
||||
if not gen:
|
||||
return
|
||||
self.decl += gen_command_decl(name, arg_type, ret_type)
|
||||
self.decl += gen_command_decl(name, arg_type, boxed, ret_type)
|
||||
if ret_type and ret_type not in self._visited_ret_types:
|
||||
self._visited_ret_types.add(ret_type)
|
||||
self.defn += gen_marshal_output(ret_type)
|
||||
if middle_mode:
|
||||
self.decl += gen_marshal_decl(name)
|
||||
self.defn += gen_marshal(name, arg_type, ret_type)
|
||||
self.defn += gen_marshal(name, arg_type, boxed, ret_type)
|
||||
if not middle_mode:
|
||||
self._regy += gen_register_command(name, success_response)
|
||||
|
||||
|
@ -14,18 +14,18 @@
|
||||
from qapi import *
|
||||
|
||||
|
||||
def gen_event_send_proto(name, arg_type):
|
||||
def gen_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, 'Error **errp')}
|
||||
'param': gen_params(arg_type, boxed, 'Error **errp')}
|
||||
|
||||
|
||||
def gen_event_send_decl(name, arg_type):
|
||||
def gen_event_send_decl(name, arg_type, boxed):
|
||||
return mcgen('''
|
||||
|
||||
%(proto)s;
|
||||
''',
|
||||
proto=gen_event_send_proto(name, arg_type))
|
||||
proto=gen_event_send_proto(name, arg_type, boxed))
|
||||
|
||||
|
||||
# Declare and initialize an object 'qapi' using parameters from gen_params()
|
||||
@ -57,7 +57,7 @@ def gen_param_var(typ):
|
||||
return ret
|
||||
|
||||
|
||||
def gen_event_send(name, arg_type):
|
||||
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
|
||||
@ -72,7 +72,7 @@ def gen_event_send(name, arg_type):
|
||||
Error *err = NULL;
|
||||
QMPEventFuncEmit emit;
|
||||
''',
|
||||
proto=gen_event_send_proto(name, arg_type))
|
||||
proto=gen_event_send_proto(name, arg_type, boxed))
|
||||
|
||||
if arg_type and not arg_type.is_empty():
|
||||
ret += mcgen('''
|
||||
@ -160,9 +160,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
|
||||
self.defn += gen_enum_lookup(event_enum_name, self._event_names)
|
||||
self._event_names = None
|
||||
|
||||
def visit_event(self, name, info, arg_type):
|
||||
self.decl += gen_event_send_decl(name, arg_type)
|
||||
self.defn += gen_event_send(name, arg_type)
|
||||
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)
|
||||
|
||||
|
||||
|
@ -154,14 +154,14 @@ const char %(c_name)s[] = %(c_string)s;
|
||||
for m in variants.variants]})
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response):
|
||||
gen, success_response, boxed):
|
||||
arg_type = arg_type or self._schema.the_empty_object_type
|
||||
ret_type = ret_type or self._schema.the_empty_object_type
|
||||
self._gen_json(name, 'command',
|
||||
{'arg-type': self._use_type(arg_type),
|
||||
'ret-type': self._use_type(ret_type)})
|
||||
|
||||
def visit_event(self, name, info, arg_type):
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
arg_type = arg_type or self._schema.the_empty_object_type
|
||||
self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
|
||||
|
||||
|
@ -826,10 +826,10 @@ class QAPISchemaVisitor(object):
|
||||
pass
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response):
|
||||
gen, success_response, boxed):
|
||||
pass
|
||||
|
||||
def visit_event(self, name, info, arg_type):
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
pass
|
||||
|
||||
|
||||
@ -1165,7 +1165,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
|
||||
|
||||
|
||||
class QAPISchemaCommand(QAPISchemaEntity):
|
||||
def __init__(self, name, info, arg_type, ret_type, gen, success_response):
|
||||
def __init__(self, name, info, arg_type, ret_type, gen, success_response,
|
||||
boxed):
|
||||
QAPISchemaEntity.__init__(self, name, info)
|
||||
assert not arg_type or isinstance(arg_type, str)
|
||||
assert not ret_type or isinstance(ret_type, str)
|
||||
@ -1175,12 +1176,14 @@ class QAPISchemaCommand(QAPISchemaEntity):
|
||||
self.ret_type = None
|
||||
self.gen = gen
|
||||
self.success_response = success_response
|
||||
self.boxed = boxed
|
||||
|
||||
def check(self, schema):
|
||||
if self._arg_type_name:
|
||||
self.arg_type = schema.lookup_type(self._arg_type_name)
|
||||
assert isinstance(self.arg_type, QAPISchemaObjectType)
|
||||
assert not self.arg_type.variants # not implemented
|
||||
assert not self.boxed # not implemented
|
||||
if self._ret_type_name:
|
||||
self.ret_type = schema.lookup_type(self._ret_type_name)
|
||||
assert isinstance(self.ret_type, QAPISchemaType)
|
||||
@ -1188,24 +1191,26 @@ class QAPISchemaCommand(QAPISchemaEntity):
|
||||
def visit(self, visitor):
|
||||
visitor.visit_command(self.name, self.info,
|
||||
self.arg_type, self.ret_type,
|
||||
self.gen, self.success_response)
|
||||
self.gen, self.success_response, self.boxed)
|
||||
|
||||
|
||||
class QAPISchemaEvent(QAPISchemaEntity):
|
||||
def __init__(self, name, info, arg_type):
|
||||
def __init__(self, name, info, arg_type, boxed):
|
||||
QAPISchemaEntity.__init__(self, name, info)
|
||||
assert not arg_type or isinstance(arg_type, str)
|
||||
self._arg_type_name = arg_type
|
||||
self.arg_type = None
|
||||
self.boxed = boxed
|
||||
|
||||
def check(self, schema):
|
||||
if self._arg_type_name:
|
||||
self.arg_type = schema.lookup_type(self._arg_type_name)
|
||||
assert isinstance(self.arg_type, QAPISchemaObjectType)
|
||||
assert not self.arg_type.variants # not implemented
|
||||
assert not self.boxed # not implemented
|
||||
|
||||
def visit(self, visitor):
|
||||
visitor.visit_event(self.name, self.info, self.arg_type)
|
||||
visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
|
||||
|
||||
|
||||
class QAPISchema(object):
|
||||
@ -1381,6 +1386,7 @@ class QAPISchema(object):
|
||||
rets = expr.get('returns')
|
||||
gen = expr.get('gen', True)
|
||||
success_response = expr.get('success-response', True)
|
||||
boxed = expr.get('boxed', False)
|
||||
if isinstance(data, OrderedDict):
|
||||
data = self._make_implicit_object_type(
|
||||
name, info, 'arg', self._make_members(data, info))
|
||||
@ -1388,15 +1394,16 @@ class QAPISchema(object):
|
||||
assert len(rets) == 1
|
||||
rets = self._make_array_type(rets[0], info)
|
||||
self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
|
||||
success_response))
|
||||
success_response, boxed))
|
||||
|
||||
def _def_event(self, expr, info):
|
||||
name = expr['event']
|
||||
data = expr.get('data')
|
||||
boxed = expr.get('boxed', False)
|
||||
if isinstance(data, OrderedDict):
|
||||
data = self._make_implicit_object_type(
|
||||
name, info, 'arg', self._make_members(data, info))
|
||||
self._def_entity(QAPISchemaEvent(name, info, data))
|
||||
self._def_entity(QAPISchemaEvent(name, info, data, boxed))
|
||||
|
||||
def _def_exprs(self):
|
||||
for expr_elem in self.exprs:
|
||||
@ -1639,18 +1646,22 @@ extern const char *const %(c_name)s_lookup[];
|
||||
return ret
|
||||
|
||||
|
||||
def gen_params(arg_type, extra):
|
||||
def gen_params(arg_type, boxed, extra):
|
||||
if not arg_type:
|
||||
return extra
|
||||
assert not arg_type.variants
|
||||
ret = ''
|
||||
sep = ''
|
||||
for memb in arg_type.members:
|
||||
ret += sep
|
||||
sep = ', '
|
||||
if memb.optional:
|
||||
ret += 'bool has_%s, ' % c_name(memb.name)
|
||||
ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
|
||||
if boxed:
|
||||
assert False # not implemented
|
||||
else:
|
||||
assert not arg_type.variants
|
||||
for memb in arg_type.members:
|
||||
ret += sep
|
||||
sep = ', '
|
||||
if memb.optional:
|
||||
ret += 'bool has_%s, ' % c_name(memb.name)
|
||||
ret += '%s %s' % (memb.type.c_param_type(),
|
||||
c_name(memb.name))
|
||||
if extra:
|
||||
ret += sep + extra
|
||||
return ret
|
||||
|
@ -1,4 +1,5 @@
|
||||
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
|
||||
prefix QTYPE
|
||||
event oops None
|
||||
boxed=False
|
||||
object q_empty
|
||||
|
@ -1,7 +1,7 @@
|
||||
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
|
||||
prefix QTYPE
|
||||
command fooA q_obj_fooA-arg -> None
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
object q_empty
|
||||
object q_obj_fooA-arg
|
||||
member bar1: str optional=False
|
||||
|
@ -1,7 +1,7 @@
|
||||
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
|
||||
prefix QTYPE
|
||||
command eins None -> None
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
object q_empty
|
||||
command zwei None -> None
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
|
@ -23,9 +23,13 @@ alternate AltStrNum
|
||||
case s: str
|
||||
case n: number
|
||||
event EVENT_A None
|
||||
boxed=False
|
||||
event EVENT_B None
|
||||
boxed=False
|
||||
event EVENT_C q_obj_EVENT_C-arg
|
||||
boxed=False
|
||||
event EVENT_D q_obj_EVENT_D-arg
|
||||
boxed=False
|
||||
object Empty1
|
||||
object Empty2
|
||||
base Empty1
|
||||
@ -124,6 +128,7 @@ object UserDefZero
|
||||
object WrapAlternate
|
||||
member alt: UserDefAlternate optional=False
|
||||
event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
|
||||
boxed=False
|
||||
alternate __org.qemu_x-Alt
|
||||
tag type
|
||||
case __org.qemu_x-branch: str
|
||||
@ -147,11 +152,11 @@ object __org.qemu_x-Union2
|
||||
tag __org.qemu_x-member1
|
||||
case __org.qemu_x-value: __org.qemu_x-Struct2
|
||||
command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
command guest-get-time q_obj_guest-get-time-arg -> int
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
command guest-sync q_obj_guest-sync-arg -> any
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
object q_empty
|
||||
object q_obj_EVENT_C-arg
|
||||
member a: int optional=True
|
||||
@ -212,10 +217,10 @@ object q_obj_user_def_cmd2-arg
|
||||
member ud1a: UserDefOne optional=False
|
||||
member ud1b: UserDefOne optional=True
|
||||
command user_def_cmd None -> None
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
command user_def_cmd0 Empty2 -> Empty2
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
|
||||
gen=True success_response=True
|
||||
gen=True success_response=True boxed=False
|
||||
|
@ -36,13 +36,15 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
||||
self._print_variants(variants)
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response):
|
||||
gen, success_response, boxed):
|
||||
print 'command %s %s -> %s' % \
|
||||
(name, arg_type and arg_type.name, ret_type and ret_type.name)
|
||||
print ' gen=%s success_response=%s' % (gen, success_response)
|
||||
print ' gen=%s success_response=%s boxed=%s' % \
|
||||
(gen, success_response, boxed)
|
||||
|
||||
def visit_event(self, name, info, arg_type):
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
print 'event %s %s' % (name, arg_type and arg_type.name)
|
||||
print ' boxed=%s' % boxed
|
||||
|
||||
@staticmethod
|
||||
def _print_variants(variants):
|
||||
|
Loading…
Reference in New Issue
Block a user