qapi: Another round of fixes and cleanups

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJV6aFGAAoJEDhwtADrkYZT8o8P/R7CZzKv6JE85xQYKtIEdgK7
 zP+GiNY+ysXL/4uRzXk/Ksh3TYuRe/ptMdeXINayOoC3qG8WYuiIjIB6VTtscWGF
 NKj/iKUxk6APLHunLBCf/ubW1uqsOHCgmuxZJEB7aZhUpWfpYL+0pvF+n8qm67f/
 RaaN2FCppTTzKrGFWjmTP1iwm2GF/ETOdlyNQ79AEjEb3n6IvjpVPuHU9ZcZhqLP
 CF0efVX172sbZqOlIBiDlvyCmPHsCpoRRUw4D/E5ctAxj/JkhKtv5pwsIAhKQVNj
 +plsYFYujhkUBT8QRZQF1oH3CQXoDD03qimCRptBSOWHTKsCPYWpSZSaE6BIzOyJ
 NaFcAr4x+/NCxkZ0Ef/qQZfwIH2NLb5gPpaSUpsVrJQUsx4ImKSpa8t1x+iTLqO4
 QnU+pkQ6PdkFNlhj1tOvKcaOWV5wlPTtEfpEflYg0Cx173Ao3nIOPIIYTqdelcn5
 1sopuADvFB61/EiMail9NS9aPPuPrnrrOtzVNyFtDZorO+sot7pWOJ24xAzylG6G
 jOZxMVJteq+XF0DLTdCKJiCxCdwMSrg/wNKnFMmKFGlqJIpRrd7XYPfzVX+pX/s7
 gpuCc3r73WPReP1b/sjn8vQ4PBRpaQb8uK8hkh+GQjnr99cSyTZgI/M1anTh5YEC
 mXPB0mw60g8YA61gJSX0
 =CGzi
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2015-09-04' into staging

qapi: Another round of fixes and cleanups

# gpg: Signature made Fri 04 Sep 2015 14:48:54 BST using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"

* remotes/armbru/tags/pull-qapi-2015-09-04: (33 commits)
  qapi: Generators crash when --output-dir isn't given, fix
  docs/qapi-code-gen.txt: Fix QAPI schema examples
  qapi: Simplify error reporting for array types
  qapi: Fix errors for non-string, non-dictionary members
  tests/qapi-schema: Cover non-string, non-dictionary members
  tests/qapi-schema: Cover two more syntax errors
  qapi: Drop one of two "simple union must not have base" checks
  qapi: Generated code cleanup
  qapi-commands: Drop useless initialization
  qapi-commands: Don't feed output of mcgen() to mcgen() again
  qapi-commands: Inline gen_marshal_output_call()
  qapi-commands: Fix gen_err_check(e) for e and e != 'local_err'
  qapi: Command returning anonymous type doesn't work, outlaw
  qapi: Fix to reject union command and event arguments
  qapi-tests: New tests for union, alternate command arguments
  tests/qapi-schema: Rename tests from data- to args-
  tests/qapi-schema: Restore test case for flat union base bug
  qapi: Document flaws in checking of names
  qapi: Document shortcoming with union 'data' branch
  qapi: Document that input visitor semantics are prone to leaks
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-09-04 15:53:48 +01:00
commit b5bff7518d
82 changed files with 317 additions and 268 deletions

View File

