From: Max Reitz <mreitz@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>,
qemu-devel@nongnu.org, qemu-block@nongnu.org,
Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH v4 01/14] qapi: Parse numeric values
Date: Thu, 14 Nov 2019 10:50:10 +0100 [thread overview]
Message-ID: <f42afeb3-422a-16f0-5f7e-be885f1132ff@redhat.com> (raw)
In-Reply-To: <87mucyq0mp.fsf@dusky.pond.sub.org>
[-- Attachment #1.1: Type: text/plain, Size: 9284 bytes --]
On 14.11.19 10:15, Markus Armbruster wrote:
> Max Reitz <mreitz@redhat.com> writes:
>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>> tests/qapi-schema/bad-type-int.json | 1 -
>> tests/qapi-schema/enum-int-member.json | 1 -
>> scripts/qapi/common.py | 25 ++++++++++++++++++++----
>> scripts/qapi/introspect.py | 2 ++
>> tests/qapi-schema/bad-type-int.err | 2 +-
>> tests/qapi-schema/enum-int-member.err | 2 +-
>> tests/qapi-schema/leading-comma-list.err | 2 +-
>> 7 files changed, 26 insertions(+), 9 deletions(-)
>>
>> diff --git a/tests/qapi-schema/bad-type-int.json b/tests/qapi-schema/bad-type-int.json
>> index 56fc6f8126..81355eb196 100644
>> --- a/tests/qapi-schema/bad-type-int.json
>> +++ b/tests/qapi-schema/bad-type-int.json
>> @@ -1,3 +1,2 @@
>> # we reject an expression with a metatype that is not a string
>> -# FIXME: once the parser understands integer inputs, improve the error message
>> { 'struct': 1, 'data': { } }
>> diff --git a/tests/qapi-schema/enum-int-member.json b/tests/qapi-schema/enum-int-member.json
>> index 6c9c32e149..6958440c6d 100644
>> --- a/tests/qapi-schema/enum-int-member.json
>> +++ b/tests/qapi-schema/enum-int-member.json
>> @@ -1,3 +1,2 @@
>> # we reject any enum member that is not a string
>> -# FIXME: once the parser understands integer inputs, improve the error message
>> { 'enum': 'MyEnum', 'data': [ 1 ] }
>> diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
>> index d61bfdc526..3396ea4a09 100644
>> --- a/scripts/qapi/common.py
>> +++ b/scripts/qapi/common.py
>> @@ -498,6 +498,8 @@ class QAPISchemaParser(object):
>> raise QAPISemError(info, "Unknown pragma '%s'" % name)
>>
>> def accept(self, skip_comment=True):
>> + num_match = re.compile(r'([-+]?inf|nan|[-+0-9.][0-9a-f.ex]*)')
>> +
>> while True:
>> self.tok = self.src[self.cursor]
>> self.pos = self.cursor
>
> This is yet another extension over plain JSON. RFC 8259:
>
> number = [ minus ] int [ frac ] [ exp ]
> decimal-point = %x2E ; .
> digit1-9 = %x31-39 ; 1-9
> e = %x65 / %x45 ; e E
> exp = e [ minus / plus ] 1*DIGIT
> frac = decimal-point 1*DIGIT
> int = zero / ( digit1-9 *DIGIT )
> minus = %x2D ; -
> plus = %x2B ; +
> zero = %x30 ; 0
>
> Extensions are acceptable when we have an actual use for it, and we
> document them properly.
Well, it isn’t really an extension, because this isn’t a JSON parser but
just something that accepts anything that looks like a number and then
lets Python try a conversion on it.
> Isn't the parenthesis in your regular expression redundant?
You’re right, but on second thought, maybe I should surround it by \<
and \>.
> What use do you have in mind for 'inf' and 'nan'?
I could imagine inf being a useful default value, actually. nan,
probably not so much.
> Why accept leading '+' as in '+123'?
>
> Why accept empty integral part as in '.123'?
>
> Why accept '.xe.'? Kidding you, that must be a bug in your regexp.
Well, kind of.
I wanted to accept anything that looks in any way like a number and then
let Python try to convert it. That’s also the reason why the case comes
last.
For that reason, I decided to keep the regex as simple as possible,
because the attempted conversions would reject anything that isn’t (to
Python) a valid number later.
It was my impression that the QAPI schema isn’t really JSON anyway and
that our QAPI schema parser isn’t a JSON parser. Under that assumption
it simply seemed useful to me to accept anything that could potentially
be a number to Python and convert it.
Now, honestly, I still don’t see the point of having a strict JSON
“parser” here, but if you insist. Seems possible to do in a regex.
Though I do think it makes sense to support hex integers as an extension.
> Please decide what number syntax you'd like to accept, then specify it
> in docs/devel/qapi-code-gen.txt, so we can first discuss the
> specification, and then check the regexp implements it.
>
> docs/devel/qapi-code-gen.txt update goes here:
>
> === Schema syntax ===
>
> Syntax is loosely based on JSON (http://www.ietf.org/rfc/rfc8259.txt).
> Differences:
>
> * Comments: start with a hash character (#) that is not part of a
> string, and extend to the end of the line.
>
> * Strings are enclosed in 'single quotes', not "double quotes".
>
> * Strings are restricted to printable ASCII, and escape sequences to
> just '\\'.
>
> --> * Numbers and null are not supported.
OK.
> Hrmm, commit 9d55380b5a "qapi: Remove null from schema language" left
> two instances in error messages behind. I'll fix them.
>
>> @@ -584,7 +586,22 @@ class QAPISchemaParser(object):
>> return
>> self.line += 1
>> self.line_pos = self.cursor
>> - elif not self.tok.isspace():
>> + elif self.tok.isspace():
>> + pass
>> + elif num_match.match(self.src[self.pos:]):
>> + match = num_match.match(self.src[self.pos:]).group(0)
>
> Sadly, the walrus operator is Python 3.8.
>
>> + try:
>> + self.val = int(match, 0)
>> + except ValueError:
>> + try:
>> + self.val = float(match)
>> + except ValueError:
>> + raise QAPIParseError(self,
>> + '"%s" is not a valid integer or float' % match)
>> +
>> + self.cursor += len(match) - 1
>> + return
>> + else:
>> raise QAPIParseError(self, 'Stray "%s"' % self.tok)
>
> Any particular reason for putting the number case last?
Because the match is so broad.
>>
>> def get_members(self):
>> @@ -617,9 +634,9 @@ class QAPISchemaParser(object):
>> if self.tok == ']':
>> self.accept()
>> return expr
>> - if self.tok not in "{['tfn":
>> + if self.tok not in "{['tfn-+0123456789.i":
>
> This is getting a bit ugly. Let's not worry about it now.
>
>> raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
>> - 'boolean or "null"')
>> + 'boolean, number or "null"')
>> while True:
>> expr.append(self.get_expr(True))
>> if self.tok == ']':
>> @@ -638,7 +655,7 @@ class QAPISchemaParser(object):
>> elif self.tok == '[':
>> self.accept()
>> expr = self.get_values()
>> - elif self.tok in "'tfn":
>> + elif self.tok in "'tfn-+0123456789.i":
>> expr = self.val
>> self.accept()
>> else:
>> diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
>> index f62cf0a2e1..6a61dd831f 100644
>> --- a/scripts/qapi/introspect.py
>> +++ b/scripts/qapi/introspect.py
>> @@ -57,6 +57,8 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
>> ret += indent(level) + '}))'
>> elif isinstance(obj, bool):
>> ret += 'QLIT_QBOOL(%s)' % ('true' if obj else 'false')
>> + elif isinstance(obj, int) and obj >= -(2 ** 63) and obj < 2 ** 63:
>> + ret += 'QLIT_QNUM(%i)' % obj
>
> Please explain the range check.
Will do.
>> else:
>> assert False # not implemented
>> if level > 0:
>> diff --git a/tests/qapi-schema/bad-type-int.err b/tests/qapi-schema/bad-type-int.err
>> index da89895404..e22fb4f655 100644
>> --- a/tests/qapi-schema/bad-type-int.err
>> +++ b/tests/qapi-schema/bad-type-int.err
>> @@ -1 +1 @@
>> -tests/qapi-schema/bad-type-int.json:3:13: Stray "1"
>> +tests/qapi-schema/bad-type-int.json:2: 'struct' key must have a string value
>
> Test needs a rename, assuming it's not redundant now.
I’m not adding a test here, it’s just the value has changed in
4d42815587063d.
Thanks for reviewing!
Max
>> diff --git a/tests/qapi-schema/enum-int-member.err b/tests/qapi-schema/enum-int-member.err
>> index 071c5213d8..112175f79d 100644
>> --- a/tests/qapi-schema/enum-int-member.err
>> +++ b/tests/qapi-schema/enum-int-member.err
>> @@ -1 +1 @@
>> -tests/qapi-schema/enum-int-member.json:3:31: Stray "1"
>> +tests/qapi-schema/enum-int-member.json:2: Member of enum 'MyEnum' requires a string name
>
> This one's name is still good.
>
>> diff --git a/tests/qapi-schema/leading-comma-list.err b/tests/qapi-schema/leading-comma-list.err
>> index f5c870bb9c..fa9c80aa57 100644
>> --- a/tests/qapi-schema/leading-comma-list.err
>> +++ b/tests/qapi-schema/leading-comma-list.err
>> @@ -1 +1 @@
>> -tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean or "null"
>> +tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean, number or "null"
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
next prev parent reply other threads:[~2019-11-14 10:03 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-24 17:39 [Qemu-devel] [PATCH v4 00/14] block: Try to create well-typed json:{} filenames Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 01/14] qapi: Parse numeric values Max Reitz
2019-11-14 9:15 ` Markus Armbruster
2019-11-14 9:50 ` Max Reitz [this message]
2019-11-14 12:01 ` Markus Armbruster
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 02/14] qapi: Move to_c_string() to common.py Max Reitz
2019-11-14 9:20 ` Markus Armbruster
2019-11-14 9:58 ` Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 03/14] qapi: Introduce default values for struct members Max Reitz
2019-11-14 15:53 ` Markus Armbruster
2019-11-21 15:07 ` Markus Armbruster
2019-11-21 15:24 ` Eric Blake
2019-11-21 19:46 ` Markus Armbruster
2019-11-21 19:56 ` Eric Blake
2019-11-22 7:29 ` Markus Armbruster
2019-11-22 10:25 ` Kevin Wolf
2019-11-22 14:40 ` Markus Armbruster
2019-11-22 16:12 ` Kevin Wolf
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 04/14] qapi: Allow optional discriminators Max Reitz
2019-11-21 15:13 ` Markus Armbruster
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 05/14] qapi: Document default values for struct members Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 06/14] test-qapi: Print struct members' default values Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 07/14] tests: Test QAPI default values for struct members Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 08/14] tests: Add QAPI optional discriminator tests Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 09/14] qapi: Formalize qcow2 encryption probing Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 10/14] qapi: Formalize qcow " Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 11/14] block: Try to create well typed json:{} filenames Max Reitz
2019-06-24 20:06 ` Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 12/14] iotests: Test internal option typing Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 13/14] iotests: qcow2's encrypt.format is now optional Max Reitz
2019-06-24 17:39 ` [Qemu-devel] [PATCH v4 14/14] block: Make use of QAPI defaults Max Reitz
2019-06-24 18:35 ` [Qemu-devel] [PATCH v4 00/14] block: Try to create well-typed json:{} filenames no-reply
2019-06-24 19:04 ` Max Reitz
2019-06-24 19:06 ` Max Reitz
2019-06-24 19:00 ` no-reply
2019-06-24 20:06 ` Max Reitz
2019-08-19 16:49 ` Max Reitz
2019-09-13 11:49 ` Max Reitz
2019-11-06 13:01 ` Max Reitz
2019-11-14 8:54 ` Markus Armbruster
2019-11-21 15:17 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f42afeb3-422a-16f0-5f7e-be885f1132ff@redhat.com \
--to=mreitz@redhat.com \
--cc=armbru@redhat.com \
--cc=kwolf@redhat.com \
--cc=mdroth@linux.vnet.ibm.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).