QAPI patches patches for 2021-09-03

-----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmEyPVESHGFybWJydUBy
 ZWRoYXQuY29tAAoJEDhwtADrkYZTu9UP+wawlxnMaxG3/3kkCT6g8i1poD+xTRSU
 Z64VK/aAtGy4K0Z/3KQpW2cNeO/bkhrMb8bwB3Nn/jfwqMav0CPVhLsrasXOu78u
 AM1nMVCGfcbqW5oINTdysWAI1z4cgsv8T8g3BOSUWAM4teKDx+Lkme/dSTOgAuE5
 6uixZZ53QUHuhY3K11mryQs/vWAWdzMBwy3Eawge6WEu48DnRH2C2wax+vb79LVa
 P/s7Bo4HKkJcPXfgyyzugd5NQCQ8uo6FIXEt2VHEThQIwHIHZC7lTn+VyzJAVlIO
 OnuayM5/5YTPxTFOrZgHwHZdBcmDwPKzNxvpayZZfh9lLVcqFhLY7SM4WxDQw8hF
 nJ0DCbUYV/JKrjv5ly0s1r7RfeXtAFBWLXWh4xlvuj2p6TdfXb6pjuxLlLdpLYfS
 qkeMteT21JEfE5U108d7AGDJ98HbQD+SXao90c8N6K1MsBh+jfifpgbcfcttOLoX
 +UItu6zOxZvDd/NO9m7JgE8o8Btd1uXK0PAwdK5V8xBf7TBgqk8FIQTPZo5SwYWI
 VUmtxc8f2NvsgLaHglXmouOXM5V2BgluW3iVmq/IIAcJo7qvFdPZnRG/BZ5bVuHG
 f6KQNRNUK3ef5rbMfMIusN7BNeCJr4yGXNr9WRhK5zP6I/AuP21kMrZ25Z+he2yV
 RhKNWF3BbSkv
 =rHX+
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-03' into staging

QAPI patches patches for 2021-09-03

# gpg: Signature made Fri 03 Sep 2021 16:20:49 BST
# gpg:                using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg:                issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2021-09-03:
  qapi: Tweak error messages for unknown / conflicting 'if' keys
  qapi: Tweak error messages for missing / conflicting meta-type
  tests/qapi-schema: Hide OrderedDict in test output
  qapi: Use re.fullmatch() where appropriate
  qapi: Use "not COND" instead of "!COND" for generated documentation
  qapi: Avoid redundant parens in code generated for conditionals
  qapi: Factor common recursion out of cgen_ifcond(), docgen_ifcond()
  qapi: Fix C code generation for 'if'
  tests/qapi-schema: Demonstrate broken C code for 'if'
  tests/qapi-schema: Correct two 'if' conditionals
  qapi: Simplify how QAPISchemaIfCond represents "no condition"
  qapi: Simplify QAPISchemaIfCond's interface for generating C
  qapi: Set boolean value correctly in examples

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-09-04 19:21:19 +01:00
commit 31ebff513f
19 changed files with 121 additions and 114 deletions

View File

@ -99,7 +99,7 @@
# Example: # Example:
# #
# -> { "execute": "trace-event-set-state", # -> { "execute": "trace-event-set-state",
# "arguments": { "name": "qemu_memalign", "enable": "true" } } # "arguments": { "name": "qemu_memalign", "enable": true } }
# <- { "return": {} } # <- { "return": {} }
# #
## ##

View File

