Commit 87adbbff authored by Marc-André Lureau's avatar Marc-André Lureau Committed by Markus Armbruster
Browse files

qapi: add a dictionary form for TYPE



Wherever a struct/union/alternate/command/event member with NAME: TYPE
form is accepted, desugar it to a NAME: { 'type': TYPE } form.

This will allow to add new member details, such as 'if' in the
following patch to introduce conditionals, or 'default' for default
values etc.

Signed-off-by: default avatarMarc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20181213123724.4866-13-marcandre.lureau@redhat.com>
Reviewed-by: default avatarMarkus Armbruster <armbru@redhat.com>
Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
parent 7bd26349
Loading
Loading
Loading
Loading
+46 −24
Original line number Diff line number Diff line
@@ -588,11 +588,11 @@ def discriminator_find_enum_define(expr):
    if not base_members:
        return None

    discriminator_type = base_members.get(discriminator)
    if not discriminator_type:
    discriminator_value = base_members.get(discriminator)
    if not discriminator_value:
        return None

    return enum_types.get(discriminator_type)
    return enum_types.get(discriminator_value['type'])


# Names must be letters, numbers, -, and _.  They must start with letter,
@@ -704,8 +704,10 @@ def check_type(info, source, value, allow_array=False,
                               % (source, key))
        # Todo: allow dictionaries to represent default values of
        # an optional argument.
        check_type(info, "Member '%s' of %s" % (key, source), arg,
                   allow_array=True,
        check_known_keys(info, "member '%s' of %s" % (key, source),
                         arg, ['type'], [])
        check_type(info, "Member '%s' of %s" % (key, source),
                   arg['type'], allow_array=True,
                   allow_metas=['built-in', 'union', 'alternate', 'struct',
                                'enum'])

@@ -776,13 +778,13 @@ def check_union(expr, info):
        # member of the base struct.
        check_name(info, "Discriminator of flat union '%s'" % name,
                   discriminator)
        discriminator_type = base_members.get(discriminator)
        if not discriminator_type:
        discriminator_value = base_members.get(discriminator)
        if not discriminator_value:
            raise QAPISemError(info,
                               "Discriminator '%s' is not a member of base "
                               "struct '%s'"
                               % (discriminator, base))
        enum_define = enum_types.get(discriminator_type)
        enum_define = enum_types.get(discriminator_value['type'])
        allow_metas = ['struct']
        # Do not allow string discriminator
        if not enum_define:
@@ -796,9 +798,12 @@ def check_union(expr, info):
    for (key, value) in members.items():
        check_name(info, "Member of union '%s'" % name, key)

        check_known_keys(info, "member '%s' of union '%s'" % (key, name),
                         value, ['type'], [])
        # Each value must name a known type
        check_type(info, "Member '%s' of union '%s'" % (key, name),
                   value, allow_array=not base, allow_metas=allow_metas)
                   value['type'],
                   allow_array=not base, allow_metas=allow_metas)

        # If the discriminator names an enum type, then all members
        # of 'data' must also be members of the enum type.
@@ -822,18 +827,21 @@ def check_alternate(expr, info):
                           "in 'data'" % name)
    for (key, value) in members.items():
        check_name(info, "Member of alternate '%s'" % name, key)
        check_known_keys(info,
                         "member '%s' of alternate '%s'" % (key, name),
                         value, ['type'], [])
        typ = value['type']

        # Ensure alternates have no type conflicts.
        check_type(info, "Member '%s' of alternate '%s'" % (key, name),
                   value,
        check_type(info, "Member '%s' of alternate '%s'" % (key, name), typ,
                   allow_metas=['built-in', 'union', 'struct', 'enum'])
        qtype = find_alternate_member_qtype(value)
        qtype = find_alternate_member_qtype(typ)
        if not qtype:
            raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
                               "type '%s'" % (name, key, value))
                               "type '%s'" % (name, key, typ))
        conflicting = set([qtype])
        if qtype == 'QTYPE_QSTRING':
            enum_expr = enum_types.get(value)
            enum_expr = enum_types.get(typ)
            if enum_expr:
                for v in enum_get_names(enum_expr):
                    if v in ['on', 'off']:
@@ -851,12 +859,6 @@ def check_alternate(expr, info):
            types_seen[qt] = key


def normalize_enum(expr):
    if isinstance(expr['data'], list):
        expr['data'] = [m if isinstance(m, dict) else {'name': m}
                        for m in expr['data']]


def check_enum(expr, info):
    name = expr['enum']
    members = expr['data']
@@ -928,6 +930,20 @@ def check_keys(expr_elem, meta, required, optional=[]):
            check_if(expr, info)


def normalize_enum(expr):
    if isinstance(expr['data'], list):
        expr['data'] = [m if isinstance(m, dict) else {'name': m}
                        for m in expr['data']]


def normalize_members(members):
    if isinstance(members, OrderedDict):
        for key, arg in members.items():
            if isinstance(arg, dict):
                continue
            members[key] = {'type': arg}


def check_exprs(exprs):
    global all_names

