Skip to content

Commit 13b9e52

Browse files
author
Charlie Egan
authored
ast: Ensure surplus leading zeros always error (#7726)
Fixes #7725 Signed-off-by: Charlie Egan <[email protected]>
1 parent 9750787 commit 13b9e52

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

v1/ast/parser.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,8 @@ func (p *Parser) parseTermFinish(head *Term, skipws bool) *Term {
17771777
func (p *Parser) parseNumber() *Term {
17781778
var prefix string
17791779
loc := p.s.Loc()
1780+
1781+
// Handle negative sign
17801782
if p.s.tok == tokens.Sub {
17811783
prefix = "-"
17821784
p.scan()
@@ -1788,6 +1790,8 @@ func (p *Parser) parseNumber() *Term {
17881790
return nil
17891791
}
17901792
}
1793+
1794+
// Handle decimal point
17911795
if p.s.tok == tokens.Dot {
17921796
prefix += "."
17931797
p.scan()
@@ -1797,12 +1801,19 @@ func (p *Parser) parseNumber() *Term {
17971801
}
17981802
}
17991803

1800-
// Check for multiple leading 0's, parsed by math/big.Float.Parse as decimal 0:
1801-
// https://golang.org/pkg/math/big/#Float.Parse
1802-
if ((len(prefix) != 0 && prefix[0] == '-') || len(prefix) == 0) &&
1803-
len(p.s.lit) > 1 && p.s.lit[0] == '0' && p.s.lit[1] == '0' {
1804-
p.illegal("expected number")
1805-
return nil
1804+
// Validate leading zeros: reject numbers like "01", "007", etc.
1805+
// Skip validation if prefix ends with '.' (like ".123")
1806+
hasDecimalPrefix := len(prefix) > 0 && prefix[len(prefix)-1] == '.'
1807+
1808+
if !hasDecimalPrefix && len(p.s.lit) > 1 && p.s.lit[0] == '0' {
1809+
// These are the only valid cases starting with '0':
1810+
isDecimal := p.s.lit[1] == '.' // "0.123"
1811+
isScientific := len(p.s.lit) > 2 && (p.s.lit[1] == 'e' || p.s.lit[1] == 'E') // "0e5", "0E-3"
1812+
1813+
if !isDecimal && !isScientific {
1814+
p.illegal("expected number without leading zero")
1815+
return nil
1816+
}
18061817
}
18071818

18081819
// Ensure that the number is valid

v1/ast/parser_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ func TestNumberTerms(t *testing.T) {
6060
{"1.1e6", "1.1e6"},
6161
{"-1e-6", "-1e-6"},
6262
{"1E6", "1E6"},
63+
{"0.1E6", "0.1E6"},
64+
{"0.1e6", "0.1e6"},
65+
{"0.1e-6", "0.1e-6"},
66+
{"0e6", "0e6"},
67+
{"0e-6", "0e-6"},
6368
{"0.1", "0.1"},
6469
{".1", "0.1"},
6570
{".0001", "0.0001"},
@@ -83,6 +88,46 @@ func TestNumberTerms(t *testing.T) {
8388
}
8489
})
8590
}
91+
92+
errorTests := map[string]struct {
93+
input string
94+
expectedError string
95+
}{
96+
"leading 0": {
97+
input: "03",
98+
expectedError: "expected number without leading zero",
99+
},
100+
"leading 0, many": {
101+
input: "003",
102+
expectedError: "expected number without leading zero",
103+
},
104+
"leading 0, 'octal'": {
105+
input: "0755",
106+
expectedError: "expected number without leading zero",
107+
},
108+
"leading 0, decimal": {
109+
input: "03.333",
110+
expectedError: "expected number without leading zero",
111+
},
112+
"leading 0, negative": {
113+
input: "-03",
114+
expectedError: "expected number without leading zero",
115+
},
116+
"leading 0, exp": {
117+
input: "03e6",
118+
expectedError: "expected number without leading zero",
119+
},
120+
"leading 0, exp, negative": {
121+
input: "-03e6",
122+
expectedError: "expected number without leading zero",
123+
},
124+
}
125+
126+
for name, tc := range errorTests {
127+
t.Run(name, func(t *testing.T) {
128+
assertParseErrorContains(t, name, tc.input, tc.expectedError)
129+
})
130+
}
86131
}
87132

88133
func TestStringTerms(t *testing.T) {

0 commit comments

Comments
 (0)