Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d743bb19f | |||
| fa1c2ab68c | |||
| a6c6ad1f5f | |||
| ab7a652912 |
@@ -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
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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, ""},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -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]|_$|^_)`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user