Commit 71b3f045 authored by Markus Armbruster's avatar Markus Armbruster Committed by Eric Blake
Browse files

qapi: Make code-generating visitors use QAPIGen more



The use of QAPIGen is rather shallow so far: most of the output
accumulation is not converted.  Take the next step: convert output
accumulation in the code-generating visitor classes.  Helper functions
outside these classes are not converted.

Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
Message-Id: <20180211093607.27351-20-armbru@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Reviewed-by: default avatarMarc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: default avatarMichael Roth <mdroth@linux.vnet.ibm.com>
[eblake: rebase to earlier guardstart cleanup]
Signed-off-by: default avatarEric Blake <eblake@redhat.com>
parent 834a3f34
Loading
Loading
Loading
Loading
+28 −43
Original line number Diff line number Diff line
@@ -223,44 +223,15 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
    return ret


class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
class QAPISchemaGenCommandVisitor(QAPISchemaMonolithicCVisitor):

    def __init__(self, prefix):
        self._prefix = prefix
        self.decl = None
        self.defn = None
        self._regy = None
        self._visited_ret_types = None

    def visit_begin(self, schema):
        self.decl = ''
        self.defn = ''
        QAPISchemaMonolithicCVisitor.__init__(
            self, prefix, 'qmp-commands',
            ' * Schema-defined QAPI/QMP commands', __doc__)
        self._regy = ''
        self._visited_ret_types = set()

    def visit_end(self):
        self.defn += gen_registry(self._regy, self._prefix)
        self._regy = None
        self._visited_ret_types = None

    def visit_command(self, name, info, arg_type, ret_type,
                      gen, success_response, boxed):
        if not gen:
            return
        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)
        self.decl += gen_marshal_decl(name)
        self.defn += gen_marshal(name, arg_type, boxed, ret_type)
        self._regy += gen_register_command(name, success_response)


