qapi: New classes QAPIGenC, QAPIGenH, QAPIGenDoc

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
This commit is contained in:
Markus Armbruster 2018-03-09 07:53:43 -05:00 committed by Lioncash
parent 3fe150978c
commit 03c3b81d7a
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 97 additions and 78 deletions

View file

@ -173,11 +173,10 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
blurb = ' * Schema-defined QAPI/QMP events'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qapi-event.c', 'qapi-event.h',
blurb, __doc__)
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
fdef.write(mcgen('''
genc.add(mcgen('''
#include "qemu-common.h"
#include "%(prefix)sqapi-event.h"
#include "%(prefix)sqapi-visit.h"
@ -189,7 +188,7 @@ fdef.write(mcgen('''
''',
prefix=prefix))
fdecl.write(mcgen('''
genh.add(mcgen('''
#include "%(prefix)sqapi-types.h"
''',
@ -200,7 +199,10 @@ event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
schema = QAPISchema(input_file)
vis = QAPISchemaGenEventVisitor()
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qapi-event.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-event.h')

View file

@ -180,7 +180,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.decl = ''
self.defn = ''
self._fwdecl = ''
self._btin = guardstart('QAPI_TYPES_BUILTIN')
self._btin = '\n' + guardstart('QAPI_TYPES_BUILTIN')
def visit_end(self):
self.decl = self._fwdecl + self.decl
@ -254,11 +254,10 @@ for o, a in opts:
blurb = ' * Schema-defined QAPI types'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qapi-types.c', 'qapi-types.h',
blurb, __doc__)
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
fdef.write(mcgen('''
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h"
@ -266,10 +265,17 @@ fdef.write(mcgen('''
''',
prefix=prefix))
genh.add(mcgen('''
/* #include "qapi/util.h" */
'''))
schema = QAPISchema(input_file)
vis = QAPISchemaGenTypeVisitor()
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qapi-types.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-types.h')

View file

@ -272,7 +272,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def visit_begin(self, schema):
self.decl = ''
self.defn = ''
self._btin = guardstart('QAPI_VISIT_BUILTIN')
self._btin = '\n' + guardstart('QAPI_VISIT_BUILTIN')
def visit_end(self):
# To avoid header dependency hell, we always generate
@ -337,11 +337,10 @@ for o, a in opts:
blurb = ' * Schema-defined QAPI visitors'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qapi-visit.c', 'qapi-visit.h',
blurb, __doc__)
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
fdef.write(mcgen('''
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h"
@ -349,7 +348,7 @@ fdef.write(mcgen('''
''',
prefix=prefix))
fdecl.write(mcgen('''
genh.add(mcgen('''
#include "qapi/visitor.h"
#include "qapi/qmp/qerror.h"
#include "%(prefix)sqapi-types.h"
@ -360,7 +359,10 @@ fdecl.write(mcgen('''
schema = QAPISchema(input_file)
vis = QAPISchemaGenVisitVisitor()
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qapi-visit.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-visit.h')

View file

@ -2,7 +2,7 @@
# QAPI helper library
#
# Copyright IBM, Corp. 2011
# Copyright (c) 2013-2016 Red Hat Inc.
# Copyright (c) 2013-2018 Red Hat Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
@ -22,10 +22,6 @@ try:
from collections import OrderedDict
except:
from ordereddict import OrderedDict
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
builtin_types = {
'null': 'QTYPE_QNULL',
@ -1840,7 +1836,6 @@ def guardname(filename):
def guardstart(name):
return mcgen('''
#ifndef %(name)s
#define %(name)s
@ -1852,7 +1847,6 @@ def guardend(name):
return mcgen('''
#endif /* %(name)s */
''',
name=guardname(name))
@ -1985,17 +1979,53 @@ def parse_command_line(extra_options='', extra_long_options=[]):
return (fname, output_dir, do_c, do_h, prefix, extra_opts)
#
# Generate output files with boilerplate
# Accumulate and write output
#
class QAPIGen(object):
def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, blurb, doc):
guard = guardname(prefix + h_file)
c_file = output_dir + prefix + c_file
h_file = output_dir + prefix + h_file
copyright = '\n * '.join(re.findall(r'^Copyright .*', doc, re.MULTILINE))
comment = mcgen('''/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
def __init__(self):
self._preamble = ''
self._body = ''
def preamble_add(self, text):
self._preamble += text
def add(self, text):
self._body += text
def _top(self, fname):
return ''
def _bottom(self, fname):
return ''
def write(self, output_dir, fname):
if output_dir:
try:
os.makedirs(output_dir)
except os.error as e:
if e.errno != errno.EEXIST:
raise
f = open(os.path.join(output_dir, fname), 'w')
f.write(self._top(fname) + self._preamble + self._body
+ self._bottom(fname))
f.close()
class QAPIGenC(QAPIGen):
def __init__(self, blurb, pydoc):
QAPIGen.__init__(self)
self._blurb = blurb
self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
re.MULTILINE))
def _top(self, fname):
return mcgen('''
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
%(blurb)s
@ -2007,40 +2037,19 @@ def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, blurb, doc):
*/
''',
blurb=blurb, copyright=copyright)
if output_dir:
try:
os.makedirs(output_dir)
except os.error as e:
if e.errno != errno.EEXIST:
raise
def maybe_open(really, name, opt):
if really:
return open(name, opt)
else:
return StringIO()
fdef = maybe_open(do_c, c_file, 'w')
fdecl = maybe_open(do_h, h_file, 'w')
fdef.write(comment)
fdecl.write(comment)
fdecl.write(mcgen('''
#ifndef %(guard)s
#define %(guard)s
''',
guard=guard))
return (fdef, fdecl)
blurb=self._blurb, copyright=self._copyright)
def close_output(fdef, fdecl):
fdecl.write(mcgen('''
class QAPIGenH(QAPIGenC):
def _top(self, fname):
return QAPIGenC._top(self, fname) + guardstart(fname)
def _bottom(self, fname):
return guardend(fname)
class QAPIGenDoc(QAPIGen):
def _top(self, fname):
return (QAPIGen._top(self, fname)
+ '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')
#endif
'''))
fdecl.close()
fdef.close()