@ -163,7 +163,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
The directive is evaluated recursively, and include paths are relative to the The directive is evaluated recursively, and include paths are relative to the
file using the directive. Multiple includes of the same file are file using the directive. Multiple includes of the same file are
safe. No other keys should appear in the expression, and the include idempotent. No other keys should appear in the expression, and the include
value should be a string. value should be a string.
As a matter of style, it is a good idea to have all files be As a matter of style, it is a good idea to have all files be
@ -300,7 +300,6 @@ an implicit C enum 'NameKind' is created, corresponding to the union
the union can be named 'max', as this would collide with the implicit the union can be named 'max', as this would collide with the implicit
enum. The value for each branch can be of any type. enum. The value for each branch can be of any type.
A flat union definition specifies a struct as its base, and A flat union definition specifies a struct as its base, and
avoids nesting on the wire. All branches of the union must be avoids nesting on the wire. All branches of the union must be
complex types, and the top-level fields of the union dictionary on complex types, and the top-level fields of the union dictionary on
@ -314,7 +313,7 @@ adding a common field 'readonly', renaming the discriminator to
something more applicable, and reducing the number of {} required on something more applicable, and reducing the number of {} required on
the wire: the wire:
{ 'enum': 'BlockdevDriver', 'data': [ 'raw', 'qcow2' ] } { 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] }
{ 'struct': 'BlockdevCommonOptions', { 'struct': 'BlockdevCommonOptions',
'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } } 'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
{ 'union': 'BlockdevOptions', { 'union': 'BlockdevOptions',
@ -350,7 +349,7 @@ is identical on the wire to:
{ 'struct': 'Base', 'data': { 'type': 'Enum' } } { 'struct': 'Base', 'data': { 'type': 'Enum' } }
{ 'struct': 'Branch1', 'data': { 'data': 'str' } } { 'struct': 'Branch1', 'data': { 'data': 'str' } }
{ 'struct': 'Branch2', 'data': { 'data': 'int' } } { 'struct': 'Branch2', 'data': { 'data': 'int' } }
{ 'union': 'Flat': 'base': 'Base', 'discriminator': 'type', { 'union': 'Flat', 'base': 'Base', 'discriminator': 'type',
'data': { 'one': 'Branch1', 'two': 'Branch2' } } 'data': { 'one': 'Branch1', 'two': 'Branch2' } }
@ -394,7 +393,7 @@ following example objects:
=== Commands === === Commands ===
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT, Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME-OR-DICT, '*returns': TYPE-NAME,
'*gen': false, '*success-response': false } '*gen': false, '*success-response': false }
Commands are defined by using a dictionary containing several members, Commands are defined by using a dictionary containing several members,
@ -405,10 +404,9 @@ Client JSON Protocol command exchange.
The 'data' argument maps to the "arguments" dictionary passed in as The 'data' argument maps to the "arguments" dictionary passed in as
part of a Client JSON Protocol command. The 'data' member is optional part of a Client JSON Protocol command. The 'data' member is optional
and defaults to {} (an empty dictionary). If present, it must be the and defaults to {} (an empty dictionary). If present, it must be the
string name of a complex type, a one-element array containing the name string name of a complex type, or a dictionary that declares an
of a complex type, or a dictionary that declares an anonymous type anonymous type with the same semantics as a 'struct' expression, with
with the same semantics as a 'struct' expression, with one exception one exception noted below when 'gen' is used.
noted below when 'gen' is used.
The 'returns' member describes what will appear in the "return" field The 'returns' member describes what will appear in the "return" field
of a Client JSON Protocol reply on successful completion of a command. of a Client JSON Protocol reply on successful completion of a command.
@ -416,14 +414,13 @@ The member is optional from the command declaration; if absent, the
"return" field will be an empty dictionary. If 'returns' is present, "return" field will be an empty dictionary. If 'returns' is present,
it must be the string name of a complex or built-in type, a it must be the string name of a complex or built-in type, a
one-element array containing the name of a complex or built-in type, one-element array containing the name of a complex or built-in type,
or a dictionary that declares an anonymous type with the same with one exception noted below when 'gen' is used. Although it is
semantics as a 'struct' expression, with one exception noted below permitted to have the 'returns' member name a built-in type or an
when 'gen' is used. Although it is permitted to have the 'returns' array of built-in types, any command that does this cannot be extended
member name a built-in type or an array of built-in types, any command to return additional information in the future; thus, new commands
that does this cannot be extended to return additional information in should strongly consider returning a dictionary-based type or an array
the future; thus, new commands should strongly consider returning a of dictionaries, even if the dictionary only contains one field at the
dictionary-based type or an array of dictionaries, even if the present.
dictionary only contains one field at the present.
All commands in Client JSON Protocol use a dictionary to report All commands in Client JSON Protocol use a dictionary to report
failure, with no way to specify that in QAPI. Where the error return failure, with no way to specify that in QAPI. Where the error return
@ -555,6 +552,7 @@ Example:
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
} }
void qapi_free_UserDefOne(UserDefOne *obj) void qapi_free_UserDefOne(UserDefOne *obj)
{ {
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
@ -569,7 +567,6 @@ Example:
visit_type_UserDefOne(v, &obj, NULL, NULL); visit_type_UserDefOne(v, &obj, NULL, NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
} }
$ cat qapi-generated/example-qapi-types.h $ cat qapi-generated/example-qapi-types.h
[Uninteresting stuff omitted...] [Uninteresting stuff omitted...]
@ -580,8 +577,7 @@ Example:
typedef struct UserDefOne UserDefOne; typedef struct UserDefOne UserDefOne;
typedef struct UserDefOneList typedef struct UserDefOneList {
{
union { union {
UserDefOne *value; UserDefOne *value;
uint64_t padding; uint64_t padding;
@ -589,10 +585,10 @@ Example:
struct UserDefOneList *next; struct UserDefOneList *next;
} UserDefOneList; } UserDefOneList;
[Functions on built-in types omitted...] [Functions on built-in types omitted...]
struct UserDefOne struct UserDefOne {
{
int64_t integer; int64_t integer;
char *string; char *string;
}; };
@ -630,6 +626,7 @@ Example:
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne **obj, Error **errp) static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne **obj, Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
visit_type_int(m, &(*obj)->integer, "integer", &err); visit_type_int(m, &(*obj)->integer, "integer", &err);
if (err) { if (err) {
goto out; goto out;
@ -743,7 +740,7 @@ Example:
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp) static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
UserDefOne *retval = NULL; UserDefOne *retval;
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args)); QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
@ -769,7 +766,6 @@ Example:
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOne(v, &arg1, "arg1", NULL); visit_type_UserDefOne(v, &arg1, "arg1", NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
return;
} }
static void qmp_init_marshal(void) static void qmp_init_marshal(void)
@ -826,7 +822,7 @@ Example:
QDECREF(qmp); QDECREF(qmp);
} }
const char *EXAMPLE_QAPIEvent_lookup[] = { const char *example_QAPIEvent_lookup[] = {
"MY_EVENT", "MY_EVENT",
NULL, NULL,
}; };
@ -843,11 +839,10 @@ Example:
void qapi_event_send_my_event(Error **errp); void qapi_event_send_my_event(Error **errp);
extern const char *EXAMPLE_QAPIEvent_lookup[]; extern const char *example_QAPIEvent_lookup[];
typedef enum EXAMPLE_QAPIEvent typedef enum example_QAPIEvent {
{
EXAMPLE_QAPI_EVENT_MY_EVENT = 0, EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
EXAMPLE_QAPI_EVENT_MAX = 1, EXAMPLE_QAPI_EVENT_MAX = 1,
} EXAMPLE_QAPIEvent; } example_QAPIEvent;
#endif #endif

View File