def gen_commands(schema, output_dir, prefix):
    blurb = ' * Schema-defined QAPI/QMP commands'
    genc = QAPIGenC(blurb, __doc__)
    genh = QAPIGenH(blurb, __doc__)

    genc.add(mcgen('''
        self._genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/module.h"
@@ -276,18 +247,32 @@ def gen_commands(schema, output_dir, prefix):

''',
                             prefix=prefix))

    genh.add(mcgen('''
        self._genh.add(mcgen('''
#include "%(prefix)sqapi-types.h"
#include "qapi/qmp/dispatch.h"

void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
''',
                   prefix=prefix, c_prefix=c_name(prefix, protect=False)))
                             prefix=prefix,
                             c_prefix=c_name(prefix, protect=False)))

    def visit_end(self):
        self._genc.add(gen_registry(self._regy, self._prefix))

    def visit_command(self, name, info, arg_type, ret_type,
                      gen, success_response, boxed):
        if not gen:
            return
        self._genh.add(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._genc.add(gen_marshal_output(ret_type))
        self._genh.add(gen_marshal_decl(name))
        self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
        self._regy += gen_register_command(name, success_response)


def gen_commands(schema, output_dir, prefix):
    vis = QAPISchemaGenCommandVisitor(prefix)
    schema.visit(vis)
    genc.add(vis.defn)
    genh.add(vis.decl)
    genc.write(output_dir, prefix + 'qmp-commands.c')
    genh.write(output_dir, prefix + 'qmp-commands.h')
    vis.write(output_dir)
+13 −0
Original line number Diff line number Diff line
@@ -2050,3 +2050,16 @@ class QAPIGenDoc(QAPIGen):
    def _top(self, fname):
        return (QAPIGen._top(self, fname)
                + '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')


class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):

    def __init__(self, prefix, what, blurb, pydoc):
        self._prefix = prefix
        self._what = what
        self._genc = QAPIGenC(blurb, pydoc)
        self._genh = QAPIGenH(blurb, pydoc)

    def write(self, output_dir):
        self._genc.write(output_dir, self._prefix + self._what + '.c')
        self._genh.write(output_dir, self._prefix + self._what + '.h')
+35 −39
Original line number Diff line number Diff line
@@ -197,33 +197,35 @@ def texi_entity(doc, what, base=None, variants=None,


class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
    def __init__(self):
        self.out = None
    def __init__(self, prefix):
        self._prefix = prefix
        self._gen = qapi.common.QAPIGenDoc()
        self.cur_doc = None

    def visit_begin(self, schema):
        self.out = ''
    def write(self, output_dir):
        self._gen.write(output_dir, self._prefix + 'qapi-doc.texi')

    def visit_enum_type(self, name, info, values, prefix):
        doc = self.cur_doc
        self.out += TYPE_FMT(type='Enum',
        self._gen.add(TYPE_FMT(type='Enum',
                               name=doc.symbol,
                               body=texi_entity(doc, 'Values',
                                              member_func=texi_enum_value))
                                                member_func=texi_enum_value)))

    def visit_object_type(self, name, info, base, members, variants):
        doc = self.cur_doc
        if base and base.is_implicit():
            base = None
        self.out += TYPE_FMT(type='Object',
        self._gen.add(TYPE_FMT(type='Object',
                               name=doc.symbol,
                             body=texi_entity(doc, 'Members', base, variants))
                               body=texi_entity(doc, 'Members',
                                                base, variants)))

    def visit_alternate_type(self, name, info, variants):
        doc = self.cur_doc
        self.out += TYPE_FMT(type='Alternate',
        self._gen.add(TYPE_FMT(type='Alternate',
                               name=doc.symbol,
                             body=texi_entity(doc, 'Members'))
                               body=texi_entity(doc, 'Members')))

    def visit_command(self, name, info, arg_type, ret_type,
                      gen, success_response, boxed):
@@ -235,44 +237,38 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
            body += texi_sections(doc)
        else:
            body = texi_entity(doc, 'Arguments')
        self.out += MSG_FMT(type='Command',
        self._gen.add(MSG_FMT(type='Command',
                              name=doc.symbol,
                            body=body)
                              body=body))

    def visit_event(self, name, info, arg_type, boxed):
        doc = self.cur_doc
        self.out += MSG_FMT(type='Event',
        self._gen.add(MSG_FMT(type='Event',
                              name=doc.symbol,
                            body=texi_entity(doc, 'Arguments'))
                              body=texi_entity(doc, 'Arguments')))

    def symbol(self, doc, entity):
        if self.out:
            self.out += '\n'
        if self._gen._body:
            self._gen.add('\n')
        self.cur_doc = doc
        entity.visit(self)
        self.cur_doc = None

    def freeform(self, doc):
        assert not doc.args
        if self.out:
            self.out += '\n'
        self.out += texi_body(doc) + texi_sections(doc)
        if self._gen._body:
            self._gen.add('\n')
        self._gen.add(texi_body(doc) + texi_sections(doc))


def texi_schema(schema):
    """Convert QAPI schema documentation to Texinfo"""
    gen = QAPISchemaGenDocVisitor()
    gen.visit_begin(schema)
def gen_doc(schema, output_dir, prefix):
    if not qapi.common.doc_required:
        return
    vis = QAPISchemaGenDocVisitor(prefix)
    vis.visit_begin(schema)
    for doc in schema.docs:
        if doc.symbol:
            gen.symbol(doc, schema.lookup_entity(doc.symbol))
            vis.symbol(doc, schema.lookup_entity(doc.symbol))
        else:
            gen.freeform(doc)
    return gen.out


def gen_doc(schema, output_dir, prefix):
    if qapi.common.doc_required:
        gen = qapi.common.QAPIGenDoc()
        gen.add(texi_schema(schema))
        gen.write(output_dir, prefix + 'qapi-doc.texi')
            vis.freeform(doc)
    vis.write(output_dir)
+21 −34
Original line number Diff line number Diff line
@@ -148,35 +148,15 @@ out:
    return ret


class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
class QAPISchemaGenEventVisitor(QAPISchemaMonolithicCVisitor):

    def __init__(self, prefix):
        QAPISchemaMonolithicCVisitor.__init__(
            self, prefix, 'qapi-event',
            ' * Schema-defined QAPI/QMP events', __doc__)
        self._enum_name = c_name(prefix + 'QAPIEvent', protect=False)
        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(self._enum_name, self._event_names)
        self.defn += gen_enum_lookup(self._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._enum_name)
        self._event_names.append(name)


def gen_events(schema, output_dir, prefix):
    blurb = ' * Schema-defined QAPI/QMP events'
    genc = QAPIGenC(blurb, __doc__)
    genh = QAPIGenH(blurb, __doc__)

    genc.add(mcgen('''
        self._genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "%(prefix)sqapi-event.h"
@@ -188,17 +168,24 @@ def gen_events(schema, output_dir, prefix):

''',
                             prefix=prefix))

    genh.add(mcgen('''
        self._genh.add(mcgen('''
#include "qapi/util.h"
#include "%(prefix)sqapi-types.h"

''',
                             prefix=prefix))

    def visit_end(self):
        self._genh.add(gen_enum(self._enum_name, self._event_names))
        self._genc.add(gen_enum_lookup(self._enum_name, self._event_names))

    def visit_event(self, name, info, arg_type, boxed):
        self._genh.add(gen_event_send_decl(name, arg_type, boxed))
        self._genc.add(gen_event_send(name, arg_type, boxed, self._enum_name))
        self._event_names.append(name)


def gen_events(schema, output_dir, prefix):
    vis = QAPISchemaGenEventVisitor(prefix)
    schema.visit(vis)
    genc.add(vis.defn)
    genh.add(vis.decl)
    genc.write(output_dir, prefix + 'qapi-event.c')
    genh.write(output_dir, prefix + 'qapi-event.h')
    vis.write(output_dir)
+23 −33
Original line number Diff line number Diff line
@@ -40,22 +40,26 @@ def to_c_string(string):
    return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"'


class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
class QAPISchemaGenIntrospectVisitor(QAPISchemaMonolithicCVisitor):

    def __init__(self, prefix, unmask):
        self._prefix = prefix
        QAPISchemaMonolithicCVisitor.__init__(
            self, prefix, 'qmp-introspect',
            ' * QAPI/QMP schema introspection', __doc__)
        self._unmask = unmask
        self.defn = None
        self.decl = None
        self._schema = None
        self._jsons = None
        self._used_types = None
        self._name_map = None

    def visit_begin(self, schema):
        self._schema = schema
        self._jsons = []
        self._used_types = []
        self._name_map = {}
        self._genc.add(mcgen('''
#include "qemu/osdep.h"
#include "%(prefix)sqmp-introspect.h"

''',
                             prefix=prefix))

    def visit_begin(self, schema):
        self._schema = schema

    def visit_end(self):
        # visit the types that are actually used
@@ -67,21 +71,21 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
        # TODO can generate awfully long lines
        jsons.extend(self._jsons)
        name = c_name(self._prefix, protect=False) + 'qmp_schema_json'
        self.decl = mcgen('''
        self._genh.add(mcgen('''
extern const char %(c_name)s[];
''',
                          c_name=c_name(name))
                             c_name=c_name(name)))
        lines = to_json(jsons).split('\n')
        c_string = '\n    '.join([to_c_string(line) for line in lines])
        self.defn = mcgen('''
        self._genc.add(mcgen('''
const char %(c_name)s[] = %(c_string)s;
''',
                             c_name=c_name(name),
                          c_string=c_string)
                             c_string=c_string))
        self._schema = None
        self._jsons = None
        self._used_types = None
        self._name_map = None
        self._jsons = []
        self._used_types = []
        self._name_map = {}

    def visit_needed(self, entity):
        # Ignore types on first pass; visit_end() will pick up used types
@@ -169,20 +173,6 @@ const char %(c_name)s[] = %(c_string)s;


def gen_introspect(schema, output_dir, prefix, opt_unmask):
    blurb = ' * QAPI/QMP schema introspection'
    genc = QAPIGenC(blurb, __doc__)
    genh = QAPIGenH(blurb, __doc__)

    genc.add(mcgen('''
#include "qemu/osdep.h"
#include "%(prefix)sqmp-introspect.h"

''',
                   prefix=prefix))

    vis = QAPISchemaGenIntrospectVisitor(prefix, opt_unmask)
    schema.visit(vis)
    genc.add(vis.defn)
    genh.add(vis.decl)
    genc.write(output_dir, prefix + 'qmp-introspect.c')
    genh.write(output_dir, prefix + 'qmp-introspect.h')
    vis.write(output_dir)
Loading