From 6989307fb709fdf795baabc27171853f2a603441 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 20 Jul 2017 21:56:06 +0200 Subject: [PATCH] [spec/test/interpreter] Allow underscores in numbers --- document/core/text/values.rst | 11 +- interpreter/exec/int.ml | 2 + interpreter/text/lexer.mll | 14 +- test/core/float_literals.wast | 350 ++++++++++++++++++++++++++++++++++ test/core/int_literals.wast | 102 ++++++++++ 5 files changed, 469 insertions(+), 10 deletions(-) diff --git a/document/core/text/values.rst b/document/core/text/values.rst index 28e0c371a1..67c22d0f8a 100644 --- a/document/core/text/values.rst +++ b/document/core/text/values.rst @@ -27,6 +27,7 @@ Integers ~~~~~~~~ All :ref:`integers ` can be written in either decimal or hexadecimal notation. +In both cases, digits can optionally be separated by underscores. .. math:: \begin{array}{llclll@{\qquad}l} @@ -43,10 +44,10 @@ All :ref:`integers ` can be written in either decimal or hexadecimal \\[1ex] \production{decimal number} & \Tnum &::=& d{:}\Tdigit &\Rightarrow& d \\ &&|& - n{:}\Tnum~~d{:}\Tdigit &\Rightarrow& 10\cdot n + d \\ + n{:}\Tnum~~\text{\_}^?~~d{:}\Tdigit &\Rightarrow& 10\cdot n + d \\ \production{hexadecimal number} & \Thexnum &::=& h{:}\Thexdigit &\Rightarrow& h \\ &&|& - n{:}\Thexnum~~h{:}\Thexdigit &\Rightarrow& 16\cdot n + h \\ + n{:}\Thexnum~~\text{\_}^?~~h{:}\Thexdigit &\Rightarrow& 16\cdot n + h \\ \end{array} The allowed syntax for integer literals depends on size and signedness. @@ -88,10 +89,12 @@ Floating-Point \begin{array}{llclll@{\qquad\qquad}l} \production{decimal floating-point fraction} & \Tfrac &::=& \epsilon &\Rightarrow& 0 \\ &&|& - d{:}\Tdigit~q{:}\Tfrac &\Rightarrow& (d+q)/10 \\ + d{:}\Tdigit~~q{:}\Tfrac &\Rightarrow& (d+q)/10 \\ &&|& + d{:}\Tdigit~~\text{\_}~~p{:}\Tdigit~~q{:}\Tfrac &\Rightarrow& (d+(p+q)/10)/10 \\ \production{hexadecimal floating-point fraction} & \Thexfrac &::=& \epsilon &\Rightarrow& 0 \\ &&|& - h{:}\Thexdigit~q{:}\Thexfrac &\Rightarrow& (h+q)/16 \\ + h{:}\Thexdigit~~q{:}\Thexfrac &\Rightarrow& (h+q)/16 \\ &&|& + h{:}\Thexdigit~~\text{\_}~~~~p{:}\Thexdigit~~q{:}\Thexfrac &\Rightarrow& (h+(p+q)/16)/16 \\ \production{decimal floating-point number} & \Tfloat &::=& p{:}\Tnum~\text{.}~q{:}\Tfrac &\Rightarrow& p+q \\ &&|& diff --git a/interpreter/exec/int.ml b/interpreter/exec/int.ml index a2574fe3ae..d81e6af4a1 100644 --- a/interpreter/exec/int.ml +++ b/interpreter/exec/int.ml @@ -245,12 +245,14 @@ struct let len = String.length s in let rec parse_hex i num = if i = len then num else + if s.[i] = '_' then parse_hex (i + 1) num else let digit = of_int (hex_digit s.[i]) in require (le_u num (shr_u minus_one (of_int 4))); parse_hex (i + 1) (logor (shift_left num 4) digit) in let rec parse_dec i num = if i = len then num else + if s.[i] = '_' then parse_dec (i + 1) num else let digit = of_int (dec_digit s.[i]) in require (lt_u num max_upper || num = max_upper && le_u digit max_lower); parse_dec (i + 1) (add (mul num ten) digit) diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 3bb532d51c..2a41d8cfe7 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -91,8 +91,8 @@ let opt = Lib.Option.get let sign = '+' | '-' let digit = ['0'-'9'] let hexdigit = ['0'-'9''a'-'f''A'-'F'] -let num = digit+ -let hexnum = hexdigit+ +let num = digit ('_'? digit)* +let hexnum = hexdigit ('_'? hexdigit)* let letter = ['a'-'z''A'-'Z'] let symbol = @@ -123,11 +123,13 @@ let character = let nat = num | "0x" hexnum let int = sign nat +let frac = num +let hexfrac = hexnum let float = - sign? num '.' digit* - | sign? num ('.' digit*)? ('e' | 'E') sign? num - | sign? "0x" hexnum '.' hexdigit* - | sign? "0x" hexnum ('.' hexdigit*)? ('p' | 'P') sign? num + sign? num '.' frac? + | sign? num ('.' frac?)? ('e' | 'E') sign? num + | sign? "0x" hexnum '.' hexfrac? + | sign? "0x" hexnum ('.' hexfrac?)? ('p' | 'P') sign? num | sign? "inf" | sign? "nan" | sign? "nan:" "0x" hexnum diff --git a/test/core/float_literals.wast b/test/core/float_literals.wast index 1ab14f1a01..c85bfb275e 100644 --- a/test/core/float_literals.wast +++ b/test/core/float_literals.wast @@ -72,6 +72,28 @@ (func (export "f64_dec.max_subnormal") (result i64) (i64.reinterpret/f64 (f64.const 2.2250738585072011e-308))) (func (export "f64_dec.max_finite") (result i64) (i64.reinterpret/f64 (f64.const 1.7976931348623157e+308))) (func (export "f64_dec.trailing_dot") (result i64) (i64.reinterpret/f64 (f64.const 1.e100))) + + (func (export "f32-dec-sep1") (result f32) (f32.const 1_000_000)) + (func (export "f32-dec-sep2") (result f32) (f32.const 1_0_0_0)) + (func (export "f32-dec-sep3") (result f32) (f32.const 100_3.141_592)) + (func (export "f32-dec-sep4") (result f32) (f32.const 99e+1_3)) + (func (export "f32-dec-sep5") (result f32) (f32.const 122_000.11_3_54E0_2_3)) + (func (export "f32-hex-sep1") (result f32) (f32.const 0xa_0f_00_99)) + (func (export "f32-hex-sep2") (result f32) (f32.const 0x1_a_A_0_f)) + (func (export "f32-hex-sep3") (result f32) (f32.const 0xa0_ff.f141_a59a)) + (func (export "f32-hex-sep4") (result f32) (f32.const 0xf0P+1_3)) + (func (export "f32-hex-sep5") (result f32) (f32.const 0x2a_f00a.1f_3_eep2_3)) + + (func (export "f64-dec-sep1") (result f64) (f64.const 1_000_000)) + (func (export "f64-dec-sep2") (result f64) (f64.const 1_0_0_0)) + (func (export "f64-dec-sep3") (result f64) (f64.const 100_3.141_592)) + (func (export "f64-dec-sep4") (result f64) (f64.const 99e-1_23)) + (func (export "f64-dec-sep5") (result f64) (f64.const 122_000.11_3_54e0_2_3)) + (func (export "f64-hex-sep1") (result f64) (f64.const 0xa_f00f_0000_9999)) + (func (export "f64-hex-sep2") (result f64) (f64.const 0x1_a_A_0_f)) + (func (export "f64-hex-sep3") (result f64) (f64.const 0xa0_ff.f141_a59a)) + (func (export "f64-hex-sep4") (result f64) (f64.const 0xf0P+1_3)) + (func (export "f64-hex-sep5") (result f64) (f64.const 0x2a_f00a.1f_3_eep2_3)) ) (assert_return (invoke "f32.nan") (i32.const 0x7fc00000)) @@ -135,3 +157,331 @@ (assert_return (invoke "f64_dec.max_subnormal") (i64.const 0xfffffffffffff)) (assert_return (invoke "f64_dec.max_finite") (i64.const 0x7fefffffffffffff)) (assert_return (invoke "f64_dec.trailing_dot") (i64.const 0x54b249ad2594c37d)) + +(assert_return (invoke "f32-dec-sep1") (f32.const 1000000)) +(assert_return (invoke "f32-dec-sep2") (f32.const 1000)) +(assert_return (invoke "f32-dec-sep3") (f32.const 1003.141592)) +(assert_return (invoke "f32-dec-sep4") (f32.const 99e+13)) +(assert_return (invoke "f32-dec-sep5") (f32.const 122000.11354e23)) +(assert_return (invoke "f32-hex-sep1") (f32.const 0xa0f0099)) +(assert_return (invoke "f32-hex-sep2") (f32.const 0x1aa0f)) +(assert_return (invoke "f32-hex-sep3") (f32.const 0xa0ff.f141a59a)) +(assert_return (invoke "f32-hex-sep4") (f32.const 0xf0P+13)) +(assert_return (invoke "f32-hex-sep5") (f32.const 0x2af00a.1f3eep23)) + +(assert_return (invoke "f64-dec-sep1") (f64.const 1000000)) +(assert_return (invoke "f64-dec-sep2") (f64.const 1000)) +(assert_return (invoke "f64-dec-sep3") (f64.const 1003.141592)) +(assert_return (invoke "f64-dec-sep4") (f64.const 99e-123)) +(assert_return (invoke "f64-dec-sep5") (f64.const 122000.11354e23)) +(assert_return (invoke "f64-hex-sep1") (f64.const 0xaf00f00009999)) +(assert_return (invoke "f64-hex-sep2") (f64.const 0x1aa0f)) +(assert_return (invoke "f64-hex-sep3") (f64.const 0xa0ff.f141a59a)) +(assert_return (invoke "f64-hex-sep4") (f64.const 0xf0P+13)) +(assert_return (invoke "f64-hex-sep5") (f64.const 0x2af00a.1f3eep23)) + +(assert_malformed + (module quote "(global f32 (f32.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _1e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _1.0e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e_+1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0xff__ffff))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_1p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_1.0p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p_+1))") + "unknown operator" +) + +(assert_malformed + (module quote "(global f64 (f64.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _1e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _1.0e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e_+1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0xff__ffff))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_1p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_1.0p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p_+1))") + "unknown operator" +) diff --git a/test/core/int_literals.wast b/test/core/int_literals.wast index f0ec041785..73b37cc5a9 100644 --- a/test/core/int_literals.wast +++ b/test/core/int_literals.wast @@ -22,6 +22,16 @@ (func (export "i64.not_octal") (result i64) (return (i64.const 010))) (func (export "i64.unsigned_decimal") (result i64) (return (i64.const 18446744073709551615))) (func (export "i64.plus_sign") (result i64) (return (i64.const +42))) + + (func (export "i32-dec-sep1") (result i32) (i32.const 1_000_000)) + (func (export "i32-dec-sep2") (result i32) (i32.const 1_0_0_0)) + (func (export "i32-hex-sep1") (result i32) (i32.const 0xa_0f_00_99)) + (func (export "i32-hex-sep2") (result i32) (i32.const 0x1_a_A_0_f)) + + (func (export "i64-dec-sep1") (result i64) (i64.const 1_000_000)) + (func (export "i64-dec-sep2") (result i64) (i64.const 1_0_0_0)) + (func (export "i64-hex-sep1") (result i64) (i64.const 0xa_f00f_0000_9999)) + (func (export "i64-hex-sep2") (result i64) (i64.const 0x1_a_A_0_f)) ) (assert_return (invoke "i32.test") (i32.const 195940365)) @@ -47,3 +57,95 @@ (assert_return (invoke "i64.not_octal") (i64.const 10)) (assert_return (invoke "i64.unsigned_decimal") (i64.const -1)) (assert_return (invoke "i64.plus_sign") (i64.const 42)) + +(assert_return (invoke "i32-dec-sep1") (i32.const 1000000)) +(assert_return (invoke "i32-dec-sep2") (i32.const 1000)) +(assert_return (invoke "i32-hex-sep1") (i32.const 0xa0f0099)) +(assert_return (invoke "i32-hex-sep2") (i32.const 0x1aa0f)) + +(assert_return (invoke "i64-dec-sep1") (i64.const 1000000)) +(assert_return (invoke "i64-dec-sep2") (i64.const 1000)) +(assert_return (invoke "i64-hex-sep1") (i64.const 0xaf00f00009999)) +(assert_return (invoke "i64-hex-sep2") (i64.const 0x1aa0f)) + +(assert_malformed + (module quote "(global i32 (i32.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0xff__ffff))") + "unknown operator" +) + +(assert_malformed + (module quote "(global i64 (i64.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0xff__ffff))") + "unknown operator" +)