2
0
Эх сурвалжийг харах

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>
Eric Blake 9 жил өмнө
parent
commit
48825ca419

+ 11 - 9
scripts/qapi-commands.py

@@ -16,20 +16,22 @@
 import re
 import re
 
 
 
 
-def gen_command_decl(name, arg_type, ret_type):
+def gen_command_decl(name, arg_type, boxed, ret_type):
     return mcgen('''
     return mcgen('''
 %(c_type)s qmp_%(c_name)s(%(params)s);
 %(c_type)s qmp_%(c_name)s(%(params)s);
 ''',
 ''',
                  c_type=(ret_type and ret_type.c_type()) or 'void',
                  c_type=(ret_type and ret_type.c_type()) or 'void',
                  c_name=c_name(name),
                  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 = ''
     ret = ''
 
 
     argstr = ''
     argstr = ''
-    if arg_type:
+    if boxed:
+        assert False    # not implemented
+    elif arg_type:
         assert not arg_type.variants
         assert not arg_type.variants
         for memb in arg_type.members:
         for memb in arg_type.members:
             if memb.optional:
             if memb.optional:
@@ -94,7 +96,7 @@ def gen_marshal_decl(name):
                  proto=gen_marshal_proto(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('''
     ret = mcgen('''
 
 
 %(proto)s
 %(proto)s
@@ -136,7 +138,7 @@ def gen_marshal(name, arg_type, ret_type):
     (void)args;
     (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
     # '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:
     if (arg_type and not arg_type.is_empty()) or ret_type:
@@ -212,16 +214,16 @@ def visit_end(self):
         self._visited_ret_types = None
         self._visited_ret_types = None
 
 
     def visit_command(self, name, info, arg_type, ret_type,
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, boxed):
         if not gen:
         if not gen:
             return
             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:
         if ret_type and ret_type not in self._visited_ret_types:
             self._visited_ret_types.add(ret_type)
             self._visited_ret_types.add(ret_type)
             self.defn += gen_marshal_output(ret_type)
             self.defn += gen_marshal_output(ret_type)
         if middle_mode:
         if middle_mode:
             self.decl += gen_marshal_decl(name)
             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:
         if not middle_mode:
             self._regy += gen_register_command(name, success_response)
             self._regy += gen_register_command(name, success_response)
 
 

+ 9 - 9
scripts/qapi-event.py

@@ -14,18 +14,18 @@
 from qapi import *
 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)' % {
     return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
         'c_name': c_name(name.lower()),
         '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('''
     return mcgen('''
 
 
 %(proto)s;
 %(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()
 # Declare and initialize an object 'qapi' using parameters from gen_params()
@@ -57,7 +57,7 @@ def gen_param_var(typ):
     return ret
     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
     # FIXME: Our declaration of local variables (and of 'errp' in the
     # parameter list) can collide with exploded members of the event's
     # parameter list) can collide with exploded members of the event's
     # data type passed in as parameters.  If this collision ever hits in
     # 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;
     Error *err = NULL;
     QMPEventFuncEmit emit;
     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():
     if arg_type and not arg_type.is_empty():
         ret += mcgen('''
         ret += mcgen('''
@@ -160,9 +160,9 @@ def visit_end(self):
         self.defn += gen_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):
-        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)
         self._event_names.append(name)
 
 
 
 

+ 2 - 2
scripts/qapi-introspect.py

@@ -154,14 +154,14 @@ def visit_alternate_type(self, name, info, variants):
                                     for m in variants.variants]})
                                     for m in variants.variants]})
 
 
     def visit_command(self, name, info, arg_type, ret_type,
     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
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
         self._gen_json(name, 'command',
         self._gen_json(name, 'command',
                        {'arg-type': self._use_type(arg_type),
                        {'arg-type': self._use_type(arg_type),
                         'ret-type': self._use_type(ret_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
         arg_type = arg_type or self._schema.the_empty_object_type
         self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
         self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
 
 

+ 27 - 16
scripts/qapi.py

@@ -826,10 +826,10 @@ def visit_alternate_type(self, name, info, variants):
         pass
         pass
 
 
     def visit_command(self, name, info, arg_type, ret_type,
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, boxed):
         pass
         pass
 
 
-    def visit_event(self, name, info, arg_type):
+    def visit_event(self, name, info, arg_type, boxed):
         pass
         pass
 
 
 
 
@@ -1165,7 +1165,8 @@ def visit(self, visitor):
 
 
 
 
 class QAPISchemaCommand(QAPISchemaEntity):
 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)
         QAPISchemaEntity.__init__(self, name, info)
         assert not arg_type or isinstance(arg_type, str)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
         assert not ret_type or isinstance(ret_type, str)
@@ -1175,12 +1176,14 @@ def __init__(self, name, info, arg_type, ret_type, gen, success_response):
         self.ret_type = None
         self.ret_type = None
         self.gen = gen
         self.gen = gen
         self.success_response = success_response
         self.success_response = success_response
+        self.boxed = boxed
 
 
     def check(self, schema):
     def check(self, schema):
         if self._arg_type_name:
         if self._arg_type_name:
             self.arg_type = schema.lookup_type(self._arg_type_name)
             self.arg_type = schema.lookup_type(self._arg_type_name)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
             assert not self.arg_type.variants   # not implemented
             assert not self.arg_type.variants   # not implemented
+            assert not self.boxed               # not implemented
         if self._ret_type_name:
         if self._ret_type_name:
             self.ret_type = schema.lookup_type(self._ret_type_name)
             self.ret_type = schema.lookup_type(self._ret_type_name)
             assert isinstance(self.ret_type, QAPISchemaType)
             assert isinstance(self.ret_type, QAPISchemaType)
@@ -1188,24 +1191,26 @@ def check(self, schema):
     def visit(self, visitor):
     def visit(self, visitor):
         visitor.visit_command(self.name, self.info,
         visitor.visit_command(self.name, self.info,
                               self.arg_type, self.ret_type,
                               self.arg_type, self.ret_type,
-                              self.gen, self.success_response)
+                              self.gen, self.success_response, self.boxed)
 
 
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
 class QAPISchemaEvent(QAPISchemaEntity):
-    def __init__(self, name, info, arg_type):
+    def __init__(self, name, info, arg_type, boxed):
         QAPISchemaEntity.__init__(self, name, info)
         QAPISchemaEntity.__init__(self, name, info)
         assert not arg_type or isinstance(arg_type, str)
         assert not arg_type or isinstance(arg_type, str)
         self._arg_type_name = arg_type
         self._arg_type_name = arg_type
         self.arg_type = None
         self.arg_type = None
+        self.boxed = boxed
 
 
     def check(self, schema):
     def check(self, schema):
         if self._arg_type_name:
         if self._arg_type_name:
             self.arg_type = schema.lookup_type(self._arg_type_name)
             self.arg_type = schema.lookup_type(self._arg_type_name)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
             assert not self.arg_type.variants   # not implemented
             assert not self.arg_type.variants   # not implemented
+            assert not self.boxed               # not implemented
 
 
     def visit(self, visitor):
     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):
 class QAPISchema(object):
@@ -1381,6 +1386,7 @@ def _def_command(self, expr, info):
         rets = expr.get('returns')
         rets = expr.get('returns')
         gen = expr.get('gen', True)
         gen = expr.get('gen', True)
         success_response = expr.get('success-response', True)
         success_response = expr.get('success-response', True)
+        boxed = expr.get('boxed', False)
         if isinstance(data, OrderedDict):
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
             data = self._make_implicit_object_type(
                 name, info, 'arg', self._make_members(data, info))
                 name, info, 'arg', self._make_members(data, info))
@@ -1388,15 +1394,16 @@ def _def_command(self, expr, info):
             assert len(rets) == 1
             assert len(rets) == 1
             rets = self._make_array_type(rets[0], info)
             rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
-                                           success_response))
+                                           success_response, boxed))
 
 
     def _def_event(self, expr, info):
     def _def_event(self, expr, info):
         name = expr['event']
         name = expr['event']
         data = expr.get('data')
         data = expr.get('data')
+        boxed = expr.get('boxed', False)
         if isinstance(data, OrderedDict):
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
             data = self._make_implicit_object_type(
                 name, info, 'arg', self._make_members(data, info))
                 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):
     def _def_exprs(self):
         for expr_elem in self.exprs:
         for expr_elem in self.exprs:
@@ -1639,18 +1646,22 @@ def gen_enum(name, values, prefix=None):
     return ret
     return ret
 
 
 
 
-def gen_params(arg_type, extra):
+def gen_params(arg_type, boxed, extra):
     if not arg_type:
     if not arg_type:
         return extra
         return extra
-    assert not arg_type.variants
     ret = ''
     ret = ''
     sep = ''
     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:
     if extra:
         ret += sep + extra
         ret += sep + extra
     return ret
     return ret

+ 1 - 0
tests/qapi-schema/event-case.out

@@ -1,4 +1,5 @@
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
     prefix QTYPE
 event oops None
 event oops None
+   boxed=False
 object q_empty
 object q_empty

+ 1 - 1
tests/qapi-schema/ident-with-escape.out

@@ -1,7 +1,7 @@
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
     prefix QTYPE
 command fooA q_obj_fooA-arg -> None
 command fooA q_obj_fooA-arg -> None
-   gen=True success_response=True
+   gen=True success_response=True boxed=False
 object q_empty
 object q_empty
 object q_obj_fooA-arg
 object q_obj_fooA-arg
     member bar1: str optional=False
     member bar1: str optional=False

+ 2 - 2
tests/qapi-schema/indented-expr.out

@@ -1,7 +1,7 @@
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
     prefix QTYPE
 command eins None -> None
 command eins None -> None
-   gen=True success_response=True
+   gen=True success_response=True boxed=False
 object q_empty
 object q_empty
 command zwei None -> None
 command zwei None -> None
-   gen=True success_response=True
+   gen=True success_response=True boxed=False

+ 12 - 7
tests/qapi-schema/qapi-schema-test.out

@@ -23,9 +23,13 @@ alternate AltStrNum
     case s: str
     case s: str
     case n: number
     case n: number
 event EVENT_A None
 event EVENT_A None
+   boxed=False
 event EVENT_B None
 event EVENT_B None
+   boxed=False
 event EVENT_C q_obj_EVENT_C-arg
 event EVENT_C q_obj_EVENT_C-arg
+   boxed=False
 event EVENT_D q_obj_EVENT_D-arg
 event EVENT_D q_obj_EVENT_D-arg
+   boxed=False
 object Empty1
 object Empty1
 object Empty2
 object Empty2
     base Empty1
     base Empty1
@@ -124,6 +128,7 @@ object UserDefZero
 object WrapAlternate
 object WrapAlternate
     member alt: UserDefAlternate optional=False
     member alt: UserDefAlternate optional=False
 event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
 event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
+   boxed=False
 alternate __org.qemu_x-Alt
 alternate __org.qemu_x-Alt
     tag type
     tag type
     case __org.qemu_x-branch: str
     case __org.qemu_x-branch: str
@@ -147,11 +152,11 @@ object __org.qemu_x-Union2
     tag __org.qemu_x-member1
     tag __org.qemu_x-member1
     case __org.qemu_x-value: __org.qemu_x-Struct2
     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
 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
 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
 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_empty
 object q_obj_EVENT_C-arg
 object q_obj_EVENT_C-arg
     member a: int optional=True
     member a: int optional=True
@@ -212,10 +217,10 @@ object q_obj_user_def_cmd2-arg
     member ud1a: UserDefOne optional=False
     member ud1a: UserDefOne optional=False
     member ud1b: UserDefOne optional=True
     member ud1b: UserDefOne optional=True
 command user_def_cmd None -> None
 command user_def_cmd None -> None
-   gen=True success_response=True
+   gen=True success_response=True boxed=False
 command user_def_cmd0 Empty2 -> Empty2
 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
 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
 command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
-   gen=True success_response=True
+   gen=True success_response=True boxed=False

+ 5 - 3
tests/qapi-schema/test-qapi.py

@@ -36,13 +36,15 @@ def visit_alternate_type(self, name, info, variants):
         self._print_variants(variants)
         self._print_variants(variants)
 
 
     def visit_command(self, name, info, arg_type, ret_type,
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, boxed):
         print 'command %s %s -> %s' % \
         print 'command %s %s -> %s' % \
             (name, arg_type and arg_type.name, ret_type and ret_type.name)
             (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 'event %s %s' % (name, arg_type and arg_type.name)
+        print '   boxed=%s' % boxed
 
 
     @staticmethod
     @staticmethod
     def _print_variants(variants):
     def _print_variants(variants):