qapi: Clean up after recent conversions to QAPISchemaVisitor

Generate just 'FOO' instead of 'struct FOO' when possible.

Drop helper functions that are now unused.

Make pep8 and pylint reasonably happy.

Rename generate_FOO() functions to gen_FOO() for consistency.

Use more consistent and sensible variable names.

Consistently use c_ for mapping keys when their value is a C
identifier or type.

Simplify gen_enum() and gen_visit_union()

Consistently use single quotes for C text string literals.

Backports commit e98859a9b96d71dea8f9af43325edd43c7effe66 from qemu
This commit is contained in:
Markus Armbruster 2018-02-19 17:33:32 -05:00 committed by Lioncash
parent 64e9fceab9
commit d6866a50f6
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 134 additions and 231 deletions

View file

@ -154,6 +154,7 @@ void qapi_free_uint8List(uint8List *obj);
#endif /* QAPI_TYPES_BUILTIN */
typedef enum ErrorClass {
ERROR_CLASS_GENERIC_ERROR = 0,
ERROR_CLASS_COMMAND_NOT_FOUND = 1,
@ -170,6 +171,7 @@ typedef struct ErrorClassList ErrorClassList;
typedef struct X86CPUFeatureWordInfo X86CPUFeatureWordInfo;
typedef struct X86CPUFeatureWordInfoList X86CPUFeatureWordInfoList;
typedef enum X86CPURegister32 {
X86_CPU_REGISTER32_EAX = 0,
X86_CPU_REGISTER32_EBX = 1,

View file

@ -13,24 +13,26 @@
from qapi import *
def gen_fwd_object_or_array(name):
return mcgen('''
typedef struct %(name)s %(name)s;
typedef struct %(c_name)s %(c_name)s;
''',
name=c_name(name))
c_name=c_name(name))
def gen_array(name, element_type):
return mcgen('''
struct %(name)s {
struct %(c_name)s {
union {
%(c_type)s value;
uint64_t padding;
};
struct %(name)s *next;
struct %(c_name)s *next;
};
''',
name=c_name(name), c_type=element_type.c_type())
c_name=c_name(name), c_type=element_type.c_type())
def gen_struct_field(name, typ, optional):
ret = ''
@ -46,7 +48,8 @@ def gen_struct_field(name, typ, optional):
c_type=typ.c_type(), c_name=c_name(name))
return ret
def generate_struct_fields(members):
def gen_struct_fields(members):
ret = ''
for memb in members:
@ -55,18 +58,19 @@ def generate_struct_fields(members):
def gen_struct(name, base, members):
ret = mcgen('''
struct %(name)s {
struct %(c_name)s {
''',
name=c_name(name))
c_name=c_name(name))
if base:
ret += gen_struct_field('base', base, False)
ret += generate_struct_fields(members)
ret += gen_struct_fields(members)
# Make sure that all structs have at least one field; this avoids
# potential issues with attempting to malloc space for zero-length structs
# in C, and also incompatibility with C++ (where an empty struct is size 1).
# potential issues with attempting to malloc space for zero-length
# structs in C, and also incompatibility with C++ (where an empty
# struct is size 1).
if not base and not members:
ret += mcgen('''
char qapi_dummy_field_for_empty_struct;
@ -78,37 +82,6 @@ struct %(name)s {
return ret
def generate_enum(name, values, prefix=None):
name = c_name(name)
lookup_decl = mcgen('''
extern const char *const %(name)s_lookup[];
''',
name=name)
enum_decl = mcgen('''
typedef enum %(name)s {
''',
name=name)
# append automatically generated _MAX value
enum_values = values + [ 'MAX' ]
i = 0
for value in enum_values:
enum_full_value = c_enum_const(name, value, prefix)
enum_decl += mcgen('''
%(enum_full_value)s = %(i)d,
''',
enum_full_value = enum_full_value,
i=i)
i += 1
enum_decl += mcgen('''
} %(name)s;
''',
name=name)
return enum_decl + lookup_decl
def gen_alternate_qtypes_decl(name):
return mcgen('''
@ -117,12 +90,13 @@ extern const int %(c_name)s_qtypes[];
''',
c_name=c_name(name))
def gen_alternate_qtypes(name, variants):
ret = mcgen('''
const int %(name)s_qtypes[QTYPE_MAX] = {
const int %(c_name)s_qtypes[QTYPE_MAX] = {
''',
name=c_name(name))
c_name=c_name(name))
for var in variants.variants:
qtype = var.type.alternate_qtype()
@ -131,6 +105,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
ret += mcgen('''
[%(qtype)s] = %(enum_const)s,
''',
qtype=qtype,
enum_const=c_enum_const(variants.tag_member.type.name,
var.name))
@ -142,26 +117,24 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
def gen_union(name, base, variants):
name = c_name(name)
ret = mcgen('''
struct %(name)s {
struct %(c_name)s {
''',
name=name)
c_name=c_name(name))
if base:
ret += mcgen('''
/* Members inherited from %(c_name)s: */
''',
c_name=c_name(base.name))
ret += generate_struct_fields(base.members)
ret += gen_struct_fields(base.members)
ret += mcgen('''
/* Own members: */
''')
else:
ret += mcgen('''
%(discriminator_type_name)s kind;
%(c_type)s kind;
''',
discriminator_type_name=c_name(variants.tag_member.type.name))
c_type=c_name(variants.tag_member.type.name))
# FIXME: What purpose does data serve, besides preventing a union that
# has a branch named 'data'? We use it in qapi-visit.py to decide
@ -196,17 +169,19 @@ struct %(name)s {
return ret
def generate_type_cleanup_decl(name):
def gen_type_cleanup_decl(name):
ret = mcgen('''
void qapi_free_%(name)s(%(name)s *obj);
void qapi_free_%(c_name)s(%(c_name)s *obj);
''',
name=c_name(name))
c_name=c_name(name))
return ret
def generate_type_cleanup(name):
def gen_type_cleanup(name):
ret = mcgen('''
void qapi_free_%(name)s(%(name)s *obj)
void qapi_free_%(c_name)s(%(c_name)s *obj)
{
QapiDeallocVisitor *md;
Visitor *v;
@ -217,11 +192,11 @@ void qapi_free_%(name)s(%(name)s *obj)
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
visit_type_%(name)s(v, &obj, NULL, NULL);
visit_type_%(c_name)s(v, &obj, NULL, NULL);
qapi_dealloc_visitor_cleanup(md);
}
''',
name=c_name(name))
c_name=c_name(name))
return ret
@ -254,20 +229,20 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self._btin = None
def _gen_type_cleanup(self, name):
self.decl += generate_type_cleanup_decl(name)
self.defn += generate_type_cleanup(name)
self.decl += gen_type_cleanup_decl(name)
self.defn += gen_type_cleanup(name)
def visit_enum_type(self, name, info, values, prefix):
self._fwdecl += generate_enum(name, values, prefix)
self._fwdefn += generate_enum_lookup(name, values, prefix)
self._fwdecl += gen_enum(name, values, prefix)
self._fwdefn += gen_enum_lookup(name, values, prefix)
def visit_array_type(self, name, info, element_type):
if isinstance(element_type, QAPISchemaBuiltinType):
self._btin += gen_fwd_object_or_array(name)
self._btin += gen_array(name, element_type)
self._btin += generate_type_cleanup_decl(name)
self._btin += gen_type_cleanup_decl(name)
if do_builtins:
self.defn += generate_type_cleanup(name)
self.defn += gen_type_cleanup(name)
else:
self._fwdecl += gen_fwd_object_or_array(name)
self.decl += gen_array(name, element_type)

View file

@ -18,18 +18,19 @@ import re
implicit_structs_seen = set()
struct_fields_seen = set()
def generate_visit_implicit_struct(type):
if type in implicit_structs_seen:
def gen_visit_implicit_struct(typ):
if typ in implicit_structs_seen:
return ''
implicit_structs_seen.add(type)
implicit_structs_seen.add(typ)
ret = ''
if type.name not in struct_fields_seen:
if typ.name not in struct_fields_seen:
# Need a forward declaration
ret += mcgen('''
static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
''',
c_type=type.c_name())
c_type=typ.c_name())
ret += mcgen('''
@ -45,35 +46,35 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error *
error_propagate(errp, err);
}
''',
c_type=type.c_name())
c_type=typ.c_name())
return ret
def generate_visit_struct_fields(name, members, base = None):
def gen_visit_struct_fields(name, base, members):
struct_fields_seen.add(name)
ret = ''
if base:
ret += generate_visit_implicit_struct(base)
ret += gen_visit_implicit_struct(base)
ret += mcgen('''
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
static void visit_type_%(c_name)s_fields(Visitor *m, %(c_name)s **obj, Error **errp)
{
Error *err = NULL;
''',
name=c_name(name))
c_name=c_name(name))
push_indent()
if base:
ret += mcgen('''
visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);
if (err) {
goto out;
}
''',
type=base.c_name(), c_name=c_name('base'))
c_type=base.c_name(), c_name=c_name('base'))
for memb in members:
if memb.optional:
@ -85,9 +86,9 @@ if (!err && (*obj)->has_%(c_name)s) {
push_indent()
ret += mcgen('''
visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
''',
type=memb.type.c_name(), c_name=c_name(memb.name),
c_type=memb.type.c_name(), c_name=c_name(memb.name),
name=memb.name)
if memb.optional:
@ -102,7 +103,7 @@ if (err) {
''')
pop_indent()
if re.search('^ *goto out\\;', ret, re.MULTILINE):
if re.search('^ *goto out;', ret, re.MULTILINE):
ret += mcgen('''
out:
@ -114,7 +115,7 @@ out:
return ret
def generate_visit_struct_body(name):
def gen_visit_struct_body(name):
ret = mcgen('''
Error *err = NULL;
@ -129,30 +130,29 @@ def generate_visit_struct_body(name):
error_propagate(errp, err);
''',
name=name, c_name=c_name(name))
return ret
def gen_visit_struct(name, base, members):
ret = generate_visit_struct_fields(name, members, base)
ret = gen_visit_struct_fields(name, base, members)
ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{
''',
name=c_name(name))
c_name=c_name(name))
ret += generate_visit_struct_body(name)
ret += gen_visit_struct_body(name)
ret += mcgen('''
}
''')
return ret
def gen_visit_list(name, element_type):
return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{
Error *err = NULL;
GenericList *i, **prev;
@ -165,7 +165,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
for (prev = (GenericList **)obj;
!err && (i = visit_next_list(m, prev)) != NULL;
prev = &i) {
%(name)s *native_i = (%(name)s *)i;
%(c_name)s *native_i = (%(c_name)s *)i;
visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err);
}
@ -176,10 +176,10 @@ out:
error_propagate(errp, err);
}
''',
name=c_name(name),
c_elt_type=element_type.c_name())
c_name=c_name(name), c_elt_type=element_type.c_name())
def generate_visit_enum(name):
def gen_visit_enum(name):
return mcgen('''
void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp)
@ -189,36 +189,36 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error
''',
c_name=c_name(name), name=name)
def gen_visit_alternate(name, variants):
ret = mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{
Error *err = NULL;
visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
visit_start_implicit_struct(m, (void**) obj, sizeof(%(c_name)s), &err);
if (err) {
goto out;
}
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
visit_get_next_type(m, (int*) &(*obj)->kind, %(c_name)s_qtypes, name, &err);
if (err) {
goto out_end;
}
switch ((*obj)->kind) {
''',
name=c_name(name))
c_name=c_name(name))
for var in variants.variants:
enum_full_value = c_enum_const(variants.tag_member.type.name,
var.name)
ret += mcgen('''
case %(enum_full_value)s:
case %(case)s:
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
break;
''',
enum_full_value = enum_full_value,
c_type=var.type.c_name(),
c_name=c_name(var.name))
case=c_enum_const(variants.tag_member.type.name,
var.name),
c_type=var.type.c_name(),
c_name=c_name(var.name))
ret += mcgen('''
default:
@ -235,17 +235,18 @@ out:
return ret
def gen_visit_union(name, base, variants):
ret = ''
if base:
members = [m for m in base.members if m != variants.tag_member]
ret += generate_visit_struct_fields(name, members)
ret += gen_visit_struct_fields(name, None, members)
for var in variants.variants:
# Ugly special case for simple union TODO get rid of it
if not var.simple_union_type():
ret += generate_visit_implicit_struct(var.type)
ret += gen_visit_implicit_struct(var.type)
ret += mcgen('''
@ -263,19 +264,19 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error
if base:
ret += mcgen('''
visit_type_%(name)s_fields(m, obj, &err);
visit_type_%(c_name)s_fields(m, obj, &err);
if (err) {
goto out_obj;
}
''',
name=c_name(name))
c_name=c_name(name))
disc_key = variants.tag_member.name
tag_key = variants.tag_member.name
if not variants.tag_name:
# we pointlessly use a different key for simple unions
disc_key = 'type'
tag_key = 'type'
ret += mcgen('''
visit_type_%(disc_type)s(m, &(*obj)->%(c_name)s, "%(disc_key)s", &err);
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
if (err) {
goto out_obj;
}
@ -284,30 +285,37 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error
}
switch ((*obj)->%(c_name)s) {
''',
disc_type=variants.tag_member.type.c_name(),
c_type=variants.tag_member.type.c_name(),
# TODO ugly special case for simple union
# Use same tag name in C as on the wire to get rid of
# it, then: c_name=c_name(variants.tag_member.name)
c_name=c_name(variants.tag_name or 'kind'),
disc_key = disc_key)
name=tag_key)
for var in variants.variants:
# TODO ugly special case for simple union
simple_union_type = var.simple_union_type()
if simple_union_type:
fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
else:
fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
enum_full_value = c_enum_const(variants.tag_member.type.name, var.name)
ret += mcgen('''
case %(enum_full_value)s:
''' + fmt + '''
break;
case %(case)s:
''',
enum_full_value = enum_full_value,
c_type=(simple_union_type or var.type).c_name(),
c_name=c_name(var.name))
case=c_enum_const(variants.tag_member.type.name,
var.name))
if simple_union_type:
ret += mcgen('''
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
''',
c_type=simple_union_type.c_name(),
c_name=c_name(var.name))
else:
ret += mcgen('''
visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);
''',
c_type=var.type.c_name(),
c_name=c_name(var.name))
ret += mcgen('''
break;
''')
ret += mcgen('''
default:
@ -328,6 +336,7 @@ out:
return ret
def gen_visit_decl(name, scalar=False):
c_type = c_name(name) + ' *'
if not scalar:
@ -361,7 +370,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def visit_enum_type(self, name, info, values, prefix):
self.decl += gen_visit_decl(name, scalar=True)
self.defn += generate_visit_enum(name)
self.defn += gen_visit_enum(name)
def visit_array_type(self, name, info, element_type):
decl = gen_visit_decl(name)
@ -437,7 +446,7 @@ fdef.write(mcgen('''
#include "qemu-common.h"
#include "%(prefix)sqapi-visit.h"
''',
prefix = prefix))
prefix=prefix))
fdecl.write(mcgen('''
#include "qapi/visitor.h"

View file

@ -1083,9 +1083,6 @@ class QAPISchema(object):
self._def_exprs()
self.check()
def get_exprs(self):
return [expr_elem['expr'] for expr_elem in self.exprs]
def _def_entity(self, ent):
assert ent.name not in self._entity_dict
self._entity_dict[ent.name] = ent
@ -1277,23 +1274,6 @@ class QAPISchema(object):
# Code generation helpers
#
def parse_args(typeinfo):
if isinstance(typeinfo, str):
struct = find_struct(typeinfo)
assert struct != None
typeinfo = struct['data']
for member in typeinfo:
argname = member
argentry = typeinfo[member]
optional = False
if member.startswith('*'):
argname = member[1:]
optional = True
# Todo: allow argentry to be OrderedDict, for providing the
# value of an optional argument.
yield (argname, argentry, optional)
def camel_case(name):
new_name = ''
first = True
@ -1376,67 +1356,9 @@ def c_name(name, protect=True):
return "q_" + name
return name.translate(c_name_trans)
# Map type @name to the C typedef name for the list form.
#
# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList'
def c_list_type(name):
return name + 'List'
# Map type @value to the C typedef form.
#
# Used for converting 'type' from a 'member':'type' qapi definition
# into the alphanumeric portion of the type for a generated C parameter,
# as well as generated C function names. See c_type() for the rest of
# the conversion such as adding '*' on pointer types.
# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c'
def type_name(value):
if type(value) == list:
return c_list_type(value[0])
if value in builtin_types.keys():
return value
return c_name(value)
eatspace = '\033EATSPACE.'
pointer_suffix = ' *' + eatspace
# Map type @name to its C type expression.
# If @is_param, const-qualify the string type.
#
# This function is used for computing the full C type of 'member':'name'.
# A special suffix is added in c_type() for pointer types, and it's
# stripped in mcgen(). So please notice this when you check the return
# value of c_type() outside mcgen().
def c_type(value, is_param=False):
if value == 'str':
if is_param:
return 'const char' + pointer_suffix
return 'char' + pointer_suffix
elif value == 'int':
return 'int64_t'
elif (value == 'int8' or value == 'int16' or value == 'int32' or
value == 'int64' or value == 'uint8' or value == 'uint16' or
value == 'uint32' or value == 'uint64'):
return value + '_t'
elif value == 'size':
return 'uint64_t'
elif value == 'bool':
return 'bool'
elif value == 'number':
return 'double'
elif type(value) == list:
return c_list_type(value[0]) + pointer_suffix
elif is_enum(value):
return c_name(value)
elif value == None:
return 'void'
elif value in events:
return camel_case(value) + 'Event' + pointer_suffix
else:
# complex type name
assert isinstance(value, str) and value != ""
return c_name(value) + pointer_suffix
def genindent(count):
ret = ""
for i in range(count):
@ -1490,18 +1412,18 @@ def guardend(name):
''',
name=guardname(name))
def generate_enum_lookup(name, values, prefix=None):
def gen_enum_lookup(name, values, prefix=None):
ret = mcgen('''
const char *const %(name)s_lookup[] = {
const char *const %(c_name)s_lookup[] = {
''',
name=c_name(name))
c_name=c_name(name))
for value in values:
index = c_enum_const(name, value, prefix)
ret += mcgen('''
"%(value)s",
''',
index = index, value = value)
value=value)
# Unicorn: We don't use C99 [ARRAY_INDICING] = Thing because
# MSVC is still in the stone-age with this part of C compiler
@ -1510,43 +1432,38 @@ const char *const %(name)s_lookup[] = {
ret += mcgen('''
NULL,
};
''',
max_index=max_index)
''')
return ret
def generate_enum(name, values, prefix=None):
name = c_name(name)
lookup_decl = mcgen('''
extern const char *const %(name)s_lookup[];
''',
name=name)
enum_decl = mcgen('''
typedef enum %(name)s {
''',
name=name)
def gen_enum(name, values, prefix=None):
# append automatically generated _MAX value
enum_values = values + [ 'MAX' ]
enum_values = values + ['MAX']
ret = mcgen('''
typedef enum %(c_name)s {
''',
c_name=c_name(name))
i = 0
for value in enum_values:
enum_full_value = c_enum_const(name, value, prefix)
enum_decl += mcgen('''
%(enum_full_value)s = %(i)d,
ret += mcgen('''
%(c_enum)s = %(i)d,
''',
enum_full_value = enum_full_value,
c_enum=c_enum_const(name, value, prefix),
i=i)
i += 1
enum_decl += mcgen('''
} %(name)s;
ret += mcgen('''
} %(c_name)s;
''',
name=name)
c_name=c_name(name))
return enum_decl + lookup_decl
ret += mcgen('''
extern const char *const %(c_name)s_lookup[];
''',
c_name=c_name(name))
return ret
#
# Common command line parsing