Compare commits

...

4 Commits

Author SHA1 Message Date
Thomas Pelletier 6d743bb19f Improve error checking on number parsing 2015-12-01 14:38:33 +01:00
Thomas Pelletier fa1c2ab68c Error when parsing an empty key 2015-12-01 14:02:02 +01:00
Thomas Pelletier a6c6ad1f5f Don't crash when assigning group array to array 2015-12-01 13:56:31 +01:00
Thomas Pelletier ab7a652912 Fix TOML URL in doc.go 2015-12-01 09:53:09 +01:00
7 changed files with 73 additions and 5 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
// Package toml is a TOML markup language parser. // Package toml is a TOML markup language parser.
// //
// This version supports the specification as described in // This version supports the specification as described in
// https://github.com/toml-lang/toml/blob/master/versions/toml-v0.2.0.md // https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md
// //
// TOML Parsing // TOML Parsing
// //
+3
View File
@@ -70,6 +70,9 @@ func parseKey(key string) ([]string, error) {
if buffer.Len() > 0 { if buffer.Len() > 0 {
groups = append(groups, buffer.String()) groups = append(groups, buffer.String())
} }
if len(groups) == 0 {
return nil, fmt.Errorf("empty key")
}
return groups, nil return groups, nil
} }
+5
View File
@@ -42,3 +42,8 @@ func TestDottedKeyBasic(t *testing.T) {
func TestBaseKeyPound(t *testing.T) { func TestBaseKeyPound(t *testing.T) {
testError(t, "hello#world", "invalid bare character: #") testError(t, "hello#world", "invalid bare character: #")
} }
func TestEmptyKey(t *testing.T) {
testError(t, "", "empty key")
testError(t, " ", "empty key")
}
+2 -1
View File
@@ -184,6 +184,8 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
return l.lexVoid return l.lexVoid
} }
return l.lexRvalue return l.lexRvalue
case '_':
return l.errorf("cannot start number with underscore")
} }
if l.follow("true") { if l.follow("true") {
@@ -550,7 +552,6 @@ func (l *tomlLexer) lexNumber() tomlLexStateFn {
} else if isDigit(next) { } else if isDigit(next) {
digitSeen = true digitSeen = true
} else if next == '_' { } else if next == '_' {
l.pos++
} else { } else {
l.backup() l.backup()
break break
+9
View File
@@ -618,3 +618,12 @@ func TestKeyNewline(t *testing.T) {
token{Position{1, 1}, tokenError, "keys cannot contain new lines"}, 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, ""},
})
}
+24 -3
View File
@@ -5,6 +5,7 @@ package toml
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"regexp"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -107,7 +108,7 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
var array []*TomlTree var array []*TomlTree
if destTree == nil { if destTree == nil {
array = make([]*TomlTree, 0) array = make([]*TomlTree, 0)
} else if destTree.([]*TomlTree) != nil { } else if target, ok := destTree.([]*TomlTree); ok && target != nil {
array = destTree.([]*TomlTree) array = destTree.([]*TomlTree)
} else { } else {
p.raiseError(key, "key %s is already assigned and not of type group array", key) p.raiseError(key, "key %s is already assigned and not of type group array", key)
@@ -211,6 +212,16 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
return p.parseStart 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{} { func (p *tomlParser) parseRvalue() interface{} {
tok := p.getToken() tok := p.getToken()
if tok == nil || tok.typ == tokenEOF { if tok == nil || tok.typ == tokenEOF {
@@ -225,14 +236,20 @@ func (p *tomlParser) parseRvalue() interface{} {
case tokenFalse: case tokenFalse:
return false return false
case tokenInteger: 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) val, err := strconv.ParseInt(cleanedVal, 10, 64)
if err != nil { if err != nil {
p.raiseError(tok, "%s", err) p.raiseError(tok, "%s", err)
} }
return val return val
case tokenFloat: 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) val, err := strconv.ParseFloat(cleanedVal, 64)
if err != nil { if err != nil {
p.raiseError(tok, "%s", err) p.raiseError(tok, "%s", err)
@@ -361,3 +378,7 @@ func parseToml(flow chan token) *TomlTree {
parser.run() parser.run()
return result return result
} }
func init() {
numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d]|_$|^_)`)
}
+29
View File
@@ -626,3 +626,32 @@ func TestDoubleEqual(t *testing.T) {
t.Error("Bad error message:", err.Error()) t.Error("Bad error message:", err.Error())
} }
} }
func TestGroupArrayReassign(t *testing.T) {
_, err := Load("[hello]\n[[hello]]")
if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type group array" {
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())
}
}