From e19a6f35f1ec8e6828632d9786a737375e42f248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Thu, 17 Sep 2026 21:29:07 +0200 Subject: [PATCH] fix: reject a float exponent without digits Assisted-by: GLM 5.3 Flash --- interpres_test.go | 1 + number.go | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/interpres_test.go b/interpres_test.go index c2c5c63..2dc047f 100644 --- a/interpres_test.go +++ b/interpres_test.go @@ -370,6 +370,7 @@ func TestRejectsInvalidNumbers(t *testing.T) { "01", "-01", "00", "1__0", "_1", "1_", "0x_1", "1_.0", "1.", ".5", "1.2.3", "1.e2", + "1e", "1e+", "1e-", "0.0E", "0.0e", "1.5e+", "0x", "0o", "0b", "0b2", "0o8", "0xG", "+0x1", } { diff --git a/number.go b/number.go index f3d350b..5da3421 100644 --- a/number.go +++ b/number.go @@ -74,15 +74,16 @@ func decodeFloat(tok string) (any, error) { sign, s := splitSign(tok) mantissa, exp := s, "" + hasExp := false if i := strings.IndexAny(s, "eE"); i >= 0 { - mantissa, exp = s[:i], s[i+1:] + mantissa, exp, hasExp = s[:i], s[i+1:], true } intPart, frac, hasDot := mantissa, "", false if i := strings.IndexByte(mantissa, '.'); i >= 0 { intPart, frac, hasDot = mantissa[:i], mantissa[i+1:], true } - if !hasDot && exp == "" { + if !hasDot && !hasExp { return nil, fmt.Errorf("invalid float %q", tok) } @@ -102,7 +103,9 @@ func decodeFloat(tok string) (any, error) { } build += "." + fp } - if exp != "" { + // The ABNF requires at least one digit after the exponent marker, so a + // trailing e or E is an error even though strconv would accept it. + if hasExp { esign, edigits := splitSign(exp) ed, err := joinDigits(edigits, isDecDigit) if err != nil {