@ -27,18 +27,19 @@ def generate_command_decl(name, args, ret_type):
%(ret_type)s qmp_%(name)s(%(args)sError **errp); %(ret_type)s qmp_%(name)s(%(args)sError **errp);
''', ''',
ret_type=c_type(ret_type), name=c_name(name), ret_type=c_type(ret_type), name=c_name(name),
args=arglist).strip() args=arglist)
def gen_err_check(errvar): def gen_err_check(err):
if errvar: if not err:
return mcgen(''' return ''
if (local_err) { return mcgen('''
if (%(err)s) {
goto out; goto out;
} }
''') ''',
return '' err=err)
def gen_sync_call(name, args, ret_type, indent=0): def gen_sync_call(name, args, ret_type):
ret = "" ret = ""
arglist="" arglist=""
retval="" retval=""
@ -48,41 +49,34 @@ def gen_sync_call(name, args, ret_type, indent=0):
if optional: if optional:
arglist += "has_%s, " % c_name(argname) arglist += "has_%s, " % c_name(argname)
arglist += "%s, " % (c_name(argname)) arglist += "%s, " % (c_name(argname))
push_indent(indent) push_indent()
ret = mcgen(''' ret = mcgen('''
%(retval)sqmp_%(name)s(%(args)s&local_err); %(retval)sqmp_%(name)s(%(args)s&local_err);
''', ''',
name=c_name(name), args=arglist, retval=retval).rstrip() name=c_name(name), args=arglist, retval=retval)
if ret_type: if ret_type:
ret += "\n" + gen_err_check('local_err') ret += gen_err_check('local_err')
ret += "\n" + mcgen('''' ret += mcgen('''
%(marshal_output_call)s
qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
''', ''',
marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip() c_name=c_name(name))
pop_indent(indent) pop_indent()
return ret.rstrip() return ret
def gen_visitor_input_containers_decl(args):
def gen_marshal_output_call(name, ret_type):
if not ret_type:
return ""
return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_name(name)
def gen_visitor_input_containers_decl(args, obj):
ret = "" ret = ""
push_indent() push_indent()
if len(args) > 0: if len(args) > 0:
ret += mcgen(''' ret += mcgen('''
QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s); QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
''', ''')
obj=obj)
pop_indent() pop_indent()
return ret.rstrip() return ret
def gen_visitor_input_vars_decl(args): def gen_visitor_input_vars_decl(args):
ret = "" ret = ""
@ -105,7 +99,7 @@ bool has_%(argname)s = false;
argname=c_name(argname), argtype=c_type(argtype)) argname=c_name(argname), argtype=c_type(argtype))
pop_indent() pop_indent()
return ret.rstrip() return ret
def gen_visitor_input_block(args, dealloc=False): def gen_visitor_input_block(args, dealloc=False):
ret = "" ret = ""
@ -159,9 +153,9 @@ visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
''') ''')
pop_indent() pop_indent()
return ret.rstrip() return ret
def gen_marshal_output(name, args, ret_type, middle_mode): def gen_marshal_output(name, ret_type):
if not ret_type: if not ret_type:
return "" return ""
@ -194,14 +188,14 @@ out:
return ret return ret
def gen_marshal_input_decl(name, args, ret_type, middle_mode): def gen_marshal_input_decl(name, middle_mode):
ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name) ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
if not middle_mode: if not middle_mode:
ret = "static " + ret ret = "static " + ret
return ret return ret
def gen_marshal_input(name, args, ret_type, middle_mode): def gen_marshal_input(name, args, ret_type, middle_mode):
hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode) hdr = gen_marshal_input_decl(name, middle_mode)
ret = mcgen(''' ret = mcgen('''
%(header)s %(header)s
@ -211,36 +205,24 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
header=hdr) header=hdr)
if ret_type: if ret_type:
if is_c_ptr(ret_type):
retval = " %s retval = NULL;" % c_type(ret_type)
else:
retval = " %s retval;" % c_type(ret_type)
ret += mcgen(''' ret += mcgen('''
%(retval)s %(c_type)s retval;
''', ''',
retval=retval) c_type=c_type(ret_type))
if len(args) > 0: if len(args) > 0:
ret += mcgen(''' ret += gen_visitor_input_containers_decl(args)
%(visitor_input_containers_decl)s ret += gen_visitor_input_vars_decl(args) + '\n'
%(visitor_input_vars_decl)s ret += gen_visitor_input_block(args) + '\n'
%(visitor_input_block)s
''',
visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"),
visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
visitor_input_block=gen_visitor_input_block(args))
else: else:
ret += mcgen(''' ret += mcgen('''
(void)args; (void)args;
''') ''')
ret += mcgen(''' ret += gen_sync_call(name, args, ret_type)
%(sync_call)s
''',
sync_call=gen_sync_call(name, args, ret_type, indent=4))
if re.search('^ *goto out\\;', ret, re.MULTILINE): if re.search('^ *goto out\\;', ret, re.MULTILINE):
ret += mcgen(''' ret += mcgen('''
@ -248,11 +230,11 @@ out:
''') ''')
ret += mcgen(''' ret += mcgen('''
error_propagate(errp, local_err); error_propagate(errp, local_err);
%(visitor_input_block_cleanup)s ''')
ret += gen_visitor_input_block(args, dealloc=True)
ret += mcgen('''
} }
''', ''')
visitor_input_block_cleanup=gen_visitor_input_block(args,
dealloc=True))
return ret return ret
def gen_registry(commands): def gen_registry(commands):
@ -272,12 +254,13 @@ qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
ret = mcgen(''' ret = mcgen('''
static void qmp_init_marshal(void) static void qmp_init_marshal(void)
{ {
%(registry)s ''')
ret += registry
ret += mcgen('''
} }
qapi_init(qmp_init_marshal); qapi_init(qmp_init_marshal);
''', ''')
registry=registry.rstrip())
return ret return ret
middle_mode = False middle_mode = False
@ -357,14 +340,14 @@ for cmd in commands:
arglist = cmd['data'] arglist = cmd['data']
if cmd.has_key('returns'): if cmd.has_key('returns'):
ret_type = cmd['returns'] ret_type = cmd['returns']
ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" ret = generate_command_decl(cmd['command'], arglist, ret_type)
fdecl.write(ret) fdecl.write(ret)
if ret_type: if ret_type:
ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n" ret = gen_marshal_output(cmd['command'], ret_type) + "\n"
fdef.write(ret) fdef.write(ret)
if middle_mode: if middle_mode:
fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], middle_mode))
ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
fdef.write(ret) fdef.write(ret)

View File

