* [Qemu-devel] [PATCH v8 01/26] qapi: Rename class QAPISchema to QAPISchemaParser
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation Markus Armbruster
` (26 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
I want to name a new class QAPISchema.
While there, make it a new-style class.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
scripts/qapi.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index c4423b7..2a0f465 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -103,7 +103,7 @@ class QAPIExprError(Exception):
return error_path(self.info['parent']) + \
"%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
-class QAPISchema:
+class QAPISchemaParser(object):
def __init__(self, fp, previously_included = [], incl_info = None):
abs_fname = os.path.abspath(fp.name)
@@ -149,8 +149,8 @@ class QAPISchema:
except IOError, e:
raise QAPIExprError(expr_info,
'%s: %s' % (e.strerror, include))
- exprs_include = QAPISchema(fobj, previously_included,
- expr_info)
+ exprs_include = QAPISchemaParser(fobj, previously_included,
+ expr_info)
self.exprs.extend(exprs_include.exprs)
else:
expr_elem = {'expr': expr,
@@ -755,7 +755,7 @@ def check_exprs(exprs):
def parse_schema(fname):
try:
- schema = QAPISchema(open(fname, "r"))
+ schema = QAPISchemaParser(open(fname, "r"))
return check_exprs(schema.exprs)
except (QAPISchemaError, QAPIExprError), e:
print >>sys.stderr, e
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 01/26] qapi: Rename class QAPISchema to QAPISchemaParser Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:44 ` Daniel P. Berrange
2015-09-16 15:08 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 03/26] qapi: QAPISchema code generation helper methods Markus Armbruster
` (25 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
The QAPI code generators work with a syntax tree (nested dictionaries)
plus a few symbol tables (also dictionaries) on the side.
They have clearly outgrown these simple data structures. There's lots
of rummaging around in dictionaries, and information is recomputed on
the fly. For the work I'm going to do, I want more clearly defined
and more convenient interfaces.
Going forward, I also want less coupling between the back-ends and the
syntax tree, to make messing with the syntax easier.
Create a bunch of classes to represent QAPI schemata.
Have the QAPISchema initializer call the parser, then walk the syntax
tree to create the new internal representation, and finally perform
semantic analysis.
Shortcut: the semantic analysis still relies on existing check_exprs()
to do the actual semantic checking. All this code needs to move into
the classes. Mark as TODO.
Simple unions are lowered to flat unions. Flat unions and structs are
represented as a more general object type.
Catching name collisions in generated code would be nice. Mark as
TODO.
We generate array types eagerly, even though most of them aren't used.
Mark as TODO.
Nothing uses the new intermediate representation just yet, thus no
change to generated files.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi-commands.py | 2 +-
scripts/qapi-event.py | 2 +-
scripts/qapi-types.py | 2 +-
scripts/qapi-visit.py | 2 +-
scripts/qapi.py | 381 ++++++++++++++++++++++++++++++++++++++++-
tests/qapi-schema/test-qapi.py | 2 +-
6 files changed, 377 insertions(+), 14 deletions(-)
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 890ce5d..12bdc4c 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -272,7 +272,7 @@ for o, a in opts:
if o in ("-m", "--middle"):
middle_mode = True
-exprs = parse_schema(input_file)
+exprs = QAPISchema(input_file).get_exprs()
commands = filter(lambda expr: expr.has_key('command'), exprs)
commands = filter(lambda expr: not expr.has_key('gen'), commands)
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 7f238df..aec2d32 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -263,7 +263,7 @@ fdecl.write(mcgen('''
''',
prefix=prefix))
-exprs = parse_schema(input_file)
+exprs = QAPISchema(input_file).get_exprs()
event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
event_enum_values = []
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index a8453d1..23e9505 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -336,7 +336,7 @@ fdecl.write(mcgen('''
#include <stdint.h>
'''))
-exprs = parse_schema(input_file)
+exprs = QAPISchema(input_file).get_exprs()
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
for typename in builtin_types.keys():
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 3cd662b..c493964 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -446,7 +446,7 @@ fdecl.write(mcgen('''
''',
prefix=prefix))
-exprs = parse_schema(input_file)
+exprs = QAPISchema(input_file).get_exprs()
# to avoid header dependency hell, we always generate declarations
# for built-in types in our header files and simply guard them
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 2a0f465..c35f892 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -302,6 +302,8 @@ class QAPISchemaParser(object):
#
# Semantic analysis of schema expressions
+# TODO fold into QAPISchema
+# TODO catching name collisions in generated code would be nice
#
def find_base_fields(base):
@@ -751,15 +753,376 @@ def check_exprs(exprs):
else:
assert False, 'unexpected meta type'
- return map(lambda expr_elem: expr_elem['expr'], exprs)
-
-def parse_schema(fname):
- try:
- schema = QAPISchemaParser(open(fname, "r"))
- return check_exprs(schema.exprs)
- except (QAPISchemaError, QAPIExprError), e:
- print >>sys.stderr, e
- exit(1)
+ return exprs
+
+
+#
+# Schema compiler frontend
+#
+
+class QAPISchemaEntity(object):
+ def __init__(self, name, info):
+ assert isinstance(name, str)
+ self.name = name
+ self.info = info
+
+ def check(self, schema):
+ pass
+
+
+class QAPISchemaType(QAPISchemaEntity):
+ pass
+
+
+class QAPISchemaBuiltinType(QAPISchemaType):
+ def __init__(self, name):
+ QAPISchemaType.__init__(self, name, None)
+
+
+class QAPISchemaEnumType(QAPISchemaType):
+ def __init__(self, name, info, values, prefix):
+ QAPISchemaType.__init__(self, name, info)
+ for v in values:
+ assert isinstance(v, str)
+ self.values = values
+ self.prefix = prefix
+
+ def check(self, schema):
+ assert len(set(self.values)) == len(self.values)
+
+
+class QAPISchemaArrayType(QAPISchemaType):
+ def __init__(self, name, info, element_type):
+ QAPISchemaType.__init__(self, name, info)
+ assert isinstance(element_type, str)
+ self._element_type_name = element_type
+ self.element_type = None
+
+ def check(self, schema):
+ self.element_type = schema.lookup_type(self._element_type_name)
+ assert self.element_type
+
+
+class QAPISchemaObjectType(QAPISchemaType):
+ def __init__(self, name, info, base, local_members, variants):
+ QAPISchemaType.__init__(self, name, info)
+ assert base is None or isinstance(base, str)
+ for m in local_members:
+ assert isinstance(m, QAPISchemaObjectTypeMember)
+ assert (variants is None or
+ isinstance(variants, QAPISchemaObjectTypeVariants))
+ self._base_name = base
+ self.base = None
+ self.local_members = local_members
+ self.variants = variants
+ self.members = None
+
+ def check(self, schema):
+ assert self.members is not False # not running in cycles
+ if self.members:
+ return
+ self.members = False # mark as being checked
+ if self._base_name:
+ self.base = schema.lookup_type(self._base_name)
+ assert isinstance(self.base, QAPISchemaObjectType)
+ assert not self.base.variants # not implemented
+ self.base.check(schema)
+ members = list(self.base.members)
+ else:
+ members = []
+ seen = {}
+ for m in members:
+ seen[m.name] = m
+ for m in self.local_members:
+ m.check(schema, members, seen)
+ if self.variants:
+ self.variants.check(schema, members, seen)
+ self.members = members
+
+
+class QAPISchemaObjectTypeMember(object):
+ def __init__(self, name, typ, optional):
+ assert isinstance(name, str)
+ assert isinstance(typ, str)
+ assert isinstance(optional, bool)
+ self.name = name
+ self._type_name = typ
+ self.type = None
+ self.optional = optional
+
+ def check(self, schema, all_members, seen):
+ assert self.name not in seen
+ self.type = schema.lookup_type(self._type_name)
+ assert self.type
+ all_members.append(self)
+ seen[self.name] = self
+
+
+class QAPISchemaObjectTypeVariants(object):
+ def __init__(self, tag_name, tag_enum, variants):
+ assert tag_name is None or isinstance(tag_name, str)
+ assert tag_enum is None or isinstance(tag_enum, str)
+ for v in variants:
+ assert isinstance(v, QAPISchemaObjectTypeVariant)
+ self.tag_name = tag_name
+ if tag_name:
+ assert not tag_enum
+ self.tag_member = None
+ else:
+ self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
+ False)
+ self.variants = variants
+
+ def check(self, schema, members, seen):
+ if self.tag_name:
+ self.tag_member = seen[self.tag_name]
+ else:
+ self.tag_member.check(schema, members, seen)
+ assert isinstance(self.tag_member.type, QAPISchemaEnumType)
+ for v in self.variants:
+ vseen = dict(seen)
+ v.check(schema, self.tag_member.type, vseen)
+
+
+class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
+ def __init__(self, name, typ):
+ QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
+
+ def check(self, schema, tag_type, seen):
+ QAPISchemaObjectTypeMember.check(self, schema, [], seen)
+ assert self.name in tag_type.values
+
+
+class QAPISchemaAlternateType(QAPISchemaType):
+ def __init__(self, name, info, variants):
+ QAPISchemaType.__init__(self, name, info)
+ assert isinstance(variants, QAPISchemaObjectTypeVariants)
+ assert not variants.tag_name
+ self.variants = variants
+
+ def check(self, schema):
+ self.variants.check(schema, [], {})
+
+
+class QAPISchemaCommand(QAPISchemaEntity):
+ def __init__(self, name, info, arg_type, ret_type, gen, success_response):
+ QAPISchemaEntity.__init__(self, name, info)
+ assert not arg_type or isinstance(arg_type, str)
+ assert not ret_type or isinstance(ret_type, str)
+ self._arg_type_name = arg_type
+ self.arg_type = None
+ self._ret_type_name = ret_type
+ self.ret_type = None
+ self.gen = gen
+ self.success_response = success_response
+
+ def check(self, schema):
+ if self._arg_type_name:
+ self.arg_type = schema.lookup_type(self._arg_type_name)
+ assert isinstance(self.arg_type, QAPISchemaObjectType)
+ assert not self.arg_type.variants # not implemented
+ if self._ret_type_name:
+ self.ret_type = schema.lookup_type(self._ret_type_name)
+ assert isinstance(self.ret_type, QAPISchemaType)
+
+
+class QAPISchemaEvent(QAPISchemaEntity):
+ def __init__(self, name, info, arg_type):
+ QAPISchemaEntity.__init__(self, name, info)
+ assert not arg_type or isinstance(arg_type, str)
+ self._arg_type_name = arg_type
+ self.arg_type = None
+
+ def check(self, schema):
+ if self._arg_type_name:
+ self.arg_type = schema.lookup_type(self._arg_type_name)
+ assert isinstance(self.arg_type, QAPISchemaObjectType)
+ assert not self.arg_type.variants # not implemented
+
+
+class QAPISchema(object):
+ def __init__(self, fname):
+ try:
+ self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
+ except (QAPISchemaError, QAPIExprError), err:
+ print >>sys.stderr, err
+ exit(1)
+ self._entity_dict = {}
+ self._def_predefineds()
+ 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
+
+ def lookup_entity(self, name, typ=None):
+ ent = self._entity_dict.get(name)
+ if typ and not isinstance(ent, typ):
+ return None
+ return ent
+
+ def lookup_type(self, name):
+ return self.lookup_entity(name, QAPISchemaType)
+
+ def _def_builtin_type(self, name):
+ self._def_entity(QAPISchemaBuiltinType(name))
+ if name != '**':
+ self._make_array_type(name) # TODO really needed?
+
+ def _def_predefineds(self):
+ for t in ['str', 'number', 'int', 'int8', 'int16', 'int32', 'int64',
+ 'uint8', 'uint16', 'uint32', 'uint64', 'size', 'bool', '**']:
+ self._def_builtin_type(t)
+
+ def _make_implicit_enum_type(self, name, values):
+ name = name + 'Kind'
+ self._def_entity(QAPISchemaEnumType(name, None, values, None))
+ return name
+
+ def _make_array_type(self, element_type):
+ name = element_type + 'List'
+ if not self.lookup_type(name):
+ self._def_entity(QAPISchemaArrayType(name, None, element_type))
+ return name
+
+ def _make_implicit_object_type(self, name, role, members):
+ if not members:
+ return None
+ name = ':obj-%s-%s' % (name, role)
+ if not self.lookup_entity(name, QAPISchemaObjectType):
+ self._def_entity(QAPISchemaObjectType(name, None, None,
+ members, None))
+ return name
+
+ def _def_enum_type(self, expr, info):
+ name = expr['enum']
+ data = expr['data']
+ prefix = expr.get('prefix')
+ self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
+ self._make_array_type(name) # TODO really needed?
+
+ def _make_member(self, name, typ):
+ optional = False
+ if name.startswith('*'):
+ name = name[1:]
+ optional = True
+ if isinstance(typ, list):
+ assert len(typ) == 1
+ typ = self._make_array_type(typ[0])
+ return QAPISchemaObjectTypeMember(name, typ, optional)
+
+ def _make_members(self, data):
+ return [self._make_member(key, value)
+ for (key, value) in data.iteritems()]
+
+ def _def_struct_type(self, expr, info):
+ name = expr['struct']
+ base = expr.get('base')
+ data = expr['data']
+ self._def_entity(QAPISchemaObjectType(name, info, base,
+ self._make_members(data),
+ None))
+ self._make_array_type(name) # TODO really needed?
+
+ def _make_variant(self, case, typ):
+ return QAPISchemaObjectTypeVariant(case, typ)
+
+ def _make_simple_variant(self, case, typ):
+ if isinstance(typ, list):
+ assert len(typ) == 1
+ typ = self._make_array_type(typ[0])
+ typ = self._make_implicit_object_type(typ, 'wrapper',
+ [self._make_member('data', typ)])
+ return QAPISchemaObjectTypeVariant(case, typ)
+
+ def _make_tag_enum(self, type_name, variants):
+ return self._make_implicit_enum_type(type_name,
+ [v.name for v in variants])
+
+ def _def_union_type(self, expr, info):
+ name = expr['union']
+ data = expr['data']
+ base = expr.get('base')
+ tag_name = expr.get('discriminator')
+ tag_enum = None
+ if tag_name:
+ variants = [self._make_variant(key, value)
+ for (key, value) in data.iteritems()]
+ else:
+ variants = [self._make_simple_variant(key, value)
+ for (key, value) in data.iteritems()]
+ tag_enum = self._make_tag_enum(name, variants)
+ self._def_entity(
+ QAPISchemaObjectType(name, info, base,
+ self._make_members(OrderedDict()),
+ QAPISchemaObjectTypeVariants(tag_name,
+ tag_enum,
+ variants)))
+ self._make_array_type(name) # TODO really needed?
+
+ def _def_alternate_type(self, expr, info):
+ name = expr['alternate']
+ data = expr['data']
+ variants = [self._make_variant(key, value)
+ for (key, value) in data.iteritems()]
+ tag_enum = self._make_tag_enum(name, variants)
+ self._def_entity(
+ QAPISchemaAlternateType(name, info,
+ QAPISchemaObjectTypeVariants(None,
+ tag_enum,
+ variants)))
+ self._make_array_type(name) # TODO really needed?
+
+ def _def_command(self, expr, info):
+ name = expr['command']
+ data = expr.get('data')
+ rets = expr.get('returns')
+ gen = expr.get('gen', True)
+ success_response = expr.get('success-response', True)
+ if isinstance(data, OrderedDict):
+ data = self._make_implicit_object_type(name, 'arg',
+ self._make_members(data))
+ if isinstance(rets, list):
+ assert len(rets) == 1
+ rets = self._make_array_type(rets[0])
+ self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
+ success_response))
+
+ def _def_event(self, expr, info):
+ name = expr['event']
+ data = expr.get('data')
+ if isinstance(data, OrderedDict):
+ data = self._make_implicit_object_type(name, 'arg',
+ self._make_members(data))
+ self._def_entity(QAPISchemaEvent(name, info, data))
+
+ def _def_exprs(self):
+ for expr_elem in self.exprs:
+ expr = expr_elem['expr']
+ info = expr_elem['info']
+ if 'enum' in expr:
+ self._def_enum_type(expr, info)
+ elif 'struct' in expr:
+ self._def_struct_type(expr, info)
+ elif 'union' in expr:
+ self._def_union_type(expr, info)
+ elif 'alternate' in expr:
+ self._def_alternate_type(expr, info)
+ elif 'command' in expr:
+ self._def_command(expr, info)
+ elif 'event' in expr:
+ self._def_event(expr, info)
+ else:
+ assert False
+
+ def check(self):
+ for ent in self._entity_dict.values():
+ ent.check(self)
+
#
# Code generation helpers
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 634ef2d..461c713 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -16,7 +16,7 @@ import os
import sys
try:
- exprs = parse_schema(sys.argv[1])
+ exprs = QAPISchema(sys.argv[1]).get_exprs()
except SystemExit:
raise
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation Markus Armbruster
@ 2015-09-16 14:44 ` Daniel P. Berrange
2015-09-16 15:08 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:44 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:05PM +0200, Markus Armbruster wrote:
> The QAPI code generators work with a syntax tree (nested dictionaries)
> plus a few symbol tables (also dictionaries) on the side.
>
> They have clearly outgrown these simple data structures. There's lots
> of rummaging around in dictionaries, and information is recomputed on
> the fly. For the work I'm going to do, I want more clearly defined
> and more convenient interfaces.
>
> Going forward, I also want less coupling between the back-ends and the
> syntax tree, to make messing with the syntax easier.
>
> Create a bunch of classes to represent QAPI schemata.
>
> Have the QAPISchema initializer call the parser, then walk the syntax
> tree to create the new internal representation, and finally perform
> semantic analysis.
>
> Shortcut: the semantic analysis still relies on existing check_exprs()
> to do the actual semantic checking. All this code needs to move into
> the classes. Mark as TODO.
>
> Simple unions are lowered to flat unions. Flat unions and structs are
> represented as a more general object type.
>
> Catching name collisions in generated code would be nice. Mark as
> TODO.
>
> We generate array types eagerly, even though most of them aren't used.
> Mark as TODO.
>
> Nothing uses the new intermediate representation just yet, thus no
> change to generated files.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> scripts/qapi-commands.py | 2 +-
> scripts/qapi-event.py | 2 +-
> scripts/qapi-types.py | 2 +-
> scripts/qapi-visit.py | 2 +-
> scripts/qapi.py | 381 ++++++++++++++++++++++++++++++++++++++++-
> tests/qapi-schema/test-qapi.py | 2 +-
> 6 files changed, 377 insertions(+), 14 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation Markus Armbruster
2015-09-16 14:44 ` Daniel P. Berrange
@ 2015-09-16 15:08 ` Eric Blake
2015-09-17 7:44 ` Markus Armbruster
1 sibling, 1 reply; 55+ messages in thread
From: Eric Blake @ 2015-09-16 15:08 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 1011 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> The QAPI code generators work with a syntax tree (nested dictionaries)
> plus a few symbol tables (also dictionaries) on the side.
> Nothing uses the new intermediate representation just yet, thus no
> change to generated files.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> +class QAPISchemaEnumType(QAPISchemaType):
> + def __init__(self, name, info, values, prefix):
> + QAPISchemaType.__init__(self, name, info)
> + for v in values:
> + assert isinstance(v, str)
> + self.values = values
> + self.prefix = prefix
Missing:
assert prefix is None or isinstance(prefix, str)
Should this be self._prefix, since no clients ever directly use the
member field (they just use the string passed through the visitor)?
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation
2015-09-16 15:08 ` Eric Blake
@ 2015-09-17 7:44 ` Markus Armbruster
2015-09-17 15:40 ` Markus Armbruster
0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2015-09-17 7:44 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, mdroth
Eric Blake <eblake@redhat.com> writes:
> On 09/16/2015 05:06 AM, Markus Armbruster wrote:
>> The QAPI code generators work with a syntax tree (nested dictionaries)
>> plus a few symbol tables (also dictionaries) on the side.
>
>> Nothing uses the new intermediate representation just yet, thus no
>> change to generated files.
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
>
>> +class QAPISchemaEnumType(QAPISchemaType):
>> + def __init__(self, name, info, values, prefix):
>> + QAPISchemaType.__init__(self, name, info)
>> + for v in values:
>> + assert isinstance(v, str)
>> + self.values = values
>> + self.prefix = prefix
>
> Missing:
> assert prefix is None or isinstance(prefix, str)
Yes.
> Should this be self._prefix, since no clients ever directly use the
> member field (they just use the string passed through the visitor)?
Yes.
If nothing else comes up in review, I'll touch this up on commit.
> Reviewed-by: Eric Blake <eblake@redhat.com>
Thanks!
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation
2015-09-17 7:44 ` Markus Armbruster
@ 2015-09-17 15:40 ` Markus Armbruster
0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-17 15:40 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, mdroth
Markus Armbruster <armbru@redhat.com> writes:
> Eric Blake <eblake@redhat.com> writes:
>
>> On 09/16/2015 05:06 AM, Markus Armbruster wrote:
>>> The QAPI code generators work with a syntax tree (nested dictionaries)
>>> plus a few symbol tables (also dictionaries) on the side.
>>
>>> Nothing uses the new intermediate representation just yet, thus no
>>> change to generated files.
>>>
>>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>>> ---
>>
>>
>>> +class QAPISchemaEnumType(QAPISchemaType):
>>> + def __init__(self, name, info, values, prefix):
>>> + QAPISchemaType.__init__(self, name, info)
>>> + for v in values:
>>> + assert isinstance(v, str)
>>> + self.values = values
>>> + self.prefix = prefix
>>
>> Missing:
>> assert prefix is None or isinstance(prefix, str)
>
> Yes.
>
>> Should this be self._prefix, since no clients ever directly use the
>> member field (they just use the string passed through the visitor)?
>
> Yes.
Second thoughts: I'll keep self.prefix for consistency. So far, we use
the _-prefix only for instance variables holding values flowing from
__init__() to check().
> If nothing else comes up in review, I'll touch this up on commit.
>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>
> Thanks!
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 03/26] qapi: QAPISchema code generation helper methods
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 01/26] qapi: Rename class QAPISchema to QAPISchemaParser Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 02/26] qapi: New QAPISchema intermediate reperesentation Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:51 ` Daniel P. Berrange
2015-09-16 15:11 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor Markus Armbruster
` (24 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
New methods c_name(), c_type(), c_null(), json_type(),
alternate_qtype().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 87 insertions(+), 7 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index c35f892..0c32ce3 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -766,17 +766,57 @@ class QAPISchemaEntity(object):
self.name = name
self.info = info
+ def c_name(self):
+ return c_name(self.name)
+
def check(self, schema):
pass
class QAPISchemaType(QAPISchemaEntity):
- pass
+ def c_type(self, is_param=False):
+ return c_name(self.name) + pointer_suffix
+
+ def c_null(self):
+ return 'NULL'
+
+ def json_type(self):
+ pass
+
+ def alternate_qtype(self):
+ json2qtype = {
+ 'string': 'QTYPE_QSTRING',
+ 'number': 'QTYPE_QFLOAT',
+ 'int': 'QTYPE_QINT',
+ 'boolean': 'QTYPE_QBOOL',
+ 'object': 'QTYPE_QDICT'
+ }
+ return json2qtype.get(self.json_type())
class QAPISchemaBuiltinType(QAPISchemaType):
- def __init__(self, name):
+ def __init__(self, name, json_type, c_type, c_null):
QAPISchemaType.__init__(self, name, None)
+ assert not c_type or isinstance(c_type, str)
+ assert json_type in ('string', 'number', 'int', 'boolean', 'null',
+ 'value')
+ self._json_type_name = json_type
+ self._c_type_name = c_type
+ self._c_null_val = c_null
+
+ def c_name(self):
+ return self.name
+
+ def c_type(self, is_param=False):
+ if is_param and self.name == 'str':
+ return 'const ' + self._c_type_name
+ return self._c_type_name
+
+ def c_null(self):
+ return self._c_null_val
+
+ def json_type(self):
+ return self._json_type_name
class QAPISchemaEnumType(QAPISchemaType):
@@ -790,6 +830,16 @@ class QAPISchemaEnumType(QAPISchemaType):
def check(self, schema):
assert len(set(self.values)) == len(self.values)
+ def c_type(self, is_param=False):
+ return c_name(self.name)
+
+ def c_null(self):
+ return c_enum_const(self.name, (self.values + ['MAX'])[0],
+ self.prefix)
+
+ def json_type(self):
+ return 'string'
+
class QAPISchemaArrayType(QAPISchemaType):
def __init__(self, name, info, element_type):
@@ -802,6 +852,9 @@ class QAPISchemaArrayType(QAPISchemaType):
self.element_type = schema.lookup_type(self._element_type_name)
assert self.element_type
+ def json_type(self):
+ return 'array'
+
class QAPISchemaObjectType(QAPISchemaType):
def __init__(self, name, info, base, local_members, variants):
@@ -839,6 +892,17 @@ class QAPISchemaObjectType(QAPISchemaType):
self.variants.check(schema, members, seen)
self.members = members
+ def c_name(self):
+ assert self.info
+ return QAPISchemaType.c_name(self)
+
+ def c_type(self, is_param=False):
+ assert self.info
+ return QAPISchemaType.c_type(self)
+
+ def json_type(self):
+ return 'object'
+
class QAPISchemaObjectTypeMember(object):
def __init__(self, name, typ, optional):
@@ -903,6 +967,9 @@ class QAPISchemaAlternateType(QAPISchemaType):
def check(self, schema):
self.variants.check(schema, [], {})
+ def json_type(self):
+ return 'value'
+
class QAPISchemaCommand(QAPISchemaEntity):
def __init__(self, name, info, arg_type, ret_type, gen, success_response):
@@ -968,15 +1035,28 @@ class QAPISchema(object):
def lookup_type(self, name):
return self.lookup_entity(name, QAPISchemaType)
- def _def_builtin_type(self, name):
- self._def_entity(QAPISchemaBuiltinType(name))
+ def _def_builtin_type(self, name, json_type, c_type, c_null):
+ self._def_entity(QAPISchemaBuiltinType(name, json_type,
+ c_type, c_null))
if name != '**':
self._make_array_type(name) # TODO really needed?
def _def_predefineds(self):
- for t in ['str', 'number', 'int', 'int8', 'int16', 'int32', 'int64',
- 'uint8', 'uint16', 'uint32', 'uint64', 'size', 'bool', '**']:
- self._def_builtin_type(t)
+ for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
+ ('number', 'number', 'double', '0'),
+ ('int', 'int', 'int64_t', '0'),
+ ('int8', 'int', 'int8_t', '0'),
+ ('int16', 'int', 'int16_t', '0'),
+ ('int32', 'int', 'int32_t', '0'),
+ ('int64', 'int', 'int64_t', '0'),
+ ('uint8', 'int', 'uint8_t', '0'),
+ ('uint16', 'int', 'uint16_t', '0'),
+ ('uint32', 'int', 'uint32_t', '0'),
+ ('uint64', 'int', 'uint64_t', '0'),
+ ('size', 'int', 'uint64_t', '0'),
+ ('bool', 'boolean', 'bool', 'false'),
+ ('**', 'value', None, None)]:
+ self._def_builtin_type(*t)
def _make_implicit_enum_type(self, name, values):
name = name + 'Kind'
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 03/26] qapi: QAPISchema code generation helper methods
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 03/26] qapi: QAPISchema code generation helper methods Markus Armbruster
@ 2015-09-16 14:51 ` Daniel P. Berrange
2015-09-16 15:11 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:51 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:06PM +0200, Markus Armbruster wrote:
> New methods c_name(), c_type(), c_null(), json_type(),
> alternate_qtype().
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> scripts/qapi.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 87 insertions(+), 7 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 03/26] qapi: QAPISchema code generation helper methods
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 03/26] qapi: QAPISchema code generation helper methods Markus Armbruster
2015-09-16 14:51 ` Daniel P. Berrange
@ 2015-09-16 15:11 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Eric Blake @ 2015-09-16 15:11 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 937 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> New methods c_name(), c_type(), c_null(), json_type(),
> alternate_qtype().
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> scripts/qapi.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 87 insertions(+), 7 deletions(-)
>
> @@ -790,6 +830,16 @@ class QAPISchemaEnumType(QAPISchemaType):
> def check(self, schema):
> assert len(set(self.values)) == len(self.values)
>
> + def c_type(self, is_param=False):
> + return c_name(self.name)
> +
> + def c_null(self):
> + return c_enum_const(self.name, (self.values + ['MAX'])[0],
> + self.prefix)
Yep, that becomes important in later patches.
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (2 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 03/26] qapi: QAPISchema code generation helper methods Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:51 ` Daniel P. Berrange
2015-09-16 15:21 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor Markus Armbruster
` (23 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
The visitor will help keeping the code generation code simple and
reasonably separated from QAPISchema details.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0c32ce3..e9cee38 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -772,6 +772,39 @@ class QAPISchemaEntity(object):
def check(self, schema):
pass
+ def visit(self, visitor):
+ pass
+
+
+class QAPISchemaVisitor(object):
+ def visit_begin(self, schema):
+ pass
+
+ def visit_end(self):
+ pass
+
+ def visit_builtin_type(self, name, info, json_type):
+ pass
+
+ def visit_enum_type(self, name, info, values, prefix):
+ pass
+
+ def visit_array_type(self, name, info, element_type):
+ pass
+
+ def visit_object_type(self, name, info, base, members, variants):
+ pass
+
+ def visit_alternate_type(self, name, info, variants):
+ pass
+
+ def visit_command(self, name, info, arg_type, ret_type,
+ gen, success_response):
+ pass
+
+ def visit_event(self, name, info, arg_type):
+ pass
+
class QAPISchemaType(QAPISchemaEntity):
def c_type(self, is_param=False):
@@ -818,6 +851,9 @@ class QAPISchemaBuiltinType(QAPISchemaType):
def json_type(self):
return self._json_type_name
+ def visit(self, visitor):
+ visitor.visit_builtin_type(self.name, self.info, self.json_type())
+
class QAPISchemaEnumType(QAPISchemaType):
def __init__(self, name, info, values, prefix):
@@ -840,6 +876,10 @@ class QAPISchemaEnumType(QAPISchemaType):
def json_type(self):
return 'string'
+ def visit(self, visitor):
+ visitor.visit_enum_type(self.name, self.info,
+ self.values, self.prefix)
+
class QAPISchemaArrayType(QAPISchemaType):
def __init__(self, name, info, element_type):
@@ -855,6 +895,9 @@ class QAPISchemaArrayType(QAPISchemaType):
def json_type(self):
return 'array'
+ def visit(self, visitor):
+ visitor.visit_array_type(self.name, self.info, self.element_type)
+
class QAPISchemaObjectType(QAPISchemaType):
def __init__(self, name, info, base, local_members, variants):
@@ -903,6 +946,10 @@ class QAPISchemaObjectType(QAPISchemaType):
def json_type(self):
return 'object'
+ def visit(self, visitor):
+ visitor.visit_object_type(self.name, self.info,
+ self.base, self.local_members, self.variants)
+
class QAPISchemaObjectTypeMember(object):
def __init__(self, name, typ, optional):
@@ -970,6 +1017,9 @@ class QAPISchemaAlternateType(QAPISchemaType):
def json_type(self):
return 'value'
+ def visit(self, visitor):
+ visitor.visit_alternate_type(self.name, self.info, self.variants)
+
class QAPISchemaCommand(QAPISchemaEntity):
def __init__(self, name, info, arg_type, ret_type, gen, success_response):
@@ -992,6 +1042,11 @@ class QAPISchemaCommand(QAPISchemaEntity):
self.ret_type = schema.lookup_type(self._ret_type_name)
assert isinstance(self.ret_type, QAPISchemaType)
+ def visit(self, visitor):
+ visitor.visit_command(self.name, self.info,
+ self.arg_type, self.ret_type,
+ self.gen, self.success_response)
+
class QAPISchemaEvent(QAPISchemaEntity):
def __init__(self, name, info, arg_type):
@@ -1006,6 +1061,9 @@ class QAPISchemaEvent(QAPISchemaEntity):
assert isinstance(self.arg_type, QAPISchemaObjectType)
assert not self.arg_type.variants # not implemented
+ def visit(self, visitor):
+ visitor.visit_event(self.name, self.info, self.arg_type)
+
class QAPISchema(object):
def __init__(self, fname):
@@ -1203,6 +1261,12 @@ class QAPISchema(object):
for ent in self._entity_dict.values():
ent.check(self)
+ def visit(self, visitor):
+ visitor.visit_begin(self)
+ for name in sorted(self._entity_dict.keys()):
+ self._entity_dict[name].visit(visitor)
+ visitor.visit_end()
+
#
# Code generation helpers
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor Markus Armbruster
@ 2015-09-16 14:51 ` Daniel P. Berrange
2015-09-16 15:21 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:51 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:07PM +0200, Markus Armbruster wrote:
> The visitor will help keeping the code generation code simple and
> reasonably separated from QAPISchema details.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> scripts/qapi.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 64 insertions(+)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor Markus Armbruster
2015-09-16 14:51 ` Daniel P. Berrange
@ 2015-09-16 15:21 ` Eric Blake
2015-09-17 7:46 ` Markus Armbruster
1 sibling, 1 reply; 55+ messages in thread
From: Eric Blake @ 2015-09-16 15:21 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 1341 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> The visitor will help keeping the code generation code simple and
> reasonably separated from QAPISchema details.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> scripts/qapi.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 64 insertions(+)
>
> @@ -840,6 +876,10 @@ class QAPISchemaEnumType(QAPISchemaType):
> def json_type(self):
> return 'string'
>
> + def visit(self, visitor):
> + visitor.visit_enum_type(self.name, self.info,
> + self.values, self.prefix)
Thinking aloud: Should this visit 'self.prefix or self.name', rather
than letting callers see None? If we did that, we could simplify
c_enum_const() back to 2 parameters, and update all callers to just
blindly pass the prefix instead of the enum name. On the other hand, I
think that's a bit too much churn, and I don't see what it would buy us
that we don't already have with a 3-arg c_enum_const().
So I'm fine with the version you have here as-is (modulo any obvious
rebase to pass self._prefix based on my comments on 2).
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor
2015-09-16 15:21 ` Eric Blake
@ 2015-09-17 7:46 ` Markus Armbruster
0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-17 7:46 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, mdroth
Eric Blake <eblake@redhat.com> writes:
> On 09/16/2015 05:06 AM, Markus Armbruster wrote:
>> The visitor will help keeping the code generation code simple and
>> reasonably separated from QAPISchema details.
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>> scripts/qapi.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 64 insertions(+)
>>
>
>> @@ -840,6 +876,10 @@ class QAPISchemaEnumType(QAPISchemaType):
>> def json_type(self):
>> return 'string'
>>
>> + def visit(self, visitor):
>> + visitor.visit_enum_type(self.name, self.info,
>> + self.values, self.prefix)
>
> Thinking aloud: Should this visit 'self.prefix or self.name', rather
> than letting callers see None? If we did that, we could simplify
> c_enum_const() back to 2 parameters, and update all callers to just
> blindly pass the prefix instead of the enum name. On the other hand, I
> think that's a bit too much churn, and I don't see what it would buy us
> that we don't already have with a 3-arg c_enum_const().
Could be explored on top. We need to wrap up this series.
> So I'm fine with the version you have here as-is (modulo any obvious
> rebase to pass self._prefix based on my comments on 2).
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
Thanks!
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (3 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 04/26] qapi: New QAPISchemaVisitor Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:53 ` Daniel P. Berrange
2015-09-16 15:27 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions Markus Armbruster
` (22 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
The old code prints the result of parsing (list of expression
dictionaries), and partial results of semantic analysis (list of enum
dictionaries, list of struct dictionaries).
The new code prints a trace of a schema visit, i.e. what the back-ends
are going to use. Built-in and array types are omitted, because
they're boring.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
tests/qapi-schema/alternate-good.out | 15 +-
tests/qapi-schema/args-member-array.out | 13 +-
| 4 +-
tests/qapi-schema/empty.out | 3 -
tests/qapi-schema/enum-empty.out | 4 +-
tests/qapi-schema/event-case.out | 4 +-
tests/qapi-schema/flat-union-reverse-define.out | 21 ++-
tests/qapi-schema/ident-with-escape.out | 7 +-
tests/qapi-schema/include-relpath.out | 4 +-
tests/qapi-schema/include-repetition.out | 4 +-
tests/qapi-schema/include-simple.out | 4 +-
tests/qapi-schema/indented-expr.out | 7 +-
tests/qapi-schema/qapi-schema-test.out | 217 +++++++++++++++++-------
tests/qapi-schema/returns-int.out | 5 +-
tests/qapi-schema/test-qapi.py | 45 ++++-
tests/qapi-schema/type-bypass.out | 7 +-
16 files changed, 246 insertions(+), 118 deletions(-)
diff --git a/tests/qapi-schema/alternate-good.out b/tests/qapi-schema/alternate-good.out
index 99848ee..75a58cd 100644
--- a/tests/qapi-schema/alternate-good.out
+++ b/tests/qapi-schema/alternate-good.out
@@ -1,6 +1,9 @@
-[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))]),
- OrderedDict([('enum', 'Enum'), ('data', ['hello', 'world'])]),
- OrderedDict([('alternate', 'Alt'), ('data', OrderedDict([('value', 'int'), ('string', 'Enum'), ('struct', 'Data')]))])]
-[{'enum_name': 'Enum', 'enum_values': ['hello', 'world']},
- {'enum_name': 'AltKind', 'enum_values': None}]
-[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))])]
+alternate Alt
+ case value: int
+ case string: Enum
+ case struct: Data
+enum AltKind ['value', 'string', 'struct'] prefix=None
+object Data
+ member number: int optional=True
+ member name: str optional=True
+enum Enum ['hello', 'world'] prefix=None
diff --git a/tests/qapi-schema/args-member-array.out b/tests/qapi-schema/args-member-array.out
index c39fa25..7c58cef 100644
--- a/tests/qapi-schema/args-member-array.out
+++ b/tests/qapi-schema/args-member-array.out
@@ -1,5 +1,8 @@
-[OrderedDict([('enum', 'abc'), ('data', ['a', 'b', 'c'])]),
- OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))]),
- OrderedDict([('command', 'okay'), ('data', OrderedDict([('member1', ['int']), ('member2', ['def'])]))])]
-[{'enum_name': 'abc', 'enum_values': ['a', 'b', 'c']}]
-[OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))])]
+object :obj-okay-arg
+ member member1: intList optional=False
+ member member2: defList optional=False
+enum abc ['a', 'b', 'c'] prefix=None
+object def
+ member array: abcList optional=False
+command okay :obj-okay-arg -> None
+ gen=True success_response=True
--git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 4ce3dcf..537419c 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,3 +1 @@
-[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
-[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
-[]
+enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index b7f89a4..e69de29 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1,3 +0,0 @@
-[]
-[]
-[]
diff --git a/tests/qapi-schema/enum-empty.out b/tests/qapi-schema/enum-empty.out
index 3b75c16..3628fbd 100644
--- a/tests/qapi-schema/enum-empty.out
+++ b/tests/qapi-schema/enum-empty.out
@@ -1,3 +1 @@
-[OrderedDict([('enum', 'MyEnum'), ('data', [])])]
-[{'enum_name': 'MyEnum', 'enum_values': []}]
-[]
+enum MyEnum [] prefix=None
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index 3764bc7..b5ae4c2 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1,3 +1 @@
-[OrderedDict([('event', 'oops')])]
-[]
-[]
+event oops None
diff --git a/tests/qapi-schema/flat-union-reverse-define.out b/tests/qapi-schema/flat-union-reverse-define.out
index 1ed7b8a..6f4df73 100644
--- a/tests/qapi-schema/flat-union-reverse-define.out
+++ b/tests/qapi-schema/flat-union-reverse-define.out
@@ -1,9 +1,12 @@
-[OrderedDict([('union', 'TestUnion'), ('base', 'TestBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'TestTypeA'), ('value2', 'TestTypeB')]))]),
- OrderedDict([('struct', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
- OrderedDict([('enum', 'TestEnum'), ('data', ['value1', 'value2'])]),
- OrderedDict([('struct', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
- OrderedDict([('struct', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]
-[{'enum_name': 'TestEnum', 'enum_values': ['value1', 'value2']}]
-[OrderedDict([('struct', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
- OrderedDict([('struct', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
- OrderedDict([('struct', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]
+object TestBase
+ member enum1: TestEnum optional=False
+enum TestEnum ['value1', 'value2'] prefix=None
+object TestTypeA
+ member string: str optional=False
+object TestTypeB
+ member integer: int optional=False
+object TestUnion
+ base TestBase
+ tag enum1
+ case value1: TestTypeA
+ case value2: TestTypeB
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index 4028430..9577d1b 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -1,3 +1,4 @@
-[OrderedDict([('command', 'fooA'), ('data', OrderedDict([('bar1', 'str')]))])]
-[]
-[]
+object :obj-fooA-arg
+ member bar1: str optional=False
+command fooA :obj-fooA-arg -> None
+ gen=True success_response=True
diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
index 4ce3dcf..537419c 100644
--- a/tests/qapi-schema/include-relpath.out
+++ b/tests/qapi-schema/include-relpath.out
@@ -1,3 +1 @@
-[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
-[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
-[]
+enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 4ce3dcf..537419c 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,3 +1 @@
-[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
-[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
-[]
+enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 4ce3dcf..537419c 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,3 +1 @@
-[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
-[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
-[]
+enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index b5ce915..c5af55a 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,3 +1,4 @@
-[OrderedDict([('command', 'eins')]), OrderedDict([('command', 'zwei')])]
-[]
-[]
+command eins None -> None
+ gen=True success_response=True
+command zwei None -> None
+ gen=True success_response=True
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 32f17c5..45c39bc 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,57 +1,160 @@
-[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]),
- OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
- OrderedDict([('enum', 'QEnumTwo'), ('prefix', 'QENUM_TWO'), ('data', ['value1', 'value2'])]),
- 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', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
- OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
- OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
- OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('intb', 'int')]))]),
- 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([('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([('command', 'user_def_cmd'), ('data', OrderedDict())]),
- OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]),
- OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]),
- OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]),
- 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([('event', 'EVENT_A')]),
- OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]),
- OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]),
- OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))]),
- OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])]),
- OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]),
- OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]),
- OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))]),
- OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))]),
- OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))]),
- OrderedDict([('alternate', '__org.qemu_x-Alt'), ('data', OrderedDict([('__org.qemu_x-branch', 'str'), ('b', '__org.qemu_x-Base')]))]),
- OrderedDict([('event', '__ORG.QEMU_X-EVENT'), ('data', '__org.qemu_x-Struct')]),
- OrderedDict([('command', '__org.qemu_x-command'), ('data', OrderedDict([('a', ['__org.qemu_x-Enum']), ('b', ['__org.qemu_x-Struct']), ('c', '__org.qemu_x-Union2'), ('d', '__org.qemu_x-Alt')])), ('returns', '__org.qemu_x-Union1')])]
-[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
- {'enum_name': 'QEnumTwo', 'enum_values': ['value1', 'value2']},
- {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']},
- {'enum_name': 'UserDefAlternateKind', 'enum_values': None},
- {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None},
- {'enum_name': '__org.qemu_x-Union1Kind', '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', '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', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
- OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
- OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
- 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', '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', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]),
- OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]),
- OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))])]
+object :obj-EVENT_C-arg
+ member a: int optional=True
+ member b: UserDefOne optional=True
+ member c: str optional=False
+object :obj-EVENT_D-arg
+ member a: EventStructOne optional=False
+ member b: str optional=False
+ member c: str optional=True
+ member enum3: EnumOne optional=True
+object :obj-__org.qemu_x-command-arg
+ member a: __org.qemu_x-EnumList optional=False
+ member b: __org.qemu_x-StructList optional=False
+ member c: __org.qemu_x-Union2 optional=False
+ member d: __org.qemu_x-Alt optional=False
+object :obj-boolList-wrapper
+ member data: boolList optional=False
+object :obj-int16List-wrapper
+ member data: int16List optional=False
+object :obj-int32List-wrapper
+ member data: int32List optional=False
+object :obj-int64List-wrapper
+ member data: int64List optional=False
+object :obj-int8List-wrapper
+ member data: int8List optional=False
+object :obj-intList-wrapper
+ member data: intList optional=False
+object :obj-numberList-wrapper
+ member data: numberList optional=False
+object :obj-sizeList-wrapper
+ member data: sizeList optional=False
+object :obj-str-wrapper
+ member data: str optional=False
+object :obj-strList-wrapper
+ member data: strList optional=False
+object :obj-uint16List-wrapper
+ member data: uint16List optional=False
+object :obj-uint32List-wrapper
+ member data: uint32List optional=False
+object :obj-uint64List-wrapper
+ member data: uint64List optional=False
+object :obj-uint8List-wrapper
+ member data: uint8List optional=False
+object :obj-user_def_cmd1-arg
+ member ud1a: UserDefOne optional=False
+object :obj-user_def_cmd2-arg
+ member ud1a: UserDefOne optional=False
+ member ud1b: UserDefOne optional=True
+object :obj-user_def_cmd3-arg
+ member a: int optional=False
+ member b: int optional=True
+event EVENT_A None
+event EVENT_B None
+event EVENT_C :obj-EVENT_C-arg
+event EVENT_D :obj-EVENT_D-arg
+enum EnumOne ['value1', 'value2', 'value3'] prefix=None
+object EventStructOne
+ member struct1: UserDefOne optional=False
+ member string: str optional=False
+ member enum2: EnumOne optional=True
+object NestedEnumsOne
+ member enum1: EnumOne optional=False
+ member enum2: EnumOne optional=True
+ member enum3: EnumOne optional=False
+ member enum4: EnumOne optional=True
+enum QEnumTwo ['value1', 'value2'] prefix=QENUM_TWO
+object UserDefA
+ member boolean: bool optional=False
+alternate UserDefAlternate
+ case uda: UserDefA
+ case s: str
+ case i: int
+enum UserDefAlternateKind ['uda', 's', 'i'] prefix=None
+object UserDefB
+ member intb: int optional=False
+object UserDefC
+ member string1: str optional=False
+ member string2: str optional=False
+object UserDefFlatUnion
+ base UserDefUnionBase
+ tag enum1
+ case value1: UserDefA
+ case value2: UserDefB
+ case value3: UserDefB
+object UserDefFlatUnion2
+ base UserDefUnionBase
+ tag enum1
+ case value1: UserDefC
+ case value2: UserDefB
+ case value3: UserDefA
+object UserDefNativeListUnion
+ case integer: :obj-intList-wrapper
+ case s8: :obj-int8List-wrapper
+ case s16: :obj-int16List-wrapper
+ case s32: :obj-int32List-wrapper
+ case s64: :obj-int64List-wrapper
+ case u8: :obj-uint8List-wrapper
+ case u16: :obj-uint16List-wrapper
+ case u32: :obj-uint32List-wrapper
+ case u64: :obj-uint64List-wrapper
+ case number: :obj-numberList-wrapper
+ case boolean: :obj-boolList-wrapper
+ case string: :obj-strList-wrapper
+ case sizes: :obj-sizeList-wrapper
+enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes'] prefix=None
+object UserDefOne
+ base UserDefZero
+ member string: str optional=False
+ member enum1: EnumOne optional=True
+object UserDefOptions
+ member i64: intList optional=True
+ member u64: uint64List optional=True
+ member u16: uint16List optional=True
+ member i64x: int optional=True
+ member u64x: uint64 optional=True
+object UserDefTwo
+ member string0: str optional=False
+ member dict1: UserDefTwoDict optional=False
+object UserDefTwoDict
+ member string1: str optional=False
+ member dict2: UserDefTwoDictDict optional=False
+ member dict3: UserDefTwoDictDict optional=True
+object UserDefTwoDictDict
+ member userdef: UserDefOne optional=False
+ member string: str optional=False
+object UserDefUnionBase
+ base UserDefZero
+ member string: str optional=False
+ member enum1: EnumOne optional=False
+object UserDefZero
+ member integer: int optional=False
+event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
+alternate __org.qemu_x-Alt
+ case __org.qemu_x-branch: str
+ case b: __org.qemu_x-Base
+enum __org.qemu_x-AltKind ['__org.qemu_x-branch', 'b'] prefix=None
+object __org.qemu_x-Base
+ member __org.qemu_x-member1: __org.qemu_x-Enum optional=False
+enum __org.qemu_x-Enum ['__org.qemu_x-value'] prefix=None
+object __org.qemu_x-Struct
+ base __org.qemu_x-Base
+ member __org.qemu_x-member2: str optional=False
+object __org.qemu_x-Struct2
+ member array: __org.qemu_x-Union1List optional=False
+object __org.qemu_x-Union1
+ case __org.qemu_x-branch: :obj-str-wrapper
+enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch'] prefix=None
+object __org.qemu_x-Union2
+ base __org.qemu_x-Base
+ tag __org.qemu_x-member1
+ case __org.qemu_x-value: __org.qemu_x-Struct2
+command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
+ gen=True success_response=True
+command user_def_cmd None -> None
+ gen=True success_response=True
+command user_def_cmd1 :obj-user_def_cmd1-arg -> None
+ gen=True success_response=True
+command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
+ gen=True success_response=True
+command user_def_cmd3 :obj-user_def_cmd3-arg -> int
+ gen=True success_response=True
diff --git a/tests/qapi-schema/returns-int.out b/tests/qapi-schema/returns-int.out
index 70b3ac5..1ac3e1e 100644
--- a/tests/qapi-schema/returns-int.out
+++ b/tests/qapi-schema/returns-int.out
@@ -1,3 +1,2 @@
-[OrderedDict([('command', 'guest-get-time'), ('returns', 'int')])]
-[]
-[]
+command guest-get-time None -> int
+ gen=True success_response=True
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 461c713..7295b4f 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -15,11 +15,40 @@ from pprint import pprint
import os
import sys
-try:
- exprs = QAPISchema(sys.argv[1]).get_exprs()
-except SystemExit:
- raise
-
-pprint(exprs)
-pprint(enum_types)
-pprint(struct_types)
+
+class QAPISchemaTestVisitor(QAPISchemaVisitor):
+ def visit_enum_type(self, name, info, values, prefix):
+ print 'enum %s %s prefix=%s' % (name, values, prefix)
+
+ def visit_object_type(self, name, info, base, members, variants):
+ print 'object %s' % name
+ if base:
+ print ' base %s' % base.name
+ for m in members:
+ print ' member %s: %s optional=%s' % \
+ (m.name, m.type.name, m.optional)
+ self._print_variants(variants)
+
+ def visit_alternate_type(self, name, info, variants):
+ print 'alternate %s' % name
+ self._print_variants(variants)
+
+ def visit_command(self, name, info, arg_type, ret_type,
+ gen, success_response):
+ print 'command %s %s -> %s' % \
+ (name, arg_type and arg_type.name, ret_type and ret_type.name)
+ print ' gen=%s success_response=%s' % (gen, success_response)
+
+ def visit_event(self, name, info, arg_type):
+ print 'event %s %s' % (name, arg_type and arg_type.name)
+
+ @staticmethod
+ def _print_variants(variants):
+ if variants:
+ if variants.tag_name:
+ print ' tag %s' % variants.tag_name
+ for v in variants.variants:
+ print ' case %s: %s' % (v.name, v.type.name)
+
+schema = QAPISchema(sys.argv[1])
+schema.visit(QAPISchemaTestVisitor())
diff --git a/tests/qapi-schema/type-bypass.out b/tests/qapi-schema/type-bypass.out
index eaf20f8..0070d4b 100644
--- a/tests/qapi-schema/type-bypass.out
+++ b/tests/qapi-schema/type-bypass.out
@@ -1,3 +1,4 @@
-[OrderedDict([('command', 'unsafe'), ('data', OrderedDict([('arg', '**')])), ('returns', '**'), ('gen', False)])]
-[]
-[]
+object :obj-unsafe-arg
+ member arg: ** optional=False
+command unsafe :obj-unsafe-arg -> **
+ gen=False success_response=True
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor Markus Armbruster
@ 2015-09-16 14:53 ` Daniel P. Berrange
2015-09-16 15:27 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:53 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:08PM +0200, Markus Armbruster wrote:
> The old code prints the result of parsing (list of expression
> dictionaries), and partial results of semantic analysis (list of enum
> dictionaries, list of struct dictionaries).
>
> The new code prints a trace of a schema visit, i.e. what the back-ends
> are going to use. Built-in and array types are omitted, because
> they're boring.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> tests/qapi-schema/alternate-good.out | 15 +-
> tests/qapi-schema/args-member-array.out | 13 +-
> tests/qapi-schema/comments.out | 4 +-
> tests/qapi-schema/empty.out | 3 -
> tests/qapi-schema/enum-empty.out | 4 +-
> tests/qapi-schema/event-case.out | 4 +-
> tests/qapi-schema/flat-union-reverse-define.out | 21 ++-
> tests/qapi-schema/ident-with-escape.out | 7 +-
> tests/qapi-schema/include-relpath.out | 4 +-
> tests/qapi-schema/include-repetition.out | 4 +-
> tests/qapi-schema/include-simple.out | 4 +-
> tests/qapi-schema/indented-expr.out | 7 +-
> tests/qapi-schema/qapi-schema-test.out | 217 +++++++++++++++++-------
> tests/qapi-schema/returns-int.out | 5 +-
> tests/qapi-schema/test-qapi.py | 45 ++++-
> tests/qapi-schema/type-bypass.out | 7 +-
> 16 files changed, 246 insertions(+), 118 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor Markus Armbruster
2015-09-16 14:53 ` Daniel P. Berrange
@ 2015-09-16 15:27 ` Eric Blake
2015-09-17 7:49 ` Markus Armbruster
1 sibling, 1 reply; 55+ messages in thread
From: Eric Blake @ 2015-09-16 15:27 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 1927 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> The old code prints the result of parsing (list of expression
> dictionaries), and partial results of semantic analysis (list of enum
> dictionaries, list of struct dictionaries).
>
> The new code prints a trace of a schema visit, i.e. what the back-ends
> are going to use. Built-in and array types are omitted, because
> they're boring.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> +class QAPISchemaTestVisitor(QAPISchemaVisitor):
> + def visit_enum_type(self, name, info, values, prefix):
> + print 'enum %s %s prefix=%s' % (name, values, prefix)
> +
> + def visit_object_type(self, name, info, base, members, variants):
> + print 'object %s' % name
> + if base:
> + print ' base %s' % base.name
For consistency with other visitors, I might have done:
if prefix:
print ' prefix %s' % prefix
instead of printing prefix=None for most enums. In particular,
> +enum EnumOne ['value1', 'value2', 'value3'] prefix=None
> +object EventStructOne
> + member struct1: UserDefOne optional=False
> + member string: str optional=False
> + member enum2: EnumOne optional=True
> +object NestedEnumsOne
> + member enum1: EnumOne optional=False
> + member enum2: EnumOne optional=True
> + member enum3: EnumOne optional=False
> + member enum4: EnumOne optional=True
> +enum QEnumTwo ['value1', 'value2'] prefix=QENUM_TWO
the fact that prefix=None and prefix=QENUM_TWO doesn't offer any visual
clues on whether the string was user-supplied, means that the following
would result in ambiguous output:
{ 'enum':'Foo', 'prefix':'None', 'data':[] }
But it's not necessarily a strong enough reason for a respin.
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor
2015-09-16 15:27 ` Eric Blake
@ 2015-09-17 7:49 ` Markus Armbruster
0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-17 7:49 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, mdroth
Eric Blake <eblake@redhat.com> writes:
> On 09/16/2015 05:06 AM, Markus Armbruster wrote:
>> The old code prints the result of parsing (list of expression
>> dictionaries), and partial results of semantic analysis (list of enum
>> dictionaries, list of struct dictionaries).
>>
>> The new code prints a trace of a schema visit, i.e. what the back-ends
>> are going to use. Built-in and array types are omitted, because
>> they're boring.
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
>> +class QAPISchemaTestVisitor(QAPISchemaVisitor):
>> + def visit_enum_type(self, name, info, values, prefix):
>> + print 'enum %s %s prefix=%s' % (name, values, prefix)
>> +
>> + def visit_object_type(self, name, info, base, members, variants):
>> + print 'object %s' % name
>> + if base:
>> + print ' base %s' % base.name
>
> For consistency with other visitors, I might have done:
>
> if prefix:
> print ' prefix %s' % prefix
>
> instead of printing prefix=None for most enums. In particular,
>
>> +enum EnumOne ['value1', 'value2', 'value3'] prefix=None
>> +object EventStructOne
>> + member struct1: UserDefOne optional=False
>> + member string: str optional=False
>> + member enum2: EnumOne optional=True
>> +object NestedEnumsOne
>> + member enum1: EnumOne optional=False
>> + member enum2: EnumOne optional=True
>> + member enum3: EnumOne optional=False
>> + member enum4: EnumOne optional=True
>> +enum QEnumTwo ['value1', 'value2'] prefix=QENUM_TWO
>
> the fact that prefix=None and prefix=QENUM_TWO doesn't offer any visual
> clues on whether the string was user-supplied, means that the following
> would result in ambiguous output:
> { 'enum':'Foo', 'prefix':'None', 'data':[] }
No big deal. But avoiding it is no big deal, either. I'll give it a
try.
> But it's not necessarily a strong enough reason for a respin.
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
Thanks!
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (4 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:54 ` Daniel P. Berrange
` (2 more replies)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs Markus Armbruster
` (21 subsequent siblings)
27 siblings, 3 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Fixes flat unions to get the base's base members. Test case is from
commit 2fc0043, in qapi-schema-test.json:
{ 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase',
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
{ 'struct': 'UserDefUnionBase',
'base': 'UserDefZero',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
{ 'struct': 'UserDefZero',
'data': { 'integer': 'int' } }
Patch's effect on UserDefFlatUnion:
struct UserDefFlatUnion {
/* Members inherited from UserDefUnionBase: */
+ int64_t integer;
char *string;
EnumOne enum1;
/* Own members: */
union { /* union tag is @enum1 */
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
};
Flat union visitors remain broken. They'll be fixed next.
Two ugly special cases for simple unions now stand out like sore
thumbs:
1. The type tag is named 'type' everywhere, except in generated C,
where it's 'kind'.
2. QAPISchema lowers simple unions to semantically equivalent flat
unions. However, the C generated for a simple unions differs from
the C generated for its equivalent flat union, and we therefore
need special code to preserve that pointless difference for now.
Mark both TODO.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
docs/qapi-code-gen.txt | 51 +++---
scripts/qapi-types.py | 286 ++++++++++++++------------------
scripts/qapi.py | 10 +-
tests/qapi-schema/qapi-schema-test.json | 4 +-
4 files changed, 164 insertions(+), 187 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index d960dc0..c9e21fc 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -545,22 +545,6 @@ Example:
$ cat qapi-generated/example-qapi-types.c
[Uninteresting stuff omitted...]
- void qapi_free_UserDefOneList(UserDefOneList *obj)
- {
- QapiDeallocVisitor *md;
- Visitor *v;
-
- if (!obj) {
- return;
- }
-
- md = qapi_dealloc_visitor_new();
- v = qapi_dealloc_get_visitor(md);
- visit_type_UserDefOneList(v, &obj, NULL, NULL);
- qapi_dealloc_visitor_cleanup(md);
- }
-
-
void qapi_free_UserDefOne(UserDefOne *obj)
{
QapiDeallocVisitor *md;
@@ -575,6 +559,21 @@ Example:
visit_type_UserDefOne(v, &obj, NULL, NULL);
qapi_dealloc_visitor_cleanup(md);
}
+
+ void qapi_free_UserDefOneList(UserDefOneList *obj)
+ {
+ QapiDeallocVisitor *md;
+ Visitor *v;
+
+ if (!obj) {
+ return;
+ }
+
+ md = qapi_dealloc_visitor_new();
+ v = qapi_dealloc_get_visitor(md);
+ visit_type_UserDefOneList(v, &obj, NULL, NULL);
+ qapi_dealloc_visitor_cleanup(md);
+ }
$ cat qapi-generated/example-qapi-types.h
[Uninteresting stuff omitted...]
@@ -585,24 +584,24 @@ Example:
typedef struct UserDefOne UserDefOne;
- typedef struct UserDefOneList {
+ typedef struct UserDefOneList UserDefOneList;
+
+ struct UserDefOne {
+ int64_t integer;
+ char *string;
+ };
+
+ void qapi_free_UserDefOne(UserDefOne *obj);
+
+ struct UserDefOneList {
union {
UserDefOne *value;
uint64_t padding;
};
struct UserDefOneList *next;
- } UserDefOneList;
-
-
-[Functions on built-in types omitted...]
-
- struct UserDefOne {
- int64_t integer;
- char *string;
};
void qapi_free_UserDefOneList(UserDefOneList *obj);
- void qapi_free_UserDefOne(UserDefOne *obj);
#endif
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 23e9505..d78f529 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -2,88 +2,67 @@
# QAPI types generator
#
# Copyright IBM, Corp. 2011
+# Copyright (c) 2013-2015 Red Hat Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
+# Markus Armbruster <armbru@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
-from ordereddict import OrderedDict
from qapi import *
-def generate_fwd_builtin(name):
- return mcgen('''
-
-typedef struct %(name)sList {
- union {
- %(type)s value;
- uint64_t padding;
- };
- struct %(name)sList *next;
-} %(name)sList;
-''',
- type=c_type(name),
- name=name)
-
-def generate_fwd_struct(name):
+def gen_fwd_object_or_array(name):
return mcgen('''
typedef struct %(name)s %(name)s;
-
-typedef struct %(name)sList {
- union {
- %(name)s *value;
- uint64_t padding;
- };
- struct %(name)sList *next;
-} %(name)sList;
''',
name=c_name(name))
-def generate_fwd_enum_struct(name):
+def gen_array(name, element_type):
return mcgen('''
-typedef struct %(name)sList {
+struct %(name)s {
union {
- %(name)s value;
+ %(c_type)s value;
uint64_t padding;
};
- struct %(name)sList *next;
-} %(name)sList;
+ struct %(name)s *next;
+};
''',
- name=c_name(name))
+ name=c_name(name), c_type=element_type.c_type())
-def generate_struct_fields(members):
+def gen_struct_field(name, typ, optional):
ret = ''
- for argname, argentry, optional in parse_args(members):
- if optional:
- ret += mcgen('''
+ if optional:
+ ret += mcgen('''
bool has_%(c_name)s;
''',
- c_name=c_name(argname))
- ret += mcgen('''
+ c_name=c_name(name))
+ ret += mcgen('''
%(c_type)s %(c_name)s;
''',
- c_type=c_type(argentry), c_name=c_name(argname))
-
+ c_type=typ.c_type(), c_name=c_name(name))
return ret
-def generate_struct(expr):
+def generate_struct_fields(members):
+ ret = ''
- structname = expr.get('struct', "")
- members = expr['data']
- base = expr.get('base')
+ for memb in members:
+ ret += gen_struct_field(memb.name, memb.type, memb.optional)
+ return ret
+def gen_struct(name, base, members):
ret = mcgen('''
struct %(name)s {
''',
- name=c_name(structname))
+ name=c_name(name))
if base:
- ret += generate_struct_fields({'base': base})
+ ret += gen_struct_field('base', base, False)
ret += generate_struct_fields(members)
@@ -156,46 +135,38 @@ typedef enum %(name)s {
return enum_decl + lookup_decl
-def generate_alternate_qtypes(expr):
+def gen_alternate_qtypes_decl(name):
+ return mcgen('''
- name = expr['alternate']
- members = expr['data']
+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] = {
''',
name=c_name(name))
- for key in members:
- qtype = find_alternate_member_qtype(members[key])
- assert qtype, "Invalid alternate member"
+ for var in variants.variants:
+ qtype = var.type.alternate_qtype()
+ assert qtype
ret += mcgen('''
[%(qtype)s] = %(enum_const)s,
''',
qtype = qtype,
- enum_const = c_enum_const(name + 'Kind', key))
+ enum_const=c_enum_const(variants.tag_member.type.name,
+ var.name))
ret += mcgen('''
};
''')
return ret
-
-def generate_union(expr, meta):
-
- name = c_name(expr[meta])
- typeinfo = expr['data']
-
- base = expr.get('base')
- discriminator = expr.get('discriminator')
-
- enum_define = discriminator_find_enum_define(expr)
- if enum_define:
- discriminator_type_name = enum_define['enum_name']
- else:
- discriminator_type_name = '%sKind' % (name)
+def gen_union(name, base, variants):
+ name = c_name(name)
ret = mcgen('''
@@ -206,18 +177,16 @@ struct %(name)s {
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)
+ c_name=c_name(base.name))
+ ret += generate_struct_fields(base.members)
ret += mcgen('''
/* Own members: */
''')
else:
- assert not discriminator
ret += mcgen('''
%(discriminator_type_name)s kind;
''',
- discriminator_type_name=c_name(discriminator_type_name))
+ discriminator_type_name=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
@@ -231,39 +200,39 @@ struct %(name)s {
union { /* union tag is @%(c_name)s */
void *data;
''',
- c_name=c_name(discriminator or 'kind'))
+ # 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'))
- for key in typeinfo:
+ for var in variants.variants:
+ # Ugly special case for simple union TODO get rid of it
+ typ = var.simple_union_type() or var.type
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
- c_type=c_type(typeinfo[key]),
- c_name=c_name(key))
+ c_type=typ.c_type(),
+ c_name=c_name(var.name))
ret += mcgen('''
};
};
''')
- if meta == 'alternate':
- ret += mcgen('''
-extern const int %(name)s_qtypes[];
-''',
- name=name)
-
return ret
def generate_type_cleanup_decl(name):
ret = mcgen('''
-void qapi_free_%(name)s(%(c_type)s obj);
+
+void qapi_free_%(name)s(%(name)s *obj);
''',
- c_type=c_type(name), name=c_name(name))
+ name=c_name(name))
return ret
def generate_type_cleanup(name):
ret = mcgen('''
-void qapi_free_%(name)s(%(c_type)s obj)
+void qapi_free_%(name)s(%(name)s *obj)
{
QapiDeallocVisitor *md;
Visitor *v;
@@ -278,9 +247,79 @@ void qapi_free_%(name)s(%(c_type)s obj)
qapi_dealloc_visitor_cleanup(md);
}
''',
- c_type=c_type(name), name=c_name(name))
+ name=c_name(name))
return ret
+
+class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
+ def __init__(self):
+ self.decl = None
+ self.defn = None
+ self._fwdecl = None
+ self._fwdefn = None
+ self._btin = None
+
+ def visit_begin(self, schema):
+ self.decl = ''
+ self.defn = ''
+ self._fwdecl = ''
+ self._fwdefn = ''
+ self._btin = guardstart('QAPI_TYPES_BUILTIN')
+
+ def visit_end(self):
+ self.decl = self._fwdecl + self.decl
+ self._fwdecl = None
+ self.defn = self._fwdefn + self.defn
+ self._fwdefn = None
+ # To avoid header dependency hell, we always generate
+ # declarations for built-in types in our header files and
+ # simply guard them. See also do_builtins (command line
+ # option -b).
+ self._btin += guardend('QAPI_TYPES_BUILTIN')
+ self.decl = self._btin + self.decl
+ self._btin = None
+
+ def _gen_type_cleanup(self, name):
+ self.decl += generate_type_cleanup_decl(name)
+ self.defn += generate_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)
+
+ 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)
+ if do_builtins:
+ self.defn += generate_type_cleanup(name)
+ else:
+ self._fwdecl += gen_fwd_object_or_array(name)
+ self.decl += gen_array(name, element_type)
+ self._gen_type_cleanup(name)
+
+ def visit_object_type(self, name, info, base, members, variants):
+ if info:
+ self._fwdecl += gen_fwd_object_or_array(name)
+ if variants:
+ assert not members # not implemented
+ self.decl += gen_union(name, base, variants)
+ else:
+ self.decl += gen_struct(name, base, members)
+ self._gen_type_cleanup(name)
+
+ def visit_alternate_type(self, name, info, variants):
+ self._fwdecl += gen_fwd_object_or_array(name)
+ self._fwdefn += gen_alternate_qtypes(name, variants)
+ self.decl += gen_union(name, None, variants)
+ self.decl += gen_alternate_qtypes_decl(name)
+ self._gen_type_cleanup(name)
+
+# If you link code generated from multiple schemata, you want only one
+# instance of the code for built-in types. Generate it only when
+# do_builtins, enabled by command line option -b. See also
+# QAPISchemaGenTypeVisitor.visit_end().
do_builtins = False
(input_file, output_dir, do_c, do_h, prefix, opts) = \
@@ -336,79 +375,10 @@ fdecl.write(mcgen('''
#include <stdint.h>
'''))
-exprs = QAPISchema(input_file).get_exprs()
-
-fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
-for typename in builtin_types.keys():
- fdecl.write(generate_fwd_builtin(typename))
-fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
-
-for expr in exprs:
- ret = ""
- if expr.has_key('struct'):
- ret += generate_fwd_struct(expr['struct'])
- elif expr.has_key('enum'):
- ret += generate_enum(expr['enum'], expr['data'],
- expr.get('prefix'))
- ret += generate_fwd_enum_struct(expr['enum'])
- fdef.write(generate_enum_lookup(expr['enum'], expr['data'],
- expr.get('prefix')))
- elif expr.has_key('union'):
- ret += generate_fwd_struct(expr['union'])
- enum_define = discriminator_find_enum_define(expr)
- if not enum_define:
- ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
- fdef.write(generate_enum_lookup('%sKind' % expr['union'],
- expr['data'].keys()))
- elif expr.has_key('alternate'):
- ret += generate_fwd_struct(expr['alternate'])
- ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
- fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
- expr['data'].keys()))
- fdef.write(generate_alternate_qtypes(expr))
- else:
- continue
- fdecl.write(ret)
-
-# to avoid header dependency hell, we always generate declarations
-# for built-in types in our header files and simply guard them
-fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
-for typename in builtin_types.keys():
- fdecl.write(generate_type_cleanup_decl(typename + "List"))
-fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
-
-# ...this doesn't work for cases where we link in multiple objects that
-# have the functions defined, so we use -b option to provide control
-# over these cases
-if do_builtins:
- for typename in builtin_types.keys():
- fdef.write(generate_type_cleanup(typename + "List"))
-
-for expr in exprs:
- ret = ""
- if expr.has_key('struct'):
- ret += generate_struct(expr) + "\n"
- ret += generate_type_cleanup_decl(expr['struct'] + "List")
- fdef.write(generate_type_cleanup(expr['struct'] + "List"))
- ret += generate_type_cleanup_decl(expr['struct'])
- fdef.write(generate_type_cleanup(expr['struct']))
- elif expr.has_key('union'):
- ret += generate_union(expr, 'union') + "\n"
- ret += generate_type_cleanup_decl(expr['union'] + "List")
- fdef.write(generate_type_cleanup(expr['union'] + "List"))
- ret += generate_type_cleanup_decl(expr['union'])
- fdef.write(generate_type_cleanup(expr['union']))
- elif expr.has_key('alternate'):
- ret += generate_union(expr, 'alternate') + "\n"
- ret += generate_type_cleanup_decl(expr['alternate'] + "List")
- fdef.write(generate_type_cleanup(expr['alternate'] + "List"))
- ret += generate_type_cleanup_decl(expr['alternate'])
- fdef.write(generate_type_cleanup(expr['alternate']))
- elif expr.has_key('enum'):
- ret += "\n" + generate_type_cleanup_decl(expr['enum'] + "List")
- fdef.write(generate_type_cleanup(expr['enum'] + "List"))
- else:
- continue
- fdecl.write(ret)
+schema = QAPISchema(input_file)
+gen = QAPISchemaGenTypeVisitor()
+schema.visit(gen)
+fdef.write(gen.defn)
+fdecl.write(gen.decl)
close_output(fdef, fdecl)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index e9cee38..3e0fc12 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -994,7 +994,6 @@ class QAPISchemaObjectTypeVariants(object):
vseen = dict(seen)
v.check(schema, self.tag_member.type, vseen)
-
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
def __init__(self, name, typ):
QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
@@ -1003,6 +1002,15 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
QAPISchemaObjectTypeMember.check(self, schema, [], seen)
assert self.name in tag_type.values
+ # This function exists to support ugly simple union special cases
+ # TODO get rid of them, and drop the function
+ def simple_union_type(self):
+ if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
+ assert len(self.type.members) == 1
+ assert not self.type.variants
+ return self.type.members[0].type
+ return None
+
class QAPISchemaAlternateType(QAPISchemaType):
def __init__(self, name, info, variants):
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 677190c..ca81a82 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -44,8 +44,8 @@
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
-# FIXME generated struct UserDefFlatUnion has members for direct base
-# UserDefUnionBase, but lacks members for indirect base UserDefZero
+# FIXME generated visit_type_UserDefFlatUnion_fields() fails to visit
+# members of indirect base UserDefZero
{ 'struct': 'UserDefUnionBase',
'base': 'UserDefZero',
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions Markus Armbruster
@ 2015-09-16 14:54 ` Daniel P. Berrange
2015-09-16 17:09 ` Eric Blake
2015-09-17 17:00 ` Eric Blake
2 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:54 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:09PM +0200, Markus Armbruster wrote:
> Fixes flat unions to get the base's base members. Test case is from
> commit 2fc0043, in qapi-schema-test.json:
>
> { 'union': 'UserDefFlatUnion',
> 'base': 'UserDefUnionBase',
> 'discriminator': 'enum1',
> 'data': { 'value1' : 'UserDefA',
> 'value2' : 'UserDefB',
> 'value3' : 'UserDefB' } }
>
> { 'struct': 'UserDefUnionBase',
> 'base': 'UserDefZero',
> 'data': { 'string': 'str', 'enum1': 'EnumOne' } }
>
> { 'struct': 'UserDefZero',
> 'data': { 'integer': 'int' } }
>
> Patch's effect on UserDefFlatUnion:
>
> struct UserDefFlatUnion {
> /* Members inherited from UserDefUnionBase: */
> + int64_t integer;
> char *string;
> EnumOne enum1;
> /* Own members: */
> union { /* union tag is @enum1 */
> void *data;
> UserDefA *value1;
> UserDefB *value2;
> UserDefB *value3;
> };
> };
>
> Flat union visitors remain broken. They'll be fixed next.
>
> Two ugly special cases for simple unions now stand out like sore
> thumbs:
>
> 1. The type tag is named 'type' everywhere, except in generated C,
> where it's 'kind'.
>
> 2. QAPISchema lowers simple unions to semantically equivalent flat
> unions. However, the C generated for a simple unions differs from
> the C generated for its equivalent flat union, and we therefore
> need special code to preserve that pointless difference for now.
>
> Mark both TODO.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> docs/qapi-code-gen.txt | 51 +++---
> scripts/qapi-types.py | 286 ++++++++++++++------------------
> scripts/qapi.py | 10 +-
> tests/qapi-schema/qapi-schema-test.json | 4 +-
> 4 files changed, 164 insertions(+), 187 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions Markus Armbruster
2015-09-16 14:54 ` Daniel P. Berrange
@ 2015-09-16 17:09 ` Eric Blake
2015-09-17 17:00 ` Eric Blake
2 siblings, 0 replies; 55+ messages in thread
From: Eric Blake @ 2015-09-16 17:09 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 1182 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> Fixes flat unions to get the base's base members. Test case is from
> commit 2fc0043, in qapi-schema-test.json:
>
>
> Flat union visitors remain broken. They'll be fixed next.
>
> Two ugly special cases for simple unions now stand out like sore
> thumbs:
>
> 1. The type tag is named 'type' everywhere, except in generated C,
> where it's 'kind'.
>
> 2. QAPISchema lowers simple unions to semantically equivalent flat
> unions. However, the C generated for a simple unions differs from
> the C generated for its equivalent flat union, and we therefore
> need special code to preserve that pointless difference for now.
>
> Mark both TODO.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> +
> + def visit_enum_type(self, name, info, values, prefix):
> + self._fwdecl += generate_enum(name, values, prefix)
> + self._fwdefn += generate_enum_lookup(name, values, prefix)
straightforward.
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions Markus Armbruster
2015-09-16 14:54 ` Daniel P. Berrange
2015-09-16 17:09 ` Eric Blake
@ 2015-09-17 17:00 ` Eric Blake
2015-09-18 6:54 ` Markus Armbruster
2 siblings, 1 reply; 55+ messages in thread
From: Eric Blake @ 2015-09-17 17:00 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 2150 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> Fixes flat unions to get the base's base members. Test case is from
> commit 2fc0043, in qapi-schema-test.json:
>
> { 'union': 'UserDefFlatUnion',
> 'base': 'UserDefUnionBase',
> 'discriminator': 'enum1',
> 'data': { 'value1' : 'UserDefA',
> 'value2' : 'UserDefB',
> 'value3' : 'UserDefB' } }
>
> { 'struct': 'UserDefUnionBase',
> 'base': 'UserDefZero',
> 'data': { 'string': 'str', 'enum1': 'EnumOne' } }
>
> { 'struct': 'UserDefZero',
> 'data': { 'integer': 'int' } }
>
> Patch's effect on UserDefFlatUnion:
>
> struct UserDefFlatUnion {
> /* Members inherited from UserDefUnionBase: */
> + int64_t integer;
> char *string;
There is another change not listed here. When you were developing with
scaffolding patches, you split the 'typedef struct UserDefFlatUnion {'
into two lines in that patch, and then the diff seen by this patch when
generating the commit message didn't see anything change. But now that
you reverted the scaffolding out of the series, it is now THIS patch
that is converting from inline:
typedef struct UserDefFlatUnion {
...
} UserDefFlatUnion;
to the separate:
typedef struct UserDefFlatUnion;
...
struct UserDefFlatUnion {
...
};
> -def generate_fwd_struct(name):
> +def gen_fwd_object_or_array(name):
> return mcgen('''
>
> typedef struct %(name)s %(name)s;
> -
> -typedef struct %(name)sList {
> - union {
> - %(name)s *value;
> - uint64_t padding;
> - };
> - struct %(name)sList *next;
> -} %(name)sList;
> ''',
> name=c_name(name))
>
> -def generate_fwd_enum_struct(name):
> +def gen_array(name, element_type):
> return mcgen('''
>
> -typedef struct %(name)sList {
> +struct %(name)s {
My R-b still stands, but it would be nice to update this commit message
to reflect that this change was intentional.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions
2015-09-17 17:00 ` Eric Blake
@ 2015-09-18 6:54 ` Markus Armbruster
0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-18 6:54 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, mdroth
Eric Blake <eblake@redhat.com> writes:
> On 09/16/2015 05:06 AM, Markus Armbruster wrote:
>> Fixes flat unions to get the base's base members. Test case is from
>> commit 2fc0043, in qapi-schema-test.json:
>>
>> { 'union': 'UserDefFlatUnion',
>> 'base': 'UserDefUnionBase',
>> 'discriminator': 'enum1',
>> 'data': { 'value1' : 'UserDefA',
>> 'value2' : 'UserDefB',
>> 'value3' : 'UserDefB' } }
>>
>> { 'struct': 'UserDefUnionBase',
>> 'base': 'UserDefZero',
>> 'data': { 'string': 'str', 'enum1': 'EnumOne' } }
>>
>> { 'struct': 'UserDefZero',
>> 'data': { 'integer': 'int' } }
>>
>> Patch's effect on UserDefFlatUnion:
>>
>> struct UserDefFlatUnion {
>> /* Members inherited from UserDefUnionBase: */
>> + int64_t integer;
>> char *string;
>
> There is another change not listed here. When you were developing with
> scaffolding patches, you split the 'typedef struct UserDefFlatUnion {'
> into two lines in that patch, and then the diff seen by this patch when
> generating the commit message didn't see anything change. But now that
> you reverted the scaffolding out of the series, it is now THIS patch
> that is converting from inline:
>
> typedef struct UserDefFlatUnion {
> ...
> } UserDefFlatUnion;
>
> to the separate:
>
> typedef struct UserDefFlatUnion;
> ...
> struct UserDefFlatUnion {
> ...
> };
>
>
>> -def generate_fwd_struct(name):
>> +def gen_fwd_object_or_array(name):
>> return mcgen('''
>>
>> typedef struct %(name)s %(name)s;
>> -
>> -typedef struct %(name)sList {
>> - union {
>> - %(name)s *value;
>> - uint64_t padding;
>> - };
>> - struct %(name)sList *next;
>> -} %(name)sList;
>> ''',
>> name=c_name(name))
>>
>> -def generate_fwd_enum_struct(name):
>> +def gen_array(name, element_type):
>> return mcgen('''
>>
>> -typedef struct %(name)sList {
>> +struct %(name)s {
>
> My R-b still stands, but it would be nice to update this commit message
> to reflect that this change was intentional.
Can do. Thanks!
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (5 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:54 ` Daniel P. Berrange
2015-09-16 17:10 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 08/26] qapi-commands: Convert to QAPISchemaVisitor Markus Armbruster
` (20 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Fixes flat unions to visit the base's base members (the previous
commit merely added them to the struct). Same test case.
Patch's effect on visit_type_UserDefFlatUnion():
static void visit_type_UserDefFlatUnion_fields(Visitor *m, UserDefFlatUnion **obj, Error **errp)
{
Error *err = NULL;
+ visit_type_int(m, &(*obj)->integer, "integer", &err);
+ if (err) {
+ goto out;
+ }
visit_type_str(m, &(*obj)->string, "string", &err);
if (err) {
goto out;
Test cases updated for the bug fix.
Fixes alternates to generate a visitor for their implicit enumeration
type. None of them are currently used, obviously. Example:
block-core.json's BlockdevRef now generates
visit_type_BlockdevRefKind().
The previous commit's two ugly special cases exist here, too. Mark
both TODO.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi-visit.py | 270 +++++++++++++-------------------
tests/qapi-schema/qapi-schema-test.json | 3 -
tests/test-qmp-input-strict.c | 4 +-
tests/test-qmp-input-visitor.c | 4 +-
4 files changed, 117 insertions(+), 164 deletions(-)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index c493964..8e6e8ca 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -12,7 +12,6 @@
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
-from ordereddict import OrderedDict
from qapi import *
import re
@@ -24,13 +23,13 @@ def generate_visit_implicit_struct(type):
return ''
implicit_structs_seen.add(type)
ret = ''
- if type not in struct_fields_seen:
+ if type.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_name(type))
+ c_type=type.c_name())
ret += mcgen('''
@@ -46,7 +45,7 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error *
error_propagate(errp, err);
}
''',
- c_type=type_name(type))
+ c_type=type.c_name())
return ret
def generate_visit_struct_fields(name, members, base = None):
@@ -74,24 +73,24 @@ if (err) {
goto out;
}
''',
- type=type_name(base), c_name=c_name('base'))
+ type=base.c_name(), c_name=c_name('base'))
- for argname, argentry, optional in parse_args(members):
- if optional:
+ for memb in members:
+ if memb.optional:
ret += mcgen('''
visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
if (!err && (*obj)->has_%(c_name)s) {
''',
- c_name=c_name(argname), name=argname)
+ c_name=c_name(memb.name), name=memb.name)
push_indent()
ret += mcgen('''
visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
''',
- type=type_name(argentry), c_name=c_name(argname),
- name=argname)
+ type=memb.type.c_name(), c_name=c_name(memb.name),
+ name=memb.name)
- if optional:
+ if memb.optional:
pop_indent()
ret += mcgen('''
}
@@ -136,12 +135,7 @@ def generate_visit_struct_body(name):
return ret
-def generate_visit_struct(expr):
-
- name = expr['struct']
- members = expr['data']
- base = expr.get('base')
-
+def gen_visit_struct(name, base, members):
ret = generate_visit_struct_fields(name, members, base)
ret += mcgen('''
@@ -158,10 +152,10 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
''')
return ret
-def generate_visit_list(name):
+def gen_visit_list(name, element_type):
return mcgen('''
-void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
+void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
{
Error *err = NULL;
GenericList *i, **prev;
@@ -174,8 +168,8 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
for (prev = (GenericList **)obj;
!err && (i = visit_next_list(m, prev, &err)) != NULL;
prev = &i) {
- %(name)sList *native_i = (%(name)sList *)i;
- visit_type_%(name)s(m, &native_i->value, NULL, &err);
+ %(name)s *native_i = (%(name)s *)i;
+ visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err);
}
error_propagate(errp, err);
@@ -185,7 +179,8 @@ out:
error_propagate(errp, err);
}
''',
- name=type_name(name))
+ name=c_name(name),
+ c_elt_type=element_type.c_name())
def generate_visit_enum(name):
return mcgen('''
@@ -197,7 +192,7 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error
''',
c_name=c_name(name), name=name)
-def generate_visit_alternate(name, members):
+def gen_visit_alternate(name, variants):
ret = mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
@@ -216,25 +211,17 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
''',
name=c_name(name))
- # For alternate, always use the default enum type automatically generated
- # as name + 'Kind'
- disc_type = c_name(name) + 'Kind'
-
- for key in members:
- assert (members[key] in builtin_types.keys()
- or find_struct(members[key])
- or find_union(members[key])
- or find_enum(members[key])), "Invalid alternate member"
-
- enum_full_value = c_enum_const(disc_type, key)
+ 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:
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
break;
''',
enum_full_value = enum_full_value,
- c_type = type_name(members[key]),
- c_name = c_name(key))
+ c_type=var.type.c_name(),
+ c_name=c_name(var.name))
ret += mcgen('''
default:
@@ -251,35 +238,17 @@ out:
return ret
-
-def generate_visit_union(expr):
-
- name = expr['union']
- members = expr['data']
-
- base = expr.get('base')
- discriminator = expr.get('discriminator')
-
- enum_define = discriminator_find_enum_define(expr)
- if enum_define:
- # Use the enum type as discriminator
- ret = ""
- disc_type = c_name(enum_define['enum_name'])
- else:
- # There will always be a discriminator in the C switch code, by default
- # it is an enum type generated silently
- ret = generate_visit_enum(name + 'Kind')
- disc_type = c_name(name) + 'Kind'
+def gen_visit_union(name, base, variants):
+ ret = ''
if base:
- assert discriminator
- base_fields = find_struct(base)['data'].copy()
- del base_fields[discriminator]
- ret += generate_visit_struct_fields(name, base_fields)
+ members = [m for m in base.members if m != variants.tag_member]
+ ret += generate_visit_struct_fields(name, members)
- if discriminator:
- for key in members:
- ret += generate_visit_implicit_struct(members[key])
+ 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 += mcgen('''
@@ -304,41 +273,44 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error
''',
name=c_name(name))
- if not discriminator:
- tag = 'kind'
- disc_key = "type"
- else:
- tag = discriminator
- disc_key = discriminator
+ disc_key = variants.tag_member.name
+ if not variants.tag_name:
+ # we pointlessly use a different key for simple unions
+ disc_key = 'type'
ret += mcgen('''
- visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
+ visit_type_%(disc_type)s(m, &(*obj)->%(c_name)s, "%(disc_key)s", &err);
if (err) {
goto out_obj;
}
if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
goto out_obj;
}
- switch ((*obj)->%(c_tag)s) {
+ switch ((*obj)->%(c_name)s) {
''',
- disc_type = disc_type,
- c_tag=c_name(tag),
+ disc_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)
- for key in members:
- if not discriminator:
+ 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(disc_type, key)
+ enum_full_value = c_enum_const(variants.tag_member.type.name, var.name)
ret += mcgen('''
case %(enum_full_value)s:
''' + fmt + '''
break;
''',
enum_full_value = enum_full_value,
- c_type=type_name(members[key]),
- c_name=c_name(key))
+ c_type=(simple_union_type or var.type).c_name(),
+ c_name=c_name(var.name))
ret += mcgen('''
default:
@@ -359,38 +331,68 @@ out:
return ret
-def generate_declaration(name, builtin_type=False):
- ret = ""
- if not builtin_type:
- name = c_name(name)
- ret += mcgen('''
-
-void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
-''',
- name=name)
-
- ret += mcgen('''
-void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
-''',
- name=name)
-
- return ret
-
-def generate_enum_declaration(name):
- ret = mcgen('''
-void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
-''',
- name=c_name(name))
-
- return ret
-
-def generate_decl_enum(name):
+def gen_visit_decl(name, scalar=False):
+ c_type = c_name(name) + ' *'
+ if not scalar:
+ c_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_type)sobj, const char *name, Error **errp);
''',
- name=c_name(name))
+ c_name=c_name(name), c_type=c_type)
+
+class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
+ def __init__(self):
+ self.decl = None
+ self.defn = None
+ self._btin = None
+
+ def visit_begin(self, schema):
+ self.decl = ''
+ self.defn = ''
+ self._btin = guardstart('QAPI_VISIT_BUILTIN')
+
+ def visit_end(self):
+ # To avoid header dependency hell, we always generate
+ # declarations for built-in types in our header files and
+ # simply guard them. See also do_builtins (command line
+ # option -b).
+ self._btin += guardend('QAPI_VISIT_BUILTIN')
+ self.decl = self._btin + self.decl
+ self._btin = None
+
+ def visit_enum_type(self, name, info, values, prefix):
+ self.decl += gen_visit_decl(name, scalar=True)
+ self.defn += generate_visit_enum(name)
+
+ def visit_array_type(self, name, info, element_type):
+ decl = gen_visit_decl(name)
+ defn = gen_visit_list(name, element_type)
+ if isinstance(element_type, QAPISchemaBuiltinType):
+ self._btin += decl
+ if do_builtins:
+ self.defn += defn
+ else:
+ self.decl += decl
+ self.defn += defn
+
+ def visit_object_type(self, name, info, base, members, variants):
+ if info:
+ self.decl += gen_visit_decl(name)
+ if variants:
+ assert not members # not implemented
+ self.defn += gen_visit_union(name, base, variants)
+ else:
+ self.defn += gen_visit_struct(name, base, members)
+
+ def visit_alternate_type(self, name, info, variants):
+ self.decl += gen_visit_decl(name)
+ self.defn += gen_visit_alternate(name, variants)
+
+# If you link code generated from multiple schemata, you want only one
+# instance of the code for built-in types. Generate it only when
+# do_builtins, enabled by command line option -b. See also
+# QAPISchemaGenVisitVisitor.visit_end().
do_builtins = False
(input_file, output_dir, do_c, do_h, prefix, opts) = \
@@ -446,56 +448,10 @@ fdecl.write(mcgen('''
''',
prefix=prefix))
-exprs = QAPISchema(input_file).get_exprs()
-
-# to avoid header dependency hell, we always generate declarations
-# for built-in types in our header files and simply guard them
-fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
-for typename in builtin_types.keys():
- fdecl.write(generate_declaration(typename, builtin_type=True))
-fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
-
-# ...this doesn't work for cases where we link in multiple objects that
-# have the functions defined, so we use -b option to provide control
-# over these cases
-if do_builtins:
- for typename in builtin_types.keys():
- fdef.write(generate_visit_list(typename))
-
-for expr in exprs:
- if expr.has_key('struct'):
- ret = generate_visit_struct(expr)
- ret += generate_visit_list(expr['struct'])
- fdef.write(ret)
-
- ret = generate_declaration(expr['struct'])
- fdecl.write(ret)
- elif expr.has_key('union'):
- ret = generate_visit_union(expr)
- ret += generate_visit_list(expr['union'])
- fdef.write(ret)
-
- enum_define = discriminator_find_enum_define(expr)
- ret = ""
- if not enum_define:
- ret = generate_decl_enum('%sKind' % expr['union'])
- ret += generate_declaration(expr['union'])
- fdecl.write(ret)
- elif expr.has_key('alternate'):
- ret = generate_visit_alternate(expr['alternate'], expr['data'])
- ret += generate_visit_list(expr['alternate'])
- fdef.write(ret)
-
- ret = generate_decl_enum('%sKind' % expr['alternate'])
- ret += generate_declaration(expr['alternate'])
- fdecl.write(ret)
- elif expr.has_key('enum'):
- ret = generate_visit_list(expr['enum'])
- ret += generate_visit_enum(expr['enum'])
- fdef.write(ret)
-
- ret = generate_decl_enum(expr['enum'])
- ret += generate_enum_declaration(expr['enum'])
- fdecl.write(ret)
+schema = QAPISchema(input_file)
+gen = QAPISchemaGenVisitVisitor()
+schema.visit(gen)
+fdef.write(gen.defn)
+fdecl.write(gen.decl)
close_output(fdef, fdecl)
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index ca81a82..7d984b6 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -44,8 +44,6 @@
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
-# FIXME generated visit_type_UserDefFlatUnion_fields() fails to visit
-# members of indirect base UserDefZero
{ 'struct': 'UserDefUnionBase',
'base': 'UserDefZero',
@@ -62,7 +60,6 @@
{ 'alternate': 'UserDefAlternate',
'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
-# FIXME only a declaration of visit_type_UserDefAlternateKind() generated
{ 'struct': 'UserDefC',
'data': { 'string1': 'str', 'string2': 'str' } }
diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
index 68f855b..a2ae786 100644
--- a/tests/test-qmp-input-strict.c
+++ b/tests/test-qmp-input-strict.c
@@ -167,9 +167,9 @@ static void test_validate_union_flat(TestInputVisitorData *data,
v = validate_test_init(data,
"{ 'enum1': 'value1', "
+ "'integer': 41, "
"'string': 'str', "
"'boolean': true }");
- /* TODO when generator bug is fixed, add 'integer': 41 */
visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
g_assert(!err);
@@ -272,7 +272,7 @@ static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data,
Visitor *v;
/* test situation where discriminator field ('enum1' here) is missing */
- v = validate_test_init(data, "{ 'string': 'c', 'string1': 'd', 'string2': 'e' }");
+ v = validate_test_init(data, "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2': 'e' }");
visit_type_UserDefFlatUnion2(v, &tmp, NULL, &err);
g_assert(err);
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index a5cfefa..508c11a 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -307,15 +307,15 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
v = visitor_input_test_init(data,
"{ 'enum1': 'value1', "
+ "'integer': 41, "
"'string': 'str', "
"'boolean': true }");
- /* TODO when generator bug is fixed, add 'integer': 41 */
visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
g_assert(err == NULL);
g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
g_assert_cmpstr(tmp->string, ==, "str");
- /* TODO g_assert_cmpint(tmp->integer, ==, 41); */
+ g_assert_cmpint(tmp->integer, ==, 41);
g_assert_cmpint(tmp->value1->boolean, ==, true);
qapi_free_UserDefFlatUnion(tmp);
}
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs Markus Armbruster
@ 2015-09-16 14:54 ` Daniel P. Berrange
2015-09-16 17:10 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:54 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:10PM +0200, Markus Armbruster wrote:
> Fixes flat unions to visit the base's base members (the previous
> commit merely added them to the struct). Same test case.
>
> Patch's effect on visit_type_UserDefFlatUnion():
>
> static void visit_type_UserDefFlatUnion_fields(Visitor *m, UserDefFlatUnion **obj, Error **errp)
> {
> Error *err = NULL;
>
> + visit_type_int(m, &(*obj)->integer, "integer", &err);
> + if (err) {
> + goto out;
> + }
> visit_type_str(m, &(*obj)->string, "string", &err);
> if (err) {
> goto out;
>
> Test cases updated for the bug fix.
>
> Fixes alternates to generate a visitor for their implicit enumeration
> type. None of them are currently used, obviously. Example:
> block-core.json's BlockdevRef now generates
> visit_type_BlockdevRefKind().
>
> The previous commit's two ugly special cases exist here, too. Mark
> both TODO.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> scripts/qapi-visit.py | 270 +++++++++++++-------------------
> tests/qapi-schema/qapi-schema-test.json | 3 -
> tests/test-qmp-input-strict.c | 4 +-
> tests/test-qmp-input-visitor.c | 4 +-
> 4 files changed, 117 insertions(+), 164 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs Markus Armbruster
2015-09-16 14:54 ` Daniel P. Berrange
@ 2015-09-16 17:10 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Eric Blake @ 2015-09-16 17:10 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 1104 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> Fixes flat unions to visit the base's base members (the previous
> commit merely added them to the struct). Same test case.
>
> Test cases updated for the bug fix.
>
> Fixes alternates to generate a visitor for their implicit enumeration
> type. None of them are currently used, obviously. Example:
> block-core.json's BlockdevRef now generates
> visit_type_BlockdevRefKind().
>
> The previous commit's two ugly special cases exist here, too. Mark
> both TODO.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> +
> + def visit_enum_type(self, name, info, values, prefix):
> + self.decl += gen_visit_decl(name, scalar=True)
> + self.defn += generate_visit_enum(name)
Not even used; just part of the overriding contract. I don't know if
python has any convention for marking known-unused parameters, so this
looks okay to me :)
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 08/26] qapi-commands: Convert to QAPISchemaVisitor
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (6 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:57 ` Daniel P. Berrange
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation Markus Armbruster
` (19 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Output unchanged apart from reordering and white-space.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
scripts/qapi-commands.py | 159 +++++++++++++++++++++++++++--------------------
scripts/qapi.py | 2 +-
2 files changed, 91 insertions(+), 70 deletions(-)
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 12bdc4c..a68517a 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -12,21 +12,22 @@
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
-from ordereddict import OrderedDict
from qapi import *
import re
def generate_command_decl(name, args, ret_type):
arglist=""
- for argname, argtype, optional in parse_args(args):
- argtype = c_type(argtype, is_param=True)
- if optional:
- arglist += "bool has_%s, " % c_name(argname)
- arglist += "%s %s, " % (argtype, c_name(argname))
+ if args:
+ for memb in args.members:
+ argtype = memb.type.c_type(is_param=True)
+ if memb.optional:
+ arglist += "bool has_%s, " % c_name(memb.name)
+ arglist += "%s %s, " % (argtype, c_name(memb.name))
return mcgen('''
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
''',
- ret_type=c_type(ret_type), name=c_name(name),
+ ret_type=(ret_type and ret_type.c_type()) or 'void',
+ name=c_name(name),
args=arglist)
def gen_err_check(err):
@@ -45,10 +46,11 @@ def gen_sync_call(name, args, ret_type):
retval=""
if ret_type:
retval = "retval = "
- for argname, argtype, optional in parse_args(args):
- if optional:
- arglist += "has_%s, " % c_name(argname)
- arglist += "%s, " % (c_name(argname))
+ if args:
+ for memb in args.members:
+ if memb.optional:
+ arglist += "has_%s, " % c_name(memb.name)
+ arglist += "%s, " % c_name(memb.name)
push_indent()
ret = mcgen('''
%(retval)sqmp_%(name)s(%(args)s&local_err);
@@ -68,7 +70,7 @@ def gen_visitor_input_containers_decl(args):
ret = ""
push_indent()
- if len(args) > 0:
+ if args:
ret += mcgen('''
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md;
@@ -81,22 +83,26 @@ Visitor *v;
def gen_visitor_input_vars_decl(args):
ret = ""
push_indent()
- for argname, argtype, optional in parse_args(args):
- if optional:
- ret += mcgen('''
+
+ if args:
+ for memb in args.members:
+ if memb.optional:
+ ret += mcgen('''
bool has_%(argname)s = false;
''',
- argname=c_name(argname))
- if is_c_ptr(argtype):
- ret += mcgen('''
+ argname=c_name(memb.name))
+ if is_c_ptr(memb.type.c_type()):
+ ret += mcgen('''
%(argtype)s %(argname)s = NULL;
''',
- argname=c_name(argname), argtype=c_type(argtype))
- else:
- ret += mcgen('''
+ argname=c_name(memb.name),
+ argtype=memb.type.c_type())
+ else:
+ ret += mcgen('''
%(argtype)s %(argname)s = {0};
''',
- argname=c_name(argname), argtype=c_type(argtype))
+ argname=c_name(memb.name),
+ argtype=memb.type.c_type())
pop_indent()
return ret
@@ -106,7 +112,7 @@ def gen_visitor_input_block(args, dealloc=False):
errparg = '&local_err'
errarg = 'local_err'
- if len(args) == 0:
+ if not args:
return ret
push_indent()
@@ -124,25 +130,26 @@ v = qapi_dealloc_get_visitor(md);
v = qmp_input_get_visitor(mi);
''')
- for argname, argtype, optional in parse_args(args):
- if optional:
+ for memb in args.members:
+ if memb.optional:
ret += mcgen('''
visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
''',
- c_name=c_name(argname), name=argname, errp=errparg)
+ c_name=c_name(memb.name), name=memb.name,
+ errp=errparg)
ret += gen_err_check(errarg)
ret += mcgen('''
if (has_%(c_name)s) {
''',
- c_name=c_name(argname))
+ c_name=c_name(memb.name))
push_indent()
ret += mcgen('''
visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
''',
- c_name=c_name(argname), name=argname, argtype=argtype,
- visitor=type_name(argtype), errp=errparg)
+ c_name=c_name(memb.name), name=memb.name,
+ visitor=memb.type.c_name(), errp=errparg)
ret += gen_err_check(errarg)
- if optional:
+ if memb.optional:
pop_indent()
ret += mcgen('''
}
@@ -160,6 +167,7 @@ def gen_marshal_output(name, ret_type):
return ""
ret = mcgen('''
+
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
{
Error *local_err = NULL;
@@ -183,8 +191,8 @@ out:
qapi_dealloc_visitor_cleanup(md);
}
''',
- c_ret_type=c_type(ret_type), c_name=c_name(name),
- visitor=type_name(ret_type))
+ c_ret_type=ret_type.c_type(), c_name=c_name(name),
+ visitor=ret_type.c_name())
return ret
@@ -198,6 +206,7 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
hdr = gen_marshal_input_decl(name, middle_mode)
ret = mcgen('''
+
%(header)s
{
Error *local_err = NULL;
@@ -208,9 +217,9 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
ret += mcgen('''
%(c_type)s retval;
''',
- c_type=c_type(ret_type))
+ c_type=ret_type.c_type())
- if len(args) > 0:
+ if args:
ret += gen_visitor_input_containers_decl(args)
ret += gen_visitor_input_vars_decl(args) + '\n'
ret += gen_visitor_input_block(args) + '\n'
@@ -237,21 +246,23 @@ out:
''')
return ret
-def gen_registry(commands):
- registry=""
+def gen_register_command(name, success_response):
push_indent()
- for cmd in commands:
- options = 'QCO_NO_OPTIONS'
- if not cmd.get('success-response', True):
- options = 'QCO_NO_SUCCESS_RESP'
+ options = 'QCO_NO_OPTIONS'
+ if not success_response:
+ options = 'QCO_NO_SUCCESS_RESP'
- registry += mcgen('''
+ ret = mcgen('''
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
''',
- name=cmd['command'], c_name=c_name(cmd['command']),
+ name=name, c_name=c_name(name),
opts=options)
pop_indent()
+ return ret
+
+def gen_registry(registry):
ret = mcgen('''
+
static void qmp_init_marshal(void)
{
''')
@@ -263,6 +274,37 @@ qapi_init(qmp_init_marshal);
''')
return ret
+
+class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
+ def __init__(self):
+ self.decl = None
+ self.defn = None
+ self._regy = None
+
+ def visit_begin(self, schema):
+ self.decl = ''
+ self.defn = ''
+ self._regy = ''
+
+ def visit_end(self):
+ if not middle_mode:
+ self.defn += gen_registry(self._regy)
+ self._regy = None
+
+ def visit_command(self, name, info, arg_type, ret_type,
+ gen, success_response):
+ if not gen:
+ return
+ self.decl += generate_command_decl(name, arg_type, ret_type)
+ if ret_type:
+ self.defn += gen_marshal_output(name, ret_type)
+ if middle_mode:
+ self.decl += gen_marshal_input_decl(name, middle_mode) + ';\n'
+ self.defn += gen_marshal_input(name, arg_type, ret_type, middle_mode)
+ if not middle_mode:
+ self._regy += gen_register_command(name, success_response)
+
+
middle_mode = False
(input_file, output_dir, do_c, do_h, prefix, opts) = \
@@ -272,10 +314,6 @@ for o, a in opts:
if o in ("-m", "--middle"):
middle_mode = True
-exprs = QAPISchema(input_file).get_exprs()
-commands = filter(lambda expr: expr.has_key('command'), exprs)
-commands = filter(lambda expr: not expr.has_key('gen'), commands)
-
c_comment = '''
/*
* schema-defined QMP->QAPI command dispatch
@@ -331,29 +369,12 @@ fdecl.write(mcgen('''
#include "qapi/error.h"
''',
- prefix=prefix))
+ prefix=prefix))
-for cmd in commands:
- arglist = []
- ret_type = None
- if cmd.has_key('data'):
- arglist = cmd['data']
- if cmd.has_key('returns'):
- ret_type = cmd['returns']
- ret = generate_command_decl(cmd['command'], arglist, ret_type)
- fdecl.write(ret)
- if ret_type:
- ret = gen_marshal_output(cmd['command'], ret_type) + "\n"
- fdef.write(ret)
-
- if 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"
- fdef.write(ret)
-
-if not middle_mode:
- ret = gen_registry(commands)
- fdef.write(ret)
+schema = QAPISchema(input_file)
+gen = QAPISchemaGenCommandVisitor()
+schema.visit(gen)
+fdef.write(gen.defn)
+fdecl.write(gen.decl)
close_output(fdef, fdecl)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 3e0fc12..136b23b 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1441,7 +1441,7 @@ def c_type(value, is_param=False):
return c_name(value) + pointer_suffix
def is_c_ptr(value):
- return c_type(value).endswith(pointer_suffix)
+ return value.endswith(pointer_suffix)
def genindent(count):
ret = ""
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (7 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 08/26] qapi-commands: Convert to QAPISchemaVisitor Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:58 ` Daniel P. Berrange
2015-09-16 17:16 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 10/26] qapi-event: Eliminate global variable event_enum_value Markus Armbruster
` (18 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Duplicated in commit 21cd70d. Yes, we can't import qapi-types, but
that's no excuse. Move the helpers from qapi-types.py to qapi.py, and
replace the duplicates in qapi-event.py.
The generated event enumeration type's lookup table becomes
const-correct (see commit 2e4450f), and uses explicit indexes instead
of relying on order (see commit 912ae9c).
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
docs/qapi-code-gen.txt | 9 ++++---
scripts/qapi-event.py | 67 +++-----------------------------------------------
scripts/qapi-types.py | 55 -----------------------------------------
scripts/qapi.py | 55 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 64 insertions(+), 122 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index c9e21fc..81e87d2 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -829,9 +829,9 @@ Example:
QDECREF(qmp);
}
- const char *example_QAPIEvent_lookup[] = {
- "MY_EVENT",
- NULL,
+ const char *const example_QAPIEvent_lookup[] = {
+ [EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT",
+ [EXAMPLE_QAPI_EVENT_MAX] = NULL,
};
$ cat qapi-generated/example-qapi-event.h
[Uninteresting stuff omitted...]
@@ -846,10 +846,11 @@ Example:
void qapi_event_send_my_event(Error **errp);
- extern const char *example_QAPIEvent_lookup[];
typedef enum example_QAPIEvent {
EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
EXAMPLE_QAPI_EVENT_MAX = 1,
} example_QAPIEvent;
+ extern const char *const example_QAPIEvent_lookup[];
+
#endif
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index aec2d32..aed45d6 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -153,63 +153,6 @@ def generate_event_implement(api_name, event_name, params):
return ret
-
-# Following are the functions that generate an enum type for all defined
-# events, similar to qapi-types.py. Here we already have enum name and
-# values which were generated before and recorded in event_enum_*. It also
-# works around the issue that "import qapi-types" can't work.
-
-def generate_event_enum_decl(event_enum_name, event_enum_values):
- lookup_decl = mcgen('''
-
-extern const char *%(event_enum_name)s_lookup[];
-''',
- event_enum_name = event_enum_name)
-
- enum_decl = mcgen('''
-typedef enum %(event_enum_name)s {
-''',
- event_enum_name = event_enum_name)
-
- # append automatically generated _MAX value
- enum_max_value = c_enum_const(event_enum_name, "MAX")
- enum_values = event_enum_values + [ enum_max_value ]
-
- i = 0
- for value in enum_values:
- enum_decl += mcgen('''
- %(value)s = %(i)d,
-''',
- value = value,
- i = i)
- i += 1
-
- enum_decl += mcgen('''
-} %(event_enum_name)s;
-''',
- event_enum_name = event_enum_name)
-
- return lookup_decl + enum_decl
-
-def generate_event_enum_lookup(event_enum_name, event_enum_strings):
- ret = mcgen('''
-
-const char *%(event_enum_name)s_lookup[] = {
-''',
- event_enum_name = event_enum_name)
-
- for string in event_enum_strings:
- ret += mcgen('''
- "%(string)s",
-''',
- string = string)
-
- ret += mcgen('''
- NULL,
-};
-''')
- return ret
-
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
c_comment = '''
@@ -266,8 +209,7 @@ fdecl.write(mcgen('''
exprs = QAPISchema(input_file).get_exprs()
event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
-event_enum_values = []
-event_enum_strings = []
+event_names = []
for expr in exprs:
if expr.has_key('event'):
@@ -286,12 +228,11 @@ for expr in exprs:
fdef.write(ret)
# Record it, and generate enum later
- event_enum_values.append(event_enum_value)
- event_enum_strings.append(event_name)
+ event_names.append(event_name)
-ret = generate_event_enum_decl(event_enum_name, event_enum_values)
+ret = generate_enum(event_enum_name, event_names)
fdecl.write(ret)
-ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
+ret = generate_enum_lookup(event_enum_name, event_names)
fdef.write(ret)
close_output(fdef, fdecl)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index d78f529..76c82d9 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -80,61 +80,6 @@ struct %(name)s {
return ret
-def generate_enum_lookup(name, values, prefix=None):
- ret = mcgen('''
-
-const char *const %(name)s_lookup[] = {
-''',
- name=c_name(name))
- for value in values:
- index = c_enum_const(name, value, prefix)
- ret += mcgen('''
- [%(index)s] = "%(value)s",
-''',
- index = index, value = value)
-
- max_index = c_enum_const(name, 'MAX', prefix)
- ret += mcgen('''
- [%(max_index)s] = 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)
-
- # 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('''
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 136b23b..b305106 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1497,6 +1497,61 @@ def guardend(name):
''',
name=guardname(name))
+def generate_enum_lookup(name, values, prefix=None):
+ ret = mcgen('''
+
+const char *const %(name)s_lookup[] = {
+''',
+ name=c_name(name))
+ for value in values:
+ index = c_enum_const(name, value, prefix)
+ ret += mcgen('''
+ [%(index)s] = "%(value)s",
+''',
+ index = index, value = value)
+
+ max_index = c_enum_const(name, 'MAX', prefix)
+ ret += mcgen('''
+ [%(max_index)s] = 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)
+
+ # 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
+
#
# Common command line parsing
#
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation Markus Armbruster
@ 2015-09-16 14:58 ` Daniel P. Berrange
2015-09-16 17:16 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:58 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:12PM +0200, Markus Armbruster wrote:
> Duplicated in commit 21cd70d. Yes, we can't import qapi-types, but
> that's no excuse. Move the helpers from qapi-types.py to qapi.py, and
> replace the duplicates in qapi-event.py.
>
> The generated event enumeration type's lookup table becomes
> const-correct (see commit 2e4450f), and uses explicit indexes instead
> of relying on order (see commit 912ae9c).
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> docs/qapi-code-gen.txt | 9 ++++---
> scripts/qapi-event.py | 67 +++-----------------------------------------------
> scripts/qapi-types.py | 55 -----------------------------------------
> scripts/qapi.py | 55 +++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 64 insertions(+), 122 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation Markus Armbruster
2015-09-16 14:58 ` Daniel P. Berrange
@ 2015-09-16 17:16 ` Eric Blake
2015-09-17 8:04 ` Markus Armbruster
1 sibling, 1 reply; 55+ messages in thread
From: Eric Blake @ 2015-09-16 17:16 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 1713 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> Duplicated in commit 21cd70d. Yes, we can't import qapi-types, but
> that's no excuse. Move the helpers from qapi-types.py to qapi.py, and
> replace the duplicates in qapi-event.py.
>
> The generated event enumeration type's lookup table becomes
> const-correct (see commit 2e4450f), and uses explicit indexes instead
> of relying on order (see commit 912ae9c).
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> docs/qapi-code-gen.txt | 9 ++++---
> scripts/qapi-event.py | 67 +++-----------------------------------------------
> scripts/qapi-types.py | 55 -----------------------------------------
> scripts/qapi.py | 55 +++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 64 insertions(+), 122 deletions(-)
>
> +++ b/scripts/qapi.py
> @@ -1497,6 +1497,61 @@ def guardend(name):
> ''',
> name=guardname(name))
>
> +def generate_enum_lookup(name, values, prefix=None):
To keep pep8 happier, you could use two blank lines before def here...
> + return ret
> +
> +def generate_enum(name, values, prefix=None):
and here. Then again, 13/26 does more of these sorts of cleanups, and
v7 had the same use of 1 blank line. Up to you if it is worth avoiding
the churn; but it is whitespace either way so it doesn't affect review.
Also, do you still need prefix=None, or can we rely on the fact that now
all callers supply prefix by virtue of the visitor callback, and make
the parameter non-optional?
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation
2015-09-16 17:16 ` Eric Blake
@ 2015-09-17 8:04 ` Markus Armbruster
0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-17 8:04 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, mdroth
Eric Blake <eblake@redhat.com> writes:
> On 09/16/2015 05:06 AM, Markus Armbruster wrote:
>> Duplicated in commit 21cd70d. Yes, we can't import qapi-types, but
>> that's no excuse. Move the helpers from qapi-types.py to qapi.py, and
>> replace the duplicates in qapi-event.py.
>>
>> The generated event enumeration type's lookup table becomes
>> const-correct (see commit 2e4450f), and uses explicit indexes instead
>> of relying on order (see commit 912ae9c).
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>> docs/qapi-code-gen.txt | 9 ++++---
>> scripts/qapi-event.py | 67 +++-----------------------------------------------
>> scripts/qapi-types.py | 55 -----------------------------------------
>> scripts/qapi.py | 55 +++++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 64 insertions(+), 122 deletions(-)
>>
>
>> +++ b/scripts/qapi.py
>> @@ -1497,6 +1497,61 @@ def guardend(name):
>> ''',
>> name=guardname(name))
>>
>> +def generate_enum_lookup(name, values, prefix=None):
>
> To keep pep8 happier, you could use two blank lines before def here...
>
>> + return ret
>> +
>> +def generate_enum(name, values, prefix=None):
>
> and here. Then again, 13/26 does more of these sorts of cleanups, and
> v7 had the same use of 1 blank line. Up to you if it is worth avoiding
> the churn; but it is whitespace either way so it doesn't affect review.
Matches the code around it, which trumps pep8.
pep8 is quite unhappy with qapi.py. This series makes it slightly
happier by deleting unhappy code. Finishing the conversion to the new
intermediate representation involves folding semantic analysis into
QAPISchema, good opportunity to tidy up the moved code. After that, we
should probably tidy up whatever's left.
> Also, do you still need prefix=None, or can we rely on the fact that now
> all callers supply prefix by virtue of the visitor callback, and make
> the parameter non-optional?
There are calls without prefix left in qapi-event.py.
> Reviewed-by: Eric Blake <eblake@redhat.com>
Thanks!
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 10/26] qapi-event: Eliminate global variable event_enum_value
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (8 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 09/26] qapi: De-duplicate enum code generation Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 11/26] qapi-event: Convert to QAPISchemaVisitor, fixing data with base Markus Armbruster
` (17 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
scripts/qapi-event.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index aed45d6..537da17 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -137,7 +137,7 @@ def generate_event_implement(api_name, event_name, params):
emit(%(event_enum_value)s, qmp, &local_err);
""",
- event_enum_value = event_enum_value)
+ event_enum_value = c_enum_const(event_enum_name, event_name))
# step 5: clean up
if params:
@@ -223,7 +223,6 @@ for expr in exprs:
fdecl.write(ret)
# We need an enum value per event
- event_enum_value = c_enum_const(event_enum_name, event_name)
ret = generate_event_implement(api_name, event_name, params)
fdef.write(ret)
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 11/26] qapi-event: Convert to QAPISchemaVisitor, fixing data with base
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (9 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 10/26] qapi-event: Eliminate global variable event_enum_value Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 14:59 ` Daniel P. Berrange
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 12/26] qapi: Replace dirty is_c_ptr() by method c_null() Markus Armbruster
` (16 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Fixes events whose data is struct with base to include the struct's
base members. Test case is qapi-schema-test.json's event
__org.qemu_x-command:
{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
{ 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base',
'data': { '__org.qemu_x-member2': 'str' } }
{ 'struct': '__org.qemu_x-Base',
'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } }
Patch's effect on generated qapi_event_send___org_qemu_x_event():
-void qapi_event_send___org_qemu_x_event(const char *__org_qemu_x_member2,
+void qapi_event_send___org_qemu_x_event(__org_qemu_x_Enum __org_qemu_x_member1,
+ const char *__org_qemu_x_member2,
Error **errp)
{
QDict *qmp;
@@ -224,6 +225,10 @@ void qapi_event_send___org_qemu_x_event(
goto clean;
}
+ visit_type___org_qemu_x_Enum(v, &__org_qemu_x_member1, "__org.qemu_x-member1", &local_err);
+ if (local_err) {
+ goto clean;
+ }
visit_type_str(v, (char **)&__org_qemu_x_member2, "__org.qemu_x-member2", &local_err);
if (local_err) {
goto clean;
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
scripts/qapi-event.py | 89 +++++++++++++++++----------------
tests/qapi-schema/qapi-schema-test.json | 3 --
2 files changed, 47 insertions(+), 45 deletions(-)
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 537da17..d19acda 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -2,14 +2,15 @@
# QAPI event generator
#
# Copyright (c) 2014 Wenchao Xia
+# Copyright (c) 2015 Red Hat Inc.
#
# Authors:
# Wenchao Xia <wenchaoqemu@gmail.com>
+# Markus Armbruster <armbru@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
-from ordereddict import OrderedDict
from qapi import *
def _generate_event_api_name(event_name, params):
@@ -17,13 +18,13 @@ def _generate_event_api_name(event_name, params):
l = len(api_name)
if params:
- for argname, argentry, optional in parse_args(params):
- if optional:
- api_name += "bool has_%s,\n" % c_name(argname)
+ for m in params.members:
+ if m.optional:
+ api_name += "bool has_%s,\n" % c_name(m.name)
api_name += "".ljust(l)
- api_name += "%s %s,\n" % (c_type(argentry, is_param=True),
- c_name(argname))
+ api_name += "%s %s,\n" % (m.type.c_type(is_param=True),
+ c_name(m.name))
api_name += "".ljust(l)
api_name += "Error **errp)"
@@ -51,7 +52,7 @@ def generate_event_implement(api_name, event_name, params):
""",
api_name = api_name)
- if params:
+ if params and params.members:
ret += mcgen("""
QmpOutputVisitor *qov;
Visitor *v;
@@ -72,7 +73,7 @@ def generate_event_implement(api_name, event_name, params):
event_name = event_name)
# step 3: visit the params if params != None
- if params:
+ if params and params.members:
ret += mcgen("""
qov = qmp_output_visitor_new();
g_assert(qov);
@@ -89,15 +90,15 @@ def generate_event_implement(api_name, event_name, params):
""",
event_name = event_name)
- for argname, argentry, optional in parse_args(params):
- if optional:
+ for memb in params.members:
+ if memb.optional:
ret += mcgen("""
if (has_%(var)s) {
""",
- var = c_name(argname))
+ var=c_name(memb.name))
push_indent()
- if argentry == "str":
+ if memb.type.name == "str":
var_type = "(char **)"
else:
var_type = ""
@@ -109,11 +110,11 @@ def generate_event_implement(api_name, event_name, params):
}
""",
var_type = var_type,
- var = c_name(argname),
- type = type_name(argentry),
- name = argname)
+ var=c_name(memb.name),
+ type=memb.type.c_name(),
+ name=memb.name)
- if optional:
+ if memb.optional:
pop_indent()
ret += mcgen("""
}
@@ -140,7 +141,7 @@ def generate_event_implement(api_name, event_name, params):
event_enum_value = c_enum_const(event_enum_name, event_name))
# step 5: clean up
- if params:
+ if params and params.members:
ret += mcgen("""
clean:
qmp_output_visitor_cleanup(qov);
@@ -153,6 +154,30 @@ def generate_event_implement(api_name, event_name, params):
return ret
+
+class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
+ def __init__(self):
+ self.decl = None
+ self.defn = None
+ self._event_names = None
+
+ def visit_begin(self, schema):
+ self.decl = ''
+ self.defn = ''
+ self._event_names = []
+
+ def visit_end(self):
+ self.decl += generate_enum(event_enum_name, self._event_names)
+ self.defn += generate_enum_lookup(event_enum_name, self._event_names)
+ self._event_names = None
+
+ def visit_event(self, name, info, arg_type):
+ api_name = _generate_event_api_name(name, arg_type)
+ self.decl += generate_event_declaration(api_name)
+ self.defn += generate_event_implement(api_name, name, arg_type)
+ self._event_names.append(name)
+
+
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
c_comment = '''
@@ -206,32 +231,12 @@ fdecl.write(mcgen('''
''',
prefix=prefix))
-exprs = QAPISchema(input_file).get_exprs()
-
event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
-event_names = []
-for expr in exprs:
- if expr.has_key('event'):
- event_name = expr['event']
- params = expr.get('data')
- if params and len(params) == 0:
- params = None
-
- api_name = _generate_event_api_name(event_name, params)
- ret = generate_event_declaration(api_name)
- fdecl.write(ret)
-
- # We need an enum value per event
- ret = generate_event_implement(api_name, event_name, params)
- fdef.write(ret)
-
- # Record it, and generate enum later
- event_names.append(event_name)
-
-ret = generate_enum(event_enum_name, event_names)
-fdecl.write(ret)
-ret = generate_enum_lookup(event_enum_name, event_names)
-fdef.write(ret)
+schema = QAPISchema(input_file)
+gen = QAPISchemaGenEventVisitor()
+schema.visit(gen)
+fdef.write(gen.defn)
+fdecl.write(gen.decl)
close_output(fdef, fdecl)
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 7d984b6..d488157 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -131,9 +131,6 @@
{ 'alternate': '__org.qemu_x-Alt',
'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } }
{ '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',
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 11/26] qapi-event: Convert to QAPISchemaVisitor, fixing data with base
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 11/26] qapi-event: Convert to QAPISchemaVisitor, fixing data with base Markus Armbruster
@ 2015-09-16 14:59 ` Daniel P. Berrange
0 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 14:59 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:14PM +0200, Markus Armbruster wrote:
> Fixes events whose data is struct with base to include the struct's
> base members. Test case is qapi-schema-test.json's event
> __org.qemu_x-command:
>
> { 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
>
> { 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base',
> 'data': { '__org.qemu_x-member2': 'str' } }
>
> { 'struct': '__org.qemu_x-Base',
> 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } }
>
> Patch's effect on generated qapi_event_send___org_qemu_x_event():
>
> -void qapi_event_send___org_qemu_x_event(const char *__org_qemu_x_member2,
> +void qapi_event_send___org_qemu_x_event(__org_qemu_x_Enum __org_qemu_x_member1,
> + const char *__org_qemu_x_member2,
> Error **errp)
> {
> QDict *qmp;
> @@ -224,6 +225,10 @@ void qapi_event_send___org_qemu_x_event(
> goto clean;
> }
>
> + visit_type___org_qemu_x_Enum(v, &__org_qemu_x_member1, "__org.qemu_x-member1", &local_err);
> + if (local_err) {
> + goto clean;
> + }
> visit_type_str(v, (char **)&__org_qemu_x_member2, "__org.qemu_x-member2", &local_err);
> if (local_err) {
> goto clean;
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
> scripts/qapi-event.py | 89 +++++++++++++++++----------------
> tests/qapi-schema/qapi-schema-test.json | 3 --
> 2 files changed, 47 insertions(+), 45 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 12/26] qapi: Replace dirty is_c_ptr() by method c_null()
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (10 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 11/26] qapi-event: Convert to QAPISchemaVisitor, fixing data with base Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor Markus Armbruster
` (15 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
is_c_ptr() looks whether the end of the C text for the type looks like
a pointer. Works, but is fragile.
We now have a better tool: use QAPISchemaType method c_null(). The
initializers for non-pointers become prettier: 0, false or the
enumeration constant with the value 0 instead of {0}.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
scripts/qapi-commands.py | 16 +++++-----------
scripts/qapi.py | 3 ---
2 files changed, 5 insertions(+), 14 deletions(-)
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index a68517a..cbff356 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -91,18 +91,12 @@ def gen_visitor_input_vars_decl(args):
bool has_%(argname)s = false;
''',
argname=c_name(memb.name))
- if is_c_ptr(memb.type.c_type()):
- ret += mcgen('''
-%(argtype)s %(argname)s = NULL;
+ ret += mcgen('''
+%(c_type)s %(c_name)s = %(c_null)s;
''',
- argname=c_name(memb.name),
- argtype=memb.type.c_type())
- else:
- ret += mcgen('''
-%(argtype)s %(argname)s = {0};
-''',
- argname=c_name(memb.name),
- argtype=memb.type.c_type())
+ c_name=c_name(memb.name),
+ c_type=memb.type.c_type(),
+ c_null=memb.type.c_null())
pop_indent()
return ret
diff --git a/scripts/qapi.py b/scripts/qapi.py
index b305106..c1b14b2 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1440,9 +1440,6 @@ def c_type(value, is_param=False):
assert isinstance(value, str) and value != ""
return c_name(value) + pointer_suffix
-def is_c_ptr(value):
- return value.endswith(pointer_suffix)
-
def genindent(count):
ret = ""
for i in range(count):
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (11 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 12/26] qapi: Replace dirty is_c_ptr() by method c_null() Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 15:00 ` Daniel P. Berrange
2015-09-16 17:20 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 14/26] qapi-visit: Rearrange code a bit Markus Armbruster
` (14 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
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.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
docs/qapi-code-gen.txt | 2 +-
scripts/qapi-commands.py | 140 ++++++++++++++++++++++++++---------------------
scripts/qapi-event.py | 122 ++++++++++++++++++++---------------------
scripts/qapi-types.py | 79 ++++++++++++++------------
scripts/qapi-visit.py | 127 ++++++++++++++++++++++--------------------
scripts/qapi.py | 131 +++++++++-----------------------------------
6 files changed, 274 insertions(+), 327 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 81e87d2..3eaff36 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -598,7 +598,7 @@ Example:
UserDefOne *value;
uint64_t padding;
};
- struct UserDefOneList *next;
+ UserDefOneList *next;
};
void qapi_free_UserDefOneList(UserDefOneList *obj);
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index cbff356..0501582 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -15,20 +15,22 @@
from qapi import *
import re
-def generate_command_decl(name, args, ret_type):
- arglist=""
- if args:
- for memb in args.members:
- argtype = memb.type.c_type(is_param=True)
+
+def gen_command_decl(name, arg_type, ret_type):
+ argstr = ''
+ if arg_type:
+ for memb in arg_type.members:
if memb.optional:
- arglist += "bool has_%s, " % c_name(memb.name)
- arglist += "%s %s, " % (argtype, c_name(memb.name))
+ argstr += 'bool has_%s, ' % c_name(memb.name)
+ argstr += '%s %s, ' % (memb.type.c_type(is_param=True),
+ c_name(memb.name))
return mcgen('''
-%(ret_type)s qmp_%(name)s(%(args)sError **errp);
+%(c_type)s qmp_%(c_name)s(%(args)sError **errp);
''',
- ret_type=(ret_type and ret_type.c_type()) or 'void',
- name=c_name(name),
- args=arglist)
+ c_type=(ret_type and ret_type.c_type()) or 'void',
+ c_name=c_name(name),
+ args=argstr)
+
def gen_err_check(err):
if not err:
@@ -40,37 +42,42 @@ if (%(err)s) {
''',
err=err)
-def gen_sync_call(name, args, ret_type):
- ret = ""
- arglist=""
- retval=""
- if ret_type:
- retval = "retval = "
- if args:
- for memb in args.members:
+
+def gen_call(name, arg_type, ret_type):
+ ret = ''
+
+ argstr = ''
+ if arg_type:
+ for memb in arg_type.members:
if memb.optional:
- arglist += "has_%s, " % c_name(memb.name)
- arglist += "%s, " % c_name(memb.name)
+ argstr += 'has_%s, ' % c_name(memb.name)
+ argstr += '%s, ' % c_name(memb.name)
+
+ lhs = ''
+ if ret_type:
+ lhs = 'retval = '
+
push_indent()
ret = mcgen('''
-%(retval)sqmp_%(name)s(%(args)s&local_err);
+%(lhs)sqmp_%(c_name)s(%(args)s&local_err);
''',
- name=c_name(name), args=arglist, retval=retval)
+ c_name=c_name(name), args=argstr, lhs=lhs)
if ret_type:
ret += gen_err_check('local_err')
ret += mcgen('''
qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
''',
- c_name=c_name(name))
+ c_name=c_name(name))
pop_indent()
return ret
-def gen_visitor_input_containers_decl(args):
- ret = ""
+
+def gen_visitor_input_containers_decl(arg_type):
+ ret = ''
push_indent()
- if args:
+ if arg_type:
ret += mcgen('''
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md;
@@ -80,17 +87,18 @@ Visitor *v;
return ret
-def gen_visitor_input_vars_decl(args):
- ret = ""
+
+def gen_visitor_input_vars_decl(arg_type):
+ ret = ''
push_indent()
- if args:
- for memb in args.members:
+ if arg_type:
+ for memb in arg_type.members:
if memb.optional:
ret += mcgen('''
-bool has_%(argname)s = false;
+bool has_%(c_name)s = false;
''',
- argname=c_name(memb.name))
+ c_name=c_name(memb.name))
ret += mcgen('''
%(c_type)s %(c_name)s = %(c_null)s;
''',
@@ -101,19 +109,20 @@ bool has_%(argname)s = false;
pop_indent()
return ret
-def gen_visitor_input_block(args, dealloc=False):
- ret = ""
+
+def gen_visitor_input_block(arg_type, dealloc=False):
+ ret = ''
errparg = '&local_err'
errarg = 'local_err'
- if not args:
+ if not arg_type:
return ret
push_indent()
if dealloc:
errparg = 'NULL'
- errarg = None;
+ errarg = None
ret += mcgen('''
qmp_input_visitor_cleanup(mi);
md = qapi_dealloc_visitor_new();
@@ -124,7 +133,7 @@ v = qapi_dealloc_get_visitor(md);
v = qmp_input_get_visitor(mi);
''')
- for memb in args.members:
+ for memb in arg_type.members:
if memb.optional:
ret += mcgen('''
visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
@@ -138,10 +147,10 @@ if (has_%(c_name)s) {
c_name=c_name(memb.name))
push_indent()
ret += mcgen('''
-visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
+visit_type_%(c_type)s(v, &%(c_name)s, "%(name)s", %(errp)s);
''',
c_name=c_name(memb.name), name=memb.name,
- visitor=memb.type.c_name(), errp=errparg)
+ c_type=memb.type.c_name(), errp=errparg)
ret += gen_err_check(errarg)
if memb.optional:
pop_indent()
@@ -156,13 +165,14 @@ qapi_dealloc_visitor_cleanup(md);
pop_indent()
return ret
+
def gen_marshal_output(name, ret_type):
if not ret_type:
- return ""
+ return ''
ret = mcgen('''
-static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
+static void qmp_marshal_output_%(c_cmd_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
{
Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new();
@@ -170,7 +180,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o
Visitor *v;
v = qmp_output_get_visitor(mo);
- visit_type_%(visitor)s(v, &ret_in, "unused", &local_err);
+ visit_type_%(c_name)s(v, &ret_in, "unused", &local_err);
if (local_err) {
goto out;
}
@@ -181,23 +191,25 @@ out:
qmp_output_visitor_cleanup(mo);
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
- visit_type_%(visitor)s(v, &ret_in, "unused", NULL);
+ visit_type_%(c_name)s(v, &ret_in, "unused", NULL);
qapi_dealloc_visitor_cleanup(md);
}
''',
- c_ret_type=ret_type.c_type(), c_name=c_name(name),
- visitor=ret_type.c_name())
+ c_type=ret_type.c_type(), c_cmd_name=c_name(name),
+ c_name=ret_type.c_name())
return ret
-def gen_marshal_input_decl(name, middle_mode):
+
+def gen_marshal_input_decl(name):
ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
if not middle_mode:
- ret = "static " + ret
+ ret = 'static ' + ret
return ret
-def gen_marshal_input(name, args, ret_type, middle_mode):
- hdr = gen_marshal_input_decl(name, middle_mode)
+
+def gen_marshal_input(name, arg_type, ret_type):
+ hdr = gen_marshal_input_decl(name)
ret = mcgen('''
@@ -213,10 +225,10 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
''',
c_type=ret_type.c_type())
- if args:
- ret += gen_visitor_input_containers_decl(args)
- ret += gen_visitor_input_vars_decl(args) + '\n'
- ret += gen_visitor_input_block(args) + '\n'
+ if arg_type:
+ ret += gen_visitor_input_containers_decl(arg_type)
+ ret += gen_visitor_input_vars_decl(arg_type) + '\n'
+ ret += gen_visitor_input_block(arg_type) + '\n'
else:
ret += mcgen('''
@@ -224,9 +236,9 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
''')
- ret += gen_sync_call(name, args, ret_type)
+ ret += gen_call(name, arg_type, ret_type)
- if re.search('^ *goto out\\;', ret, re.MULTILINE):
+ if re.search('^ *goto out;', ret, re.MULTILINE):
ret += mcgen('''
out:
@@ -234,12 +246,13 @@ out:
ret += mcgen('''
error_propagate(errp, local_err);
''')
- ret += gen_visitor_input_block(args, dealloc=True)
+ ret += gen_visitor_input_block(arg_type, dealloc=True)
ret += mcgen('''
}
''')
return ret
+
def gen_register_command(name, success_response):
push_indent()
options = 'QCO_NO_OPTIONS'
@@ -249,11 +262,12 @@ def gen_register_command(name, success_response):
ret = mcgen('''
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
''',
- name=name, c_name=c_name(name),
- opts=options)
+ name=name, c_name=c_name(name),
+ opts=options)
pop_indent()
return ret
+
def gen_registry(registry):
ret = mcgen('''
@@ -289,12 +303,12 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
gen, success_response):
if not gen:
return
- self.decl += generate_command_decl(name, arg_type, ret_type)
+ self.decl += gen_command_decl(name, arg_type, ret_type)
if ret_type:
self.defn += gen_marshal_output(name, ret_type)
if middle_mode:
- self.decl += gen_marshal_input_decl(name, middle_mode) + ';\n'
- self.defn += gen_marshal_input(name, arg_type, ret_type, middle_mode)
+ self.decl += gen_marshal_input_decl(name) + ';\n'
+ self.defn += gen_marshal_input(name, arg_type, ret_type)
if not middle_mode:
self._regy += gen_register_command(name, success_response)
@@ -355,7 +369,7 @@ fdef.write(mcgen('''
#include "%(prefix)sqmp-commands.h"
''',
- prefix=prefix))
+ prefix=prefix))
fdecl.write(mcgen('''
#include "%(prefix)sqapi-types.h"
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index d19acda..5873a05 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -13,12 +13,13 @@
from qapi import *
-def _generate_event_api_name(event_name, params):
- api_name = "void qapi_event_send_%s(" % c_name(event_name).lower();
+
+def gen_event_send_proto(name, arg_type):
+ api_name = "void qapi_event_send_%s(" % c_name(name).lower()
l = len(api_name)
- if params:
- for m in params.members:
+ if arg_type:
+ for m in arg_type.members:
if m.optional:
api_name += "bool has_%s,\n" % c_name(m.name)
api_name += "".ljust(l)
@@ -28,53 +29,49 @@ def _generate_event_api_name(event_name, params):
api_name += "".ljust(l)
api_name += "Error **errp)"
- return api_name;
+ return api_name
-# Following are the core functions that generate C APIs to emit event.
-
-def generate_event_declaration(api_name):
+def gen_event_send_decl(name, arg_type):
return mcgen('''
-%(api_name)s;
+%(proto)s;
''',
- api_name = api_name)
+ proto=gen_event_send_proto(name, arg_type))
-def generate_event_implement(api_name, event_name, params):
- # step 1: declare any variables
- ret = mcgen("""
-%(api_name)s
+def gen_event_send(name, arg_type):
+ ret = mcgen('''
+
+%(proto)s
{
QDict *qmp;
Error *local_err = NULL;
QMPEventFuncEmit emit;
-""",
- api_name = api_name)
+''',
+ proto=gen_event_send_proto(name, arg_type))
- if params and params.members:
- ret += mcgen("""
+ if arg_type and arg_type.members:
+ ret += mcgen('''
QmpOutputVisitor *qov;
Visitor *v;
QObject *obj;
-""")
+''')
- # step 2: check emit function, create a dict
- ret += mcgen("""
+ ret += mcgen('''
emit = qmp_event_get_func_emit();
if (!emit) {
return;
}
- qmp = qmp_event_build_dict("%(event_name)s");
+ qmp = qmp_event_build_dict("%(name)s");
-""",
- event_name = event_name)
+''',
+ name=name)
- # step 3: visit the params if params != None
- if params and params.members:
- ret += mcgen("""
+ if arg_type and arg_type.members:
+ ret += mcgen('''
qov = qmp_output_visitor_new();
g_assert(qov);
@@ -82,45 +79,46 @@ def generate_event_implement(api_name, event_name, params):
g_assert(v);
/* Fake visit, as if all members are under a structure */
- visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err);
+ visit_start_struct(v, NULL, "", "%(name)s", 0, &local_err);
if (local_err) {
goto clean;
}
-""",
- event_name = event_name)
+''',
+ name=name)
- for memb in params.members:
+ for memb in arg_type.members:
if memb.optional:
- ret += mcgen("""
- if (has_%(var)s) {
-""",
- var=c_name(memb.name))
+ ret += mcgen('''
+ if (has_%(c_name)s) {
+''',
+ c_name=c_name(memb.name))
push_indent()
+ # Ugly: need to cast away the const
if memb.type.name == "str":
- var_type = "(char **)"
+ cast = '(char **)'
else:
- var_type = ""
+ cast = ''
- ret += mcgen("""
- visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err);
+ ret += mcgen('''
+ visit_type_%(c_type)s(v, %(cast)s&%(c_name)s, "%(name)s", &local_err);
if (local_err) {
goto clean;
}
-""",
- var_type = var_type,
- var=c_name(memb.name),
- type=memb.type.c_name(),
+''',
+ cast=cast,
+ c_name=c_name(memb.name),
+ c_type=memb.type.c_name(),
name=memb.name)
if memb.optional:
pop_indent()
- ret += mcgen("""
+ ret += mcgen('''
}
-""")
+''')
- ret += mcgen("""
+ ret += mcgen('''
visit_end_struct(v, &local_err);
if (local_err) {
@@ -131,27 +129,24 @@ def generate_event_implement(api_name, event_name, params):
g_assert(obj != NULL);
qdict_put_obj(qmp, "data", obj);
-""")
+''')
- # step 4: call qmp event api
- ret += mcgen("""
- emit(%(event_enum_value)s, qmp, &local_err);
+ ret += mcgen('''
+ emit(%(c_enum)s, qmp, &local_err);
-""",
- event_enum_value = c_enum_const(event_enum_name, event_name))
+''',
+ c_enum=c_enum_const(event_enum_name, name))
- # step 5: clean up
- if params and params.members:
- ret += mcgen("""
+ if arg_type and arg_type.members:
+ ret += mcgen('''
clean:
qmp_output_visitor_cleanup(qov);
-""")
- ret += mcgen("""
+''')
+ ret += mcgen('''
error_propagate(errp, local_err);
QDECREF(qmp);
}
-""")
-
+''')
return ret
@@ -167,14 +162,13 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
self._event_names = []
def visit_end(self):
- self.decl += generate_enum(event_enum_name, self._event_names)
- self.defn += generate_enum_lookup(event_enum_name, self._event_names)
+ self.decl += gen_enum(event_enum_name, self._event_names)
+ self.defn += gen_enum_lookup(event_enum_name, self._event_names)
self._event_names = None
def visit_event(self, name, info, arg_type):
- api_name = _generate_event_api_name(name, arg_type)
- self.decl += generate_event_declaration(api_name)
- self.defn += generate_event_implement(api_name, name, arg_type)
+ self.decl += gen_event_send_decl(name, arg_type)
+ self.defn += gen_event_send(name, arg_type)
self._event_names.append(name)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 76c82d9..d1fee20 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -13,25 +13,28 @@
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;
+ %(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 = ''
@@ -47,30 +50,33 @@ 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:
ret += gen_struct_field(memb.name, memb.type, memb.optional)
return ret
+
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('''
+ ret += mcgen('''
char qapi_dummy_field_for_empty_struct;
''')
@@ -80,6 +86,7 @@ struct %(name)s {
return ret
+
def gen_alternate_qtypes_decl(name):
return mcgen('''
@@ -87,12 +94,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()
@@ -101,7 +109,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
ret += mcgen('''
[%(qtype)s] = %(enum_const)s,
''',
- qtype = qtype,
+ qtype=qtype,
enum_const=c_enum_const(variants.tag_member.type.name,
var.name))
@@ -110,28 +118,27 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
''')
return ret
+
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
@@ -166,18 +173,20 @@ 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;
@@ -188,11 +197,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
@@ -225,20 +234,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)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 8e6e8ca..fae70e2 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -18,18 +18,20 @@ 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 +47,36 @@ 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 +88,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 +105,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 +117,7 @@ out:
return ret
-def generate_visit_struct_body(name):
+def gen_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
@@ -132,30 +135,30 @@ 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;
@@ -168,7 +171,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, &err)) != 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);
}
@@ -179,10 +182,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)
@@ -192,36 +195,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:
@@ -238,17 +241,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('''
@@ -266,19 +270,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;
}
@@ -287,30 +291,36 @@ 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()
+ ret += mcgen('''
+ case %(case)s:
+''',
+ case=c_enum_const(variants.tag_member.type.name,
+ var.name))
if simple_union_type:
- fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
+ 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:
- 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('''
+ 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('''
- case %(enum_full_value)s:
- ''' + fmt + '''
break;
-''',
- enum_full_value = enum_full_value,
- c_type=(simple_union_type or var.type).c_name(),
- c_name=c_name(var.name))
+''')
ret += mcgen('''
default:
@@ -331,6 +341,7 @@ out:
return ret
+
def gen_visit_decl(name, scalar=False):
c_type = c_name(name) + ' *'
if not scalar:
@@ -363,7 +374,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)
@@ -439,7 +450,7 @@ fdef.write(mcgen('''
#include "qemu-common.h"
#include "%(prefix)sqapi-visit.h"
''',
- prefix = prefix))
+ prefix=prefix))
fdecl.write(mcgen('''
#include "qapi/visitor.h"
diff --git a/scripts/qapi.py b/scripts/qapi.py
index c1b14b2..bd6e52b 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1085,9 +1085,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
@@ -1280,23 +1277,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
@@ -1379,67 +1359,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 type_name(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):
@@ -1494,60 +1416,57 @@ 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('''
[%(index)s] = "%(value)s",
''',
- index = index, value = value)
+ index=index, value=value)
max_index = c_enum_const(name, 'MAX', prefix)
ret += mcgen('''
[%(max_index)s] = NULL,
};
''',
- max_index=max_index)
+ 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
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor Markus Armbruster
@ 2015-09-16 15:00 ` Daniel P. Berrange
2015-09-16 17:20 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 15:00 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:16PM +0200, Markus Armbruster wrote:
> 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.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> docs/qapi-code-gen.txt | 2 +-
> scripts/qapi-commands.py | 140 ++++++++++++++++++++++++++---------------------
> scripts/qapi-event.py | 122 ++++++++++++++++++++---------------------
> scripts/qapi-types.py | 79 ++++++++++++++------------
> scripts/qapi-visit.py | 127 ++++++++++++++++++++++--------------------
> scripts/qapi.py | 131 +++++++++-----------------------------------
> 6 files changed, 274 insertions(+), 327 deletions(-)
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor Markus Armbruster
2015-09-16 15:00 ` Daniel P. Berrange
@ 2015-09-16 17:20 ` Eric Blake
1 sibling, 0 replies; 55+ messages in thread
From: Eric Blake @ 2015-09-16 17:20 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 814 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> 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.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
Diff from v7 limited to handling of enum prefix.
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 14/26] qapi-visit: Rearrange code a bit
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (12 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 15/26] qapi-commands: Rearrange code Markus Armbruster
` (13 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Move gen_visit_decl() to a better place. Inline
generate_visit_struct_body().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
scripts/qapi-visit.py | 50 ++++++++++++++++++++------------------------------
1 file changed, 20 insertions(+), 30 deletions(-)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index fae70e2..97343cf 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -19,6 +19,16 @@ implicit_structs_seen = set()
struct_fields_seen = set()
+def gen_visit_decl(name, scalar=False):
+ c_type = c_name(name) + ' *'
+ if not scalar:
+ c_type += '*'
+ return mcgen('''
+void visit_type_%(c_name)s(Visitor *m, %(c_type)sobj, const char *name, Error **errp);
+''',
+ c_name=c_name(name), c_type=c_type)
+
+
def gen_visit_implicit_struct(typ):
if typ in implicit_structs_seen:
return ''
@@ -117,12 +127,17 @@ out:
return ret
-def gen_visit_struct_body(name):
+def gen_visit_struct(name, base, members):
+ ret = gen_visit_struct_fields(name, base, members)
+
# 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('''
+
+void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
+{
Error *err = NULL;
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
@@ -133,25 +148,10 @@ def gen_visit_struct_body(name):
visit_end_struct(m, &err);
}
error_propagate(errp, err);
-''',
- name=name, c_name=c_name(name))
- return ret
-
-
-def gen_visit_struct(name, base, members):
- ret = gen_visit_struct_fields(name, base, members)
- ret += mcgen('''
-
-void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
-{
-''',
- c_name=c_name(name))
-
- ret += gen_visit_struct_body(name)
-
- ret += mcgen('''
}
-''')
+''',
+ name=name, c_name=c_name(name))
+
return ret
@@ -342,16 +342,6 @@ out:
return ret
-def gen_visit_decl(name, scalar=False):
- c_type = c_name(name) + ' *'
- if not scalar:
- c_type += '*'
- return mcgen('''
-void visit_type_%(c_name)s(Visitor *m, %(c_type)sobj, const char *name, Error **errp);
-''',
- c_name=c_name(name), c_type=c_type)
-
-
class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def __init__(self):
self.decl = None
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 15/26] qapi-commands: Rearrange code
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (13 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 14/26] qapi-visit: Rearrange code a bit Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 16/26] qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO() Markus Armbruster
` (12 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Rename gen_marshal_input() to gen_marshal(), because the generated
function marshals both arguments and results.
Rename gen_visitor_input_containers_decl() to gen_marshal_vars(), and
move the other variable declarations there, too.
Rename gen_visitor_input_block() to gen_marshal_input_visit(), and
rearrange its code slightly.
Rename gen_marshal_input_decl() to gen_marshal_proto(), because the
result isn't a full declaration, unlike gen_command_decl()'s.
New gen_marshal_decl() actually returns a full declaration.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
scripts/qapi-commands.py | 87 ++++++++++++++++++++++--------------------------
1 file changed, 39 insertions(+), 48 deletions(-)
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 0501582..6a52c88 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -59,6 +59,7 @@ def gen_call(name, arg_type, ret_type):
push_indent()
ret = mcgen('''
+
%(lhs)sqmp_%(c_name)s(%(args)s&local_err);
''',
c_name=c_name(name), args=argstr, lhs=lhs)
@@ -73,26 +74,26 @@ qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
return ret
-def gen_visitor_input_containers_decl(arg_type):
- ret = ''
+def gen_marshal_vars(arg_type, ret_type):
+ ret = mcgen('''
+ Error *local_err = NULL;
+''')
push_indent()
+
+ if ret_type:
+ ret += mcgen('''
+%(c_type)s retval;
+''',
+ c_type=ret_type.c_type())
+
if arg_type:
ret += mcgen('''
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md;
Visitor *v;
''')
- pop_indent()
- return ret
-
-
-def gen_visitor_input_vars_decl(arg_type):
- ret = ''
- push_indent()
-
- if arg_type:
for memb in arg_type.members:
if memb.optional:
ret += mcgen('''
@@ -105,15 +106,19 @@ bool has_%(c_name)s = false;
c_name=c_name(memb.name),
c_type=memb.type.c_type(),
c_null=memb.type.c_null())
+ ret += '\n'
+ else:
+ ret += mcgen('''
+
+(void)args;
+''')
pop_indent()
return ret
-def gen_visitor_input_block(arg_type, dealloc=False):
+def gen_marshal_input_visit(arg_type, dealloc=False):
ret = ''
- errparg = '&local_err'
- errarg = 'local_err'
if not arg_type:
return ret
@@ -129,6 +134,8 @@ md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
''')
else:
+ errparg = '&local_err'
+ errarg = 'local_err'
ret += mcgen('''
v = qmp_input_get_visitor(mi);
''')
@@ -167,10 +174,7 @@ qapi_dealloc_visitor_cleanup(md);
def gen_marshal_output(name, ret_type):
- if not ret_type:
- return ''
-
- ret = mcgen('''
+ return mcgen('''
static void qmp_marshal_output_%(c_cmd_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
{
@@ -195,47 +199,34 @@ out:
qapi_dealloc_visitor_cleanup(md);
}
''',
- c_type=ret_type.c_type(), c_cmd_name=c_name(name),
- c_name=ret_type.c_name())
+ c_type=ret_type.c_type(), c_cmd_name=c_name(name),
+ c_name=ret_type.c_name())
- return ret
-
-def gen_marshal_input_decl(name):
+def gen_marshal_proto(name):
ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
if not middle_mode:
ret = 'static ' + ret
return ret
-def gen_marshal_input(name, arg_type, ret_type):
- hdr = gen_marshal_input_decl(name)
+def gen_marshal_decl(name):
+ return mcgen('''
+%(proto)s;
+''',
+ proto=gen_marshal_proto(name))
+
+def gen_marshal(name, arg_type, ret_type):
ret = mcgen('''
-%(header)s
+%(proto)s
{
- Error *local_err = NULL;
''',
- header=hdr)
-
- if ret_type:
- ret += mcgen('''
- %(c_type)s retval;
-''',
- c_type=ret_type.c_type())
-
- if arg_type:
- ret += gen_visitor_input_containers_decl(arg_type)
- ret += gen_visitor_input_vars_decl(arg_type) + '\n'
- ret += gen_visitor_input_block(arg_type) + '\n'
- else:
- ret += mcgen('''
-
- (void)args;
-
-''')
+ proto=gen_marshal_proto(name))
+ ret += gen_marshal_vars(arg_type, ret_type)
+ ret += gen_marshal_input_visit(arg_type)
ret += gen_call(name, arg_type, ret_type)
if re.search('^ *goto out;', ret, re.MULTILINE):
@@ -246,7 +237,7 @@ out:
ret += mcgen('''
error_propagate(errp, local_err);
''')
- ret += gen_visitor_input_block(arg_type, dealloc=True)
+ ret += gen_marshal_input_visit(arg_type, dealloc=True)
ret += mcgen('''
}
''')
@@ -307,8 +298,8 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
if ret_type:
self.defn += gen_marshal_output(name, ret_type)
if middle_mode:
- self.decl += gen_marshal_input_decl(name) + ';\n'
- self.defn += gen_marshal_input(name, arg_type, ret_type)
+ self.decl += gen_marshal_decl(name)
+ self.defn += gen_marshal(name, arg_type, ret_type)
if not middle_mode:
self._regy += gen_register_command(name, success_response)
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 16/26] qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO()
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (14 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 15/26] qapi-commands: Rearrange code Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 17/26] qapi: De-duplicate parameter list generation Markus Armbruster
` (11 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
These functions marshal both input and output.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
docs/qapi-code-gen.txt | 4 +-
docs/writing-qmp-commands.txt | 8 +-
monitor.c | 2 +-
qmp-commands.hx | 242 +++++++++++++++++++++---------------------
qmp.c | 6 +-
scripts/qapi-commands.py | 4 +-
6 files changed, 133 insertions(+), 133 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 3eaff36..50da1d0 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -744,7 +744,7 @@ Example:
qapi_dealloc_visitor_cleanup(md);
}
- static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
+ static void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
{
Error *local_err = NULL;
UserDefOne *retval;
@@ -777,7 +777,7 @@ Example:
static void qmp_init_marshal(void)
{
- qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
+ qmp_register_command("my-command", qmp_marshal_my_command, QCO_NO_OPTIONS);
}
qapi_init(qmp_init_marshal);
diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
index f7693ca..8647cac 100644
--- a/docs/writing-qmp-commands.txt
+++ b/docs/writing-qmp-commands.txt
@@ -127,7 +127,7 @@ following at the bottom:
{
.name = "hello-world",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_hello_world,
+ .mhandler.cmd_new = qmp_marshal_hello_world,
},
You're done. Now build qemu, run it as suggested in the "Testing" section,
@@ -179,7 +179,7 @@ The last step is to update the qmp-commands.hx file:
{
.name = "hello-world",
.args_type = "message:s?",
- .mhandler.cmd_new = qmp_marshal_input_hello_world,
+ .mhandler.cmd_new = qmp_marshal_hello_world,
},
Notice that the "args_type" member got our "message" argument. The character
@@ -461,7 +461,7 @@ The last step is to add the correspoding entry in the qmp-commands.hx file:
{
.name = "query-alarm-clock",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_alarm_clock,
+ .mhandler.cmd_new = qmp_marshal_query_alarm_clock,
},
Time to test the new command. Build qemu, run it as described in the "Testing"
@@ -607,7 +607,7 @@ To test this you have to add the corresponding qmp-commands.hx entry:
{
.name = "query-alarm-methods",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_alarm_methods,
+ .mhandler.cmd_new = qmp_marshal_query_alarm_methods,
},
Now Build qemu, run it as explained in the "Testing" section and try our new
diff --git a/monitor.c b/monitor.c
index 5455ab9..e083716 100644
--- a/monitor.c
+++ b/monitor.c
@@ -5142,7 +5142,7 @@ static QObject *get_qmp_greeting(void)
{
QObject *ver = NULL;
- qmp_marshal_input_query_version(NULL, &ver, NULL);
+ qmp_marshal_query_version(NULL, &ver, NULL);
return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
}
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9848fd8..4640a3d 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -63,7 +63,7 @@ EQMP
{
.name = "quit",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_quit,
+ .mhandler.cmd_new = qmp_marshal_quit,
},
SQMP
@@ -84,7 +84,7 @@ EQMP
{
.name = "eject",
.args_type = "force:-f,device:B",
- .mhandler.cmd_new = qmp_marshal_input_eject,
+ .mhandler.cmd_new = qmp_marshal_eject,
},
SQMP
@@ -110,7 +110,7 @@ EQMP
{
.name = "change",
.args_type = "device:B,target:F,arg:s?",
- .mhandler.cmd_new = qmp_marshal_input_change,
+ .mhandler.cmd_new = qmp_marshal_change,
},
SQMP
@@ -146,7 +146,7 @@ EQMP
{
.name = "screendump",
.args_type = "filename:F",
- .mhandler.cmd_new = qmp_marshal_input_screendump,
+ .mhandler.cmd_new = qmp_marshal_screendump,
},
SQMP
@@ -169,7 +169,7 @@ EQMP
{
.name = "stop",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_stop,
+ .mhandler.cmd_new = qmp_marshal_stop,
},
SQMP
@@ -190,7 +190,7 @@ EQMP
{
.name = "cont",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_cont,
+ .mhandler.cmd_new = qmp_marshal_cont,
},
SQMP
@@ -211,7 +211,7 @@ EQMP
{
.name = "system_wakeup",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_system_wakeup,
+ .mhandler.cmd_new = qmp_marshal_system_wakeup,
},
SQMP
@@ -232,7 +232,7 @@ EQMP
{
.name = "system_reset",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_system_reset,
+ .mhandler.cmd_new = qmp_marshal_system_reset,
},
SQMP
@@ -253,7 +253,7 @@ EQMP
{
.name = "system_powerdown",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_system_powerdown,
+ .mhandler.cmd_new = qmp_marshal_system_powerdown,
},
SQMP
@@ -310,7 +310,7 @@ EQMP
{
.name = "device_del",
.args_type = "id:s",
- .mhandler.cmd_new = qmp_marshal_input_device_del,
+ .mhandler.cmd_new = qmp_marshal_device_del,
},
SQMP
@@ -333,7 +333,7 @@ EQMP
{
.name = "send-key",
.args_type = "keys:q,hold-time:i?",
- .mhandler.cmd_new = qmp_marshal_input_send_key,
+ .mhandler.cmd_new = qmp_marshal_send_key,
},
SQMP
@@ -364,7 +364,7 @@ EQMP
{
.name = "cpu",
.args_type = "index:i",
- .mhandler.cmd_new = qmp_marshal_input_cpu,
+ .mhandler.cmd_new = qmp_marshal_cpu,
},
SQMP
@@ -389,7 +389,7 @@ EQMP
{
.name = "cpu-add",
.args_type = "id:i",
- .mhandler.cmd_new = qmp_marshal_input_cpu_add,
+ .mhandler.cmd_new = qmp_marshal_cpu_add,
},
SQMP
@@ -412,7 +412,7 @@ EQMP
{
.name = "memsave",
.args_type = "val:l,size:i,filename:s,cpu:i?",
- .mhandler.cmd_new = qmp_marshal_input_memsave,
+ .mhandler.cmd_new = qmp_marshal_memsave,
},
SQMP
@@ -441,7 +441,7 @@ EQMP
{
.name = "pmemsave",
.args_type = "val:l,size:i,filename:s",
- .mhandler.cmd_new = qmp_marshal_input_pmemsave,
+ .mhandler.cmd_new = qmp_marshal_pmemsave,
},
SQMP
@@ -469,7 +469,7 @@ EQMP
{
.name = "inject-nmi",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_inject_nmi,
+ .mhandler.cmd_new = qmp_marshal_inject_nmi,
},
SQMP
@@ -492,7 +492,7 @@ EQMP
{
.name = "ringbuf-write",
.args_type = "device:s,data:s,format:s?",
- .mhandler.cmd_new = qmp_marshal_input_ringbuf_write,
+ .mhandler.cmd_new = qmp_marshal_ringbuf_write,
},
SQMP
@@ -523,7 +523,7 @@ EQMP
{
.name = "ringbuf-read",
.args_type = "device:s,size:i,format:s?",
- .mhandler.cmd_new = qmp_marshal_input_ringbuf_read,
+ .mhandler.cmd_new = qmp_marshal_ringbuf_read,
},
SQMP
@@ -559,7 +559,7 @@ EQMP
{
.name = "xen-save-devices-state",
.args_type = "filename:F",
- .mhandler.cmd_new = qmp_marshal_input_xen_save_devices_state,
+ .mhandler.cmd_new = qmp_marshal_xen_save_devices_state,
},
SQMP
@@ -586,7 +586,7 @@ EQMP
{
.name = "xen-set-global-dirty-log",
.args_type = "enable:b",
- .mhandler.cmd_new = qmp_marshal_input_xen_set_global_dirty_log,
+ .mhandler.cmd_new = qmp_marshal_xen_set_global_dirty_log,
},
SQMP
@@ -610,7 +610,7 @@ EQMP
{
.name = "migrate",
.args_type = "detach:-d,blk:-b,inc:-i,uri:s",
- .mhandler.cmd_new = qmp_marshal_input_migrate,
+ .mhandler.cmd_new = qmp_marshal_migrate,
},
SQMP
@@ -643,7 +643,7 @@ EQMP
{
.name = "migrate_cancel",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_migrate_cancel,
+ .mhandler.cmd_new = qmp_marshal_migrate_cancel,
},
SQMP
@@ -664,7 +664,7 @@ EQMP
{
.name = "migrate-incoming",
.args_type = "uri:s",
- .mhandler.cmd_new = qmp_marshal_input_migrate_incoming,
+ .mhandler.cmd_new = qmp_marshal_migrate_incoming,
},
SQMP
@@ -692,7 +692,7 @@ EQMP
{
.name = "migrate-set-cache-size",
.args_type = "value:o",
- .mhandler.cmd_new = qmp_marshal_input_migrate_set_cache_size,
+ .mhandler.cmd_new = qmp_marshal_migrate_set_cache_size,
},
SQMP
@@ -715,7 +715,7 @@ EQMP
{
.name = "query-migrate-cache-size",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_migrate_cache_size,
+ .mhandler.cmd_new = qmp_marshal_query_migrate_cache_size,
},
SQMP
@@ -737,7 +737,7 @@ EQMP
{
.name = "migrate_set_speed",
.args_type = "value:o",
- .mhandler.cmd_new = qmp_marshal_input_migrate_set_speed,
+ .mhandler.cmd_new = qmp_marshal_migrate_set_speed,
},
SQMP
@@ -760,7 +760,7 @@ EQMP
{
.name = "migrate_set_downtime",
.args_type = "value:T",
- .mhandler.cmd_new = qmp_marshal_input_migrate_set_downtime,
+ .mhandler.cmd_new = qmp_marshal_migrate_set_downtime,
},
SQMP
@@ -785,7 +785,7 @@ EQMP
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
.params = "protocol hostname port tls-port cert-subject",
.help = "set migration information for remote display",
- .mhandler.cmd_new = qmp_marshal_input_client_migrate_info,
+ .mhandler.cmd_new = qmp_marshal_client_migrate_info,
},
SQMP
@@ -819,7 +819,7 @@ EQMP
.args_type = "paging:b,protocol:s,begin:i?,end:i?,format:s?",
.params = "-p protocol [begin] [length] [format]",
.help = "dump guest memory to file",
- .mhandler.cmd_new = qmp_marshal_input_dump_guest_memory,
+ .mhandler.cmd_new = qmp_marshal_dump_guest_memory,
},
SQMP
@@ -855,7 +855,7 @@ EQMP
{
.name = "query-dump-guest-memory-capability",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_dump_guest_memory_capability,
+ .mhandler.cmd_new = qmp_marshal_query_dump_guest_memory_capability,
},
SQMP
@@ -876,7 +876,7 @@ EQMP
{
.name = "dump-skeys",
.args_type = "filename:F",
- .mhandler.cmd_new = qmp_marshal_input_dump_skeys,
+ .mhandler.cmd_new = qmp_marshal_dump_skeys,
},
#endif
@@ -929,7 +929,7 @@ EQMP
{
.name = "netdev_del",
.args_type = "id:s",
- .mhandler.cmd_new = qmp_marshal_input_netdev_del,
+ .mhandler.cmd_new = qmp_marshal_netdev_del,
},
SQMP
@@ -979,7 +979,7 @@ EQMP
{
.name = "object-del",
.args_type = "id:s",
- .mhandler.cmd_new = qmp_marshal_input_object_del,
+ .mhandler.cmd_new = qmp_marshal_object_del,
},
SQMP
@@ -1004,7 +1004,7 @@ EQMP
{
.name = "block_resize",
.args_type = "device:s?,node-name:s?,size:o",
- .mhandler.cmd_new = qmp_marshal_input_block_resize,
+ .mhandler.cmd_new = qmp_marshal_block_resize,
},
SQMP
@@ -1029,7 +1029,7 @@ EQMP
{
.name = "block-stream",
.args_type = "device:B,base:s?,speed:o?,backing-file:s?,on-error:s?",
- .mhandler.cmd_new = qmp_marshal_input_block_stream,
+ .mhandler.cmd_new = qmp_marshal_block_stream,
},
SQMP
@@ -1072,7 +1072,7 @@ EQMP
{
.name = "block-commit",
.args_type = "device:B,base:s?,top:s?,backing-file:s?,speed:o?",
- .mhandler.cmd_new = qmp_marshal_input_block_commit,
+ .mhandler.cmd_new = qmp_marshal_block_commit,
},
SQMP
@@ -1136,7 +1136,7 @@ EQMP
.name = "drive-backup",
.args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?,"
"bitmap:s?,on-source-error:s?,on-target-error:s?",
- .mhandler.cmd_new = qmp_marshal_input_drive_backup,
+ .mhandler.cmd_new = qmp_marshal_drive_backup,
},
SQMP
@@ -1190,7 +1190,7 @@ EQMP
.name = "blockdev-backup",
.args_type = "sync:s,device:B,target:B,speed:i?,"
"on-source-error:s?,on-target-error:s?",
- .mhandler.cmd_new = qmp_marshal_input_blockdev_backup,
+ .mhandler.cmd_new = qmp_marshal_blockdev_backup,
},
SQMP
@@ -1230,33 +1230,33 @@ EQMP
{
.name = "block-job-set-speed",
.args_type = "device:B,speed:o",
- .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
+ .mhandler.cmd_new = qmp_marshal_block_job_set_speed,
},
{
.name = "block-job-cancel",
.args_type = "device:B,force:b?",
- .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
+ .mhandler.cmd_new = qmp_marshal_block_job_cancel,
},
{
.name = "block-job-pause",
.args_type = "device:B",
- .mhandler.cmd_new = qmp_marshal_input_block_job_pause,
+ .mhandler.cmd_new = qmp_marshal_block_job_pause,
},
{
.name = "block-job-resume",
.args_type = "device:B",
- .mhandler.cmd_new = qmp_marshal_input_block_job_resume,
+ .mhandler.cmd_new = qmp_marshal_block_job_resume,
},
{
.name = "block-job-complete",
.args_type = "device:B",
- .mhandler.cmd_new = qmp_marshal_input_block_job_complete,
+ .mhandler.cmd_new = qmp_marshal_block_job_complete,
},
{
.name = "transaction",
.args_type = "actions:q",
- .mhandler.cmd_new = qmp_marshal_input_transaction,
+ .mhandler.cmd_new = qmp_marshal_transaction,
},
SQMP
@@ -1335,7 +1335,7 @@ EQMP
{
.name = "block-dirty-bitmap-add",
.args_type = "node:B,name:s,granularity:i?",
- .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_add,
+ .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_add,
},
SQMP
@@ -1363,7 +1363,7 @@ EQMP
{
.name = "block-dirty-bitmap-remove",
.args_type = "node:B,name:s",
- .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_remove,
+ .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_remove,
},
SQMP
@@ -1391,7 +1391,7 @@ EQMP
{
.name = "block-dirty-bitmap-clear",
.args_type = "node:B,name:s",
- .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_clear,
+ .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_clear,
},
SQMP
@@ -1420,7 +1420,7 @@ EQMP
{
.name = "blockdev-snapshot-sync",
.args_type = "device:s?,node-name:s?,snapshot-file:s,snapshot-node-name:s?,format:s?,mode:s?",
- .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
+ .mhandler.cmd_new = qmp_marshal_blockdev_snapshot_sync,
},
SQMP
@@ -1456,7 +1456,7 @@ EQMP
{
.name = "blockdev-snapshot-internal-sync",
.args_type = "device:B,name:s",
- .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_internal_sync,
+ .mhandler.cmd_new = qmp_marshal_blockdev_snapshot_internal_sync,
},
SQMP
@@ -1486,7 +1486,7 @@ EQMP
.name = "blockdev-snapshot-delete-internal-sync",
.args_type = "device:B,id:s?,name:s?",
.mhandler.cmd_new =
- qmp_marshal_input_blockdev_snapshot_delete_internal_sync,
+ qmp_marshal_blockdev_snapshot_delete_internal_sync,
},
SQMP
@@ -1530,7 +1530,7 @@ EQMP
"on-source-error:s?,on-target-error:s?,"
"unmap:b?,"
"granularity:i?,buf-size:i?",
- .mhandler.cmd_new = qmp_marshal_input_drive_mirror,
+ .mhandler.cmd_new = qmp_marshal_drive_mirror,
},
SQMP
@@ -1590,7 +1590,7 @@ EQMP
{
.name = "change-backing-file",
.args_type = "device:s,image-node-name:s,backing-file:s",
- .mhandler.cmd_new = qmp_marshal_input_change_backing_file,
+ .mhandler.cmd_new = qmp_marshal_change_backing_file,
},
SQMP
@@ -1629,7 +1629,7 @@ EQMP
{
.name = "balloon",
.args_type = "value:M",
- .mhandler.cmd_new = qmp_marshal_input_balloon,
+ .mhandler.cmd_new = qmp_marshal_balloon,
},
SQMP
@@ -1652,7 +1652,7 @@ EQMP
{
.name = "set_link",
.args_type = "name:s,up:b",
- .mhandler.cmd_new = qmp_marshal_input_set_link,
+ .mhandler.cmd_new = qmp_marshal_set_link,
},
SQMP
@@ -1678,7 +1678,7 @@ EQMP
.args_type = "fdname:s",
.params = "getfd name",
.help = "receive a file descriptor via SCM rights and assign it a name",
- .mhandler.cmd_new = qmp_marshal_input_getfd,
+ .mhandler.cmd_new = qmp_marshal_getfd,
},
SQMP
@@ -1711,7 +1711,7 @@ EQMP
.args_type = "fdname:s",
.params = "closefd name",
.help = "close a file descriptor previously passed via SCM rights",
- .mhandler.cmd_new = qmp_marshal_input_closefd,
+ .mhandler.cmd_new = qmp_marshal_closefd,
},
SQMP
@@ -1736,7 +1736,7 @@ EQMP
.args_type = "fdset-id:i?,opaque:s?",
.params = "add-fd fdset-id opaque",
.help = "Add a file descriptor, that was passed via SCM rights, to an fd set",
- .mhandler.cmd_new = qmp_marshal_input_add_fd,
+ .mhandler.cmd_new = qmp_marshal_add_fd,
},
SQMP
@@ -1775,7 +1775,7 @@ EQMP
.args_type = "fdset-id:i,fd:i?",
.params = "remove-fd fdset-id fd",
.help = "Remove a file descriptor from an fd set",
- .mhandler.cmd_new = qmp_marshal_input_remove_fd,
+ .mhandler.cmd_new = qmp_marshal_remove_fd,
},
SQMP
@@ -1807,7 +1807,7 @@ EQMP
.name = "query-fdsets",
.args_type = "",
.help = "Return information describing all fd sets",
- .mhandler.cmd_new = qmp_marshal_input_query_fdsets,
+ .mhandler.cmd_new = qmp_marshal_query_fdsets,
},
SQMP
@@ -1856,7 +1856,7 @@ EQMP
{
.name = "block_passwd",
.args_type = "device:s?,node-name:s?,password:s",
- .mhandler.cmd_new = qmp_marshal_input_block_passwd,
+ .mhandler.cmd_new = qmp_marshal_block_passwd,
},
SQMP
@@ -1882,7 +1882,7 @@ EQMP
{
.name = "block_set_io_throttle",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l,bps_max:l?,bps_rd_max:l?,bps_wr_max:l?,iops_max:l?,iops_rd_max:l?,iops_wr_max:l?,iops_size:l?,group:s?",
- .mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
+ .mhandler.cmd_new = qmp_marshal_block_set_io_throttle,
},
SQMP
@@ -1932,7 +1932,7 @@ EQMP
{
.name = "set_password",
.args_type = "protocol:s,password:s,connected:s?",
- .mhandler.cmd_new = qmp_marshal_input_set_password,
+ .mhandler.cmd_new = qmp_marshal_set_password,
},
SQMP
@@ -1958,7 +1958,7 @@ EQMP
{
.name = "expire_password",
.args_type = "protocol:s,time:s",
- .mhandler.cmd_new = qmp_marshal_input_expire_password,
+ .mhandler.cmd_new = qmp_marshal_expire_password,
},
SQMP
@@ -1983,7 +1983,7 @@ EQMP
{
.name = "add_client",
.args_type = "protocol:s,fdname:s,skipauth:b?,tls:b?",
- .mhandler.cmd_new = qmp_marshal_input_add_client,
+ .mhandler.cmd_new = qmp_marshal_add_client,
},
SQMP
@@ -2034,7 +2034,7 @@ EQMP
{
.name = "human-monitor-command",
.args_type = "command-line:s,cpu-index:i?",
- .mhandler.cmd_new = qmp_marshal_input_human_monitor_command,
+ .mhandler.cmd_new = qmp_marshal_human_monitor_command,
},
SQMP
@@ -2113,7 +2113,7 @@ EQMP
{
.name = "query-version",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_version,
+ .mhandler.cmd_new = qmp_marshal_query_version,
},
SQMP
@@ -2150,7 +2150,7 @@ EQMP
{
.name = "query-commands",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_commands,
+ .mhandler.cmd_new = qmp_marshal_query_commands,
},
SQMP
@@ -2187,7 +2187,7 @@ EQMP
{
.name = "query-events",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_events,
+ .mhandler.cmd_new = qmp_marshal_query_events,
},
SQMP
@@ -2232,7 +2232,7 @@ EQMP
{
.name = "query-chardev",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_chardev,
+ .mhandler.cmd_new = qmp_marshal_query_chardev,
},
SQMP
@@ -2273,7 +2273,7 @@ EQMP
{
.name = "query-chardev-backends",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_chardev_backends,
+ .mhandler.cmd_new = qmp_marshal_query_chardev_backends,
},
SQMP
@@ -2457,7 +2457,7 @@ EQMP
{
.name = "query-block",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_block,
+ .mhandler.cmd_new = qmp_marshal_query_block,
},
SQMP
@@ -2584,7 +2584,7 @@ EQMP
{
.name = "query-blockstats",
.args_type = "query-nodes:b?",
- .mhandler.cmd_new = qmp_marshal_input_query_blockstats,
+ .mhandler.cmd_new = qmp_marshal_query_blockstats,
},
SQMP
@@ -2635,7 +2635,7 @@ EQMP
{
.name = "query-cpus",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_cpus,
+ .mhandler.cmd_new = qmp_marshal_query_cpus,
},
SQMP
@@ -2674,7 +2674,7 @@ EQMP
{
.name = "query-iothreads",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_iothreads,
+ .mhandler.cmd_new = qmp_marshal_query_iothreads,
},
SQMP
@@ -2891,7 +2891,7 @@ EQMP
{
.name = "query-pci",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_pci,
+ .mhandler.cmd_new = qmp_marshal_query_pci,
},
SQMP
@@ -2915,7 +2915,7 @@ EQMP
{
.name = "query-kvm",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_kvm,
+ .mhandler.cmd_new = qmp_marshal_query_kvm,
},
SQMP
@@ -2955,7 +2955,7 @@ EQMP
{
.name = "query-status",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_status,
+ .mhandler.cmd_new = qmp_marshal_query_status,
},
SQMP
@@ -2999,7 +2999,7 @@ EQMP
{
.name = "query-mice",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_mice,
+ .mhandler.cmd_new = qmp_marshal_query_mice,
},
SQMP
@@ -3062,12 +3062,12 @@ EQMP
{
.name = "query-vnc",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_vnc,
+ .mhandler.cmd_new = qmp_marshal_query_vnc,
},
{
.name = "query-vnc-servers",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_vnc_servers,
+ .mhandler.cmd_new = qmp_marshal_query_vnc_servers,
},
SQMP
@@ -3144,7 +3144,7 @@ EQMP
{
.name = "query-spice",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_spice,
+ .mhandler.cmd_new = qmp_marshal_query_spice,
},
#endif
@@ -3168,7 +3168,7 @@ EQMP
{
.name = "query-name",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_name,
+ .mhandler.cmd_new = qmp_marshal_query_name,
},
SQMP
@@ -3191,7 +3191,7 @@ EQMP
{
.name = "query-uuid",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_uuid,
+ .mhandler.cmd_new = qmp_marshal_query_uuid,
},
SQMP
@@ -3240,7 +3240,7 @@ EQMP
{
.name = "query-command-line-options",
.args_type = "option:s?",
- .mhandler.cmd_new = qmp_marshal_input_query_command_line_options,
+ .mhandler.cmd_new = qmp_marshal_query_command_line_options,
},
SQMP
@@ -3418,7 +3418,7 @@ EQMP
{
.name = "query-migrate",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_migrate,
+ .mhandler.cmd_new = qmp_marshal_query_migrate,
},
SQMP
@@ -3446,7 +3446,7 @@ EQMP
.name = "migrate-set-capabilities",
.args_type = "capabilities:q",
.params = "capability:s,state:b",
- .mhandler.cmd_new = qmp_marshal_input_migrate_set_capabilities,
+ .mhandler.cmd_new = qmp_marshal_migrate_set_capabilities,
},
SQMP
query-migrate-capabilities
@@ -3472,7 +3472,7 @@ EQMP
{
.name = "query-migrate-capabilities",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_migrate_capabilities,
+ .mhandler.cmd_new = qmp_marshal_query_migrate_capabilities,
},
SQMP
@@ -3498,7 +3498,7 @@ EQMP
.name = "migrate-set-parameters",
.args_type =
"compress-level:i?,compress-threads:i?,decompress-threads:i?",
- .mhandler.cmd_new = qmp_marshal_input_migrate_set_parameters,
+ .mhandler.cmd_new = qmp_marshal_migrate_set_parameters,
},
SQMP
query-migrate-parameters
@@ -3529,7 +3529,7 @@ EQMP
{
.name = "query-migrate-parameters",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_migrate_parameters,
+ .mhandler.cmd_new = qmp_marshal_query_migrate_parameters,
},
SQMP
@@ -3557,19 +3557,19 @@ EQMP
{
.name = "query-balloon",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_balloon,
+ .mhandler.cmd_new = qmp_marshal_query_balloon,
},
{
.name = "query-block-jobs",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_block_jobs,
+ .mhandler.cmd_new = qmp_marshal_query_block_jobs,
},
{
.name = "qom-list",
.args_type = "path:s",
- .mhandler.cmd_new = qmp_marshal_input_qom_list,
+ .mhandler.cmd_new = qmp_marshal_qom_list,
},
{
@@ -3587,58 +3587,58 @@ EQMP
{
.name = "nbd-server-start",
.args_type = "addr:q",
- .mhandler.cmd_new = qmp_marshal_input_nbd_server_start,
+ .mhandler.cmd_new = qmp_marshal_nbd_server_start,
},
{
.name = "nbd-server-add",
.args_type = "device:B,writable:b?",
- .mhandler.cmd_new = qmp_marshal_input_nbd_server_add,
+ .mhandler.cmd_new = qmp_marshal_nbd_server_add,
},
{
.name = "nbd-server-stop",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_nbd_server_stop,
+ .mhandler.cmd_new = qmp_marshal_nbd_server_stop,
},
{
.name = "change-vnc-password",
.args_type = "password:s",
- .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
+ .mhandler.cmd_new = qmp_marshal_change_vnc_password,
},
{
.name = "qom-list-types",
.args_type = "implements:s?,abstract:b?",
- .mhandler.cmd_new = qmp_marshal_input_qom_list_types,
+ .mhandler.cmd_new = qmp_marshal_qom_list_types,
},
{
.name = "device-list-properties",
.args_type = "typename:s",
- .mhandler.cmd_new = qmp_marshal_input_device_list_properties,
+ .mhandler.cmd_new = qmp_marshal_device_list_properties,
},
{
.name = "query-machines",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_machines,
+ .mhandler.cmd_new = qmp_marshal_query_machines,
},
{
.name = "query-cpu-definitions",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_cpu_definitions,
+ .mhandler.cmd_new = qmp_marshal_query_cpu_definitions,
},
{
.name = "query-target",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_target,
+ .mhandler.cmd_new = qmp_marshal_query_target,
},
{
.name = "query-tpm",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_tpm,
+ .mhandler.cmd_new = qmp_marshal_query_tpm,
},
SQMP
@@ -3672,7 +3672,7 @@ EQMP
{
.name = "query-tpm-models",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_tpm_models,
+ .mhandler.cmd_new = qmp_marshal_query_tpm_models,
},
SQMP
@@ -3693,7 +3693,7 @@ EQMP
{
.name = "query-tpm-types",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_tpm_types,
+ .mhandler.cmd_new = qmp_marshal_query_tpm_types,
},
SQMP
@@ -3714,7 +3714,7 @@ EQMP
{
.name = "chardev-add",
.args_type = "id:s,backend:q",
- .mhandler.cmd_new = qmp_marshal_input_chardev_add,
+ .mhandler.cmd_new = qmp_marshal_chardev_add,
},
SQMP
@@ -3751,7 +3751,7 @@ EQMP
{
.name = "chardev-remove",
.args_type = "id:s",
- .mhandler.cmd_new = qmp_marshal_input_chardev_remove,
+ .mhandler.cmd_new = qmp_marshal_chardev_remove,
},
@@ -3774,7 +3774,7 @@ EQMP
{
.name = "query-rx-filter",
.args_type = "name:s?",
- .mhandler.cmd_new = qmp_marshal_input_query_rx_filter,
+ .mhandler.cmd_new = qmp_marshal_query_rx_filter,
},
SQMP
@@ -3840,7 +3840,7 @@ EQMP
{
.name = "blockdev-add",
.args_type = "options:q",
- .mhandler.cmd_new = qmp_marshal_input_blockdev_add,
+ .mhandler.cmd_new = qmp_marshal_blockdev_add,
},
SQMP
@@ -3899,7 +3899,7 @@ EQMP
{
.name = "query-named-block-nodes",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_named_block_nodes,
+ .mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
},
SQMP
@@ -3961,7 +3961,7 @@ EQMP
{
.name = "query-memdev",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_memdev,
+ .mhandler.cmd_new = qmp_marshal_query_memdev,
},
SQMP
@@ -3999,7 +3999,7 @@ EQMP
{
.name = "query-memory-devices",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_memory_devices,
+ .mhandler.cmd_new = qmp_marshal_query_memory_devices,
},
SQMP
@@ -4026,7 +4026,7 @@ EQMP
{
.name = "query-acpi-ospm-status",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_acpi_ospm_status,
+ .mhandler.cmd_new = qmp_marshal_query_acpi_ospm_status,
},
SQMP
@@ -4049,7 +4049,7 @@ EQMP
{
.name = "rtc-reset-reinjection",
.args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_rtc_reset_reinjection,
+ .mhandler.cmd_new = qmp_marshal_rtc_reset_reinjection,
},
#endif
@@ -4070,7 +4070,7 @@ EQMP
{
.name = "trace-event-get-state",
.args_type = "name:s",
- .mhandler.cmd_new = qmp_marshal_input_trace_event_get_state,
+ .mhandler.cmd_new = qmp_marshal_trace_event_get_state,
},
SQMP
@@ -4088,7 +4088,7 @@ EQMP
{
.name = "trace-event-set-state",
.args_type = "name:s,enable:b,ignore-unavailable:b?",
- .mhandler.cmd_new = qmp_marshal_input_trace_event_set_state,
+ .mhandler.cmd_new = qmp_marshal_trace_event_set_state,
},
SQMP
@@ -4106,7 +4106,7 @@ EQMP
{
.name = "x-input-send-event",
.args_type = "console:i?,events:q",
- .mhandler.cmd_new = qmp_marshal_input_x_input_send_event,
+ .mhandler.cmd_new = qmp_marshal_x_input_send_event,
},
SQMP
@@ -4171,7 +4171,7 @@ EQMP
{
.name = "block-set-write-threshold",
.args_type = "node-name:s,write-threshold:l",
- .mhandler.cmd_new = qmp_marshal_input_block_set_write_threshold,
+ .mhandler.cmd_new = qmp_marshal_block_set_write_threshold,
},
SQMP
@@ -4199,7 +4199,7 @@ EQMP
{
.name = "query-rocker",
.args_type = "name:s",
- .mhandler.cmd_new = qmp_marshal_input_query_rocker,
+ .mhandler.cmd_new = qmp_marshal_query_rocker,
},
SQMP
@@ -4220,7 +4220,7 @@ EQMP
{
.name = "query-rocker-ports",
.args_type = "name:s",
- .mhandler.cmd_new = qmp_marshal_input_query_rocker_ports,
+ .mhandler.cmd_new = qmp_marshal_query_rocker_ports,
},
SQMP
@@ -4245,7 +4245,7 @@ EQMP
{
.name = "query-rocker-of-dpa-flows",
.args_type = "name:s,tbl-id:i?",
- .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_flows,
+ .mhandler.cmd_new = qmp_marshal_query_rocker_of_dpa_flows,
},
SQMP
@@ -4274,7 +4274,7 @@ EQMP
{
.name = "query-rocker-of-dpa-groups",
.args_type = "name:s,type:i?",
- .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_groups,
+ .mhandler.cmd_new = qmp_marshal_query_rocker_of_dpa_groups,
},
SQMP
diff --git a/qmp.c b/qmp.c
index 9623c80..3feae9f 100644
--- a/qmp.c
+++ b/qmp.c
@@ -157,9 +157,9 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
* #ifdef CONFIG_SPICE. Necessary for an accurate query-commands
* result. However, the QAPI schema is blissfully unaware of that,
* and the QAPI code generator happily generates a dead
- * qmp_marshal_input_query_spice() that calls qmp_query_spice().
- * Provide it one, or else linking fails.
- * FIXME Educate the QAPI schema on CONFIG_SPICE.
+ * qmp_marshal_query_spice() that calls qmp_query_spice(). Provide it
+ * one, or else linking fails. FIXME Educate the QAPI schema on
+ * CONFIG_SPICE.
*/
SpiceInfo *qmp_query_spice(Error **errp)
{
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 6a52c88..c68659a 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -204,7 +204,7 @@ out:
def gen_marshal_proto(name):
- ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
+ ret = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
if not middle_mode:
ret = 'static ' + ret
return ret
@@ -251,7 +251,7 @@ def gen_register_command(name, success_response):
options = 'QCO_NO_SUCCESS_RESP'
ret = mcgen('''
-qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
+qmp_register_command("%(name)s", qmp_marshal_%(c_name)s, %(opts)s);
''',
name=name, c_name=c_name(name),
opts=options)
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 17/26] qapi: De-duplicate parameter list generation
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (15 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 16/26] qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO() Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 18/26] qapi-commands: De-duplicate output marshaling functions Markus Armbruster
` (10 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Generated qapi-event.[ch] lose line breaks. No change otherwise.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
scripts/qapi-commands.py | 11 ++---------
scripts/qapi-event.py | 18 +++---------------
scripts/qapi.py | 16 ++++++++++++++++
3 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index c68659a..833768e 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -17,19 +17,12 @@ import re
def gen_command_decl(name, arg_type, ret_type):
- argstr = ''
- if arg_type:
- for memb in arg_type.members:
- if memb.optional:
- argstr += 'bool has_%s, ' % c_name(memb.name)
- argstr += '%s %s, ' % (memb.type.c_type(is_param=True),
- c_name(memb.name))
return mcgen('''
-%(c_type)s qmp_%(c_name)s(%(args)sError **errp);
+%(c_type)s qmp_%(c_name)s(%(params)s);
''',
c_type=(ret_type and ret_type.c_type()) or 'void',
c_name=c_name(name),
- args=argstr)
+ params=gen_params(arg_type, 'Error **errp'))
def gen_err_check(err):
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 5873a05..d15fad9 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -15,21 +15,9 @@ from qapi import *
def gen_event_send_proto(name, arg_type):
- api_name = "void qapi_event_send_%s(" % c_name(name).lower()
- l = len(api_name)
-
- if arg_type:
- for m in arg_type.members:
- if m.optional:
- api_name += "bool has_%s,\n" % c_name(m.name)
- api_name += "".ljust(l)
-
- api_name += "%s %s,\n" % (m.type.c_type(is_param=True),
- c_name(m.name))
- api_name += "".ljust(l)
-
- api_name += "Error **errp)"
- return api_name
+ return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
+ 'c_name': c_name(name.lower()),
+ 'param': gen_params(arg_type, 'Error **errp')}
def gen_event_send_decl(name, arg_type):
diff --git a/scripts/qapi.py b/scripts/qapi.py
index bd6e52b..8ad0273 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1468,6 +1468,22 @@ extern const char *const %(c_name)s_lookup[];
c_name=c_name(name))
return ret
+def gen_params(arg_type, extra):
+ if not arg_type:
+ return extra
+ assert not arg_type.variants
+ ret = ''
+ sep = ''
+ for memb in arg_type.members:
+ ret += sep
+ sep = ', '
+ if memb.optional:
+ ret += 'bool has_%s, ' % c_name(memb.name)
+ ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
+ if extra:
+ ret += sep + extra
+ return ret
+
#
# Common command line parsing
#
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 18/26] qapi-commands: De-duplicate output marshaling functions
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (16 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 17/26] qapi: De-duplicate parameter list generation Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 19/26] qapi: Improve built-in type documentation Markus Armbruster
` (9 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
gen_marshal_output() uses its parameter name only for name of the
generated function. Name it after the type being marshaled instead of
its caller, and drop duplicates.
Saves 7 copies of qmp_marshal_output_int() in qemu-ga, and one copy of
qmp_marshal_output_str() in qemu-system-*.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
docs/qapi-code-gen.txt | 4 ++--
scripts/qapi-commands.py | 17 ++++++++++-------
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 50da1d0..0884b58 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -721,7 +721,7 @@ Example:
$ cat qapi-generated/example-qmp-marshal.c
[Uninteresting stuff omitted...]
- static void qmp_marshal_output_my_command(UserDefOne *ret_in, QObject **ret_out, Error **errp)
+ static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp)
{
Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new();
@@ -764,7 +764,7 @@ Example:
goto out;
}
- qmp_marshal_output_my_command(retval, ret, &local_err);
+ qmp_marshal_output_UserDefOne(retval, ret, &local_err);
out:
error_propagate(errp, local_err);
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 833768e..810a897 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -62,7 +62,7 @@ def gen_call(name, arg_type, ret_type):
qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
''',
- c_name=c_name(name))
+ c_name=ret_type.c_name())
pop_indent()
return ret
@@ -166,10 +166,10 @@ qapi_dealloc_visitor_cleanup(md);
return ret
-def gen_marshal_output(name, ret_type):
+def gen_marshal_output(ret_type):
return mcgen('''
-static void qmp_marshal_output_%(c_cmd_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
+static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
{
Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new();
@@ -192,8 +192,7 @@ out:
qapi_dealloc_visitor_cleanup(md);
}
''',
- c_type=ret_type.c_type(), c_cmd_name=c_name(name),
- c_name=ret_type.c_name())
+ c_type=ret_type.c_type(), c_name=ret_type.c_name())
def gen_marshal_proto(name):
@@ -272,24 +271,28 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
self.decl = None
self.defn = None
self._regy = None
+ self._visited_ret_types = None
def visit_begin(self, schema):
self.decl = ''
self.defn = ''
self._regy = ''
+ self._visited_ret_types = set()
def visit_end(self):
if not middle_mode:
self.defn += gen_registry(self._regy)
self._regy = None
+ self._visited_ret_types = None
def visit_command(self, name, info, arg_type, ret_type,
gen, success_response):
if not gen:
return
self.decl += gen_command_decl(name, arg_type, ret_type)
- if ret_type:
- self.defn += gen_marshal_output(name, ret_type)
+ if ret_type and ret_type not in self._visited_ret_types:
+ self._visited_ret_types.add(ret_type)
+ self.defn += gen_marshal_output(ret_type)
if middle_mode:
self.decl += gen_marshal_decl(name)
self.defn += gen_marshal(name, arg_type, ret_type)
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 19/26] qapi: Improve built-in type documentation
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (17 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 18/26] qapi-commands: De-duplicate output marshaling functions Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 20/26] qapi: Make output visitor return qnull() instead of NULL Markus Armbruster
` (8 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Clarify how they map to JSON. Add how they map to C. Fix the
reference to StringInputVisitor.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
docs/qapi-code-gen.txt | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 0884b58..5c2c278 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -140,17 +140,24 @@ must have a value that forms a struct name.
=== Built-in Types ===
-The following types are built-in to the parser:
- 'str' - arbitrary UTF-8 string
- 'int' - 64-bit signed integer (although the C code may place further
- restrictions on acceptable range)
- 'number' - floating point number
- 'bool' - JSON value of true or false
- 'int8', 'int16', 'int32', 'int64' - like 'int', but enforce maximum
- bit size
- 'uint8', 'uint16', 'uint32', 'uint64' - unsigned counterparts
- 'size' - like 'uint64', but allows scaled suffix from command line
- visitor
+The following types are predefined, and map to C as follows:
+
+ Schema C JSON
+ str char * any JSON string, UTF-8
+ number double any JSON number
+ int int64_t a JSON number without fractional part
+ that fits into the C integer type
+ int8 int8_t likewise
+ int16 int16_t likewise
+ int32 int32_t likewise
+ int64 int64_t likewise
+ uint8 uint8_t likewise
+ uint16 uint16_t likewise
+ uint32 uint32_t likewise
+ uint64 uint64_t likewise
+ size uint64_t like uint64_t, except StringInputVisitor
+ accepts size suffixes
+ bool bool JSON true or false
=== Includes ===
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 20/26] qapi: Make output visitor return qnull() instead of NULL
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (18 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 19/26] qapi: Improve built-in type documentation Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 21/26] qapi: Introduce a first class 'any' type Markus Armbruster
` (7 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
Before commit 1d10b44, it crashed. Since then, it returns NULL, with
a FIXME comment. The FIXME is valid: code that assumes QObject *
can't be null exists. I'm not aware of a way to feed this problematic
return value to code that actually chokes on null in the current code,
but the next few commits will create one, failing "make check".
Commit 481b002 solved a very similar problem by introducing a special
null QObject. Using this special null QObject is clearly the right
way to resolve this FIXME, so do that, and update the test
accordingly.
However, the patch isn't quite right: it messes up the reference
counting. After about SIZE_MAX visits, the reference counter
overflows, failing the assertion in qnull_destroy_obj(). Because
that's many orders of magnitude more visits of nulls than we expect,
we take this patch despite its flaws, to get the QMP introspection
stuff in without further delay. We'll want to fix it for real before
the release.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
qapi/qmp-output-visitor.c | 8 ++++++--
tests/test-qmp-output-visitor.c | 3 ++-
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index efc19d5..8dce087 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -66,9 +66,13 @@ static QObject *qmp_output_first(QmpOutputVisitor *qov)
{
QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
- /* FIXME - find a better way to deal with NULL values */
+ /*
+ * FIXME Wrong, because qmp_output_get_qobject() will increment
+ * the refcnt *again*. We need to think through how visitors
+ * handle null.
+ */
if (!e) {
- return NULL;
+ return qnull();
}
return e->value;
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 338ada0..a48ae72 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -485,7 +485,8 @@ static void test_visitor_out_empty(TestOutputVisitorData *data,
QObject *arg;
arg = qmp_output_get_qobject(data->qov);
- g_assert(!arg);
+ g_assert(qobject_type(arg) == QTYPE_QNULL);
+ qobject_decref(arg);
}
static void init_native_list(UserDefNativeListUnion *cvalue)
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 21/26] qapi: Introduce a first class 'any' type
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (19 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 20/26] qapi: Make output visitor return qnull() instead of NULL Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 22/26] qom: Don't use 'gen': false for qom-get, qom-set, object-add Markus Armbruster
` (6 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
It's first class, because unlike '**', it actually works, i.e. doesn't
require 'gen': false.
'**' will go away next.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
docs/qapi-code-gen.txt | 1 +
include/qapi/visitor-impl.h | 2 +
include/qapi/visitor.h | 1 +
qapi/qapi-dealloc-visitor.c | 9 ++++
qapi/qapi-visit-core.c | 6 +++
qapi/qmp-input-visitor.c | 11 +++++
qapi/qmp-output-visitor.c | 9 ++++
scripts/qapi-types.py | 1 +
scripts/qapi.py | 9 ++--
tests/Makefile | 3 +-
tests/qapi-schema/args-any.err | 1 +
.../{flat-union-base-star.exit => args-any.exit} | 0
tests/qapi-schema/args-any.json | 2 +
.../{flat-union-base-star.out => args-any.out} | 0
tests/qapi-schema/flat-union-base-any.err | 1 +
tests/qapi-schema/flat-union-base-any.exit | 1 +
...ion-base-star.json => flat-union-base-any.json} | 2 +-
tests/qapi-schema/flat-union-base-any.out | 0
tests/qapi-schema/flat-union-base-star.err | 1 -
tests/qapi-schema/qapi-schema-test.json | 5 +-
tests/qapi-schema/qapi-schema-test.out | 9 +++-
tests/qapi-schema/type-bypass.out | 4 +-
tests/test-qmp-commands.c | 5 ++
tests/test-qmp-input-visitor.c | 45 ++++++++++++++++++
tests/test-qmp-output-visitor.c | 53 ++++++++++++++++++++++
25 files changed, 171 insertions(+), 10 deletions(-)
create mode 100644 tests/qapi-schema/args-any.err
rename tests/qapi-schema/{flat-union-base-star.exit => args-any.exit} (100%)
create mode 100644 tests/qapi-schema/args-any.json
rename tests/qapi-schema/{flat-union-base-star.out => args-any.out} (100%)
create mode 100644 tests/qapi-schema/flat-union-base-any.err
create mode 100644 tests/qapi-schema/flat-union-base-any.exit
rename tests/qapi-schema/{flat-union-base-star.json => flat-union-base-any.json} (95%)
create mode 100644 tests/qapi-schema/flat-union-base-any.out
delete mode 100644 tests/qapi-schema/flat-union-base-star.err
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 5c2c278..70fdae7 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -158,6 +158,7 @@ The following types are predefined, and map to C as follows:
size uint64_t like uint64_t, except StringInputVisitor
accepts size suffixes
bool bool JSON true or false
+ any QObject * any JSON value
=== Includes ===
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index f4a2f74..8c0ba57 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -40,6 +40,8 @@ struct Visitor
void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
void (*type_number)(Visitor *v, double *obj, const char *name,
Error **errp);
+ void (*type_any)(Visitor *v, QObject **obj, const char *name,
+ Error **errp);
/* May be NULL */
void (*optional)(Visitor *v, bool *present, const char *name,
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 00ba104..cfc19a6 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -58,6 +58,7 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp);
void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
+void visit_type_any(Visitor *v, QObject **obj, const char *name, Error **errp);
bool visit_start_union(Visitor *v, bool data_present, Error **errp);
void visit_end_union(Visitor *v, bool data_present, Error **errp);
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index d7f92c5..737deab 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -151,6 +151,14 @@ static void qapi_dealloc_type_number(Visitor *v, double *obj, const char *name,
{
}
+static void qapi_dealloc_type_anything(Visitor *v, QObject **obj,
+ const char *name, Error **errp)
+{
+ if (obj) {
+ qobject_decref(*obj);
+ }
+}
+
static void qapi_dealloc_type_size(Visitor *v, uint64_t *obj, const char *name,
Error **errp)
{
@@ -216,6 +224,7 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
v->visitor.type_bool = qapi_dealloc_type_bool;
v->visitor.type_str = qapi_dealloc_type_str;
v->visitor.type_number = qapi_dealloc_type_number;
+ v->visitor.type_any = qapi_dealloc_type_anything;
v->visitor.type_size = qapi_dealloc_type_size;
v->visitor.start_union = qapi_dealloc_start_union;
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 5a7c900..59ed506 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -260,6 +260,12 @@ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
v->type_number(v, obj, name, errp);
}
+void visit_type_any(Visitor *v, QObject **obj, const char *name,
+ Error **errp)
+{
+ v->type_any(v, obj, name, errp);
+}
+
void output_type_enum(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name,
Error **errp)
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index e97b8a4..5dd9ed5 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -286,6 +286,16 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
}
}
+static void qmp_input_type_any(Visitor *v, QObject **obj, const char *name,
+ Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name, true);
+
+ qobject_incref(qobj);
+ *obj = qobj;
+}
+
static void qmp_input_optional(Visitor *v, bool *present, const char *name,
Error **errp)
{
@@ -329,6 +339,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
v->visitor.type_bool = qmp_input_type_bool;
v->visitor.type_str = qmp_input_type_str;
v->visitor.type_number = qmp_input_type_number;
+ v->visitor.type_any = qmp_input_type_any;
v->visitor.optional = qmp_input_optional;
v->visitor.get_next_type = qmp_input_get_next_type;
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index 8dce087..29899ac 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -190,6 +190,14 @@ static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
qmp_output_add(qov, name, qfloat_from_double(*obj));
}
+static void qmp_output_type_any(Visitor *v, QObject **obj, const char *name,
+ Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ qobject_incref(*obj);
+ qmp_output_add_obj(qov, name, *obj);
+}
+
QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
{
QObject *obj = qmp_output_first(qov);
@@ -237,6 +245,7 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
v->visitor.type_bool = qmp_output_type_bool;
v->visitor.type_str = qmp_output_type_str;
v->visitor.type_number = qmp_output_type_number;
+ v->visitor.type_any = qmp_output_type_any;
QTAILQ_INIT(&v->stack);
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index d1fee20..b292682 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -327,6 +327,7 @@ fdef.write(mcgen('''
fdecl.write(mcgen('''
#include <stdbool.h>
#include <stdint.h>
+#include "qapi/qmp/qobject.h"
'''))
schema = QAPISchema(input_file)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8ad0273..0e8323e 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -33,6 +33,7 @@ builtin_types = {
'uint32': 'QTYPE_QINT',
'uint64': 'QTYPE_QINT',
'size': 'QTYPE_QINT',
+ 'any': None, # any qtype_code possible, actually
}
# Whitelist of commands allowed to return a non-dictionary
@@ -1101,8 +1102,7 @@ class QAPISchema(object):
def _def_builtin_type(self, name, json_type, c_type, c_null):
self._def_entity(QAPISchemaBuiltinType(name, json_type,
c_type, c_null))
- if name != '**':
- self._make_array_type(name) # TODO really needed?
+ self._make_array_type(name) # TODO really needed?
def _def_predefineds(self):
for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
@@ -1118,8 +1118,9 @@ class QAPISchema(object):
('uint64', 'int', 'uint64_t', '0'),
('size', 'int', 'uint64_t', '0'),
('bool', 'boolean', 'bool', 'false'),
- ('**', 'value', None, None)]:
+ ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
self._def_builtin_type(*t)
+ self._entity_dict['**'] = self.lookup_type('any') # TODO drop this alias
def _make_implicit_enum_type(self, name, values):
name = name + 'Kind'
@@ -1269,6 +1270,8 @@ class QAPISchema(object):
def visit(self, visitor):
visitor.visit_begin(self)
for name in sorted(self._entity_dict.keys()):
+ if self._entity_dict[name].name != name:
+ continue # ignore alias TODO drop alias and remove
self._entity_dict[name].visit(visitor)
visitor.visit_end()
diff --git a/tests/Makefile b/tests/Makefile
index 7c6025a..10e55b3 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -239,6 +239,7 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
args-array-empty.json args-array-unknown.json args-int.json \
args-unknown.json args-member-unknown.json args-member-array.json \
args-member-array-bad.json args-alternate.json args-union.json \
+ args-any.json \
returns-array-bad.json returns-int.json returns-dict.json \
returns-unknown.json returns-alternate.json returns-whitelist.json \
missing-colon.json missing-comma-list.json missing-comma-object.json \
@@ -255,7 +256,7 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
flat-union-invalid-branch-key.json flat-union-reverse-define.json \
flat-union-string-discriminator.json union-base-no-discriminator.json \
flat-union-bad-discriminator.json flat-union-bad-base.json \
- flat-union-base-star.json \
+ flat-union-base-any.json \
flat-union-array-branch.json flat-union-int-branch.json \
flat-union-base-union.json flat-union-branch-clash.json \
alternate-nested.json alternate-unknown.json alternate-clash.json \
diff --git a/tests/qapi-schema/args-any.err b/tests/qapi-schema/args-any.err
new file mode 100644
index 0000000..bf9b5e0
--- /dev/null
+++ b/tests/qapi-schema/args-any.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any'
diff --git a/tests/qapi-schema/flat-union-base-star.exit b/tests/qapi-schema/args-any.exit
similarity index 100%
rename from tests/qapi-schema/flat-union-base-star.exit
rename to tests/qapi-schema/args-any.exit
diff --git a/tests/qapi-schema/args-any.json b/tests/qapi-schema/args-any.json
new file mode 100644
index 0000000..58fe5e4
--- /dev/null
+++ b/tests/qapi-schema/args-any.json
@@ -0,0 +1,2 @@
+# we do not allow an 'any' argument
+{ 'command': 'oops', 'data': 'any' }
diff --git a/tests/qapi-schema/flat-union-base-star.out b/tests/qapi-schema/args-any.out
similarity index 100%
rename from tests/qapi-schema/flat-union-base-star.out
rename to tests/qapi-schema/args-any.out
diff --git a/tests/qapi-schema/flat-union-base-any.err b/tests/qapi-schema/flat-union-base-any.err
new file mode 100644
index 0000000..ad4d629
--- /dev/null
+++ b/tests/qapi-schema/flat-union-base-any.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-base-any.json:8: Base 'any' is not a valid struct
diff --git a/tests/qapi-schema/flat-union-base-any.exit b/tests/qapi-schema/flat-union-base-any.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/flat-union-base-any.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-base-star.json b/tests/qapi-schema/flat-union-base-any.json
similarity index 95%
rename from tests/qapi-schema/flat-union-base-star.json
rename to tests/qapi-schema/flat-union-base-any.json
index 5099439..fe66b71 100644
--- a/tests/qapi-schema/flat-union-base-star.json
+++ b/tests/qapi-schema/flat-union-base-any.json
@@ -6,7 +6,7 @@
{ 'struct': 'TestTypeB',
'data': { 'integer': 'int' } }
{ 'union': 'TestUnion',
- 'base': '**',
+ 'base': 'any',
'discriminator': 'enum1',
'data': { 'value1': 'TestTypeA',
'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-base-any.out b/tests/qapi-schema/flat-union-base-any.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/flat-union-base-star.err b/tests/qapi-schema/flat-union-base-star.err
deleted file mode 100644
index b7748f0..0000000
--- a/tests/qapi-schema/flat-union-base-star.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/flat-union-base-star.json:8: Base '**' is not a valid struct
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index d488157..6897a6e 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -78,7 +78,8 @@
'number': ['number'],
'boolean': ['bool'],
'string': ['str'],
- 'sizes': ['size'] } }
+ 'sizes': ['size'],
+ 'any': ['any'] } }
# testing commands
{ 'command': 'user_def_cmd', 'data': {} }
@@ -88,6 +89,8 @@
'returns': 'UserDefTwo' }
{ 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' },
'returns': 'int' }
+# note: command name 'guest-sync' chosen to avoid "cannot use built-in" error
+{ 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
# For testing integer range flattening in opts-visitor. The following schema
# corresponds to the option format:
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 45c39bc..231c3bf 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -12,8 +12,12 @@ object :obj-__org.qemu_x-command-arg
member b: __org.qemu_x-StructList optional=False
member c: __org.qemu_x-Union2 optional=False
member d: __org.qemu_x-Alt optional=False
+object :obj-anyList-wrapper
+ member data: anyList optional=False
object :obj-boolList-wrapper
member data: boolList optional=False
+object :obj-guest-sync-arg
+ member arg: any optional=False
object :obj-int16List-wrapper
member data: int16List optional=False
object :obj-int32List-wrapper
@@ -101,7 +105,8 @@ object UserDefNativeListUnion
case boolean: :obj-boolList-wrapper
case string: :obj-strList-wrapper
case sizes: :obj-sizeList-wrapper
-enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes'] prefix=None
+ case any: :obj-anyList-wrapper
+enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any'] prefix=None
object UserDefOne
base UserDefZero
member string: str optional=False
@@ -150,6 +155,8 @@ object __org.qemu_x-Union2
case __org.qemu_x-value: __org.qemu_x-Struct2
command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
gen=True success_response=True
+command guest-sync :obj-guest-sync-arg -> any
+ gen=True success_response=True
command user_def_cmd None -> None
gen=True success_response=True
command user_def_cmd1 :obj-user_def_cmd1-arg -> None
diff --git a/tests/qapi-schema/type-bypass.out b/tests/qapi-schema/type-bypass.out
index 0070d4b..db2a4e6 100644
--- a/tests/qapi-schema/type-bypass.out
+++ b/tests/qapi-schema/type-bypass.out
@@ -1,4 +1,4 @@
object :obj-unsafe-arg
- member arg: ** optional=False
-command unsafe :obj-unsafe-arg -> **
+ member arg: any optional=False
+command unsafe :obj-unsafe-arg -> any
gen=False success_response=True
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 9918f23..8d5249e 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -51,6 +51,11 @@ int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp)
return a + (has_b ? b : 0);
}
+QObject *qmp_guest_sync(QObject *arg, Error **errp)
+{
+ return arg;
+}
+
__org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
__org_qemu_x_StructList *b,
__org_qemu_x_Union2 *c,
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index 508c11a..61715b3 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -298,6 +298,49 @@ static void test_visitor_in_list(TestInputVisitorData *data,
qapi_free_UserDefOneList(head);
}
+static void test_visitor_in_any(TestInputVisitorData *data,
+ const void *unused)
+{
+ QObject *res = NULL;
+ Error *err = NULL;
+ Visitor *v;
+ QInt *qint;
+ QBool *qbool;
+ QString *qstring;
+ QDict *qdict;
+ QObject *qobj;
+
+ v = visitor_input_test_init(data, "-42");
+ visit_type_any(v, &res, NULL, &err);
+ g_assert(!err);
+ qint = qobject_to_qint(res);
+ g_assert(qint);
+ g_assert_cmpint(qint_get_int(qint), ==, -42);
+ qobject_decref(res);
+
+ v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
+ visit_type_any(v, &res, NULL, &err);
+ g_assert(!err);
+ qdict = qobject_to_qdict(res);
+ g_assert(qdict && qdict_size(qdict) == 3);
+ qobj = qdict_get(qdict, "integer");
+ g_assert(qobj);
+ qint = qobject_to_qint(qobj);
+ g_assert(qint);
+ g_assert_cmpint(qint_get_int(qint), ==, -42);
+ qobj = qdict_get(qdict, "boolean");
+ g_assert(qobj);
+ qbool = qobject_to_qbool(qobj);
+ g_assert(qbool);
+ g_assert(qbool_get_bool(qbool) == true);
+ qobj = qdict_get(qdict, "string");
+ g_assert(qobj);
+ qstring = qobject_to_qstring(qobj);
+ g_assert(qstring);
+ g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
+ qobject_decref(res);
+}
+
static void test_visitor_in_union_flat(TestInputVisitorData *data,
const void *unused)
{
@@ -669,6 +712,8 @@ int main(int argc, char **argv)
&in_visitor_data, test_visitor_in_struct_nested);
input_visitor_test_add("/visitor/input/list",
&in_visitor_data, test_visitor_in_list);
+ input_visitor_test_add("/visitor/input/any",
+ &in_visitor_data, test_visitor_in_any);
input_visitor_test_add("/visitor/input/union-flat",
&in_visitor_data, test_visitor_in_union_flat);
input_visitor_test_add("/visitor/input/alternate",
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index a48ae72..c84002e 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -428,6 +428,57 @@ static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
qapi_free_UserDefTwoList(head);
}
+static void test_visitor_out_any(TestOutputVisitorData *data,
+ const void *unused)
+{
+ QObject *qobj;
+ Error *err = NULL;
+ QInt *qint;
+ QBool *qbool;
+ QString *qstring;
+ QDict *qdict;
+ QObject *obj;
+
+ qobj = QOBJECT(qint_from_int(-42));
+ visit_type_any(data->ov, &qobj, NULL, &err);
+ g_assert(!err);
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QINT);
+ g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, -42);
+ qobject_decref(obj);
+ qobject_decref(qobj);
+
+ qdict = qdict_new();
+ qdict_put(qdict, "integer", qint_from_int(-42));
+ qdict_put(qdict, "boolean", qbool_from_bool(true));
+ qdict_put(qdict, "string", qstring_from_str("foo"));
+ qobj = QOBJECT(qdict);
+ visit_type_any(data->ov, &qobj, NULL, &err);
+ g_assert(!err);
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ qdict = qobject_to_qdict(obj);
+ g_assert(qdict);
+ qobj = qdict_get(qdict, "integer");
+ g_assert(qobj);
+ qint = qobject_to_qint(qobj);
+ g_assert(qint);
+ g_assert_cmpint(qint_get_int(qint), ==, -42);
+ qobj = qdict_get(qdict, "boolean");
+ g_assert(qobj);
+ qbool = qobject_to_qbool(qobj);
+ g_assert(qbool);
+ g_assert(qbool_get_bool(qbool) == true);
+ qobj = qdict_get(qdict, "string");
+ g_assert(qobj);
+ qstring = qobject_to_qstring(qobj);
+ g_assert(qstring);
+ g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
+ qobject_decref(obj);
+ qobject_decref(qobj);
+}
+
static void test_visitor_out_union_flat(TestOutputVisitorData *data,
const void *unused)
{
@@ -833,6 +884,8 @@ int main(int argc, char **argv)
&out_visitor_data, test_visitor_out_struct_errors);
output_visitor_test_add("/visitor/output/list",
&out_visitor_data, test_visitor_out_list);
+ output_visitor_test_add("/visitor/output/any",
+ &out_visitor_data, test_visitor_out_any);
output_visitor_test_add("/visitor/output/list-qapi-free",
&out_visitor_data, test_visitor_out_list_qapi_free);
output_visitor_test_add("/visitor/output/union-flat",
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 22/26] qom: Don't use 'gen': false for qom-get, qom-set, object-add
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (20 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 21/26] qapi: Introduce a first class 'any' type Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 23/26] qapi-schema: Fix up misleading specification of netdev_add Markus Armbruster
` (5 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
With the previous commit, the generated marshalers just work, and save
us a bit of handwritten code.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
include/monitor/monitor.h | 3 ---
qapi-schema.json | 9 +++------
qmp-commands.hx | 6 +++---
qmp.c | 21 +++++++--------------
scripts/qapi.py | 1 +
5 files changed, 14 insertions(+), 26 deletions(-)
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 9aff47e..bc6cb6d 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -42,9 +42,6 @@ void monitor_read_command(Monitor *mon, int show_prompt);
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
void *opaque);
-void qmp_qom_set(QDict *qdict, QObject **ret, Error **errp);
-void qmp_qom_get(QDict *qdict, QObject **ret, Error **errp);
-void qmp_object_add(QDict *qdict, QObject **ret, Error **errp);
void object_add(const char *type, const char *id, const QDict *qdict,
Visitor *v, Error **errp);
diff --git a/qapi-schema.json b/qapi-schema.json
index 2bada60..756ed9e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1698,8 +1698,7 @@
##
{ 'command': 'qom-get',
'data': { 'path': 'str', 'property': 'str' },
- 'returns': '**',
- 'gen': false }
+ 'returns': 'any' }
##
# @qom-set:
@@ -1716,8 +1715,7 @@
# Since: 1.2
##
{ 'command': 'qom-set',
- 'data': { 'path': 'str', 'property': 'str', 'value': '**' },
- 'gen': false }
+ 'data': { 'path': 'str', 'property': 'str', 'value': 'any' } }
##
# @set_password:
@@ -2127,8 +2125,7 @@
# Since: 2.0
##
{ 'command': 'object-add',
- 'data': {'qom-type': 'str', 'id': 'str', '*props': '**'},
- 'gen': false }
+ 'data': {'qom-type': 'str', 'id': 'str', '*props': 'any'} }
##
# @object-del:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4640a3d..7c74e20 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -953,7 +953,7 @@ EQMP
{
.name = "object-add",
.args_type = "qom-type:s,id:s,props:q?",
- .mhandler.cmd_new = qmp_object_add,
+ .mhandler.cmd_new = qmp_marshal_object_add,
},
SQMP
@@ -3575,13 +3575,13 @@ EQMP
{
.name = "qom-set",
.args_type = "path:s,property:s,value:q",
- .mhandler.cmd_new = qmp_qom_set,
+ .mhandler.cmd_new = qmp_marshal_qom_set,
},
{
.name = "qom-get",
.args_type = "path:s,property:s",
- .mhandler.cmd_new = qmp_qom_get,
+ .mhandler.cmd_new = qmp_marshal_qom_get,
},
{
diff --git a/qmp.c b/qmp.c
index 3feae9f..057a7cb 100644
--- a/qmp.c
+++ b/qmp.c
@@ -234,12 +234,9 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
return props;
}
-/* FIXME: teach qapi about how to pass through Visitors */
-void qmp_qom_set(QDict *qdict, QObject **ret, Error **errp)
+void qmp_qom_set(const char *path, const char *property, QObject *value,
+ Error **errp)
{
- const char *path = qdict_get_str(qdict, "path");
- const char *property = qdict_get_str(qdict, "property");
- QObject *value = qdict_get(qdict, "value");
Object *obj;
obj = object_resolve_path(path, NULL);
@@ -252,20 +249,18 @@ void qmp_qom_set(QDict *qdict, QObject **ret, Error **errp)
object_property_set_qobject(obj, value, property, errp);
}
-void qmp_qom_get(QDict *qdict, QObject **ret, Error **errp)
+QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
{
- const char *path = qdict_get_str(qdict, "path");
- const char *property = qdict_get_str(qdict, "property");
Object *obj;
obj = object_resolve_path(path, NULL);
if (!obj) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Device '%s' not found", path);
- return;
+ return NULL;
}
- *ret = object_property_get_qobject(obj, property, errp);
+ return object_property_get_qobject(obj, property, errp);
}
void qmp_set_password(const char *protocol, const char *password,
@@ -661,11 +656,9 @@ out:
object_unref(obj);
}
-void qmp_object_add(QDict *qdict, QObject **ret, Error **errp)
+void qmp_object_add(const char *type, const char *id,
+ bool has_props, QObject *props, Error **errp)
{
- const char *type = qdict_get_str(qdict, "qom-type");
- const char *id = qdict_get_str(qdict, "id");
- QObject *props = qdict_get(qdict, "props");
const QDict *pdict = NULL;
QmpInputVisitor *qiv;
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0e8323e..6423946 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -40,6 +40,7 @@ builtin_types = {
returns_whitelist = [
# From QMP:
'human-monitor-command',
+ 'qom-get',
'query-migrate-cache-size',
'query-tpm-models',
'query-tpm-types',
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 23/26] qapi-schema: Fix up misleading specification of netdev_add
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (21 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 22/26] qom: Don't use 'gen': false for qom-get, qom-set, object-add Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 24/26] qapi: Pseudo-type '**' is now unused, drop it Markus Armbruster
` (4 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
It doesn't take a 'props' argument, let alone one in the format
"NAME=VALUE,..."
The bogus arguments specification doesn't matter due to 'gen': false.
Clean it up to be incomplete rather than wrong, and document the
incompleteness.
While there, improve netdev_add usage example in the manual: add a
device option to show how it's done.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
docs/qapi-code-gen.txt | 2 +-
qapi-schema.json | 13 +++++++------
qmp-commands.hx | 4 +++-
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 70fdae7..4e331a0 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -471,7 +471,7 @@ try to avoid adding new commands that rely on this, and instead use
type-safe unions. For an example of bypass usage:
{ 'command': 'netdev_add',
- 'data': {'type': 'str', 'id': 'str', '*props': '**'},
+ 'data': {'type': 'str', 'id': 'str'},
'gen': false }
Normally, the QAPI schema is used to describe synchronous exchanges,
diff --git a/qapi-schema.json b/qapi-schema.json
index 756ed9e..3ff9fec 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2079,11 +2079,12 @@
#
# @id: the name of the new network backend
#
-# @props: #optional a list of properties to be passed to the backend in
-# the format 'name=value', like 'ifname=tap0,script=no'
+# Additional arguments depend on the type.
#
-# Notes: The semantics of @props is not well defined. Future commands will be
-# introduced that provide stronger typing for backend creation.
+# TODO This command effectively bypasses QAPI completely due to its
+# "additional arguments" business. It shouldn't have been added to
+# the schema in this form. It should be qapified properly, or
+# replaced by a properly qapified command.
#
# Since: 0.14.0
#
@@ -2091,8 +2092,8 @@
# If @type is not a valid network backend, DeviceNotFound
##
{ 'command': 'netdev_add',
- 'data': {'type': 'str', 'id': 'str', '*props': '**'},
- 'gen': false }
+ 'data': {'type': 'str', 'id': 'str'},
+ 'gen': false } # so we can get the additional arguments
##
# @netdev_del:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7c74e20..5a54406 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -917,7 +917,9 @@ Arguments:
Example:
--> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } }
+-> { "execute": "netdev_add",
+ "arguments": { "type": "user", "id": "netdev1",
+ "dnssearch": "example.org" } }
<- { "return": {} }
Note: The supported device options are the same ones supported by the '-netdev'
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 24/26] qapi: Pseudo-type '**' is now unused, drop it
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (22 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 23/26] qapi-schema: Fix up misleading specification of netdev_add Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 25/26] qapi: New QMP command query-qmp-schema for QMP introspection Markus Armbruster
` (3 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
'gen': false needs to stay for now, because netdev_add is still using
it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
---
docs/qapi-code-gen.txt | 18 ++++++------------
scripts/qapi.py | 20 ++++----------------
tests/Makefile | 2 +-
tests/qapi-schema/type-bypass-no-gen.err | 1 -
tests/qapi-schema/type-bypass-no-gen.exit | 1 -
tests/qapi-schema/type-bypass-no-gen.json | 2 --
tests/qapi-schema/type-bypass-no-gen.out | 0
tests/qapi-schema/type-bypass.err | 0
tests/qapi-schema/type-bypass.exit | 1 -
tests/qapi-schema/type-bypass.json | 2 --
tests/qapi-schema/type-bypass.out | 4 ----
11 files changed, 11 insertions(+), 40 deletions(-)
delete mode 100644 tests/qapi-schema/type-bypass-no-gen.err
delete mode 100644 tests/qapi-schema/type-bypass-no-gen.exit
delete mode 100644 tests/qapi-schema/type-bypass-no-gen.json
delete mode 100644 tests/qapi-schema/type-bypass-no-gen.out
delete mode 100644 tests/qapi-schema/type-bypass.err
delete mode 100644 tests/qapi-schema/type-bypass.exit
delete mode 100644 tests/qapi-schema/type-bypass.json
delete mode 100644 tests/qapi-schema/type-bypass.out
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 4e331a0..b917962 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -111,10 +111,7 @@ and field names within a type, should be all lower case with words
separated by a hyphen. However, some existing older commands and
complex types use underscore; when extending such expressions,
consistency is preferred over blindly avoiding underscore. Event
-names should be ALL_CAPS with words separated by underscore. The
-special string '**' appears for some commands that manually perform
-their own type checking rather than relying on the type-safe code
-produced by the qapi code generators.
+names should be ALL_CAPS with words separated by underscore.
Any name (command, event, type, field, or enum value) beginning with
"x-" is marked experimental, and may be withdrawn or changed
@@ -461,14 +458,11 @@ which would validate this Client JSON Protocol transaction:
<= { "return": [ { "value": "one" }, { } ] }
In rare cases, QAPI cannot express a type-safe representation of a
-corresponding Client JSON Protocol command. In these cases, if the
-command expression includes the key 'gen' with boolean value false,
-then the 'data' or 'returns' member that intends to bypass generated
-type-safety and do its own manual validation should use an inline
-dictionary definition, with a value of '**' rather than a valid type
-name for the keys that the generated code will not validate. Please
-try to avoid adding new commands that rely on this, and instead use
-type-safe unions. For an example of bypass usage:
+corresponding Client JSON Protocol command. You then have to suppress
+generation of a marshalling function by including a key 'gen' with
+boolean value false, and instead write your own function. Please try
+to avoid adding new commands that rely on this, and instead use
+type-safe unions. For an example of this usage:
{ 'command': 'netdev_add',
'data': {'type': 'str', 'id': 'str'},
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6423946..6a94acc 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -428,15 +428,12 @@ def is_enum(name):
def check_type(expr_info, source, value, allow_array = False,
allow_dict = False, allow_optional = False,
- allow_star = False, allow_metas = []):
+ allow_metas = []):
global all_names
if value is None:
return
- if allow_star and value == '**':
- return
-
# Check if array type for value is okay
if isinstance(value, list):
if not allow_array:
@@ -450,10 +447,6 @@ def check_type(expr_info, source, value, allow_array = False,
# Check if type name for value is okay
if isinstance(value, str):
- if value == '**':
- raise QAPIExprError(expr_info,
- "%s uses '**' but did not request 'gen':false"
- % source)
if not value in all_names:
raise QAPIExprError(expr_info,
"%s uses unknown type '%s'"
@@ -479,7 +472,7 @@ def check_type(expr_info, source, value, allow_array = False,
# Todo: allow dictionaries to represent default values of
# an optional argument.
check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
- allow_array=True, allow_star=allow_star,
+ allow_array=True,
allow_metas=['built-in', 'union', 'alternate', 'struct',
'enum'])
@@ -499,18 +492,16 @@ def check_member_clash(expr_info, base_name, data, source = ""):
def check_command(expr, expr_info):
name = expr['command']
- allow_star = expr.has_key('gen')
check_type(expr_info, "'data' for command '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
- allow_metas=['struct'], allow_star=allow_star)
+ allow_metas=['struct'])
returns_meta = ['union', 'struct']
if name in returns_whitelist:
returns_meta += ['built-in', 'alternate', 'enum']
check_type(expr_info, "'returns' for command '%s'" % name,
expr.get('returns'), allow_array=True,
- allow_optional=True, allow_metas=returns_meta,
- allow_star=allow_star)
+ allow_optional=True, allow_metas=returns_meta)
def check_event(expr, expr_info):
global events
@@ -1121,7 +1112,6 @@ class QAPISchema(object):
('bool', 'boolean', 'bool', 'false'),
('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
self._def_builtin_type(*t)
- self._entity_dict['**'] = self.lookup_type('any') # TODO drop this alias
def _make_implicit_enum_type(self, name, values):
name = name + 'Kind'
@@ -1271,8 +1261,6 @@ class QAPISchema(object):
def visit(self, visitor):
visitor.visit_begin(self)
for name in sorted(self._entity_dict.keys()):
- if self._entity_dict[name].name != name:
- continue # ignore alias TODO drop alias and remove
self._entity_dict[name].visit(visitor)
visitor.visit_end()
diff --git a/tests/Makefile b/tests/Makefile
index 10e55b3..aadfb38 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -234,7 +234,7 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
bad-type-dict.json double-data.json unknown-expr-key.json \
redefined-type.json redefined-command.json redefined-builtin.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-bad-gen.json \
args-invalid.json \
args-array-empty.json args-array-unknown.json args-int.json \
args-unknown.json args-member-unknown.json args-member-array.json \
diff --git a/tests/qapi-schema/type-bypass-no-gen.err b/tests/qapi-schema/type-bypass-no-gen.err
deleted file mode 100644
index 20cef0a..0000000
--- a/tests/qapi-schema/type-bypass-no-gen.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/type-bypass-no-gen.json:2: Member 'arg' of 'data' for command 'unsafe' uses '**' but did not request 'gen':false
diff --git a/tests/qapi-schema/type-bypass-no-gen.exit b/tests/qapi-schema/type-bypass-no-gen.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/type-bypass-no-gen.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/type-bypass-no-gen.json b/tests/qapi-schema/type-bypass-no-gen.json
deleted file mode 100644
index 4feae37..0000000
--- a/tests/qapi-schema/type-bypass-no-gen.json
+++ /dev/null
@@ -1,2 +0,0 @@
-# type bypass only works with 'gen':false
-{ 'command': 'unsafe', 'data': { 'arg': '**' }, 'returns': '**' }
diff --git a/tests/qapi-schema/type-bypass-no-gen.out b/tests/qapi-schema/type-bypass-no-gen.out
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/type-bypass.err b/tests/qapi-schema/type-bypass.err
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/type-bypass.exit b/tests/qapi-schema/type-bypass.exit
deleted file mode 100644
index 573541a..0000000
--- a/tests/qapi-schema/type-bypass.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/type-bypass.json b/tests/qapi-schema/type-bypass.json
deleted file mode 100644
index 48b2137..0000000
--- a/tests/qapi-schema/type-bypass.json
+++ /dev/null
@@ -1,2 +0,0 @@
-# Use of 'gen':false allows bypassing type system
-{ 'command': 'unsafe', 'data': { 'arg': '**' }, 'returns': '**', 'gen': false }
diff --git a/tests/qapi-schema/type-bypass.out b/tests/qapi-schema/type-bypass.out
deleted file mode 100644
index db2a4e6..0000000
--- a/tests/qapi-schema/type-bypass.out
+++ /dev/null
@@ -1,4 +0,0 @@
-object :obj-unsafe-arg
- member arg: any optional=False
-command unsafe :obj-unsafe-arg -> any
- gen=False success_response=True
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 25/26] qapi: New QMP command query-qmp-schema for QMP introspection
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (23 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 24/26] qapi: Pseudo-type '**' is now unused, drop it Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 20:08 ` Eric Blake
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 26/26] qapi-introspect: Hide type names Markus Armbruster
` (2 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
qapi/introspect.json defines the introspection schema. It's designed
for QMP introspection, but should do for similar uses, such as QGA.
The introspection schema does not reflect all the rules and
restrictions that apply to QAPI schemata. A valid QAPI schema has an
introspection value conforming to the introspection schema, but the
converse is not true.
Introspection lowers away a number of schema details, and makes
implicit things explicit:
* The built-in types are declared with their JSON type.
All integer types are mapped to 'int', because how many bits we use
internally is an implementation detail. It could be pressed into
external interface service as very approximate range information,
but that's a bad idea. If we need range information, we better do
it properly.
* Implicit type definitions are made explicit, and given
auto-generated names:
- Array types, named by appending "List" to the name of their
element type, like in generated C.
- The enumeration types implicitly defined by simple union types,
named by appending "Kind" to the name of their simple union type,
like in generated C.
- Types that don't occur in generated C. Their names start with ':'
so they don't clash with the user's names.
* All type references are by name.
* The struct and union types are generalized into an object type.
* Base types are flattened.
* Commands take a single argument and return a single result.
Dictionary argument or list result is an implicit type definition.
The empty object type is used when a command takes no arguments or
produces no results.
The argument is always of object type, but the introspection schema
doesn't reflect that.
The 'gen': false directive is omitted as implementation detail.
The 'success-response' directive is omitted as well for now, even
though it's not an implementation detail, because it's not used by
QMP.
* Events carry a single data value.
Implicit type definition and empty object type use, just like for
commands.
The value is of object type, but the introspection schema doesn't
reflect that.
* Types not used by commands or events are omitted.
Indirect use counts as use.
* Optional members have a default, which can only be null right now
Instead of a mandatory "optional" flag, we have an optional default.
No default means mandatory, default null means optional without
default value. Non-null is available for optional with default
(possible future extension).
* Clients should *not* look up types by name, because type names are
not ABI. Look up the command or event you're interested in, then
follow the references.
TODO Should we hide the type names to eliminate the temptation?
New generator scripts/qapi-introspect.py computes an introspection
value for its input, and generates a C variable holding it.
It can generate awfully long lines. Marked TODO.
A new test-qmp-input-visitor test case feeds its result for both
tests/qapi-schema/qapi-schema-test.json and qapi-schema.json to a
QmpInputVisitor to verify it actually conforms to the schema.
New QMP command query-qmp-schema takes its return value from that
variable. Its reply is some 85KiBytes for me right now.
If this turns out to be too much, we have a couple of options:
* We can use shorter names in the JSON. Not the QMP style.
* Optionally return the sub-schema for commands and events given as
arguments.
Right now qmp_query_schema() sends the string literal computed by
qmp-introspect.py. To compute sub-schema at run time, we'd have to
duplicate parts of qapi-introspect.py in C. Unattractive.
* Let clients cache the output of query-qmp-schema.
It changes only on QEMU upgrades, i.e. rarely. Provide a command
query-qmp-schema-hash. Clients can have a cache indexed by hash,
and re-query the schema only when they don't have it cached. Even
simpler: put the hash in the QMP greeting.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
.gitignore | 1 +
Makefile | 9 +-
Makefile.objs | 4 +-
docs/qapi-code-gen.txt | 237 +++++++++++++++++++-
monitor.c | 16 ++
qapi-schema.json | 3 +
qapi/introspect.json | 277 ++++++++++++++++++++++++
qmp-commands.hx | 17 ++
scripts/qapi-introspect.py | 184 ++++++++++++++++
scripts/qapi.py | 13 +-
tests/.gitignore | 1 +
tests/Makefile | 10 +-
tests/qapi-schema/alternate-good.out | 1 +
tests/qapi-schema/args-member-array.out | 1 +
| 1 +
tests/qapi-schema/empty.out | 1 +
tests/qapi-schema/enum-empty.out | 1 +
tests/qapi-schema/event-case.out | 1 +
tests/qapi-schema/flat-union-reverse-define.out | 1 +
tests/qapi-schema/ident-with-escape.out | 1 +
tests/qapi-schema/include-relpath.out | 1 +
tests/qapi-schema/include-repetition.out | 1 +
tests/qapi-schema/include-simple.out | 1 +
tests/qapi-schema/indented-expr.out | 1 +
tests/qapi-schema/qapi-schema-test.out | 1 +
tests/qapi-schema/returns-int.out | 1 +
tests/test-qmp-input-strict.c | 55 +++++
27 files changed, 830 insertions(+), 11 deletions(-)
create mode 100644 qapi/introspect.json
create mode 100644 scripts/qapi-introspect.py
diff --git a/.gitignore b/.gitignore
index cb4b8ec..ce02e3c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@
/qapi-visit.[ch]
/qapi-event.[ch]
/qmp-commands.h
+/qmp-introspect.[ch]
/qmp-marshal.c
/qemu-doc.html
/qemu-tech.html
diff --git a/Makefile b/Makefile
index 36943da..9e0f3d0 100644
--- a/Makefile
+++ b/Makefile
@@ -52,6 +52,8 @@ endif
GENERATED_HEADERS = config-host.h qemu-options.def
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h qapi-event.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
+GENERATED_HEADERS += qmp-introspect.h
+GENERATED_SOURCES += qmp-introspect.c
GENERATED_HEADERS += trace/generated-events.h
GENERATED_SOURCES += trace/generated-events.c
@@ -269,7 +271,7 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
$(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
- $(SRC_PATH)/qapi/event.json
+ $(SRC_PATH)/qapi/event.json $(SRC_PATH)/qapi/introspect.json
qapi-types.c qapi-types.h :\
$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
@@ -291,6 +293,11 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
$(gen-out-type) -o "." -m $<, \
" GEN $@")
+qmp-introspect.h qmp-introspect.c :\
+$(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
+ $(gen-out-type) -o "." $<, \
+ " GEN $@")
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
diff --git a/Makefile.objs b/Makefile.objs
index 3df2efc..ce87778 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -1,7 +1,8 @@
#######################################################################
# Common libraries for tools and emulators
stub-obj-y = stubs/
-util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
+util-obj-y = util/ qobject/ qapi/
+util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
@@ -92,6 +93,7 @@ common-obj-$(CONFIG_FDT) += device_tree.o
# qapi
common-obj-y += qmp-marshal.o
+common-obj-y += qmp-introspect.o
common-obj-y += qmp.o hmp.o
endif
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index b917962..f321d4b 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -502,13 +502,206 @@ Resulting in this JSON object:
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+== Client JSON Protocol introspection ==
+
+Clients of a Client JSON Protocol commonly need to figure out what
+exactly the server (QEMU) supports.
+
+For this purpose, QMP provides introspection via command
+query-qmp-schema. QGA currently doesn't support introspection.
+
+query-qmp-schema returns a JSON array of SchemaInfo objects. These
+objects together describe the wire ABI, as defined in the QAPI schema.
+
+However, the SchemaInfo can't reflect all the rules and restrictions
+that apply to QMP. It's interface introspection (figuring out what's
+there), not interface specification. The specification is in the QAPI
+schema. To understand how QMP is to be used, you need to study the
+QAPI schema.
+
+Like any other command, query-qmp-schema is itself defined in the QAPI
+schema, along with the SchemaInfo type. This text attempts to give an
+overview how things work. For details you need to consult the QAPI
+schema.
+
+SchemaInfo objects have common members "name" and "meta-type", and
+additional variant members depending on the value of meta-type.
+
+Each SchemaInfo object describes a wire ABI entity of a certain
+meta-type: a command, event or one of several kinds of type.
+
+SchemaInfo for entities defined in the QAPI schema have the same name
+as in the schema. This is the case for all commands and events, and
+most types.
+
+Command and event names are part of the wire ABI, but type names are
+not. Therefore, looking up a type by its name in the QAPI schema is
+wrong. Look up the command or event, then follow references by name.
+
+QAPI schema definitions not reachable that way are omitted.
+
+The SchemaInfo for a command has meta-type "command", and variant
+members "arg-type" and "ret-type". On the wire, the "arguments"
+member of a client's "execute" command must conform to the object type
+named by "arg-type". The "return" member that the server passes in a
+success response conforms to the type named by "ret-type".
+
+If the command takes no arguments, "arg-type" names an object type
+without members. Likewise, if the command returns nothing, "ret-type"
+names an object type without members.
+
+Example: the SchemaInfo for command query-qmp-schema
+
+ { "name": "query-qmp-schema", "meta-type": "command",
+ "arg-type": ":empty", "ret-type": "SchemaInfoList" }
+
+ Type ":empty" is an object type without members, and type
+ "SchemaInfoList" is the array of SchemaInfo type.
+
+The SchemaInfo for an event has meta-type "event", and variant member
+"arg-type". On the wire, a "data" member that the server passes in an
+event conforms to the object type named by "arg-type".
+
+If the event carries no additional information, "arg-type" names an
+object type without members. The event may not have a data member on
+the wire then.
+
+Each command or event defined with dictionary-valued 'data' in the
+QAPI schema implicitly defines an object type called ":obj-NAME-arg",
+where NAME is the command or event's name.
+
+Example: the SchemaInfo for EVENT_C from section Events
+
+ { "name": "EVENT_C", "meta-type": "event",
+ "arg-type": ":obj-EVENT_C-arg" }
+
+ Type ":obj-EVENT_C-arg" is an implicitly defined object type with
+ the two members from the event's definition.
+
+The SchemaInfo for struct and union types has meta-type "object".
+
+The SchemaInfo for a struct type has variant member "members".
+
+The SchemaInfo for a union type additionally has variant members "tag"
+and "variants".
+
+"members" is a JSON array describing the object's common members, if
+any. Each element is a JSON object with members "name" (the member's
+name), "type" (the name of its type), and optionally "default". The
+member is optional if "default" is present. Currently, "default" can
+only have value null. Other values are reserved for future
+extensions.
+
+Example: the SchemaInfo for MyType from section Struct types
+
+ { "name": "MyType", "meta-type": "object",
+ "members": [
+ { "name": "member1", "type": "str" },
+ { "name": "member2", "type": "int" },
+ { "name": "member3", "type": "str", "default": null } ] }
+
+"tag" is the name of the common member serving as type tag.
+"variants" is a JSON array describing the object's variant members.
+Each element is a JSON object with members "case" (the value of type
+tag this element applies to) and "type" (the name of an object type
+that provides the variant members for this type tag value).
+
+Example: the SchemaInfo for flat union BlockdevOptions from section
+Union types
+
+ { "name": "BlockdevOptions", "meta-type": "object",
+ "members": [
+ { "name": "driver", "type": "BlockdevDriver" },
+ { "name": "readonly", "type": "bool"} ],
+ "tag": "driver",
+ "variants": [
+ { "case": "file", "type": "FileOptions" },
+ { "case": "qcow2", "type": "Qcow2Options" } ] }
+
+Note that base types are "flattened": its members are included in the
+"members" array.
+
+A simple union implicitly defines an enumeration type for its implicit
+discriminator (called "type" on the wire, see section Union types).
+Such a type's name is made by appending "Kind" to the simple union's
+name.
+
+A simple union implicitly defines an object type for each of its
+variants. The type's name is ":obj-NAME-wrapper", where NAME is the
+name of the name of the variant's type.
+
+Example: the SchemaInfo for simple union BlockdevOptions from section
+Union types
+
+ { "name": "BlockdevOptions", "meta-type": "object",
+ "members": [
+ { "name": "kind", "type": "BlockdevOptionsKind" } ],
+ "tag": "type",
+ "variants": [
+ { "case": "file", "type": ":obj-FileOptions-wrapper" },
+ { "case": "qcow2", "type": ":obj-Qcow2Options-wrapper" } ] }
+
+ Enumeration type "BlockdevOptionsKind" and the object types
+ ":obj-FileOptions-wrapper", ":obj-Qcow2Options-wrapper" are
+ implicitly defined.
+
+The SchemaInfo for an alternate type has meta-type "alternate", and
+variant member "members". "members" is a JSON array. Each element is
+a JSON object with member "type", which names a type. Values of the
+alternate type conform to exactly one of its member types.
+
+Example: the SchemaInfo for BlockRef from section Alternate types
+
+ { "name": "BlockRef", "meta-type": "alternate",
+ "members": [
+ { "type": "BlockdevOptions" },
+ { "type": "str" } ] }
+
+The SchemaInfo for an array type has meta-type "array", and variant
+member "element-type", which names the array's element type. Array
+types are implicitly defined. An array type's name is made by
+appending "List" to its element type's name.
+
+Example: the SchemaInfo for ['str']
+
+ { "name": "strList", "meta-type": "array",
+ "element-type": "str" }
+
+The SchemaInfo for an enumeration type has meta-type "enum" and
+variant member "values".
+
+Example: the SchemaInfo for MyEnum from section Enumeration types
+
+ { "name": "MyEnum", "meta-type": "enum",
+ "values": [ "value1", "value2", "value3" ] }
+
+The SchemaInfo for a built-in type has the same name as the type in
+the QAPI schema (see section Built-in Types), with one exception
+detailed below. It has variant member "json-type" that shows how
+values of this type are encoded on the wire.
+
+Example: the SchemaInfo for str
+
+ { "name": "str", "meta-type": "builtin", "json-type": "string" }
+
+The QAPI schema supports a number of integer types that only differ in
+how they map to C. They are identical as far as SchemaInfo is
+concerned. Therefore, they get all mapped to a single type "int" in
+SchemaInfo.
+
+As explained above, type names are not part of the wire ABI. Not even
+the names of built-in types. Clients should examine member
+"json-type" instead of hard-coding names of built-in types.
+
+
== Code generation ==
-Schemas are fed into 3 scripts to generate all the code/files that, paired
-with the core QAPI libraries, comprise everything required to take JSON
-commands read in by a Client JSON Protocol server, unmarshal the arguments into
-the underlying C types, call into the corresponding C function, and map the
-response back to a Client JSON Protocol response to be returned to the user.
+Schemas are fed into four scripts to generate all the code/files that,
+paired with the core QAPI libraries, comprise everything required to
+take JSON commands read in by a Client JSON Protocol server, unmarshal
+the arguments into the underlying C types, call into the corresponding
+C function, and map the response back to a Client JSON Protocol
+response to be returned to the user.
As an example, we'll use the following schema, which describes a single
complex user-defined type (which will produce a C struct, along with a list
@@ -856,3 +1049,37 @@ Example:
extern const char *const example_QAPIEvent_lookup[];
#endif
+
+=== scripts/qapi-introspect.py ===
+
+Used to generate the introspection C code for a schema. The following
+files are created:
+
+$(prefix)qmp-introspect.c - Defines a string holding a JSON
+ description of the schema.
+$(prefix)qmp-introspect.h - Declares the above string.
+
+Example:
+
+ $ python scripts/qapi-introspect.py --output-dir="qapi-generated"
+ --prefix="example-" example-schema.json
+ $ cat qapi-generated/example-qmp-introspect.c
+[Uninteresting stuff omitted...]
+
+ const char example_qmp_schema_json[] = "["
+ "{\"arg-type\": \":empty\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
+ "{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
+ "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}, "
+ "{\"members\": [], \"meta-type\": \"object\", \"name\": \":empty\"}, "
+ "{\"members\": [{\"name\": \"arg1\", \"type\": \"UserDefOne\"}], \"meta-type\": \"object\", \"name\": \":obj-my-command-arg\"}, "
+ "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"UserDefOne\"}, "
+ "{\"arg-type\": \":obj-my-command-arg\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"UserDefOne\"}]";
+ $ cat qapi-generated/example-qmp-introspect.h
+[Uninteresting stuff omitted...]
+
+ #ifndef EXAMPLE_QMP_INTROSPECT_H
+ #define EXAMPLE_QMP_INTROSPECT_H
+
+ extern const char example_qmp_schema_json[];
+
+ #endif
diff --git a/monitor.c b/monitor.c
index e083716..e5ee8e4 100644
--- a/monitor.c
+++ b/monitor.c
@@ -74,6 +74,7 @@
#include "block/qapi.h"
#include "qapi/qmp-event.h"
#include "qapi-event.h"
+#include "qmp-introspect.h"
#include "sysemu/block-backend.h"
/* for hmp_info_irq/pic */
@@ -928,6 +929,21 @@ EventInfoList *qmp_query_events(Error **errp)
return ev_list;
}
+/*
+ * Minor hack: generated marshalling suppressed for this command
+ * ('gen': false in the schema) so we can parse the JSON string
+ * directly into QObject instead of first parsing it with
+ * visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it
+ * to QObject with generated output marshallers, every time. Instead,
+ * we do it in test-qmp-input-visitor.c, just to make sure
+ * qapi-introspect.py's output actually conforms to the schema.
+ */
+static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
+ Error **errp)
+{
+ *ret_data = qobject_from_json(qmp_schema_json);
+}
+
/* set the current CPU defined by the user */
int monitor_set_cpu(int cpu_index)
{
diff --git a/qapi-schema.json b/qapi-schema.json
index 3ff9fec..821362d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -17,6 +17,9 @@
# Tracing commands
{ 'include': 'qapi/trace.json' }
+# QAPI introspection
+{ 'include': 'qapi/introspect.json' }
+
##
# @LostTickPolicy:
#
diff --git a/qapi/introspect.json b/qapi/introspect.json
new file mode 100644
index 0000000..9c8ad53
--- /dev/null
+++ b/qapi/introspect.json
@@ -0,0 +1,277 @@
+# -*- Mode: Python -*-
+#
+# QAPI/QMP introspection
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# Authors:
+# Markus Armbruster <armbru@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# @query-qmp-schema
+#
+# Command query-qmp-schema exposes the QMP wire ABI as an array of
+# SchemaInfo. This lets QMP clients figure out what commands and
+# events are available in this QEMU, and their parameters and results.
+#
+# However, the SchemaInfo can't reflect all the rules and restrictions
+# that apply to QMP. It's interface introspection (figuring out
+# what's there), not interface specification. The specification is in
+# the QAPI schema.
+#
+# Returns: array of @SchemaInfo, where each element describes an
+# entity in the ABI: command, event, type, ...
+#
+# Note: the QAPI schema is also used to help define *internal*
+# interfaces, by defining QAPI types. These are not part of the QMP
+# wire ABI, and therefore not returned by this command.
+#
+# Since: 2.5
+##
+{ 'command': 'query-qmp-schema',
+ 'returns': [ 'SchemaInfo' ],
+ 'gen': false } # just to simplify qmp_query_json()
+
+##
+# @SchemaMetaType
+#
+# This is a @SchemaInfo's meta type, i.e. the kind of entity it
+# describes.
+#
+# @builtin: a predefined type such as 'int' or 'bool'.
+#
+# @enum: an enumeration type
+#
+# @array: an array type
+#
+# @object: an object type (struct or union)
+#
+# @alternate: an alternate type
+#
+# @command: a QMP command
+#
+# @event: a QMP event
+#
+# Since: 2.5
+##
+{ 'enum': 'SchemaMetaType',
+ 'data': [ 'builtin', 'enum', 'array', 'object', 'alternate',
+ 'command', 'event' ] }
+
+##
+# @SchemaInfoBase
+#
+# Members common to any @SchemaInfo.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoBase',
+ 'data': { 'name': 'str', 'meta-type': 'SchemaMetaType' } }
+
+##
+# @SchemaInfo
+#
+# @name: the entity's name, inherited from @base.
+# Entities defined in the QAPI schema have the name defined in
+# the schema. Implicitly defined entities have generated
+# names. See docs/qapi-code-gen.txt section "Client JSON
+# Protocol introspection" for details.
+#
+# All references to other SchemaInfo are by name.
+#
+# Command and event names are part of the wire ABI, but type names are
+# not. Therefore, looking up a type by "well-known" name is wrong.
+# Look up the command or event, then follow the references.
+#
+# @meta-type: the entity's meta type, inherited from @base.
+#
+# Additional members depend on the value of @meta-type.
+#
+# Since: 2.5
+##
+{ 'union': 'SchemaInfo',
+ 'base': 'SchemaInfoBase',
+ 'discriminator': 'meta-type',
+ 'data': {
+ 'builtin': 'SchemaInfoBuiltin',
+ 'enum': 'SchemaInfoEnum',
+ 'array': 'SchemaInfoArray',
+ 'object': 'SchemaInfoObject',
+ 'alternate': 'SchemaInfoAlternate',
+ 'command': 'SchemaInfoCommand',
+ 'event': 'SchemaInfoEvent' } }
+
+##
+# @SchemaInfoBuiltin
+#
+# Additional SchemaInfo members for meta-type 'builtin'.
+#
+# @json-type: the JSON type used for this type on the wire.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoBuiltin',
+ 'data': { 'json-type': 'JSONType' } }
+
+##
+# @JSONType
+#
+# The four primitive and two structured types according to RFC 7159
+# section 1, plus 'int' (split off 'number'), plus the obvious top
+# type 'value'.
+#
+# Since: 2.5
+##
+{ 'enum': 'JSONType',
+ 'data': [ 'string', 'number', 'int', 'boolean', 'null',
+ 'object', 'array', 'value' ] }
+
+##
+# @SchemaInfoEnum
+#
+# Additional SchemaInfo members for meta-type 'enum'.
+#
+# @values: the enumeration type's values.
+#
+# Values of this type are JSON string on the wire.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoEnum',
+ 'data': { 'values': ['str'] } }
+
+##
+# @SchemaInfoArray
+#
+# Additional SchemaInfo members for meta-type 'array'.
+#
+# @element-type: the array type's element type.
+#
+# Values of this type are JSON array on the wire.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoArray',
+ 'data': { 'element-type': 'str' } }
+
+##
+# @SchemaInfoObject
+#
+# Additional SchemaInfo members for meta-type 'object'.
+#
+# @members: the object type's (non-variant) members.
+#
+# @tag: #optional the name of the member serving as type tag.
+# An element of @members with this name must exist.
+#
+# @variants: #optional variant members, i.e. additional members that
+# depend on the type tag's value. Present exactly when
+# @tag is present.
+#
+# Values of this type are JSON object on the wire.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoObject',
+ 'data': { 'members': [ 'SchemaInfoObjectMember' ],
+ '*tag': 'str',
+ '*variants': [ 'SchemaInfoObjectVariant' ] } }
+
+##
+# @SchemaInfoObjectMember
+#
+# An object member.
+#
+# @name: the member's name, as defined in the QAPI schema.
+#
+# @type: the name of the member's type.
+#
+# @default: #optional default when used as command parameter.
+# If absent, the parameter is mandatory.
+# If present, the value must be null. The parameter is
+# optional, and behavior when it's missing is not specified
+# here.
+# Future extension: if present and non-null, the parameter
+# is optional, and defaults to this value.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoObjectMember',
+ 'data': { 'name': 'str', 'type': 'str', '*default': 'any' } }
+# @default's type must be null or match @type
+
+##
+# @SchemaInfoObjectVariant
+#
+# The variant members for a value of the type tag.
+#
+# @case: a value of the type tag.
+#
+# @type: the name of the object type that provides the variant members
+# when the type tag has value @case.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoObjectVariant',
+ 'data': { 'case': 'str', 'type': 'str' } }
+
+##
+# @SchemaInfoAlternate
+#
+# Additional SchemaInfo members for meta-type 'alternate'.
+#
+# @members: the alternate type's members.
+# The members' wire encoding is distinct, see
+# docs/qapi-code-gen.txt section Alternate types.
+#
+# On the wire, this can be any of the members.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoAlternate',
+ 'data': { 'members': [ 'SchemaInfoAlternateMember' ] } }
+
+##
+# @SchemaInfoAlternateMember
+#
+# An alternate member.
+#
+# @type: the name of the member's type.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoAlternateMember',
+ 'data': { 'type': 'str' } }
+
+##
+# @SchemaInfoCommand
+#
+# Additional SchemaInfo members for meta-type 'command'.
+#
+# @arg-type: the name of the object type that provides the command's
+# parameters.
+#
+# @ret-type: the name of the command's result type.
+#
+# TODO @success-response (currently irrelevant, because it's QGA, not QMP)
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoCommand',
+ 'data': { 'arg-type': 'str', 'ret-type': 'str' } }
+
+##
+# @SchemaInfoEvent
+#
+# Additional SchemaInfo members for meta-type 'event'.
+#
+# @arg-type: the name of the object type that provides the event's
+# parameters.
+#
+# Since: 2.5
+##
+{ 'struct': 'SchemaInfoEvent',
+ 'data': { 'arg-type': 'str' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 5a54406..66f0300 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2193,6 +2193,23 @@ EQMP
},
SQMP
+query-qmp-schema
+----------------
+
+Return the QMP wire schema. The returned value is a json-array of
+named schema entities. Entities are commands, events and various
+types. See docs/qapi-code-gen.txt for information on their structure
+and intended use.
+
+EQMP
+
+ {
+ .name = "query-qmp-schema",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_query_qmp_schema,
+ },
+
+SQMP
query-chardev
-------------
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
new file mode 100644
index 0000000..831d6d5
--- /dev/null
+++ b/scripts/qapi-introspect.py
@@ -0,0 +1,184 @@
+#
+# QAPI introspection generator
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# Authors:
+# Markus Armbruster <armbru@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.
+# See the COPYING file in the top-level directory.
+
+from qapi import *
+
+
+# Caveman's json.dumps() replacement (we're stuck at Python 2.4)
+# TODO try to use json.dumps() once we get unstuck
+def to_json(obj, level=0):
+ if obj is None:
+ ret = 'null'
+ elif isinstance(obj, str):
+ ret = '"' + obj.replace('"', r'\"') + '"'
+ elif isinstance(obj, list):
+ elts = [to_json(elt, level + 1)
+ for elt in obj]
+ ret = '[' + ', '.join(elts) + ']'
+ elif isinstance(obj, dict):
+ elts = ['"%s": %s' % (key.replace('"', r'\"'),
+ to_json(obj[key], level + 1))
+ for key in sorted(obj.keys())]
+ ret = '{' + ', '.join(elts) + '}'
+ else:
+ assert False # not implemented
+ if level == 1:
+ ret = '\n' + ret
+ return ret
+
+
+def to_c_string(string):
+ return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"'
+
+
+class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
+ def __init__(self):
+ self.defn = None
+ self.decl = None
+ self._schema = None
+ self._jsons = None
+ self._used_types = None
+
+ def visit_begin(self, schema):
+ self._schema = schema
+ self._jsons = []
+ self._used_types = []
+ return QAPISchemaType # don't visit types for now
+
+ def visit_end(self):
+ # visit the types that are actually used
+ for typ in self._used_types:
+ typ.visit(self)
+ self._jsons.sort()
+ # generate C
+ # TODO can generate awfully long lines
+ name = prefix + 'qmp_schema_json'
+ self.decl = mcgen('''
+extern const char %(c_name)s[];
+''',
+ c_name=c_name(name))
+ lines = to_json(self._jsons).split('\n')
+ c_string = '\n '.join([to_c_string(line) for line in lines])
+ self.defn = mcgen('''
+const char %(c_name)s[] = %(c_string)s;
+''',
+ c_name=c_name(name),
+ c_string=c_string)
+ self._schema = None
+ self._jsons = None
+ self._used_types = None
+
+ def _use_type(self, typ):
+ # Map the various integer types to plain int
+ if typ.json_type() == 'int':
+ typ = self._schema.lookup_type('int')
+ elif (isinstance(typ, QAPISchemaArrayType) and
+ typ.element_type.json_type() == 'int'):
+ typ = self._schema.lookup_type('intList')
+ # Add type to work queue if new
+ if typ not in self._used_types:
+ self._used_types.append(typ)
+ return typ.name
+
+ def _gen_json(self, name, mtype, obj):
+ obj['name'] = name
+ obj['meta-type'] = mtype
+ self._jsons.append(obj)
+
+ def _gen_member(self, member):
+ ret = {'name': member.name, 'type': self._use_type(member.type)}
+ if member.optional:
+ ret['default'] = None
+ return ret
+
+ def _gen_variants(self, tag_name, variants):
+ return {'tag': tag_name,
+ 'variants': [self._gen_variant(v) for v in variants]}
+
+ def _gen_variant(self, variant):
+ return {'case': variant.name, 'type': self._use_type(variant.type)}
+
+ def visit_builtin_type(self, name, info, json_type):
+ self._gen_json(name, 'builtin', {'json-type': json_type})
+
+ def visit_enum_type(self, name, info, values, prefix):
+ self._gen_json(name, 'enum', {'values': values})
+
+ def visit_array_type(self, name, info, element_type):
+ self._gen_json(name, 'array',
+ {'element-type': self._use_type(element_type)})
+
+ def visit_object_type_flat(self, name, info, members, variants):
+ obj = {'members': [self._gen_member(m) for m in members]}
+ if variants:
+ obj.update(self._gen_variants(variants.tag_member.name,
+ variants.variants))
+ self._gen_json(name, 'object', obj)
+
+ def visit_alternate_type(self, name, info, variants):
+ self._gen_json(name, 'alternate',
+ {'members': [{'type': self._use_type(m.type)}
+ for m in variants.variants]})
+
+ def visit_command(self, name, info, arg_type, ret_type,
+ gen, success_response):
+ arg_type = arg_type or self._schema.the_empty_object_type
+ ret_type = ret_type or self._schema.the_empty_object_type
+ self._gen_json(name, 'command',
+ {'arg-type': self._use_type(arg_type),
+ 'ret-type': self._use_type(ret_type)})
+
+ def visit_event(self, name, info, arg_type):
+ arg_type = arg_type or self._schema.the_empty_object_type
+ self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
+
+(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
+
+c_comment = '''
+/*
+ * QAPI/QMP schema introspection
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+'''
+h_comment = '''
+/*
+ * QAPI/QMP schema introspection
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+'''
+
+(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
+ 'qmp-introspect.c', 'qmp-introspect.h',
+ c_comment, h_comment)
+
+fdef.write(mcgen('''
+#include "%(prefix)sqmp-introspect.h"
+
+''',
+ prefix=prefix))
+
+schema = QAPISchema(input_file)
+gen = QAPISchemaGenIntrospectVisitor()
+schema.visit(gen)
+fdef.write(gen.defn)
+fdecl.write(gen.decl)
+
+close_output(fdef, fdecl)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6a94acc..1ed11ec 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -788,6 +788,9 @@ class QAPISchemaVisitor(object):
def visit_object_type(self, name, info, base, members, variants):
pass
+ def visit_object_type_flat(self, name, info, members, variants):
+ pass
+
def visit_alternate_type(self, name, info, variants):
pass
@@ -942,6 +945,8 @@ class QAPISchemaObjectType(QAPISchemaType):
def visit(self, visitor):
visitor.visit_object_type(self.name, self.info,
self.base, self.local_members, self.variants)
+ visitor.visit_object_type_flat(self.name, self.info,
+ self.members, self.variants)
class QAPISchemaObjectTypeMember(object):
@@ -1112,6 +1117,9 @@ class QAPISchema(object):
('bool', 'boolean', 'bool', 'false'),
('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
self._def_builtin_type(*t)
+ self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
+ [], None)
+ self._def_entity(self.the_empty_object_type)
def _make_implicit_enum_type(self, name, values):
name = name + 'Kind'
@@ -1259,9 +1267,10 @@ class QAPISchema(object):
ent.check(self)
def visit(self, visitor):
- visitor.visit_begin(self)
+ ignore = visitor.visit_begin(self)
for name in sorted(self._entity_dict.keys()):
- self._entity_dict[name].visit(visitor)
+ if not ignore or not isinstance(self._entity_dict[name], ignore):
+ self._entity_dict[name].visit(visitor)
visitor.visit_end()
diff --git a/tests/.gitignore b/tests/.gitignore
index 2c5e2c3..a607bdd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -35,6 +35,7 @@ test-qmp-commands.h
test-qmp-event
test-qmp-input-strict
test-qmp-input-visitor
+test-qmp-introspect.[ch]
test-qmp-marshal.c
test-qmp-output-visitor
test-rcu-list
diff --git a/tests/Makefile b/tests/Makefile
index aadfb38..4063639 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -269,7 +269,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
struct-base-clash.json struct-base-clash-deep.json )
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \
- tests/test-qmp-commands.h tests/test-qapi-event.h
+ tests/test-qmp-commands.h tests/test-qapi-event.h \
+ tests/test-qmp-introspect.h
test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \
@@ -289,7 +290,7 @@ QEMU_CFLAGS += -I$(SRC_PATH)/tests
test-util-obj-y = libqemuutil.a libqemustub.a
test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y)
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
- tests/test-qapi-event.o \
+ tests/test-qapi-event.o tests/test-qmp-introspect.o \
$(test-qom-obj-y)
test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
test-block-obj-y = $(block-obj-y) $(test-crypto-obj-y)
@@ -346,6 +347,11 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-eve
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
$(gen-out-type) -o tests -p "test-" $<, \
" GEN $@")
+tests/test-qmp-introspect.c tests/test-qmp-introspect.h :\
+$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
+ $(gen-out-type) -o tests -p "test-" $<, \
+ " GEN $@")
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
diff --git a/tests/qapi-schema/alternate-good.out b/tests/qapi-schema/alternate-good.out
index 75a58cd..51e37d0 100644
--- a/tests/qapi-schema/alternate-good.out
+++ b/tests/qapi-schema/alternate-good.out
@@ -1,3 +1,4 @@
+object :empty
alternate Alt
case value: int
case string: Enum
diff --git a/tests/qapi-schema/args-member-array.out b/tests/qapi-schema/args-member-array.out
index 7c58cef..5fd83b6 100644
--- a/tests/qapi-schema/args-member-array.out
+++ b/tests/qapi-schema/args-member-array.out
@@ -1,3 +1,4 @@
+object :empty
object :obj-okay-arg
member member1: intList optional=False
member member2: defList optional=False
--git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 537419c..5c29acc 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1 +1,2 @@
+object :empty
enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index e69de29..272b161 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -0,0 +1 @@
+object :empty
diff --git a/tests/qapi-schema/enum-empty.out b/tests/qapi-schema/enum-empty.out
index 3628fbd..24e9b50 100644
--- a/tests/qapi-schema/enum-empty.out
+++ b/tests/qapi-schema/enum-empty.out
@@ -1 +1,2 @@
+object :empty
enum MyEnum [] prefix=None
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index b5ae4c2..cdfd264 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1 +1,2 @@
+object :empty
event oops None
diff --git a/tests/qapi-schema/flat-union-reverse-define.out b/tests/qapi-schema/flat-union-reverse-define.out
index 6f4df73..c8f96d8 100644
--- a/tests/qapi-schema/flat-union-reverse-define.out
+++ b/tests/qapi-schema/flat-union-reverse-define.out
@@ -1,3 +1,4 @@
+object :empty
object TestBase
member enum1: TestEnum optional=False
enum TestEnum ['value1', 'value2'] prefix=None
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index 9577d1b..f4542b1 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -1,3 +1,4 @@
+object :empty
object :obj-fooA-arg
member bar1: str optional=False
command fooA :obj-fooA-arg -> None
diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
index 537419c..5c29acc 100644
--- a/tests/qapi-schema/include-relpath.out
+++ b/tests/qapi-schema/include-relpath.out
@@ -1 +1,2 @@
+object :empty
enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 537419c..5c29acc 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1 +1,2 @@
+object :empty
enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 537419c..5c29acc 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1 +1,2 @@
+object :empty
enum Status ['good', 'bad', 'ugly'] prefix=None
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index c5af55a..226d300 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,3 +1,4 @@
+object :empty
command eins None -> None
gen=True success_response=True
command zwei None -> None
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 231c3bf..fd0b6ca 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,3 +1,4 @@
+object :empty
object :obj-EVENT_C-arg
member a: int optional=True
member b: UserDefOne optional=True
diff --git a/tests/qapi-schema/returns-int.out b/tests/qapi-schema/returns-int.out
index 1ac3e1e..a2da259 100644
--- a/tests/qapi-schema/returns-int.out
+++ b/tests/qapi-schema/returns-int.out
@@ -1,2 +1,3 @@
+object :empty
command guest-get-time None -> int
gen=True success_response=True
diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
index a2ae786..53a7693 100644
--- a/tests/test-qmp-input-strict.c
+++ b/tests/test-qmp-input-strict.c
@@ -19,6 +19,9 @@
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "qapi/qmp/types.h"
+#include "test-qmp-introspect.h"
+#include "qmp-introspect.h"
+#include "qapi-visit.h"
typedef struct TestInputVisitorData {
QObject *obj;
@@ -62,6 +65,30 @@ Visitor *validate_test_init(TestInputVisitorData *data,
return v;
}
+/* similar to validate_test_init(), but does not expect a string
+ * literal/format json_string argument and so can be used for
+ * programatically generated strings (and we can't pass in programatically
+ * generated strings via %s format parameters since qobject_from_jsonv()
+ * will wrap those in double-quotes and treat the entire object as a
+ * string)
+ */
+static Visitor *validate_test_init_raw(TestInputVisitorData *data,
+ const char *json_string)
+{
+ Visitor *v;
+
+ data->obj = qobject_from_json(json_string);
+ g_assert(data->obj != NULL);
+
+ data->qiv = qmp_input_visitor_new_strict(data->obj);
+ g_assert(data->qiv != NULL);
+
+ v = qmp_input_get_visitor(data->qiv);
+ g_assert(v != NULL);
+
+ return v;
+}
+
typedef struct TestStruct
{
int64_t integer;
@@ -293,6 +320,32 @@ static void test_validate_fail_alternate(TestInputVisitorData *data,
qapi_free_UserDefAlternate(tmp);
}
+static void do_test_validate_qmp_introspect(TestInputVisitorData *data,
+ const char *schema_json)
+{
+ SchemaInfoList *schema = NULL;
+ Error *err = NULL;
+ Visitor *v;
+
+ v = validate_test_init_raw(data, schema_json);
+
+ visit_type_SchemaInfoList(v, &schema, NULL, &err);
+ if (err) {
+ fprintf(stderr, "%s", error_get_pretty(err));
+ }
+ g_assert(!err);
+ g_assert(schema);
+
+ qapi_free_SchemaInfoList(schema);
+}
+
+static void test_validate_qmp_introspect(TestInputVisitorData *data,
+ const void *unused)
+{
+ do_test_validate_qmp_introspect(data, test_qmp_schema_json);
+ do_test_validate_qmp_introspect(data, qmp_schema_json);
+}
+
static void validate_test_add(const char *testpath,
TestInputVisitorData *data,
void (*test_func)(TestInputVisitorData *data, const void *user_data))
@@ -333,6 +386,8 @@ int main(int argc, char **argv)
&testdata, test_validate_fail_alternate);
validate_test_add("/visitor/input-strict/fail/union-native-list",
&testdata, test_validate_fail_union_native_list);
+ validate_test_add("/visitor/input-strict/pass/qmp-introspect",
+ &testdata, test_validate_qmp_introspect);
g_test_run();
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 25/26] qapi: New QMP command query-qmp-schema for QMP introspection
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 25/26] qapi: New QMP command query-qmp-schema for QMP introspection Markus Armbruster
@ 2015-09-16 20:08 ` Eric Blake
0 siblings, 0 replies; 55+ messages in thread
From: Eric Blake @ 2015-09-16 20:08 UTC (permalink / raw)
To: Markus Armbruster, qemu-devel; +Cc: mdroth
[-- Attachment #1: Type: text/plain, Size: 648 bytes --]
On 09/16/2015 05:06 AM, Markus Armbruster wrote:
> qapi/introspect.json defines the introspection schema. It's designed
> for QMP introspection, but should do for similar uses, such as QGA.
>
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
Produces the same introspection string as v7, and the Makefile changes
appear correct.
Reviewed-by: Eric Blake <eblake@redhat.com>
Overall, I'm happy with how the rebased series turned out, and am now in
the process of rebasing my own pending patches on top.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH v8 26/26] qapi-introspect: Hide type names
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (24 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 25/26] qapi: New QMP command query-qmp-schema for QMP introspection Markus Armbruster
@ 2015-09-16 11:06 ` Markus Armbruster
2015-09-16 15:07 ` [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Daniel P. Berrange
2015-09-17 16:16 ` Markus Armbruster
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-16 11:06 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth
To eliminate the temptation for clients to look up types by name
(which are not ABI), replace all type names by meaningless strings.
Reduces output of query-schema by 13 out of 85KiB.
As a debugging aid, provide option -u to suppress the hiding.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
docs/qapi-code-gen.txt | 36 +++++++++++++++++-------------------
qapi/introspect.json | 12 ++++--------
scripts/qapi-introspect.py | 41 +++++++++++++++++++++++++++++++++++------
3 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index f321d4b..b1c8361 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -530,13 +530,16 @@ additional variant members depending on the value of meta-type.
Each SchemaInfo object describes a wire ABI entity of a certain
meta-type: a command, event or one of several kinds of type.
-SchemaInfo for entities defined in the QAPI schema have the same name
-as in the schema. This is the case for all commands and events, and
-most types.
+SchemaInfo for commands and events have the same name as in the QAPI
+schema.
Command and event names are part of the wire ABI, but type names are
-not. Therefore, looking up a type by its name in the QAPI schema is
-wrong. Look up the command or event, then follow references by name.
+not. Therefore, the SchemaInfo for types have auto-generated
+meaningless names. For readability, the examples in this section use
+meaningful type names instead.
+
+To examine a type, start with a command or event using it, then follow
+references by name.
QAPI schema definitions not reachable that way are omitted.
@@ -567,8 +570,7 @@ object type without members. The event may not have a data member on
the wire then.
Each command or event defined with dictionary-valued 'data' in the
-QAPI schema implicitly defines an object type called ":obj-NAME-arg",
-where NAME is the command or event's name.
+QAPI schema implicitly defines an object type.
Example: the SchemaInfo for EVENT_C from section Events
@@ -623,12 +625,9 @@ Note that base types are "flattened": its members are included in the
A simple union implicitly defines an enumeration type for its implicit
discriminator (called "type" on the wire, see section Union types).
-Such a type's name is made by appending "Kind" to the simple union's
-name.
A simple union implicitly defines an object type for each of its
-variants. The type's name is ":obj-NAME-wrapper", where NAME is the
-name of the name of the variant's type.
+variants.
Example: the SchemaInfo for simple union BlockdevOptions from section
Union types
@@ -659,8 +658,7 @@ Example: the SchemaInfo for BlockRef from section Alternate types
The SchemaInfo for an array type has meta-type "array", and variant
member "element-type", which names the array's element type. Array
-types are implicitly defined. An array type's name is made by
-appending "List" to its element type's name.
+types are implicitly defined.
Example: the SchemaInfo for ['str']
@@ -1067,13 +1065,13 @@ Example:
[Uninteresting stuff omitted...]
const char example_qmp_schema_json[] = "["
- "{\"arg-type\": \":empty\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
+ "{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
+ "{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, "
+ "{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, "
+ "{\"members\": [{\"name\": \"arg1\", \"type\": \"2\"}], \"meta-type\": \"object\", \"name\": \"1\"}, "
+ "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, "
"{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
- "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}, "
- "{\"members\": [], \"meta-type\": \"object\", \"name\": \":empty\"}, "
- "{\"members\": [{\"name\": \"arg1\", \"type\": \"UserDefOne\"}], \"meta-type\": \"object\", \"name\": \":obj-my-command-arg\"}, "
- "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"UserDefOne\"}, "
- "{\"arg-type\": \":obj-my-command-arg\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"UserDefOne\"}]";
+ "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]";
$ cat qapi-generated/example-qmp-introspect.h
[Uninteresting stuff omitted...]
diff --git a/qapi/introspect.json b/qapi/introspect.json
index 9c8ad53..cc50dc6 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -75,17 +75,13 @@
# @SchemaInfo
#
# @name: the entity's name, inherited from @base.
-# Entities defined in the QAPI schema have the name defined in
-# the schema. Implicitly defined entities have generated
-# names. See docs/qapi-code-gen.txt section "Client JSON
-# Protocol introspection" for details.
+# Commands and events have the name defined in the QAPI schema.
+# Unlike command and event names, type names are not part of
+# the wire ABI. Consequently, type names are meaningless
+# strings here.
#
# All references to other SchemaInfo are by name.
#
-# Command and event names are part of the wire ABI, but type names are
-# not. Therefore, looking up a type by "well-known" name is wrong.
-# Look up the command or event, then follow the references.
-#
# @meta-type: the entity's meta type, inherited from @base.
#
# Additional members depend on the value of @meta-type.
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 831d6d5..7d39320 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -40,32 +40,37 @@ def to_c_string(string):
class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
- def __init__(self):
+ def __init__(self, unmask):
+ self._unmask = unmask
self.defn = None
self.decl = None
self._schema = None
self._jsons = None
self._used_types = None
+ self._name_map = None
def visit_begin(self, schema):
self._schema = schema
self._jsons = []
self._used_types = []
+ self._name_map = {}
return QAPISchemaType # don't visit types for now
def visit_end(self):
# visit the types that are actually used
+ jsons = self._jsons
+ self._jsons = []
for typ in self._used_types:
typ.visit(self)
- self._jsons.sort()
# generate C
# TODO can generate awfully long lines
+ jsons.extend(self._jsons)
name = prefix + 'qmp_schema_json'
self.decl = mcgen('''
extern const char %(c_name)s[];
''',
c_name=c_name(name))
- lines = to_json(self._jsons).split('\n')
+ lines = to_json(jsons).split('\n')
c_string = '\n '.join([to_c_string(line) for line in lines])
self.defn = mcgen('''
const char %(c_name)s[] = %(c_string)s;
@@ -75,6 +80,14 @@ const char %(c_name)s[] = %(c_string)s;
self._schema = None
self._jsons = None
self._used_types = None
+ self._name_map = None
+
+ def _name(self, name):
+ if self._unmask:
+ return name
+ if name not in self._name_map:
+ self._name_map[name] = '%d' % len(self._name_map)
+ return self._name_map[name]
def _use_type(self, typ):
# Map the various integer types to plain int
@@ -86,9 +99,16 @@ const char %(c_name)s[] = %(c_string)s;
# Add type to work queue if new
if typ not in self._used_types:
self._used_types.append(typ)
- return typ.name
+ # Clients should examine commands and events, not types. Hide
+ # type names to reduce the temptation. Also saves a few
+ # characters.
+ if isinstance(typ, QAPISchemaBuiltinType):
+ return typ.name
+ return self._name(typ.name)
def _gen_json(self, name, mtype, obj):
+ if mtype != 'command' and mtype != 'event' and mtype != 'builtin':
+ name = self._name(name)
obj['name'] = name
obj['meta-type'] = mtype
self._jsons.append(obj)
@@ -140,7 +160,16 @@ const char %(c_name)s[] = %(c_string)s;
arg_type = arg_type or self._schema.the_empty_object_type
self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
-(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
+# Debugging aid: unmask QAPI schema's type names
+# We normally mask them, because they're not QMP wire ABI
+opt_unmask = False
+
+(input_file, output_dir, do_c, do_h, prefix, opts) = \
+ parse_command_line("u", ["unmask-non-abi-names"])
+
+for o, a in opts:
+ if o in ("-u", "--unmask-non-abi-names"):
+ opt_unmask = True
c_comment = '''
/*
@@ -176,7 +205,7 @@ fdef.write(mcgen('''
prefix=prefix))
schema = QAPISchema(input_file)
-gen = QAPISchemaGenIntrospectVisitor()
+gen = QAPISchemaGenIntrospectVisitor(opt_unmask)
schema.visit(gen)
fdef.write(gen.defn)
fdecl.write(gen.decl)
--
2.4.3
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (25 preceding siblings ...)
2015-09-16 11:06 ` [Qemu-devel] [PATCH v8 26/26] qapi-introspect: Hide type names Markus Armbruster
@ 2015-09-16 15:07 ` Daniel P. Berrange
2015-09-17 16:16 ` Markus Armbruster
27 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrange @ 2015-09-16 15:07 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, mdroth
On Wed, Sep 16, 2015 at 01:06:03PM +0200, Markus Armbruster wrote:
> Series needs my "[PATCH for-2.4 0/2] qom: Fix misuse of Error API" to
> pass tests. It's in Andreas's qom-next (currently at commit de1da05),
> so I based on that.
>
> You can fetch it from my git://repo.or.cz/qemu/armbru.git branch
> qapi-introspect.
>
> Review of v6 found a small flaw in the PATCH 20. Fixing it will
> require a (possibly time-consuming) dive down the visitors rabbit
> hole. To avoid further delay, we decided to go along with the flawed
> patch, then fix it up in a follow-up. See PATCH 20 for details.
>
> * PATCH 01-18 basically replace the intermediate representation. The
> replacement isn't complete, but fully functional. See PATCH 02 for
> rationale and future work.
>
> * PATCH 19-24 replace the '**' type bypass by a proper top type called
> 'any'.
>
> * PATCH 25-26 are the QMP introspection.
>
> v8:
> * Non-trivial rebase due to commit 351d36e "qapi: allow override of
> default enum prefix naming", R-bys dropped from the patches
> mentioned below unless noted otherwise.
> * PATCH 02:
> - Add prefix to QAPISchemaObjectType
> * PATCH 03:
> - Use prefix in QAPISchemaObjectType.c_null()
> * PATCH 04:
> - Add prefix to QAPISchemaVisitor.visit_enum_type()
> * PATCH 05:
> - Use prefix in QAPISchemaTestVisitor.visit_enum_type()
> * PATCH 06:
> - Use prefix in QAPISchemaGenTypeVisitor.visit_enum_type()
> * PATCH 07:
> - Ignore prefix in QAPISchemaGenTypeVisitor.visit_enum_type()
> * PATCH 09:
> - The code moved changed in commit 351d36e, redo code motion
> * PATCH 13:
> - Resolve conflicts
> * PATCH 20:
> - Commit message tweaked [Dan], R-bys retained
> * PATCH 21:
> - Resolve expected test output conflicts by regenerating it, R-bys
> retained
> * PATCH 25:
> - Resolve straightforward conflicts in Makefile.objs, tests/Makefile
> - Use prefix in QAPISchemaGenIntrospectVisitor.visit_enum_type()
> - Resolve expected test output conflicts by regenerating it
> * Since the non-trivial rebase invalidated my testing, I put back the
> scaffolding patches dropped in v6, and verified everything's still
> sane. I tagged this version qapi-introspect-v8-pre in my git
> repository.
> * Unless this fails review, I will require further conflicting QAPI
> changes to base on it.
I've compared a diff-of-diffs for v7 vs v8 and confirmed the conflict
resolution you did for my enum prefix change looks sane in all cases.
So I've replied with R-B on all the patches, which I'd previously
reviewed - that's all except 25 which I've never reviewed yet.
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection
2015-09-16 11:06 [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Markus Armbruster
` (26 preceding siblings ...)
2015-09-16 15:07 ` [Qemu-devel] [PATCH v8 00/26] qapi: QMP introspection Daniel P. Berrange
@ 2015-09-17 16:16 ` Markus Armbruster
27 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2015-09-17 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: mdroth, Andreas Färber
I squashed in the assertion missing in PATCH 02 [Eric], and changed how
test-qapi.py prints an enum type's prefix [Eric]. The latter led to the
obvious expected test output changes in later patches. Result is now at
git://repo.or.cz/qemu/armbru.git branch qapi-introspect.
Still depends on qom-next. I can either wait for that to hit master, or
copy the two fixes I need into my branch. Andreas, can you give me a
rough ETA?
^ permalink raw reply [flat|nested] 55+ messages in thread