Commit 61f7901b authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2015-10-15' into staging



QAPI patches

# gpg: Signature made Thu 15 Oct 2015 07:40:46 BST using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"

* remotes/armbru/tags/pull-qapi-2015-10-15:
  qapi: Track location that created an implicit type
  qapi: Create simple union type member earlier
  qapi: Lazy creation of array types
  qapi: Don't use info as witness of implicit object type
  qapi: Drop redundant args-member-array test
  qapi: Drop redundant flat-union-reverse-define test
  qapi: Drop redundant returns-int test
  qapi: Move empty-enum to compile-time test
  qapi: Drop redundant alternate-good test
  qapi: Prepare for errors during check()
  qapi: Use predicate callback to determine visit filtering
  qapi: Fix regression with '-netdev help'

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents e95bdb43 99df5289
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -3415,6 +3415,17 @@
            'cpuid-register': 'X86CPURegister32',
            'features': 'int' } }

##
# @DummyForceArrays
#
# Not used by QMP; hack to let us use X86CPUFeatureWordInfoList internally
#
# Since 2.5
##
{ 'struct': 'DummyForceArrays',
  'data': { 'unused': ['X86CPUFeatureWordInfo'] } }


##
# @RxState:
#
+4 −1
Original line number Diff line number Diff line
@@ -54,7 +54,6 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
        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
@@ -82,6 +81,10 @@ const char %(c_name)s[] = %(c_string)s;
        self._used_types = None
        self._name_map = None

    def visit_needed(self, entity):
        # Ignore types on first pass; visit_end() will pick up used types
        return not isinstance(entity, QAPISchemaType)

    def _name(self, name):
        if self._unmask:
            return name
+12 −8
Original line number Diff line number Diff line
@@ -233,6 +233,11 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
        self.decl = self._btin + self.decl
        self._btin = None

    def visit_needed(self, entity):
        # Visit everything except implicit objects
        return not (entity.is_implicit() and
                    isinstance(entity, QAPISchemaObjectType))

    def _gen_type_cleanup(self, name):
        self.decl += gen_type_cleanup_decl(name)
        self.defn += gen_type_cleanup(name)
@@ -254,7 +259,6 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
            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
+14 −8
Original line number Diff line number Diff line
@@ -301,7 +301,9 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
out_obj:
    error_propagate(errp, err);
    err = NULL;
    if (*obj) {
        visit_end_union(v, !!(*obj)->data, &err);
    }
    error_propagate(errp, err);
    err = NULL;
    visit_end_struct(v, &err);
@@ -333,6 +335,11 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
        self.decl = self._btin + self.decl
        self._btin = None

    def visit_needed(self, entity):
        # Visit everything except implicit objects
        return not (entity.is_implicit() and
                    isinstance(entity, QAPISchemaObjectType))

    def visit_enum_type(self, name, info, values, prefix):
        self.decl += gen_visit_decl(name, scalar=True)
        self.defn += gen_visit_enum(name)
@@ -349,7 +356,6 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
            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
+90 −59
Original line number Diff line number Diff line
@@ -56,9 +56,6 @@ returns_whitelist = [
    'guest-set-vcpus',
    'guest-sync',
    'guest-sync-delimited',

    # From qapi-schema-test:
    'user_def_cmd3',
]

enum_types = []
@@ -103,6 +100,7 @@ class QAPISchemaError(Exception):
class QAPIExprError(Exception):
    def __init__(self, expr_info, msg):
        Exception.__init__(self)
        assert expr_info
        self.info = expr_info
        self.msg = msg

@@ -792,6 +790,11 @@ class QAPISchemaEntity(object):
    def __init__(self, name, info):
        assert isinstance(name, str)
        self.name = name
        # For explicitly defined entities, info points to the (explicit)
        # definition.  For builtins (and their arrays), info is None.
        # For implicitly defined entities, info points to a place that
        # triggered the implicit definition (there may be more than one
        # such place).
        self.info = info

    def c_name(self):
@@ -800,6 +803,9 @@ class QAPISchemaEntity(object):
    def check(self, schema):
        pass

    def is_implicit(self):
        return not self.info

    def visit(self, visitor):
        pass

