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

qapi: add 'if' to top-level expressions



Accept 'if' key in top-level elements, accepted as string or list of
string type. The following patches will modify the test visitor to
check the value is correctly saved, and generate #if/#endif code (as a
single #if/endif line or a series for a list).

Example of 'if' key:
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
  'if': 'defined(TEST_IF_STRUCT)' }

The generated code is for now *unconditional*. Later patches generate
the conditionals.

Signed-off-by: default avatarMarc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: default avatarMarkus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-2-marcandre.lureau@redhat.com>
[Commit message and Documentation improved]
Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
parent b07cd3e7
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -744,6 +744,35 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a
downstream command __com.redhat_drive-mirror.


=== Configuring the schema ===

The 'struct', 'enum', 'union', 'alternate', 'command' and 'event'
top-level expressions can take an 'if' key.  Its value must be a string
or a list of strings.  A string is shorthand for a list containing just
that string.  The code generated for the top-level expression will then
be guarded by #if COND for each COND in the list.

Example: a conditional struct

 { 'struct': 'IfStruct', 'data': { 'foo': 'int' },
   'if': ['defined(CONFIG_FOO)', 'defined(HAVE_BAR)'] }

gets its generated code guarded like this:

 #if defined(CONFIG_FOO)
 #if defined(HAVE_BAR)
 ... generated code ...
 #endif /* defined(HAVE_BAR) */
 #endif /* defined(CONFIG_FOO) */

Please note that you are responsible to ensure that the C code will
compile with an arbitrary combination of conditions, since the
generators are unable to check it at this point.

The presence of 'if' keys in the schema is reflected through to the
introspection output depending on the build configuration.


== Client JSON Protocol introspection ==

Clients of a Client JSON Protocol commonly need to figure out what
+29 −6
Original line number Diff line number Diff line
@@ -638,6 +638,27 @@ def add_name(name, info, meta, implicit=False):
    all_names[name] = meta


def check_if(expr, info):

    def check_if_str(ifcond, info):
        if not isinstance(ifcond, str):
            raise QAPISemError(
                info, "'if' condition must be a string or a list of strings")
        if ifcond == '':
            raise QAPISemError(info, "'if' condition '' makes no sense")

    ifcond = expr.get('if')
    if ifcond is None:
        return
    if isinstance(ifcond, list):
        if ifcond == []:
            raise QAPISemError(info, "'if' condition [] is useless")
        for elt in ifcond:
            check_if_str(elt, info)
    else:
        check_if_str(ifcond, info)


def check_type(info, source, value, allow_array=False,
               allow_dict=False, allow_optional=False,
               allow_metas=[]):
@@ -871,6 +892,8 @@ def check_keys(expr_elem, meta, required, optional=[]):
            raise QAPISemError(info,
                               "'%s' of %s '%s' should only use true value"
                               % (key, meta, name))
        if key == 'if':
            check_if(expr, info)
    for key in required:
        if key not in expr:
            raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
@@ -899,28 +922,28 @@ def check_exprs(exprs):

        if 'enum' in expr:
            meta = 'enum'
            check_keys(expr_elem, 'enum', ['data'], ['prefix'])
            check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
            enum_types[expr[meta]] = expr
        elif 'union' in expr:
            meta = 'union'
            check_keys(expr_elem, 'union', ['data'],
                       ['base', 'discriminator'])
                       ['base', 'discriminator', 'if'])
            union_types[expr[meta]] = expr
        elif 'alternate' in expr:
            meta = 'alternate'
            check_keys(expr_elem, 'alternate', ['data'])
            check_keys(expr_elem, 'alternate', ['data'], ['if'])
        elif 'struct' in expr:
            meta = 'struct'
            check_keys(expr_elem, 'struct', ['data'], ['base'])
            check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
            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'])
                        'boxed', 'allow-oob', 'allow-preconfig', 'if'])
        elif 'event' in expr:
            meta = 'event'
            check_keys(expr_elem, 'event', [], ['data', 'boxed'])
            check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
        else:
            raise QAPISemError(expr_elem['info'],
                               "Expression is missing metatype")
+4 −0
Original line number Diff line number Diff line
@@ -442,6 +442,10 @@ qapi-schema += args-unknown.json
qapi-schema += bad-base.json
qapi-schema += bad-data.json
qapi-schema += bad-ident.json
qapi-schema += bad-if.json
qapi-schema += bad-if-empty.json
qapi-schema += bad-if-empty-list.json
qapi-schema += bad-if-list.json
qapi-schema += bad-type-bool.json
qapi-schema += bad-type-dict.json
qapi-schema += bad-type-int.json
+1 −0
Original line number Diff line number Diff line
tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
+1 −0
Original line number Diff line number Diff line
1
Loading