All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Max Reitz <mreitz@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:15:58 +0100	[thread overview]
Message-ID: <87mucyq0mp.fsf@dusky.pond.sub.org> (raw)
In-Reply-To: <20190624173935.25747-2-mreitz@redhat.com> (Max Reitz's message of "Mon, 24 Jun 2019 19:39:21 +0200")

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.

Isn't the parenthesis in your regular expression redundant?

What use do you have in mind for 'inf' and 'nan'?

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.
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.

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?

>  
>      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.

>      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.

> 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"



  reply	other threads:[~2019-11-14  9:17 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 [this message]
2019-11-14  9:50     ` Max Reitz
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=87mucyq0mp.fsf@dusky.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=mreitz@redhat.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.