@ -17,6 +17,7 @@ from typing import (
Dict, Dict,
Match, Match,
Optional, Optional,
Sequence,
Union, Union,
) )
@ -200,33 +201,39 @@ def guardend(name: str) -> str:
name=c_fname(name).upper()) name=c_fname(name).upper())
def cgen_ifcond(ifcond: Union[str, Dict[str, Any]]) -> str: def gen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]],
cond_fmt: str, not_fmt: str,
all_operator: str, any_operator: str) -> str:
def do_gen(ifcond: Union[str, Dict[str, Any]], need_parens: bool):
if isinstance(ifcond, str):
return cond_fmt % ifcond
assert isinstance(ifcond, dict) and len(ifcond) == 1
if 'not' in ifcond:
return not_fmt % do_gen(ifcond['not'], True)
if 'all' in ifcond:
gen = gen_infix(all_operator, ifcond['all'])
else:
gen = gen_infix(any_operator, ifcond['any'])
if need_parens:
gen = '(' + gen + ')'
return gen
def gen_infix(operator: str, operands: Sequence[Any]) -> str:
return operator.join([do_gen(o, True) for o in operands])
if not ifcond: if not ifcond:
return '' return ''
if isinstance(ifcond, str): return do_gen(ifcond, False)
return 'defined(' + ifcond + ')'
oper, operands = next(iter(ifcond.items()))
if oper == 'not':
return '!' + cgen_ifcond(operands)
oper = {'all': '&&', 'any': '||'}[oper]
operands = [cgen_ifcond(o) for o in operands]
return '(' + (') ' + oper + ' (').join(operands) + ')'
def docgen_ifcond(ifcond: Union[str, Dict[str, Any]]) -> str: def cgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str:
return gen_ifcond(ifcond, 'defined(%s)', '!%s', ' && ', ' || ')
def docgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str:
# TODO Doc generated for conditions needs polish # TODO Doc generated for conditions needs polish
if not ifcond: return gen_ifcond(ifcond, '%s', 'not %s', ' and ', ' or ')
return ''
if isinstance(ifcond, str):
return ifcond
oper, operands = next(iter(ifcond.items()))
if oper == 'not':
return '!' + docgen_ifcond(operands)
oper = {'all': ' and ', 'any': ' or '}[oper]
operands = [docgen_ifcond(o) for o in operands]
return '(' + oper.join(operands) + ')'
def gen_if(cond: str) -> str: def gen_if(cond: str) -> str:

View File

