qapi: Remove null from schema language

We represent the parse tree as OrderedDict.  We fetch optional dict
members with .get().  So far, so good.

We represent null literals as None.  .get() returns None both for
"absent" and for "present, value is the null literal".  Uh-oh.

Test features-if-invalid exposes this bug: "'if': null" is
misinterpreted as absent "if".

We added null to the schema language to "allow [...] an explicit
default value" (commit e53188ada5 "qapi: Allow true, false and null in
schema json", v2.4.0).  Hasn't happened; null is still unused except
as generic invalid value in tests/.

To fix, we'd have to replace .get() by something more careful, or
represent null differently.  Feasible, but we got more and bigger fish
to fry right now.  Remove the null literal from the schema language.
Replace null in tests by another invalid value.

Test features-if-invalid now behaves as it should.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20190914153506.2151-10-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Markus Armbruster 2019-09-14 17:34:56 +02:00
parent 14c3279502
commit 9d55380b5a
7 changed files with 6 additions and 24 deletions

View File

@ -52,7 +52,7 @@ Differences:
* Strings are restricted to printable ASCII, and escape sequences to
just '\\'.
* Numbers are not supported.
* Numbers and null are not supported.
A second layer of syntax defines the sequences of JSON texts that are
a correctly structured QAPI schema. We provide a grammar for this
@ -67,7 +67,7 @@ syntax in an EBNF-like notation:
expression A separated by ,
* Grouping: expression ( A ) matches expression A
* JSON's structural characters are terminals: { } [ ] : ,
* JSON's literal names are terminals: false true null
* JSON's literal names are terminals: false true
* String literals enclosed in 'single quotes' are terminal, and match
this JSON string, with a leading '*' stripped off
* When JSON object member's name starts with '*', the member is

View File

@ -548,10 +548,6 @@ def accept(self, skip_comment=True):
self.val = False
self.cursor += 4
return
elif self.src.startswith('null', self.pos):
self.val = None
self.cursor += 3
return
elif self.tok == '\n':
if self.cursor == len(self.src):
self.tok = None

View File

@ -0,0 +1 @@
tests/qapi-schema/features-if-invalid.json:2: 'if' condition must be a string or a list of strings

View File

@ -1 +1 @@
0
1

View File

@ -1,5 +1,4 @@
# Cover feature with invalid 'if'
# FIXME not rejected, misinterpreted as unconditional
{ 'struct': 'Stru',
'data': {},
'features': [{'name': 'f', 'if': null }] }
'features': [{'name': 'f', 'if': false }] }

View File

@ -1,14 +0,0 @@
module None
object q_empty
enum QType
prefix QTYPE
member none
member qnull
member qnum
member qstring
member qdict
member qlist
member qbool
module features-if-invalid.json
object Stru
feature f

View File

@ -1,3 +1,3 @@
# 'name-case-whitelist' must be list of strings
{ 'pragma': { 'name-case-whitelist': null } }
{ 'pragma': { 'name-case-whitelist': false } }