@@ -957,22 +973,28 @@ def check_exprs(exprs):
            meta = 'union'
            check_keys(expr_elem, 'union', ['data'],
                       ['base', 'discriminator', 'if'])
            normalize_members(expr.get('base'))
            normalize_members(expr['data'])
            union_types[expr[meta]] = expr
        elif 'alternate' in expr:
            meta = 'alternate'
            check_keys(expr_elem, 'alternate', ['data'], ['if'])
            normalize_members(expr['data'])
        elif 'struct' in expr:
            meta = 'struct'
            check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
            normalize_members(expr['data'])
            struct_types[expr[meta]] = expr
        elif 'command' in expr:
            meta = 'command'
            check_keys(expr_elem, 'command', [],
                       ['data', 'returns', 'gen', 'success-response',
                        'boxed', 'allow-oob', 'allow-preconfig', 'if'])
            normalize_members(expr.get('data'))
        elif 'event' in expr:
            meta = 'event'
            check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
            normalize_members(expr.get('data'))
        else:
            raise QAPISemError(expr_elem['info'],
                               "Expression is missing metatype")
@@ -1716,7 +1738,7 @@ class QAPISchema(object):
        return QAPISchemaObjectTypeMember(name, typ, optional)

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

    def _def_struct_type(self, expr, info, doc):
@@ -1752,11 +1774,11 @@ class QAPISchema(object):
                name, info, doc, ifcond,
                'base', self._make_members(base, info))
        if tag_name:
            variants = [self._make_variant(key, value)
            variants = [self._make_variant(key, value['type'])
                        for (key, value) in data.items()]
            members = []
        else:
            variants = [self._make_simple_variant(key, value, info)
            variants = [self._make_simple_variant(key, value['type'], info)
                        for (key, value) in data.items()]
            enum = [{'name': v.name} for v in variants]
            typ = self._make_implicit_enum_type(name, info, ifcond, enum)
@@ -1772,7 +1794,7 @@ class QAPISchema(object):
        name = expr['alternate']
        data = expr['data']
        ifcond = expr.get('if')
        variants = [self._make_variant(key, value)
        variants = [self._make_variant(key, value['type'])
                    for (key, value) in data.items()]
        tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
        self._def_entity(
+6 −0
Original line number Diff line number Diff line
@@ -318,6 +318,7 @@ qapi-schema += alternate-conflict-string.json
qapi-schema += alternate-conflict-bool-string.json
qapi-schema += alternate-conflict-num-string.json
qapi-schema += alternate-empty.json
qapi-schema += alternate-invalid-dict.json
qapi-schema += alternate-nested.json
qapi-schema += alternate-unknown.json
qapi-schema += args-alternate.json
@@ -394,6 +395,7 @@ qapi-schema += escape-too-big.json
qapi-schema += escape-too-short.json
qapi-schema += event-boxed-empty.json
qapi-schema += event-case.json
qapi-schema += event-member-invalid-dict.json
qapi-schema += event-nest-struct.json
qapi-schema += flat-union-array-branch.json
qapi-schema += flat-union-bad-base.json
@@ -403,6 +405,7 @@ qapi-schema += flat-union-base-union.json
qapi-schema += flat-union-clash-member.json
qapi-schema += flat-union-empty.json
qapi-schema += flat-union-inline.json
qapi-schema += flat-union-inline-invalid-dict.json
qapi-schema += flat-union-int-branch.json
qapi-schema += flat-union-invalid-branch-key.json
qapi-schema += flat-union-invalid-discriminator.json
@@ -430,6 +433,7 @@ qapi-schema += missing-comma-list.json
qapi-schema += missing-comma-object.json
qapi-schema += missing-type.json
qapi-schema += nested-struct-data.json
qapi-schema += nested-struct-data-invalid-dict.json
qapi-schema += non-objects.json
qapi-schema += oob-test.json
qapi-schema += allow-preconfig-test.json
@@ -460,6 +464,7 @@ qapi-schema += returns-whitelist.json
qapi-schema += struct-base-clash-deep.json
qapi-schema += struct-base-clash.json
qapi-schema += struct-data-invalid.json
qapi-schema += struct-member-invalid-dict.json
qapi-schema += struct-member-invalid.json
qapi-schema += trailing-comma-list.json
qapi-schema += trailing-comma-object.json
@@ -471,6 +476,7 @@ qapi-schema += unicode-str.json
qapi-schema += union-base-empty.json
qapi-schema += union-base-no-discriminator.json
qapi-schema += union-branch-case.json
qapi-schema += union-branch-invalid-dict.json
qapi-schema += union-clash-branches.json
qapi-schema += union-empty.json
qapi-schema += union-invalid-base.json
+1 −0
Original line number Diff line number Diff line
tests/qapi-schema/alternate-invalid-dict.json:2: Key 'type' is missing from member 'two' of alternate 'Alt'
+1 −0
Original line number Diff line number Diff line
1
+4 −0
Original line number Diff line number Diff line
# exploded member form must have a 'type'
{ 'alternate': 'Alt',
  'data': { 'one': 'str',
            'two': { 'if': 'foo' } } }
Loading