@ -275,7 +275,7 @@ def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
def _check_if(cond: Union[str, object]) -> None: def _check_if(cond: Union[str, object]) -> None:
if isinstance(cond, str): if isinstance(cond, str):
if not re.match(r'^[A-Z][A-Z0-9_]*$', cond): if not re.fullmatch(r'[A-Z][A-Z0-9_]*', cond):
raise QAPISemError( raise QAPISemError(
info, info,
"'if' condition '%s' of %s is not a valid identifier" "'if' condition '%s' of %s is not a valid identifier"
@ -286,13 +286,12 @@ def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
raise QAPISemError( raise QAPISemError(
info, info,
"'if' condition of %s must be a string or an object" % source) "'if' condition of %s must be a string or an object" % source)
check_keys(cond, info, "'if' condition of %s" % source, [],
["all", "any", "not"])
if len(cond) != 1: if len(cond) != 1:
raise QAPISemError( raise QAPISemError(
info, info,
"'if' condition dict of %s must have one key: " "'if' condition of %s has conflicting keys" % source)
"'all', 'any' or 'not'" % source)
check_keys(cond, info, "'if' condition", [],
["all", "any", "not"])
oper, operands = next(iter(cond.items())) oper, operands = next(iter(cond.items()))
if not operands: if not operands:
@ -630,20 +629,15 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
if 'include' in expr: if 'include' in expr:
continue continue
if 'enum' in expr: metas = expr.keys() & {'enum', 'struct', 'union', 'alternate',
meta = 'enum' 'command', 'event'}
elif 'union' in expr: if len(metas) != 1:
meta = 'union' raise QAPISemError(
elif 'alternate' in expr: info,
meta = 'alternate' "expression must have exactly one key"
elif 'struct' in expr: " 'enum', 'struct', 'union', 'alternate',"
meta = 'struct' " 'command', 'event'")
elif 'command' in expr: meta = metas.pop()
meta = 'command'
elif 'event' in expr:
meta = 'event'
else:
raise QAPISemError(info, "expression is missing metatype")
check_name_is_str(expr[meta], info, "'%s'" % meta) check_name_is_str(expr[meta], info, "'%s'" % meta)
name = cast(str, expr[meta]) name = cast(str, expr[meta])

View File

@ -24,8 +24,6 @@ from typing import (
from .common import ( from .common import (
c_fname, c_fname,
c_name, c_name,
gen_endif,
gen_if,
guardend, guardend,
guardstart, guardstart,
mcgen, mcgen,
@ -95,9 +93,9 @@ def _wrap_ifcond(ifcond: QAPISchemaIfCond, before: str, after: str) -> str:
if added[0] == '\n': if added[0] == '\n':
out += '\n' out += '\n'
added = added[1:] added = added[1:]
out += gen_if(ifcond.cgen()) out += ifcond.gen_if()
out += added out += added
out += gen_endif(ifcond.cgen()) out += ifcond.gen_endif()
return out return out

View File

@ -22,12 +22,7 @@ from typing import (
Union, Union,
) )
from .common import ( from .common import c_name, mcgen
c_name,
gen_endif,
gen_if,
mcgen,
)
from .gen import QAPISchemaMonolithicCVisitor from .gen import QAPISchemaMonolithicCVisitor
from .schema import ( from .schema import (
QAPISchema, QAPISchema,
@ -124,10 +119,10 @@ def _tree_to_qlit(obj: JSONValue,
if obj.comment: if obj.comment:
ret += indent(level) + f"/* {obj.comment} */\n" ret += indent(level) + f"/* {obj.comment} */\n"
if obj.ifcond.is_present(): if obj.ifcond.is_present():
ret += gen_if(obj.ifcond.cgen()) ret += obj.ifcond.gen_if()
ret += _tree_to_qlit(obj.value, level) ret += _tree_to_qlit(obj.value, level)
if obj.ifcond.is_present(): if obj.ifcond.is_present():
ret += '\n' + gen_endif(obj.ifcond.cgen()) ret += '\n' + obj.ifcond.gen_endif()
return ret return ret
ret = '' ret = ''

View File

@ -24,6 +24,8 @@ from .common import (
c_name, c_name,
cgen_ifcond, cgen_ifcond,
docgen_ifcond, docgen_ifcond,
gen_endif,
gen_if,
) )
from .error import QAPIError, QAPISemError, QAPISourceError from .error import QAPIError, QAPISemError, QAPISourceError
from .expr import check_exprs from .expr import check_exprs
@ -32,11 +34,17 @@ from .parser import QAPISchemaParser
class QAPISchemaIfCond: class QAPISchemaIfCond:
def __init__(self, ifcond=None): def __init__(self, ifcond=None):
self.ifcond = ifcond or {} self.ifcond = ifcond
def cgen(self): def _cgen(self):
return cgen_ifcond(self.ifcond) return cgen_ifcond(self.ifcond)
def gen_if(self):
return gen_if(self._cgen())
def gen_endif(self):
return gen_endif(self._cgen())
def docgen(self): def docgen(self):
return docgen_ifcond(self.ifcond) return docgen_ifcond(self.ifcond)

View File

@ -15,13 +15,7 @@ This work is licensed under the terms of the GNU GPL, version 2.
from typing import List, Optional from typing import List, Optional
from .common import ( from .common import c_enum_const, c_name, mcgen
c_enum_const,
c_name,
gen_endif,
gen_if,
mcgen,
)
from .gen import QAPISchemaModularCVisitor, ifcontext from .gen import QAPISchemaModularCVisitor, ifcontext
from .schema import ( from .schema import (
QAPISchema, QAPISchema,
@ -51,13 +45,13 @@ const QEnumLookup %(c_name)s_lookup = {
''', ''',
c_name=c_name(name)) c_name=c_name(name))
for memb in members: for memb in members:
ret += gen_if(memb.ifcond.cgen()) ret += memb.ifcond.gen_if()
index = c_enum_const(name, memb.name, prefix) index = c_enum_const(name, memb.name, prefix)
ret += mcgen(''' ret += mcgen('''
[%(index)s] = "%(name)s", [%(index)s] = "%(name)s",
''', ''',
index=index, name=memb.name) index=index, name=memb.name)
ret += gen_endif(memb.ifcond.cgen()) ret += memb.ifcond.gen_endif()
ret += mcgen(''' ret += mcgen('''
}, },
@ -81,12 +75,12 @@ typedef enum %(c_name)s {
c_name=c_name(name)) c_name=c_name(name))
for memb in enum_members: for memb in enum_members:
ret += gen_if(memb.ifcond.cgen()) ret += memb.ifcond.gen_if()
ret += mcgen(''' ret += mcgen('''
%(c_enum)s, %(c_enum)s,
''', ''',
c_enum=c_enum_const(name, memb.name, prefix)) c_enum=c_enum_const(name, memb.name, prefix))
ret += gen_endif(memb.ifcond.cgen()) ret += memb.ifcond.gen_endif()
ret += mcgen(''' ret += mcgen('''
} %(c_name)s; } %(c_name)s;
@ -126,7 +120,7 @@ struct %(c_name)s {
def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str: def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
ret = '' ret = ''
for memb in members: for memb in members:
ret += gen_if(memb.ifcond.cgen()) ret += memb.ifcond.gen_if()
if memb.optional: if memb.optional:
ret += mcgen(''' ret += mcgen('''
bool has_%(c_name)s; bool has_%(c_name)s;
@ -136,7 +130,7 @@ def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
%(c_type)s %(c_name)s; %(c_type)s %(c_name)s;
''', ''',
c_type=memb.type.c_type(), c_name=c_name(memb.name)) c_type=memb.type.c_type(), c_name=c_name(memb.name))
ret += gen_endif(memb.ifcond.cgen()) ret += memb.ifcond.gen_endif()
return ret return ret
@ -159,7 +153,7 @@ def gen_object(name: str, ifcond: QAPISchemaIfCond,
ret += mcgen(''' ret += mcgen('''
''') ''')
ret += gen_if(ifcond.cgen()) ret += ifcond.gen_if()
ret += mcgen(''' ret += mcgen('''
struct %(c_name)s { struct %(c_name)s {
''', ''',
@ -193,7 +187,7 @@ struct %(c_name)s {
ret += mcgen(''' ret += mcgen('''
}; };
''') ''')
ret += gen_endif(ifcond.cgen()) ret += ifcond.gen_endif()
return ret return ret
@ -220,13 +214,13 @@ def gen_variants(variants: QAPISchemaVariants) -> str:
for var in variants.variants: for var in variants.variants:
if var.type.name == 'q_empty': if var.type.name == 'q_empty':
continue continue
ret += gen_if(var.ifcond.cgen()) ret += var.ifcond.gen_if()
ret += mcgen(''' ret += mcgen('''
%(c_type)s %(c_name)s; %(c_type)s %(c_name)s;
''', ''',
c_type=var.type.c_unboxed_type(), c_type=var.type.c_unboxed_type(),
c_name=c_name(var.name)) c_name=c_name(var.name))
ret += gen_endif(var.ifcond.cgen()) ret += var.ifcond.gen_endif()
ret += mcgen(''' ret += mcgen('''
} u; } u;

View File

@ -18,8 +18,6 @@ from typing import List, Optional
from .common import ( from .common import (
c_enum_const, c_enum_const,
c_name, c_name,
gen_endif,
gen_if,
indent, indent,
mcgen, mcgen,
) )
@ -79,7 +77,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
for memb in members: for memb in members:
deprecated = 'deprecated' in [f.name for f in memb.features] deprecated = 'deprecated' in [f.name for f in memb.features]
ret += gen_if(memb.ifcond.cgen()) ret += memb.ifcond.gen_if()
if memb.optional: if memb.optional:
ret += mcgen(''' ret += mcgen('''
if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) { if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
@ -112,7 +110,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
ret += mcgen(''' ret += mcgen('''
} }
''') ''')
ret += gen_endif(memb.ifcond.cgen()) ret += memb.ifcond.gen_endif()
if variants: if variants:
tag_member = variants.tag_member tag_member = variants.tag_member
@ -126,7 +124,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
for var in variants.variants: for var in variants.variants:
case_str = c_enum_const(tag_member.type.name, var.name, case_str = c_enum_const(tag_member.type.name, var.name,
tag_member.type.prefix) tag_member.type.prefix)
ret += gen_if(var.ifcond.cgen()) ret += var.ifcond.gen_if()
if var.type.name == 'q_empty': if var.type.name == 'q_empty':
# valid variant and nothing to do # valid variant and nothing to do
ret += mcgen(''' ret += mcgen('''
@ -142,7 +140,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
case=case_str, case=case_str,
c_type=var.type.c_name(), c_name=c_name(var.name)) c_type=var.type.c_name(), c_name=c_name(var.name))
ret += gen_endif(var.ifcond.cgen()) ret += var.ifcond.gen_endif()
ret += mcgen(''' ret += mcgen('''
default: default:
abort(); abort();
@ -228,7 +226,7 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name,
c_name=c_name(name)) c_name=c_name(name))
for var in variants.variants: for var in variants.variants:
ret += gen_if(var.ifcond.cgen()) ret += var.ifcond.gen_if()
ret += mcgen(''' ret += mcgen('''
case %(case)s: case %(case)s:
''', ''',
@ -254,7 +252,7 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name,
ret += mcgen(''' ret += mcgen('''
break; break;
''') ''')
ret += gen_endif(var.ifcond.cgen()) ret += var.ifcond.gen_endif()
ret += mcgen(''' ret += mcgen('''
case QTYPE_NONE: case QTYPE_NONE:

View File

@ -1,3 +1,3 @@
bad-if-key.json: In struct 'TestIfStruct': bad-if-key.json: In struct 'TestIfStruct':
bad-if-key.json:2: 'if' condition has unknown key 'value' bad-if-key.json:2: 'if' condition of struct has unknown key 'value'
Valid keys are 'all', 'any', 'not'. Valid keys are 'all', 'any', 'not'.

View File

@ -1,2 +1,2 @@
bad-if-keys.json: In struct 'TestIfStruct': bad-if-keys.json: In struct 'TestIfStruct':
bad-if-keys.json:2: 'if' condition dict of struct must have one key: 'all', 'any' or 'not' bad-if-keys.json:2: 'if' condition of struct has conflicting keys

View File

@ -127,7 +127,7 @@
{ 'alternate': 'Alternate', { 'alternate': 'Alternate',
'features': [ 'alt-feat' ], 'features': [ 'alt-feat' ],
'data': { 'i': 'int', 'b': 'bool' }, 'data': { 'i': 'int', 'b': 'bool' },
'if': { 'not': 'IFNOT' } } 'if': { 'not': { 'any': [ 'IFONE', 'IFTWO' ] } } }
## ##
# == Another subsection # == Another subsection

View File

@ -18,7 +18,7 @@ enum Enum
feature enum-feat feature enum-feat
object Base object Base
member base1: Enum optional=False member base1: Enum optional=False
if OrderedDict([('all', ['IFALL1', 'IFALL2'])]) if {'all': ['IFALL1', 'IFALL2']}
object Variant1 object Variant1
member var1: str optional=False member var1: str optional=False
if IFSTR if IFSTR
@ -30,7 +30,7 @@ object Object
tag base1 tag base1
case one: Variant1 case one: Variant1
case two: Variant2 case two: Variant2
if OrderedDict([('any', ['IFONE', 'IFTWO'])]) if {'any': ['IFONE', 'IFTWO']}
feature union-feat1 feature union-feat1
object q_obj_Variant1-wrapper object q_obj_Variant1-wrapper
member data: Variant1 optional=False member data: Variant1 optional=False
@ -51,7 +51,7 @@ alternate Alternate
tag type tag type
case i: int case i: int
case b: bool case b: bool
if OrderedDict([('not', 'IFNOT')]) if {'not': {'any': ['IFONE', 'IFTWO']}}
feature alt-feat feature alt-feat
object q_obj_cmd-arg object q_obj_cmd-arg
member arg1: int optional=False member arg1: int optional=False

View File

@ -79,7 +79,7 @@ Members
If If
~~ ~~
"(IFALL1 and IFALL2)" "IFALL1 and IFALL2"
"Variant1" (Object) "Variant1" (Object)
@ -120,8 +120,8 @@ Members
The members of "Base" The members of "Base"
The members of "Variant1" when "base1" is ""one"" The members of "Variant1" when "base1" is ""one""
The members of "Variant2" when "base1" is ""two"" (**If: **"(IFONE or The members of "Variant2" when "base1" is ""two"" (**If: **"IFONE or
IFTWO)") IFTWO")
Features Features
~~~~~~~~ ~~~~~~~~
@ -174,7 +174,7 @@ Features
If If
~~ ~~
"!IFNOT" "not (IFONE or IFTWO)"
Another subsection Another subsection

View File

@ -1,3 +1 @@
double-type.json: In struct 'Bar': double-type.json:2: expression must have exactly one key 'enum', 'struct', 'union', 'alternate', 'command', 'event'
double-type.json:2: struct has unknown key 'command'
Valid keys are 'base', 'data', 'features', 'if', 'struct'.

View File

@ -1,3 +1,3 @@
enum-if-invalid.json: In enum 'TestIfEnum': enum-if-invalid.json: In enum 'TestIfEnum':
enum-if-invalid.json:2: 'if' condition has unknown key 'val' enum-if-invalid.json:2: 'if' condition of 'data' member 'bar' has unknown key 'val'
Valid keys are 'all', 'any', 'not'. Valid keys are 'all', 'any', 'not'.

View File

@ -1 +1 @@
missing-type.json:2: expression is missing metatype missing-type.json:2: expression must have exactly one key 'enum', 'struct', 'union', 'alternate', 'command', 'event'

View File

@ -236,7 +236,7 @@
{ 'command': 'test-if-union-cmd', { 'command': 'test-if-union-cmd',
'data': { 'union-cmd-arg': 'TestIfUnion' }, 'data': { 'union-cmd-arg': 'TestIfUnion' },
'if': 'TEST_IF_UNION' } 'if': { 'all': ['TEST_IF_UNION', 'TEST_IF_STRUCT'] } }
{ 'alternate': 'TestIfAlternate', 'data': { 'alternate': 'TestIfAlternate', 'data':
{ 'foo': 'int', { 'foo': 'int',
@ -245,8 +245,7 @@
{ 'command': 'test-if-alternate-cmd', { 'command': 'test-if-alternate-cmd',
'data': { 'alt-cmd-arg': 'TestIfAlternate' }, 'data': { 'alt-cmd-arg': 'TestIfAlternate' },
'if': { 'all': ['TEST_IF_ALT', 'if': { 'all': ['TEST_IF_ALT', 'TEST_IF_STRUCT'] } }
{'not': 'TEST_IF_NOT_ALT'}] } }
{ 'command': 'test-if-cmd', { 'command': 'test-if-cmd',
'data': { 'data': {
@ -262,6 +261,10 @@
'bar': { 'type': ['TestIfEnum'], 'if': 'TEST_IF_EVT_BAR' } }, 'bar': { 'type': ['TestIfEnum'], 'if': 'TEST_IF_EVT_BAR' } },
'if': { 'all': ['TEST_IF_EVT', 'TEST_IF_STRUCT'] } } 'if': { 'all': ['TEST_IF_EVT', 'TEST_IF_STRUCT'] } }
{ 'event': 'TEST_IF_EVENT2', 'data': {},
'if': { 'not': { 'any': [ { 'not': 'TEST_IF_EVT' },
{ 'not': 'TEST_IF_STRUCT' } ] } } }
# test 'features' # test 'features'
{ 'struct': 'FeatureStruct0', { 'struct': 'FeatureStruct0',

View File

@ -311,40 +311,40 @@ enum TestIfUnionKind
member foo member foo
member bar member bar
if TEST_IF_UNION_BAR if TEST_IF_UNION_BAR
if OrderedDict([('all', ['TEST_IF_UNION', 'TEST_IF_STRUCT'])]) if {'all': ['TEST_IF_UNION', 'TEST_IF_STRUCT']}
object TestIfUnion object TestIfUnion
member type: TestIfUnionKind optional=False member type: TestIfUnionKind optional=False
tag type tag type
case foo: q_obj_TestStruct-wrapper case foo: q_obj_TestStruct-wrapper
case bar: q_obj_str-wrapper case bar: q_obj_str-wrapper
if TEST_IF_UNION_BAR if TEST_IF_UNION_BAR
if OrderedDict([('all', ['TEST_IF_UNION', 'TEST_IF_STRUCT'])]) if {'all': ['TEST_IF_UNION', 'TEST_IF_STRUCT']}
object q_obj_test-if-union-cmd-arg object q_obj_test-if-union-cmd-arg
member union-cmd-arg: TestIfUnion optional=False member union-cmd-arg: TestIfUnion optional=False
if TEST_IF_UNION if {'all': ['TEST_IF_UNION', 'TEST_IF_STRUCT']}
command test-if-union-cmd q_obj_test-if-union-cmd-arg -> None command test-if-union-cmd q_obj_test-if-union-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
if TEST_IF_UNION if {'all': ['TEST_IF_UNION', 'TEST_IF_STRUCT']}
alternate TestIfAlternate alternate TestIfAlternate
tag type tag type
case foo: int case foo: int
case bar: TestStruct case bar: TestStruct
if TEST_IF_ALT_BAR if TEST_IF_ALT_BAR
if OrderedDict([('all', ['TEST_IF_ALT', 'TEST_IF_STRUCT'])]) if {'all': ['TEST_IF_ALT', 'TEST_IF_STRUCT']}
object q_obj_test-if-alternate-cmd-arg object q_obj_test-if-alternate-cmd-arg
member alt-cmd-arg: TestIfAlternate optional=False member alt-cmd-arg: TestIfAlternate optional=False
if OrderedDict([('all', ['TEST_IF_ALT', OrderedDict([('not', 'TEST_IF_NOT_ALT')])])]) if {'all': ['TEST_IF_ALT', 'TEST_IF_STRUCT']}
command test-if-alternate-cmd q_obj_test-if-alternate-cmd-arg -> None command test-if-alternate-cmd q_obj_test-if-alternate-cmd-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
if OrderedDict([('all', ['TEST_IF_ALT', OrderedDict([('not', 'TEST_IF_NOT_ALT')])])]) if {'all': ['TEST_IF_ALT', 'TEST_IF_STRUCT']}
object q_obj_test-if-cmd-arg object q_obj_test-if-cmd-arg
member foo: TestIfStruct optional=False member foo: TestIfStruct optional=False
member bar: TestIfEnum optional=False member bar: TestIfEnum optional=False
if TEST_IF_CMD_BAR if TEST_IF_CMD_BAR
if OrderedDict([('all', ['TEST_IF_CMD', 'TEST_IF_STRUCT'])]) if {'all': ['TEST_IF_CMD', 'TEST_IF_STRUCT']}
command test-if-cmd q_obj_test-if-cmd-arg -> UserDefThree command test-if-cmd q_obj_test-if-cmd-arg -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
if OrderedDict([('all', ['TEST_IF_CMD', 'TEST_IF_STRUCT'])]) if {'all': ['TEST_IF_CMD', 'TEST_IF_STRUCT']}
command test-cmd-return-def-three None -> UserDefThree command test-cmd-return-def-three None -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
array TestIfEnumList TestIfEnum array TestIfEnumList TestIfEnum
@ -353,10 +353,13 @@ object q_obj_TEST_IF_EVENT-arg
member foo: TestIfStruct optional=False member foo: TestIfStruct optional=False
member bar: TestIfEnumList optional=False member bar: TestIfEnumList optional=False
if TEST_IF_EVT_BAR if TEST_IF_EVT_BAR
if OrderedDict([('all', ['TEST_IF_EVT', 'TEST_IF_STRUCT'])]) if {'all': ['TEST_IF_EVT', 'TEST_IF_STRUCT']}
event TEST_IF_EVENT q_obj_TEST_IF_EVENT-arg event TEST_IF_EVENT q_obj_TEST_IF_EVENT-arg
boxed=False boxed=False
if OrderedDict([('all', ['TEST_IF_EVT', 'TEST_IF_STRUCT'])]) if {'all': ['TEST_IF_EVT', 'TEST_IF_STRUCT']}
event TEST_IF_EVENT2 None
boxed=False
if {'not': {'any': [{'not': 'TEST_IF_EVT'}, {'not': 'TEST_IF_STRUCT'}]}}
object FeatureStruct0 object FeatureStruct0
member foo: int optional=False member foo: int optional=False
object FeatureStruct1 object FeatureStruct1
@ -389,11 +392,11 @@ object CondFeatureStruct2
object CondFeatureStruct3 object CondFeatureStruct3
member foo: int optional=False member foo: int optional=False
feature feature1 feature feature1
if OrderedDict([('all', ['TEST_IF_COND_1', 'TEST_IF_COND_2'])]) if {'all': ['TEST_IF_COND_1', 'TEST_IF_COND_2']}
object CondFeatureStruct4 object CondFeatureStruct4
member foo: int optional=False member foo: int optional=False
feature feature1 feature feature1
if OrderedDict([('any', ['TEST_IF_COND_1', 'TEST_IF_COND_2'])]) if {'any': ['TEST_IF_COND_1', 'TEST_IF_COND_2']}
enum FeatureEnum1 enum FeatureEnum1
member eins member eins
member zwei member zwei
@ -444,7 +447,7 @@ command test-command-cond-features2 None -> None
command test-command-cond-features3 None -> None command test-command-cond-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1 feature feature1
if OrderedDict([('all', ['TEST_IF_COND_1', 'TEST_IF_COND_2'])]) if {'all': ['TEST_IF_COND_1', 'TEST_IF_COND_2']}
event TEST_EVENT_FEATURES0 FeatureStruct1 event TEST_EVENT_FEATURES0 FeatureStruct1
boxed=False boxed=False
event TEST_EVENT_FEATURES1 None event TEST_EVENT_FEATURES1 None

View File

@ -94,8 +94,17 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
@staticmethod @staticmethod
def _print_if(ifcond, indent=4): def _print_if(ifcond, indent=4):
# TODO Drop this hack after replacing OrderedDict by plain
# dict (requires Python 3.7)
def _massage(subcond):
if isinstance(subcond, str):
return subcond
if isinstance(subcond, list):
return [_massage(val) for val in subcond]
return {key: _massage(val) for key, val in subcond.items()}
if ifcond.is_present(): if ifcond.is_present():
print('%sif %s' % (' ' * indent, ifcond.ifcond)) print('%sif %s' % (' ' * indent, _massage(ifcond.ifcond)))
@classmethod @classmethod
def _print_features(cls, features, indent=4): def _print_features(cls, features, indent=4):