Improve error checking on number parsing
diff --git a/lexer.go b/lexer.go index 25635b4..813f21a 100644 --- a/lexer.go +++ b/lexer.go
@@ -184,6 +184,8 @@ return l.lexVoid } return l.lexRvalue + case '_': + return l.errorf("cannot start number with underscore") } if l.follow("true") { @@ -550,7 +552,6 @@ } else if isDigit(next) { digitSeen = true } else if next == '_' { - l.pos++ } else { l.backup() break
diff --git a/lexer_test.go b/lexer_test.go index df2cac9..1964a57 100644 --- a/lexer_test.go +++ b/lexer_test.go
@@ -618,3 +618,12 @@ token{Position{1, 1}, tokenError, "keys cannot contain new lines"}, }) } + +func TestInvalidFloat(t *testing.T) { + testFlow(t, "a=7e1_", []token{ + token{Position{1, 1}, tokenKey, "a"}, + token{Position{1, 2}, tokenEqual, "="}, + token{Position{1, 3}, tokenFloat, "7e1_"}, + token{Position{1, 7}, tokenEOF, ""}, + }) +}
diff --git a/parser.go b/parser.go index ba95fa5..39f72f3 100644 --- a/parser.go +++ b/parser.go
@@ -5,6 +5,7 @@ import ( "fmt" "reflect" + "regexp" "strconv" "strings" "time" @@ -211,6 +212,16 @@ return p.parseStart } +var numberUnderscoreInvalidRegexp *regexp.Regexp + +func cleanupNumberToken(value string) (string, error) { + if numberUnderscoreInvalidRegexp.MatchString(value) { + return "", fmt.Errorf("invalid use of _ in number") + } + cleanedVal := strings.Replace(value, "_", "", -1) + return cleanedVal, nil +} + func (p *tomlParser) parseRvalue() interface{} { tok := p.getToken() if tok == nil || tok.typ == tokenEOF { @@ -225,14 +236,20 @@ case tokenFalse: return false case tokenInteger: - cleanedVal := strings.Replace(tok.val, "_", "", -1) + cleanedVal, err := cleanupNumberToken(tok.val) + if err != nil { + p.raiseError(tok, "%s", err) + } val, err := strconv.ParseInt(cleanedVal, 10, 64) if err != nil { p.raiseError(tok, "%s", err) } return val case tokenFloat: - cleanedVal := strings.Replace(tok.val, "_", "", -1) + cleanedVal, err := cleanupNumberToken(tok.val) + if err != nil { + p.raiseError(tok, "%s", err) + } val, err := strconv.ParseFloat(cleanedVal, 64) if err != nil { p.raiseError(tok, "%s", err) @@ -361,3 +378,7 @@ parser.run() return result } + +func init() { + numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d]|_$|^_)`) +}
diff --git a/parser_test.go b/parser_test.go index 4481e67..53cfcde 100644 --- a/parser_test.go +++ b/parser_test.go
@@ -633,3 +633,25 @@ t.Error("Bad error message:", err.Error()) } } + +func TestInvalidFloatParsing(t *testing.T) { + _, err := Load("a=1e_2") + if err.Error() != "(1, 3): invalid use of _ in number" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a=1e2_") + if err.Error() != "(1, 3): invalid use of _ in number" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a=1__2") + if err.Error() != "(1, 3): invalid use of _ in number" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a=_1_2") + if err.Error() != "(1, 3): cannot start number with underscore" { + t.Error("Bad error message:", err.Error()) + } +}