@@ -811,6 +817,10 @@ class QAPISchemaVisitor(object):
    def visit_end(self):
        pass

    def visit_needed(self, entity):
        # Default to visiting everything
        return True

    def visit_builtin_type(self, name, info, json_type):
        pass

@@ -898,6 +908,10 @@ class QAPISchemaEnumType(QAPISchemaType):
    def check(self, schema):
        assert len(set(self.values)) == len(self.values)

    def is_implicit(self):
        # See QAPISchema._make_implicit_enum_type()
        return self.name[-4:] == 'Kind'

    def c_type(self, is_param=False):
        return c_name(self.name)

@@ -924,6 +938,9 @@ class QAPISchemaArrayType(QAPISchemaType):
        self.element_type = schema.lookup_type(self._element_type_name)
        assert self.element_type

    def is_implicit(self):
        return True

    def json_type(self):
        return 'array'

@@ -960,6 +977,7 @@ class QAPISchemaObjectType(QAPISchemaType):
            members = []
        seen = {}
        for m in members:
            assert c_name(m.name) not in seen
            seen[m.name] = m
        for m in self.local_members:
            m.check(schema, members, seen)
@@ -967,12 +985,16 @@ class QAPISchemaObjectType(QAPISchemaType):
            self.variants.check(schema, members, seen)
        self.members = members

    def is_implicit(self):
        # See QAPISchema._make_implicit_object_type()
        return self.name[0] == ':'

    def c_name(self):
        assert self.info
        assert not self.is_implicit()
        return QAPISchemaType.c_name(self)

    def c_type(self, is_param=False):
        assert self.info
        assert not self.is_implicit()
        return QAPISchemaType.c_type(self)

    def json_type(self):
@@ -1004,18 +1026,18 @@ class QAPISchemaObjectTypeMember(object):


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)
    def __init__(self, tag_name, tag_member, variants):
        # Flat unions pass tag_name but not tag_member.
        # Simple unions and alternates pass tag_member but not tag_name.
        # After check(), tag_member is always set, and tag_name remains
        # a reliable witness of being used by a flat union.
        assert bool(tag_member) != bool(tag_name)
        assert (isinstance(tag_name, str) or
                isinstance(tag_member, QAPISchemaObjectTypeMember))
        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.tag_member = tag_member
        self.variants = variants

    def check(self, schema, members, seen):
@@ -1040,7 +1062,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
    # 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:
        if (self.type.is_implicit() and
                isinstance(self.type, QAPISchemaObjectType)):
            assert len(self.type.members) == 1
            assert not self.type.variants
            return self.type.members[0].type
@@ -1112,15 +1135,19 @@ 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._predefining = True
            self._def_predefineds()
            self._predefining = False
            self._def_exprs()
            self.check()
        except (QAPISchemaError, QAPIExprError), err:
            print >>sys.stderr, err
            exit(1)

    def _def_entity(self, ent):
        # Only the predefined types are allowed to not have info
        assert ent.info or self._predefining
        assert ent.name not in self._entity_dict
        self._entity_dict[ent.name] = ent

