qapi: add 'not' condition operation
authorMarc-André Lureau <marcandre.lureau@redhat.com>
Wed, 4 Aug 2021 08:31:04 +0000 (12:31 +0400)
committerMarkus Armbruster <armbru@redhat.com>
Thu, 26 Aug 2021 11:53:56 +0000 (13:53 +0200)
For the sake of completeness, introduce the 'not' condition.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20210804083105.97531-10-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Long line broken in tests/qapi-schema/qapi-schema-test.json]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
scripts/qapi/common.py
scripts/qapi/expr.py
tests/qapi-schema/bad-if-key.err
tests/qapi-schema/bad-if-keys.err
tests/qapi-schema/doc-good.json
tests/qapi-schema/doc-good.out
tests/qapi-schema/doc-good.txt
tests/qapi-schema/enum-if-invalid.err
tests/qapi-schema/qapi-schema-test.json
tests/qapi-schema/qapi-schema-test.out

index 63a2e502fbe12a6cad1a8c6cc20db99c64d3f006..3fb2fbe7d4f2b57cf6bcd8c14b210d9d63311957 100644 (file)
@@ -207,6 +207,8 @@ def cgen_ifcond(ifcond: Union[str, Dict[str, Any]]) -> str:
         return 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) + ')'
@@ -220,6 +222,8 @@ def docgen_ifcond(ifcond: Union[str, Dict[str, Any]]) -> 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) + ')'
index f3ce10fb3ecf0f24b0627ac2f45e2b6bef034bb5..120b31089f8427ee62aaa980dbcabdb2ddd42a60 100644 (file)
@@ -290,15 +290,18 @@ def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
             raise QAPISemError(
                 info,
                 "'if' condition dict of %s must have one key: "
-                "'all' or 'any'" % source)
+                "'all', 'any' or 'not'" % source)
         check_keys(cond, info, "'if' condition", [],
-                   ["all", "any"])
+                   ["all", "any", "not"])
 
         oper, operands = next(iter(cond.items()))
         if not operands:
             raise QAPISemError(
                 info, "'if' condition [] of %s is useless" % source)
 
+        if oper == "not":
+            _check_if(operands)
+            return
         if oper in ("all", "any") and not isinstance(operands, list):
             raise QAPISemError(
                 info, "'%s' condition of %s must be an array" % (oper, source))
index 7236f46e7aa86c7947d14e20d167f585612832e8..a69dc9ee86e21e2cc9acbf6a3ed02aaf6021d96e 100644 (file)
@@ -1,3 +1,3 @@
 bad-if-key.json: In struct 'TestIfStruct':
 bad-if-key.json:2: 'if' condition has unknown key 'value'
-Valid keys are 'all', 'any'.
+Valid keys are 'all', 'any', 'not'.
index db6d019d779667b9680b2c65b9316ead4819e64e..aceb31dc6dde20d2da0f91160ff2e9782d87771f 100644 (file)
@@ -1,2 +1,2 @@
 bad-if-keys.json: In struct 'TestIfStruct':
-bad-if-keys.json:2: 'if' condition dict of struct must have one key: 'all' or 'any'
+bad-if-keys.json:2: 'if' condition dict of struct must have one key: 'all', 'any' or 'not'
index e253d89ee065d8e964830d26f04c6d2cd0b3e615..2a35c679a491ee65bb3ecda60d86e25257998600 100644 (file)
 ##
 { 'alternate': 'Alternate',
   'features': [ 'alt-feat' ],
-  'data': { 'i': 'int', 'b': 'bool' } }
+  'data': { 'i': 'int', 'b': 'bool' },
+  'if': { 'not': 'IFNOT' } }
 
 ##
 # == Another subsection
index c44c346ec8d005b46406dfeb3bb7d8966923b2fc..a8871e8f99dc898f8ca3fbcc902fdd46a0f1a750 100644 (file)
@@ -51,6 +51,7 @@ alternate Alternate
     tag type
     case i: int
     case b: bool
+    if OrderedDict([('not', 'IFNOT')])
     feature alt-feat
 object q_obj_cmd-arg
     member arg1: int optional=False
index 251e9b746c4a9ca48dc328a19f356c43fb0add70..03c98c4182e07296692a92da481e4ce57996be7a 100644 (file)
@@ -171,6 +171,12 @@ Features
    a feature
 
 
+If
+~~
+
+"!IFNOT"
+
+
 Another subsection
 ==================
 
index b96d94c48a5ac1f54c5728969dcd50c4289960bc..3bb84075a90f1a7aa45e882f5693f1ee9dfe4aae 100644 (file)
@@ -1,3 +1,3 @@
 enum-if-invalid.json: In enum 'TestIfEnum':
 enum-if-invalid.json:2: 'if' condition has unknown key 'val'
-Valid keys are 'all', 'any'.
+Valid keys are 'all', 'any', 'not'.
index 7737b32de85febdbfacf3afb9236bbdaa0e76c7d..a700f2531bc2d2ddfdcf69b3dc0732c7e7dd3e6d 100644 (file)
 
 { 'command': 'test-if-alternate-cmd',
   'data': { 'alt-cmd-arg': 'TestIfAlternate' },
-  'if': { 'all': ['defined(TEST_IF_ALT)'] } }
+  'if': { 'all': ['defined(TEST_IF_ALT)',
+                  {'not': 'defined(TEST_IF_NOT_ALT)'}] } }
 
 { 'command': 'test-if-cmd',
   'data': {
index 2f067d57af807ea02b97c6f2eabf84b10dce33e7..53e12f35345424af690e1bb74e084a056b151c37 100644 (file)
@@ -333,10 +333,10 @@ alternate TestIfAlternate
     if OrderedDict([('all', ['defined(TEST_IF_ALT)', 'defined(TEST_IF_STRUCT)'])])
 object q_obj_test-if-alternate-cmd-arg
     member alt-cmd-arg: TestIfAlternate optional=False
-    if OrderedDict([('all', ['defined(TEST_IF_ALT)'])])
+    if OrderedDict([('all', ['defined(TEST_IF_ALT)', OrderedDict([('not', 'defined(TEST_IF_NOT_ALT)')])])])
 command test-if-alternate-cmd q_obj_test-if-alternate-cmd-arg -> None
     gen=True success_response=True boxed=False oob=False preconfig=False
-    if OrderedDict([('all', ['defined(TEST_IF_ALT)'])])
+    if OrderedDict([('all', ['defined(TEST_IF_ALT)', OrderedDict([('not', 'defined(TEST_IF_NOT_ALT)')])])])
 object q_obj_test-if-cmd-arg
     member foo: TestIfStruct optional=False
     member bar: TestIfEnum optional=False