@ -167,8 +167,7 @@ extern const char *%(event_enum_name)s_lookup[];
event_enum_name = event_enum_name) event_enum_name = event_enum_name)
enum_decl = mcgen(''' enum_decl = mcgen('''
typedef enum %(event_enum_name)s typedef enum %(event_enum_name)s {
{
''', ''',
event_enum_name = event_enum_name) event_enum_name = event_enum_name)
@ -199,7 +198,6 @@ const char *%(event_enum_name)s_lookup[] = {
''', ''',
event_enum_name = event_enum_name) event_enum_name = event_enum_name)
i = 0
for string in event_enum_strings: for string in event_enum_strings:
ret += mcgen(''' ret += mcgen('''
"%(string)s", "%(string)s",
@ -267,7 +265,7 @@ fdecl.write(mcgen('''
exprs = parse_schema(input_file) exprs = parse_schema(input_file)
event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent" event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
event_enum_values = [] event_enum_values = []
event_enum_strings = [] event_enum_strings = []

View File

@ -15,8 +15,7 @@ from qapi import *
def generate_fwd_builtin(name): def generate_fwd_builtin(name):
return mcgen(''' return mcgen('''
typedef struct %(name)sList typedef struct %(name)sList {
{
union { union {
%(type)s value; %(type)s value;
uint64_t padding; uint64_t padding;
@ -32,8 +31,7 @@ def generate_fwd_struct(name):
typedef struct %(name)s %(name)s; typedef struct %(name)s %(name)s;
typedef struct %(name)sList typedef struct %(name)sList {
{
union { union {
%(name)s *value; %(name)s *value;
uint64_t padding; uint64_t padding;
@ -45,8 +43,8 @@ typedef struct %(name)sList
def generate_fwd_enum_struct(name): def generate_fwd_enum_struct(name):
return mcgen(''' return mcgen('''
typedef struct %(name)sList
{ typedef struct %(name)sList {
union { union {
%(name)s value; %(name)s value;
uint64_t padding; uint64_t padding;
@ -79,8 +77,8 @@ def generate_struct(expr):
base = expr.get('base') base = expr.get('base')
ret = mcgen(''' ret = mcgen('''
struct %(name)s
{ struct %(name)s {
''', ''',
name=c_name(structname)) name=c_name(structname))
@ -105,10 +103,10 @@ struct %(name)s
def generate_enum_lookup(name, values): def generate_enum_lookup(name, values):
ret = mcgen(''' ret = mcgen('''
const char * const %(name)s_lookup[] = {
const char *const %(name)s_lookup[] = {
''', ''',
name=c_name(name)) name=c_name(name))
i = 0
for value in values: for value in values:
index = c_enum_const(name, value) index = c_enum_const(name, value)
ret += mcgen(''' ret += mcgen('''
@ -120,7 +118,6 @@ const char * const %(name)s_lookup[] = {
ret += mcgen(''' ret += mcgen('''
[%(max_index)s] = NULL, [%(max_index)s] = NULL,
}; };
''', ''',
max_index=max_index) max_index=max_index)
return ret return ret
@ -128,13 +125,14 @@ const char * const %(name)s_lookup[] = {
def generate_enum(name, values): def generate_enum(name, values):
name = c_name(name) name = c_name(name)
lookup_decl = mcgen(''' lookup_decl = mcgen('''
extern const char * const %(name)s_lookup[];
extern const char *const %(name)s_lookup[];
''', ''',
name=name) name=name)
enum_decl = mcgen(''' enum_decl = mcgen('''
typedef enum %(name)s
{ typedef enum %(name)s {
''', ''',
name=name) name=name)
@ -156,7 +154,7 @@ typedef enum %(name)s
''', ''',
name=name) name=name)
return lookup_decl + enum_decl return enum_decl + lookup_decl
def generate_alternate_qtypes(expr): def generate_alternate_qtypes(expr):
@ -164,6 +162,7 @@ def generate_alternate_qtypes(expr):
members = expr['data'] members = expr['data']
ret = mcgen(''' ret = mcgen('''
const int %(name)s_qtypes[QTYPE_MAX] = { const int %(name)s_qtypes[QTYPE_MAX] = {
''', ''',
name=c_name(name)) name=c_name(name))
@ -199,14 +198,40 @@ def generate_union(expr, meta):
discriminator_type_name = '%sKind' % (name) discriminator_type_name = '%sKind' % (name)
ret = mcgen(''' ret = mcgen('''
struct %(name)s
{ struct %(name)s {
''',
name=name)
if base:
ret += mcgen('''
/* Members inherited from %(c_name)s: */
''',
c_name=c_name(base))
base_fields = find_struct(base)['data']
ret += generate_struct_fields(base_fields)
ret += mcgen('''
/* Own members: */
''')
else:
assert not discriminator
ret += mcgen('''
%(discriminator_type_name)s kind; %(discriminator_type_name)s kind;
union { ''',
discriminator_type_name=c_name(discriminator_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
# whether to bypass the switch statement if visiting the discriminator
# failed; but since we 0-initialize structs, and cannot tell what
# branch of the union is in use if the discriminator is invalid, there
# should not be any data leaks even without a data pointer. Or, if
# 'data' is merely added to guarantee we don't have an empty union,
# shouldn't we enforce that at .json parse time?
ret += mcgen('''
union { /* union tag is @%(c_name)s */
void *data; void *data;
''', ''',
name=name, c_name=c_name(discriminator or 'kind'))
discriminator_type_name=c_name(discriminator_type_name))
for key in typeinfo: for key in typeinfo:
ret += mcgen(''' ret += mcgen('''
@ -217,17 +242,6 @@ struct %(name)s
ret += mcgen(''' ret += mcgen('''
}; };
''')
if base:
assert discriminator
base_fields = find_struct(base)['data'].copy()
del base_fields[discriminator]
ret += generate_struct_fields(base_fields)
else:
assert not discriminator
ret += mcgen('''
}; };
''') ''')
if meta == 'alternate': if meta == 'alternate':
@ -314,14 +328,12 @@ fdef.write(mcgen('''
#include "qapi/dealloc-visitor.h" #include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h" #include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h" #include "%(prefix)sqapi-visit.h"
''', ''',
prefix=prefix)) prefix=prefix))
fdecl.write(mcgen(''' fdecl.write(mcgen('''
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
''')) '''))
exprs = parse_schema(input_file) exprs = parse_schema(input_file)
@ -332,22 +344,22 @@ for typename in builtin_types.keys():
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL")) fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
for expr in exprs: for expr in exprs:
ret = "\n" ret = ""
if expr.has_key('struct'): if expr.has_key('struct'):
ret += generate_fwd_struct(expr['struct']) ret += generate_fwd_struct(expr['struct'])
elif expr.has_key('enum'): elif expr.has_key('enum'):
ret += generate_enum(expr['enum'], expr['data']) + "\n" ret += generate_enum(expr['enum'], expr['data'])
ret += generate_fwd_enum_struct(expr['enum']) ret += generate_fwd_enum_struct(expr['enum'])
fdef.write(generate_enum_lookup(expr['enum'], expr['data'])) fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
elif expr.has_key('union'): elif expr.has_key('union'):
ret += generate_fwd_struct(expr['union']) + "\n" ret += generate_fwd_struct(expr['union'])
enum_define = discriminator_find_enum_define(expr) enum_define = discriminator_find_enum_define(expr)
if not enum_define: if not enum_define:
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys()) ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['union'], fdef.write(generate_enum_lookup('%sKind' % expr['union'],
expr['data'].keys())) expr['data'].keys()))
elif expr.has_key('alternate'): elif expr.has_key('alternate'):
ret += generate_fwd_struct(expr['alternate']) + "\n" ret += generate_fwd_struct(expr['alternate'])
ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys()) ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['alternate'], fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
expr['data'].keys())) expr['data'].keys()))
@ -367,34 +379,32 @@ fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
# have the functions defined, so we use -b option to provide control # have the functions defined, so we use -b option to provide control
# over these cases # over these cases
if do_builtins: if do_builtins:
fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for typename in builtin_types.keys(): for typename in builtin_types.keys():
fdef.write(generate_type_cleanup(typename + "List")) fdef.write(generate_type_cleanup(typename + "List"))
fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for expr in exprs: for expr in exprs:
ret = "\n" ret = ""
if expr.has_key('struct'): if expr.has_key('struct'):
ret += generate_struct(expr) + "\n" ret += generate_struct(expr) + "\n"
ret += generate_type_cleanup_decl(expr['struct'] + "List") ret += generate_type_cleanup_decl(expr['struct'] + "List")
fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n") fdef.write(generate_type_cleanup(expr['struct'] + "List"))
ret += generate_type_cleanup_decl(expr['struct']) ret += generate_type_cleanup_decl(expr['struct'])
fdef.write(generate_type_cleanup(expr['struct']) + "\n") fdef.write(generate_type_cleanup(expr['struct']))
elif expr.has_key('union'): elif expr.has_key('union'):
ret += generate_union(expr, 'union') ret += generate_union(expr, 'union') + "\n"
ret += generate_type_cleanup_decl(expr['union'] + "List") ret += generate_type_cleanup_decl(expr['union'] + "List")
fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n") fdef.write(generate_type_cleanup(expr['union'] + "List"))
ret += generate_type_cleanup_decl(expr['union']) ret += generate_type_cleanup_decl(expr['union'])
fdef.write(generate_type_cleanup(expr['union']) + "\n") fdef.write(generate_type_cleanup(expr['union']))
elif expr.has_key('alternate'): elif expr.has_key('alternate'):
ret += generate_union(expr, 'alternate') ret += generate_union(expr, 'alternate') + "\n"
ret += generate_type_cleanup_decl(expr['alternate'] + "List") ret += generate_type_cleanup_decl(expr['alternate'] + "List")
fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n") fdef.write(generate_type_cleanup(expr['alternate'] + "List"))
ret += generate_type_cleanup_decl(expr['alternate']) ret += generate_type_cleanup_decl(expr['alternate'])
fdef.write(generate_type_cleanup(expr['alternate']) + "\n") fdef.write(generate_type_cleanup(expr['alternate']))
elif expr.has_key('enum'): elif expr.has_key('enum'):
ret += generate_type_cleanup_decl(expr['enum'] + "List") ret += "\n" + generate_type_cleanup_decl(expr['enum'] + "List")
fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n") fdef.write(generate_type_cleanup(expr['enum'] + "List"))
else: else:
continue continue
fdecl.write(ret) fdecl.write(ret)

View File

@ -16,14 +16,23 @@ from ordereddict import OrderedDict
from qapi import * from qapi import *
import re import re
implicit_structs = [] implicit_structs_seen = set()
struct_fields_seen = set()
def generate_visit_implicit_struct(type): def generate_visit_implicit_struct(type):
global implicit_structs if type in implicit_structs_seen:
if type in implicit_structs:
return '' return ''
implicit_structs.append(type) implicit_structs_seen.add(type)
return mcgen(''' ret = ''
if type 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_name(type))
ret += mcgen('''
static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp) static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
{ {
@ -38,9 +47,11 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error *
} }
''', ''',
c_type=type_name(type)) c_type=type_name(type))
return ret
def generate_visit_struct_fields(name, members, base = None): def generate_visit_struct_fields(name, members, base = None):
substructs = [] struct_fields_seen.add(name)
ret = '' ret = ''
if base: if base:
@ -51,6 +62,7 @@ def generate_visit_struct_fields(name, members, base = None):
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp) static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
''', ''',
name=c_name(name)) name=c_name(name))
push_indent() push_indent()
@ -103,7 +115,11 @@ out:
return ret return ret
def generate_visit_struct_body(name, members): def generate_visit_struct_body(name):
# FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
# *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
# rather than leaving it non-NULL. As currently written, the caller must
# call qapi_free_FOO() to avoid a memory leak of the partial FOO.
ret = mcgen(''' ret = mcgen('''
Error *err = NULL; Error *err = NULL;
@ -135,14 +151,14 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
''', ''',
name=c_name(name)) name=c_name(name))
ret += generate_visit_struct_body(name, members) ret += generate_visit_struct_body(name)
ret += mcgen(''' ret += mcgen('''
} }
''') ''')
return ret return ret
def generate_visit_list(name, members): def generate_visit_list(name):
return mcgen(''' return mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp) void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
@ -171,15 +187,15 @@ out:
''', ''',
name=type_name(name)) name=type_name(name))
def generate_visit_enum(name, members): def generate_visit_enum(name):
return mcgen(''' 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)
{ {
visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp); visit_type_enum(m, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
} }
''', ''',
name=c_name(name)) c_name=c_name(name), name=name)
def generate_visit_alternate(name, members): def generate_visit_alternate(name, members):
ret = mcgen(''' ret = mcgen('''
@ -252,7 +268,7 @@ def generate_visit_union(expr):
else: else:
# There will always be a discriminator in the C switch code, by default # There will always be a discriminator in the C switch code, by default
# it is an enum type generated silently # it is an enum type generated silently
ret = generate_visit_enum(name + 'Kind', members.keys()) ret = generate_visit_enum(name + 'Kind')
disc_type = c_name(name) + 'Kind' disc_type = c_name(name) + 'Kind'
if base: if base:
@ -267,17 +283,17 @@ def generate_visit_union(expr):
ret += mcgen(''' 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; Error *err = NULL;
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
if (err) { if (err) {
goto out; goto out;
} }
if (*obj) { if (*obj) {
''', ''',
name=c_name(name)) c_name=c_name(name), name=name)
if base: if base:
ret += mcgen(''' ret += mcgen('''
@ -289,20 +305,23 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
name=c_name(name)) name=c_name(name))
if not discriminator: if not discriminator:
tag = 'kind'
disc_key = "type" disc_key = "type"
else: else:
tag = discriminator
disc_key = discriminator disc_key = discriminator
ret += mcgen(''' ret += mcgen('''
visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
if (err) { if (err) {
goto out_obj; goto out_obj;
} }
if (!visit_start_union(m, !!(*obj)->data, &err) || err) { if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
goto out_obj; goto out_obj;
} }
switch ((*obj)->kind) { switch ((*obj)->%(c_tag)s) {
''', ''',
disc_type = disc_type, disc_type = disc_type,
c_tag=c_name(tag),
disc_key = disc_key) disc_key = disc_key)
for key in members: for key in members:
@ -340,7 +359,7 @@ out:
return ret return ret
def generate_declaration(name, members, builtin_type=False): def generate_declaration(name, builtin_type=False):
ret = "" ret = ""
if not builtin_type: if not builtin_type:
name = c_name(name) name = c_name(name)
@ -357,7 +376,7 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
return ret return ret
def generate_enum_declaration(name, members): def generate_enum_declaration(name):
ret = mcgen(''' ret = mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp); void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
''', ''',
@ -365,7 +384,7 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
return ret return ret
def generate_decl_enum(name, members): def generate_decl_enum(name):
return mcgen(''' return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp); void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
@ -433,7 +452,7 @@ exprs = parse_schema(input_file)
# for built-in types in our header files and simply guard them # for built-in types in our header files and simply guard them
fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL")) fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
for typename in builtin_types.keys(): for typename in builtin_types.keys():
fdecl.write(generate_declaration(typename, None, builtin_type=True)) fdecl.write(generate_declaration(typename, builtin_type=True))
fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL")) fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# ...this doesn't work for cases where we link in multiple objects that # ...this doesn't work for cases where we link in multiple objects that
@ -441,44 +460,42 @@ fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# over these cases # over these cases
if do_builtins: if do_builtins:
for typename in builtin_types.keys(): for typename in builtin_types.keys():
fdef.write(generate_visit_list(typename, None)) fdef.write(generate_visit_list(typename))
for expr in exprs: for expr in exprs:
if expr.has_key('struct'): if expr.has_key('struct'):
ret = generate_visit_struct(expr) ret = generate_visit_struct(expr)
ret += generate_visit_list(expr['struct'], expr['data']) ret += generate_visit_list(expr['struct'])
fdef.write(ret) fdef.write(ret)
ret = generate_declaration(expr['struct'], expr['data']) ret = generate_declaration(expr['struct'])
fdecl.write(ret) fdecl.write(ret)
elif expr.has_key('union'): elif expr.has_key('union'):
ret = generate_visit_union(expr) ret = generate_visit_union(expr)
ret += generate_visit_list(expr['union'], expr['data']) ret += generate_visit_list(expr['union'])
fdef.write(ret) fdef.write(ret)
enum_define = discriminator_find_enum_define(expr) enum_define = discriminator_find_enum_define(expr)
ret = "" ret = ""
if not enum_define: if not enum_define:
ret = generate_decl_enum('%sKind' % expr['union'], ret = generate_decl_enum('%sKind' % expr['union'])
expr['data'].keys()) ret += generate_declaration(expr['union'])
ret += generate_declaration(expr['union'], expr['data'])
fdecl.write(ret) fdecl.write(ret)
elif expr.has_key('alternate'): elif expr.has_key('alternate'):
ret = generate_visit_alternate(expr['alternate'], expr['data']) ret = generate_visit_alternate(expr['alternate'], expr['data'])
ret += generate_visit_list(expr['alternate'], expr['data']) ret += generate_visit_list(expr['alternate'])
fdef.write(ret) fdef.write(ret)
ret = generate_decl_enum('%sKind' % expr['alternate'], ret = generate_decl_enum('%sKind' % expr['alternate'])
expr['data'].keys()) ret += generate_declaration(expr['alternate'])
ret += generate_declaration(expr['alternate'], expr['data'])
fdecl.write(ret) fdecl.write(ret)
elif expr.has_key('enum'): elif expr.has_key('enum'):
ret = generate_visit_list(expr['enum'], expr['data']) ret = generate_visit_list(expr['enum'])
ret += generate_visit_enum(expr['enum'], expr['data']) ret += generate_visit_enum(expr['enum'])
fdef.write(ret) fdef.write(ret)
ret = generate_decl_enum(expr['enum'], expr['data']) ret = generate_decl_enum(expr['enum'])
ret += generate_enum_declaration(expr['enum'], expr['data']) ret += generate_enum_declaration(expr['enum'])
fdecl.write(ret) fdecl.write(ret)
close_output(fdef, fdecl) close_output(fdef, fdecl)

View File

@ -341,6 +341,8 @@ def discriminator_find_enum_define(expr):
return find_enum(discriminator_type) return find_enum(discriminator_type)
# FIXME should enforce "other than downstream extensions [...], all
# names should begin with a letter".
valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$') valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
def check_name(expr_info, source, name, allow_optional = False, def check_name(expr_info, source, name, allow_optional = False,
enum_member = False): enum_member = False):
@ -367,6 +369,8 @@ def check_name(expr_info, source, name, allow_optional = False,
def add_name(name, info, meta, implicit = False): def add_name(name, info, meta, implicit = False):
global all_names global all_names
check_name(info, "'%s'" % meta, name) check_name(info, "'%s'" % meta, name)
# FIXME should reject names that differ only in '_' vs. '.'
# vs. '-', because they're liable to clash in generated C.
if name in all_names: if name in all_names:
raise QAPIExprError(info, raise QAPIExprError(info,
"%s '%s' is already defined" "%s '%s' is already defined"
@ -422,7 +426,6 @@ def check_type(expr_info, source, value, allow_array = False,
allow_dict = False, allow_optional = False, allow_dict = False, allow_optional = False,
allow_star = False, allow_metas = []): allow_star = False, allow_metas = []):
global all_names global all_names
orig_value = value
if value is None: if value is None:
return return
@ -440,7 +443,6 @@ def check_type(expr_info, source, value, allow_array = False,
"%s: array type must contain single type name" "%s: array type must contain single type name"
% source) % source)
value = value[0] value = value[0]
orig_value = "array of %s" %value
# Check if type name for value is okay # Check if type name for value is okay
if isinstance(value, str): if isinstance(value, str):
@ -451,20 +453,22 @@ def check_type(expr_info, source, value, allow_array = False,
if not value in all_names: if not value in all_names:
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
"%s uses unknown type '%s'" "%s uses unknown type '%s'"
% (source, orig_value)) % (source, value))
if not all_names[value] in allow_metas: if not all_names[value] in allow_metas:
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
"%s cannot use %s type '%s'" "%s cannot use %s type '%s'"
% (source, all_names[value], orig_value)) % (source, all_names[value], value))
return return
# value is a dictionary, check that each member is okay
if not isinstance(value, OrderedDict):
raise QAPIExprError(expr_info,
"%s should be a dictionary" % source)
if not allow_dict: if not allow_dict:
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
"%s should be a type name" % source) "%s should be a type name" % source)
if not isinstance(value, OrderedDict):
raise QAPIExprError(expr_info,
"%s should be a dictionary or type name" % source)
# value is a dictionary, check that each member is okay
for (key, arg) in value.items(): for (key, arg) in value.items():
check_name(expr_info, "Member of %s" % source, key, check_name(expr_info, "Member of %s" % source, key,
allow_optional=allow_optional) allow_optional=allow_optional)
@ -495,26 +499,25 @@ def check_command(expr, expr_info):
check_type(expr_info, "'data' for command '%s'" % name, check_type(expr_info, "'data' for command '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True, expr.get('data'), allow_dict=True, allow_optional=True,
allow_metas=['union', 'struct'], allow_star=allow_star) allow_metas=['struct'], allow_star=allow_star)
returns_meta = ['union', 'struct'] returns_meta = ['union', 'struct']
if name in returns_whitelist: if name in returns_whitelist:
returns_meta += ['built-in', 'alternate', 'enum'] returns_meta += ['built-in', 'alternate', 'enum']
check_type(expr_info, "'returns' for command '%s'" % name, check_type(expr_info, "'returns' for command '%s'" % name,
expr.get('returns'), allow_array=True, allow_dict=True, expr.get('returns'), allow_array=True,
allow_optional=True, allow_metas=returns_meta, allow_optional=True, allow_metas=returns_meta,
allow_star=allow_star) allow_star=allow_star)
def check_event(expr, expr_info): def check_event(expr, expr_info):
global events global events
name = expr['event'] name = expr['event']
params = expr.get('data')
if name.upper() == 'MAX': if name.upper() == 'MAX':
raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created") raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
events.append(name) events.append(name)
check_type(expr_info, "'data' for event '%s'" % name, check_type(expr_info, "'data' for event '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True, expr.get('data'), allow_dict=True, allow_optional=True,
allow_metas=['union', 'struct']) allow_metas=['struct'])
def check_union(expr, expr_info): def check_union(expr, expr_info):
name = expr['union'] name = expr['union']
@ -523,14 +526,6 @@ def check_union(expr, expr_info):
members = expr['data'] members = expr['data']
values = { 'MAX': '(automatic)' } values = { 'MAX': '(automatic)' }
# If the object has a member 'base', its value must name a struct,
# and there must be a discriminator.
if base is not None:
if discriminator is None:
raise QAPIExprError(expr_info,
"Union '%s' requires a discriminator to go "
"along with base" %name)
# Two types of unions, determined by discriminator. # Two types of unions, determined by discriminator.
# With no discriminator it is a simple union. # With no discriminator it is a simple union.
@ -943,24 +938,24 @@ def pop_indent(indent_amount=4):
global indent_level global indent_level
indent_level -= indent_amount indent_level -= indent_amount
# Generate @code with @kwds interpolated.
# Obey indent_level, and strip eatspace.
def cgen(code, **kwds): def cgen(code, **kwds):
indent = genindent(indent_level) raw = code % kwds
lines = code.split('\n') if indent_level:
lines = map(lambda x: indent + x, lines) indent = genindent(indent_level)
return '\n'.join(lines) % kwds + '\n' raw = re.subn("^.", indent + r'\g<0>', raw, 0, re.MULTILINE)
raw = raw[0]
def mcgen(code, **kwds):
raw = cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
return re.sub(re.escape(eatspace) + ' *', '', raw) return re.sub(re.escape(eatspace) + ' *', '', raw)
def basename(filename): def mcgen(code, **kwds):
return filename.split("/")[-1] if code[0] == '\n':
code = code[1:]
return cgen(code, **kwds)
def guardname(filename): def guardname(filename):
guard = basename(filename).rsplit(".", 1)[0] return c_name(filename, protect=False).upper()
for substr in [".", " ", "-"]:
guard = guard.replace(substr, "_")
return guard.upper() + '_H'
def guardstart(name): def guardstart(name):
return mcgen(''' return mcgen('''
@ -1003,6 +998,12 @@ def parse_command_line(extra_options = "", extra_long_options = []):
for oa in opts: for oa in opts:
o, a = oa o, a = oa
if o in ("-p", "--prefix"): if o in ("-p", "--prefix"):
match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
if match.end() != len(a):
print >>sys.stderr, \
"%s: 'funny character '%s' in argument of --prefix" \
% (sys.argv[0], a[match.end()])
sys.exit(1)
prefix = a prefix = a
elif o in ("-o", "--output-dir"): elif o in ("-o", "--output-dir"):
output_dir = a + "/" output_dir = a + "/"
@ -1030,14 +1031,16 @@ def parse_command_line(extra_options = "", extra_long_options = []):
def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
c_comment, h_comment): c_comment, h_comment):
guard = guardname(prefix + h_file)
c_file = output_dir + prefix + c_file c_file = output_dir + prefix + c_file
h_file = output_dir + prefix + h_file h_file = output_dir + prefix + h_file
try: if output_dir:
os.makedirs(output_dir) try:
except os.error, e: os.makedirs(output_dir)
if e.errno != errno.EEXIST: except os.error, e:
raise if e.errno != errno.EEXIST:
raise
def maybe_open(really, name, opt): def maybe_open(really, name, opt):
if really: if really:
@ -1062,7 +1065,7 @@ def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
#define %(guard)s #define %(guard)s
''', ''',
comment = h_comment, guard = guardname(h_file))) comment = h_comment, guard = guard))
return (fdef, fdecl) return (fdef, fdecl)

View File

@ -229,13 +229,17 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
redefined-type.json redefined-command.json redefined-builtin.json \ redefined-type.json redefined-command.json redefined-builtin.json \
redefined-event.json command-int.json bad-data.json event-max.json \ redefined-event.json command-int.json bad-data.json event-max.json \
type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \ type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \
data-array-empty.json data-array-unknown.json data-int.json \ args-invalid.json \
data-unknown.json data-member-unknown.json data-member-array.json \ args-array-empty.json args-array-unknown.json args-int.json \
data-member-array-bad.json returns-array-bad.json returns-int.json \ args-unknown.json args-member-unknown.json args-member-array.json \
args-member-array-bad.json args-alternate.json args-union.json \
returns-array-bad.json returns-int.json returns-dict.json \
returns-unknown.json returns-alternate.json returns-whitelist.json \ returns-unknown.json returns-alternate.json returns-whitelist.json \
missing-colon.json missing-comma-list.json missing-comma-object.json \ missing-colon.json missing-comma-list.json missing-comma-object.json \
nested-struct-data.json nested-struct-returns.json non-objects.json \ struct-data-invalid.json struct-member-invalid.json \
nested-struct-data.json non-objects.json \
qapi-schema-test.json quoted-structural-chars.json \ qapi-schema-test.json quoted-structural-chars.json \
leading-comma-list.json leading-comma-object.json \
trailing-comma-list.json trailing-comma-object.json \ trailing-comma-list.json trailing-comma-object.json \
unclosed-list.json unclosed-object.json unclosed-string.json \ unclosed-list.json unclosed-object.json unclosed-string.json \
duplicate-key.json union-invalid-base.json union-bad-branch.json \ duplicate-key.json union-invalid-base.json union-bad-branch.json \

View File

@ -0,0 +1 @@
tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt'

View File

@ -0,0 +1,3 @@
# we do not allow alternate arguments
{ 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } }
{ 'command': 'oops', 'data': 'Alt' }

View File

@ -1 +1 @@
tests/qapi-schema/data-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name

View File

@ -0,0 +1 @@
tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'

View File

@ -0,0 +1 @@
tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name

View File

@ -0,0 +1,2 @@
{ 'command': 'foo',
'data': false }

View File

@ -1 +1 @@
tests/qapi-schema/data-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name

View File

@ -0,0 +1 @@
tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
tests/qapi-schema/args-union.json:4: 'data' for command 'oops' cannot use union type 'Uni'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
# we do not allow union arguments
# TODO should we support this?
{ 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } }
{ 'command': 'oops', 'data': 'Uni' }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
1

View File

View File

@ -1,3 +1,2 @@
# we reject collisions between commands and types # we reject collisions between commands and types
{ 'command': 'int', 'data': { 'character': 'str' }, { 'command': 'int', 'data': { 'character': 'str' } }
'returns': { 'value': 'int' } }

View File

@ -1 +0,0 @@
tests/qapi-schema/data-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'array of NoSuchType'

View File

@ -1 +0,0 @@
tests/qapi-schema/data-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'

View File

@ -1 +0,0 @@
tests/qapi-schema/data-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -1 +0,0 @@
tests/qapi-schema/data-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean or "null"

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'enum': 'Status',
'data': [ , 'good', 'bad', 'ugly' ] }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/leading-comma-object.json:1:3: Expected string or "}"

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ , 'enum': 'Status',
'data': [ 'good', 'bad', 'ugly' ] }

View File

@ -1,4 +1,3 @@
# inline subtypes collide with our desired future use of defaults # inline subtypes collide with our desired future use of defaults
{ 'command': 'foo', { 'command': 'foo',
'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' }, 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
'returns': {} }

View File

@ -1 +0,0 @@
tests/qapi-schema/nested-struct-returns.json:2: Member 'a' of 'returns' for command 'foo' should be a type name

View File

@ -1,3 +0,0 @@
# inline subtypes collide with our desired future use of defaults
{ 'command': 'foo',
'returns': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }

View File

@ -7,13 +7,13 @@
'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } } 'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
# for testing nested structs # for testing nested structs
{ 'struct': 'UserDefOne',
'base': 'UserDefZero', # intentional forward reference
'data': { 'string': 'str', '*enum1': 'EnumOne' } }
{ 'struct': 'UserDefZero', { 'struct': 'UserDefZero',
'data': { 'integer': 'int' } } 'data': { 'integer': 'int' } }
{ 'struct': 'UserDefOne',
'base': 'UserDefZero',
'data': { 'string': 'str', '*enum1': 'EnumOne' } }
{ 'struct': 'UserDefTwoDictDict', { 'struct': 'UserDefTwoDictDict',
'data': { 'userdef': 'UserDefOne', 'string': 'str' } } 'data': { 'userdef': 'UserDefOne', 'string': 'str' } }
@ -31,30 +31,36 @@
'data': { 'boolean': 'bool' } } 'data': { 'boolean': 'bool' } }
{ 'struct': 'UserDefB', { 'struct': 'UserDefB',
'data': { 'integer': 'int' } } 'data': { 'intb': 'int' } }
{ 'struct': 'UserDefC',
'data': { 'string1': 'str', 'string2': 'str' } }
{ 'struct': 'UserDefUnionBase',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
{ 'union': 'UserDefFlatUnion', { 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase', 'base': 'UserDefUnionBase', # intentional forward reference
'discriminator': 'enum1', 'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA', 'value2' : 'UserDefB', 'value3' : 'UserDefB' } } 'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
# FIXME generated struct UserDefFlatUnion has members for direct base # FIXME generated struct UserDefFlatUnion has members for direct base
# UserDefOne, but lacks members for indirect base UserDefZero # UserDefUnionBase, but lacks members for indirect base UserDefZero
{ 'struct': 'UserDefUnionBase',
'base': 'UserDefZero',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
# this variant of UserDefFlatUnion defaults to a union that uses fields with # this variant of UserDefFlatUnion defaults to a union that uses fields with
# allocated types to test corner cases in the cleanup/dealloc visitor # allocated types to test corner cases in the cleanup/dealloc visitor
{ 'union': 'UserDefFlatUnion2', { 'union': 'UserDefFlatUnion2',
'base': 'UserDefUnionBase', 'base': 'UserDefUnionBase',
'discriminator': 'enum1', 'discriminator': 'enum1',
'data': { 'value1' : 'UserDefC', 'value2' : 'UserDefB', 'value3' : 'UserDefA' } } 'data': { 'value1' : 'UserDefC', # intentional forward reference
'value2' : 'UserDefB',
'value3' : 'UserDefA' } }
{ 'alternate': 'UserDefAlternate', { 'alternate': 'UserDefAlternate',
'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } } 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
# FIXME only a declaration of visit_type_UserDefAlternateKind() generated
{ 'struct': 'UserDefC',
'data': { 'string1': 'str', 'string2': 'str' } }
# for testing native lists # for testing native lists
{ 'union': 'UserDefNativeListUnion', { 'union': 'UserDefNativeListUnion',
@ -123,6 +129,9 @@
{ 'alternate': '__org.qemu_x-Alt', { 'alternate': '__org.qemu_x-Alt',
'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } } 'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } }
{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' } { 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
# FIXME generated qapi_event_send___org_qemu_x_event() has only a
# parameter for data's member __org_qemu_x_member2, none for its base
# __org.qemu_x-Base's member __org_qemu_x_member1
{ 'command': '__org.qemu_x-command', { 'command': '__org.qemu_x-command',
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'], 'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' }, 'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },

View File

@ -1,17 +1,17 @@
[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]), [OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]),
OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]), OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]), OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]), OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('intb', 'int')]))]),
OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]), OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]), OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]),
OrderedDict([('alternate', 'UserDefAlternate'), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]), OrderedDict([('alternate', 'UserDefAlternate'), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]),
OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str']), ('sizes', ['size'])]))]), OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str']), ('sizes', ['size'])]))]),
OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]),
OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]),
@ -39,15 +39,15 @@
{'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None}, {'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None},
{'enum_name': '__org.qemu_x-AltKind', 'enum_values': None}] {'enum_name': '__org.qemu_x-AltKind', 'enum_values': None}]
[OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), [OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]), OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]), OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]), OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('intb', 'int')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]),
OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]), OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]),
OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]),

View File

@ -0,0 +1 @@
tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject inline struct return type
{ 'command': 'oops', 'returns': { 'a': 'str' } }

View File

View File

@ -1 +1 @@
tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'array of int' tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'

View File

@ -0,0 +1 @@
tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'struct': 'foo',
'data': false }

View File

@ -0,0 +1 @@
tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'struct': 'foo',
'data': { 'a': false } }

View File

@ -1 +1 @@
tests/qapi-schema/union-base-no-discriminator.json:11: Union 'TestUnion' requires a discriminator to go along with base tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base

View File

@ -94,7 +94,7 @@ static bool qdict_cmp_simple(QDict *a, QDict *b)
/* This function is hooked as final emit function, which can verify the /* This function is hooked as final emit function, which can verify the
correctness. */ correctness. */
static void event_test_emit(TEST_QAPIEvent event, QDict *d, Error **errp) static void event_test_emit(test_QAPIEvent event, QDict *d, Error **errp)
{ {
QObject *obj; QObject *obj;
QDict *t; QDict *t;

View File

@ -313,7 +313,7 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
g_assert(err == NULL); g_assert(err == NULL);
g_assert_cmpint(tmp->kind, ==, ENUM_ONE_VALUE1); g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
g_assert_cmpstr(tmp->string, ==, "str"); g_assert_cmpstr(tmp->string, ==, "str");
/* TODO g_assert_cmpint(tmp->integer, ==, 41); */ /* TODO g_assert_cmpint(tmp->integer, ==, 41); */
g_assert_cmpint(tmp->value1->boolean, ==, true); g_assert_cmpint(tmp->value1->boolean, ==, true);
@ -636,6 +636,8 @@ static void test_visitor_in_errors(TestInputVisitorData *data,
visit_type_TestStruct(v, &p, NULL, &err); visit_type_TestStruct(v, &p, NULL, &err);
g_assert(err); g_assert(err);
/* FIXME - a failed parse should not leave a partially-allocated p
* for us to clean up; this could cause callers to leak memory. */
g_assert(p->string == NULL); g_assert(p->string == NULL);
error_free(err); error_free(err);

View File

@ -437,7 +437,7 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
Error *err = NULL; Error *err = NULL;
UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion)); UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
tmp->kind = ENUM_ONE_VALUE1; tmp->enum1 = ENUM_ONE_VALUE1;
tmp->string = g_strdup("str"); tmp->string = g_strdup("str");
tmp->value1 = g_malloc0(sizeof(UserDefA)); tmp->value1 = g_malloc0(sizeof(UserDefA));
/* TODO when generator bug is fixed: tmp->integer = 41; */ /* TODO when generator bug is fixed: tmp->integer = 41; */