@@ -1136,7 +1163,12 @@ 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))
        self._make_array_type(name)     # TODO really needed?
        # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
        # qapi-types.h from a single .c, all arrays of builtins must be
        # declared in the first file whether or not they are used.  Nicer
        # would be to use lazy instantiation, while figuring out how to
        # avoid compilation issues with multiple qapi-types.h.
        self._make_array_type(name, None)

    def _def_predefineds(self):
        for t in [('str',    'string',  'char' + pointer_suffix, 'NULL'),
@@ -1158,23 +1190,25 @@ class QAPISchema(object):
                                                          [], None)
        self._def_entity(self.the_empty_object_type)

    def _make_implicit_enum_type(self, name, values):
        name = name + 'Kind'
        self._def_entity(QAPISchemaEnumType(name, None, values, None))
    def _make_implicit_enum_type(self, name, info, values):
        name = name + 'Kind'   # Use namespace reserved by add_name()
        self._def_entity(QAPISchemaEnumType(name, info, values, None))
        return name

    def _make_array_type(self, element_type):
    def _make_array_type(self, element_type, info):
        # TODO fooList namespace is not reserved; user can create collisions,
        # or abuse our type system with ['fooList'] for 2D array
        name = element_type + 'List'
        if not self.lookup_type(name):
            self._def_entity(QAPISchemaArrayType(name, None, element_type))
            self._def_entity(QAPISchemaArrayType(name, info, element_type))
        return name

    def _make_implicit_object_type(self, name, role, members):
    def _make_implicit_object_type(self, name, info, 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,
            self._def_entity(QAPISchemaObjectType(name, info, None,
                                                  members, None))
        return name

@@ -1183,20 +1217,19 @@ class QAPISchema(object):
        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):
    def _make_member(self, name, typ, info):
        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])
            typ = self._make_array_type(typ[0], info)
        return QAPISchemaObjectTypeMember(name, typ, optional)

    def _make_members(self, data):
        return [self._make_member(key, value)
    def _make_members(self, data, info):
        return [self._make_member(key, value, info)
                for (key, value) in data.iteritems()]

    def _def_struct_type(self, expr, info):
@@ -1204,58 +1237,56 @@ class QAPISchema(object):
        base = expr.get('base')
        data = expr['data']
        self._def_entity(QAPISchemaObjectType(name, info, base,
                                              self._make_members(data),
                                              self._make_members(data, info),
                                              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):
    def _make_simple_variant(self, case, typ, info):
        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)])
            typ = self._make_array_type(typ[0], info)
        typ = self._make_implicit_object_type(
            typ, info, 'wrapper', [self._make_member('data', typ, info)])
        return QAPISchemaObjectTypeVariant(case, typ)

    def _make_tag_enum(self, type_name, variants):
        return self._make_implicit_enum_type(type_name,
    def _make_implicit_tag(self, type_name, info, variants):
        typ = self._make_implicit_enum_type(type_name, info,
                                            [v.name for v in variants])
        return QAPISchemaObjectTypeMember('type', typ, False)

    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
        tag_member = None
        if tag_name:
            variants = [self._make_variant(key, value)
                        for (key, value) in data.iteritems()]
        else:
            variants = [self._make_simple_variant(key, value)
            variants = [self._make_simple_variant(key, value, info)
                        for (key, value) in data.iteritems()]
            tag_enum = self._make_tag_enum(name, variants)
            tag_member = self._make_implicit_tag(name, info, variants)
        self._def_entity(
            QAPISchemaObjectType(name, info, base,
                                 self._make_members(OrderedDict()),
                                 self._make_members(OrderedDict(), info),
                                 QAPISchemaObjectTypeVariants(tag_name,
                                                              tag_enum,
                                                              tag_member,
                                                              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)
        tag_member = self._make_implicit_tag(name, info, variants)
        self._def_entity(
            QAPISchemaAlternateType(name, info,
                                    QAPISchemaObjectTypeVariants(None,
                                                                 tag_enum,
                                                                 tag_member,
                                                                 variants)))
        self._make_array_type(name)     # TODO really needed?

    def _def_command(self, expr, info):
        name = expr['command']
@@ -1264,11 +1295,11 @@ class QAPISchema(object):
        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))
            data = self._make_implicit_object_type(
                name, info, 'arg', self._make_members(data, info))
        if isinstance(rets, list):
            assert len(rets) == 1
            rets = self._make_array_type(rets[0])
            rets = self._make_array_type(rets[0], info)
        self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
                                           success_response))

@@ -1276,8 +1307,8 @@ class QAPISchema(object):
        name = expr['event']
        data = expr.get('data')
        if isinstance(data, OrderedDict):
            data = self._make_implicit_object_type(name, 'arg',
                                                   self._make_members(data))
            data = self._make_implicit_object_type(
                name, info, 'arg', self._make_members(data, info))
        self._def_entity(QAPISchemaEvent(name, info, data))

    def _def_exprs(self):
@@ -1304,10 +1335,10 @@ class QAPISchema(object):
            ent.check(self)

    def visit(self, visitor):
        ignore = visitor.visit_begin(self)
        for name in sorted(self._entity_dict.keys()):
            if not ignore or not isinstance(self._entity_dict[name], ignore):
                self._entity_dict[name].visit(visitor)
        visitor.visit_begin(self)
        for (name, entity) in sorted(self._entity_dict.items()):
            if visitor.visit_needed(entity):
                entity.visit(visitor)
        visitor.visit_end()


Loading