cue: fix number parsing
- allow 0. for floats
- allow old-school octal numbers (just too common)
- fix productions in spec.
Change-Id: Ifaf9bbc8f221c637875a26ab02d379865d4af151
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2164
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/lit.go b/cue/lit.go
index 8e5b3e0..0d8e4f6 100644
--- a/cue/lit.go
+++ b/cue/lit.go
@@ -131,8 +131,10 @@
p.ch = p.src[p.p]
p.p++
if p.ch == '.' {
+ if len(p.buf) == 0 {
+ p.buf = append(p.buf, '0')
+ }
p.buf = append(p.buf, '.')
-
}
return true
}
@@ -229,7 +231,6 @@
}
func (p *litParser) scanNumber(seenDecimalPoint bool) value {
- // digitVal(s.ch) < 10
isFloat := false
base := 10
@@ -242,7 +243,8 @@
if p.ch == '0' {
// int or float
p.next()
- if p.ch == 'x' || p.ch == 'X' {
+ switch p.ch {
+ case 'x', 'X':
base = 16
// hexadecimal int
p.next()
@@ -251,7 +253,7 @@
// only scanned "0x" or "0X"
return p.error(p.node, "illegal hexadecimal number %q", p.src)
}
- } else if p.ch == 'b' {
+ case 'b':
base = 2
// binary int
p.next()
@@ -260,7 +262,7 @@
// only scanned "0b"
return p.error(p.node, "illegal binary number %q", p.src)
}
- } else if p.ch == 'o' {
+ case 'o':
base = 8
// octal int
p.next()
@@ -269,12 +271,19 @@
// only scanned "0o"
return p.error(p.node, "illegal octal number %q", p.src)
}
- } else {
- // int or float
- p.scanMantissa(10)
- if p.ch == '.' || p.ch == 'e' {
+ default:
+ // int (base 8 or 10) or float
+ p.scanMantissa(8)
+ if p.ch == '.' || p.ch == 'e' || p.ch == '8' || p.ch == '9' {
+ p.scanMantissa(10)
+ if p.ch != '.' && p.ch != 'e' {
+ return p.error(p.node, "illegal octal number %q", p.src)
+ }
goto fraction
}
+ if len(p.buf) > 0 {
+ base = 8
+ }
}
goto exit
}
diff --git a/cue/lit_test.go b/cue/lit_test.go
index 6ad6905..b98c892 100644
--- a/cue/lit_test.go
+++ b/cue/lit_test.go
@@ -121,7 +121,12 @@
{"1.", mkFloat("1")},
{"0.0", mkFloat("0.0")},
{".0", mkFloat(".0")},
+ {"012.34", mkFloat("012.34")},
+ {".01", mkFloat(".01")},
+ {".01e2", mkFloat("1")},
+ {"0.", mkFloat("0.")},
{"1K", mkMul(1000, mulK, 10)},
+ {".5K", mkMul(500, mulK, 10)},
{"1Mi", mkMul(1024*1024, mulMi, 10)},
{"1.5Mi", mkMul((1024+512)*1024, mulMi, 10)},
{"1.3Mi", &bottom{}}, // Cannot be accurately represented.
@@ -134,6 +139,7 @@
{"0b11001000", mkMul(0xc8, 0, 2)},
{"0b1", mkMul(1, 0, 2)},
{"0o755", mkMul(0755, 0, 8)},
+ {"0755", mkMul(0755, 0, 8)},
}
p := litParser{
ctx: &context{Context: &apd.BaseContext},
diff --git a/doc/ref/spec.md b/doc/ref/spec.md
index 5263f29..0e3439b 100644
--- a/doc/ref/spec.md
+++ b/doc/ref/spec.md
@@ -293,14 +293,20 @@
towards zero if it is not an integer.
```
-int_lit = decimal_lit | octal_lit | binary_lit | hex_lit .
-decimals = ( "0" … "9" ) { [ "_" ] decimal_digit } .
-decimal_lit = ( "1" … "9" ) { [ "_" ] decimal_digit } [ [ "." decimals ] multiplier ] |
- "." decimals multiplier.
+int_lit = decimal_lit | si_lit | octal_lit | binary_lit | hex_lit .
+decimal_lit = ( "1" … "9" ) { [ "_" ] decimal_digit } .
+decimals = decimal_digit { [ "_" ] decimal_digit } .
+si_it = decimals [ "." decimals ] multiplier |
+ "." decimals multiplier .
binary_lit = "0b" binary_digit { binary_digit } .
hex_lit = "0" ( "x" | "X" ) hex_digit { [ "_" ] hex_digit } .
-octal_lit = "0o" octal_digit { [ "_" ] octal_digit } .
+octal_lit = "0" [ "o" ] octal_digit { [ "_" ] octal_digit } .
multiplier = ( "K" | "M" | "G" | "T" | "P" | "E" | "Y" | "Z" ) [ "i" ]
+
+float_lit = decimals "." [ decimals ] [ exponent ] |
+ decimals exponent |
+ "." decimals [ exponent ].
+exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .
```
```