Allow numbers in keys parsing
diff --git a/keysparsing.go b/keysparsing.go
index 6bdb0b8..528f1de 100644
--- a/keysparsing.go
+++ b/keysparsing.go
@@ -5,6 +5,7 @@
import (
"bytes"
"fmt"
+ "unicode"
)
func parseKey(key string) ([]string, error) {
@@ -51,5 +52,5 @@
}
func isValidBareChar(r rune) bool {
- return isAlphanumeric(r) || r == '-'
+ return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r)
}
diff --git a/lexer.go b/lexer.go
index e6c3566..f162565 100644
--- a/lexer.go
+++ b/lexer.go
@@ -253,9 +253,14 @@
func (l *tomlLexer) lexKey() tomlLexStateFn {
l.ignore()
+ inQuotes := false
for r := l.next(); isKeyChar(r); r = l.next() {
- if r == '#' {
- return l.errorf("keys cannot contain # character")
+ if r == '"' {
+ inQuotes = !inQuotes
+ } else if isSpace(r) && !inQuotes {
+ break
+ } else if !isValidBareChar(r) && !inQuotes {
+ return l.errorf("keys cannot contain %c character", r)
}
}
l.backup()
diff --git a/lexer_test.go b/lexer_test.go
index 683d7f7..6b18a57 100644
--- a/lexer_test.go
+++ b/lexer_test.go
@@ -124,10 +124,7 @@
func TestKeyWithSymbolsAndEqual(t *testing.T) {
testFlow(t, "~!@$^&*()_+-`1234567890[]\\|/?><.,;:' = 5", []token{
- token{Position{1, 1}, tokenKey, "~!@$^&*()_+-`1234567890[]\\|/?><.,;:'"},
- token{Position{1, 38}, tokenEqual, "="},
- token{Position{1, 40}, tokenInteger, "5"},
- token{Position{1, 41}, tokenEOF, ""},
+ token{Position{1, 1}, tokenError, "keys cannot contain ~ character"},
})
}
@@ -549,3 +546,12 @@
token{Position{1, 8}, tokenEOF, ""},
})
}
+
+func TestQuotedKey(t *testing.T) {
+ testFlow(t, "\"a b\" = 42", []token{
+ token{Position{1, 1}, tokenKey, "\"a b\""},
+ token{Position{1, 7}, tokenEqual, "="},
+ token{Position{1, 9}, tokenInteger, "42"},
+ token{Position{1, 11}, tokenEOF, ""},
+ })
+}
diff --git a/parser.go b/parser.go
index e4d1083..8911261 100644
--- a/parser.go
+++ b/parser.go
@@ -192,13 +192,21 @@
}
// assign value to the found group
- localKey := []string{key.val}
- finalKey := append(groupKey, key.val)
+ keyVals, err := parseKey(key.val)
+ if err != nil {
+ p.raiseError(key, "%s", err)
+ }
+ if len(keyVals) != 1 {
+ p.raiseError(key, "Invalid key")
+ }
+ keyVal := keyVals[0]
+ localKey := []string{keyVal}
+ finalKey := append(groupKey, keyVal)
if targetNode.GetPath(localKey) != nil {
p.raiseError(key, "The following key was defined twice: %s",
strings.Join(finalKey, "."))
}
- targetNode.values[key.val] = &tomlValue{value, key.Position}
+ targetNode.values[keyVal] = &tomlValue{value, key.Position}
return p.parseStart
}
diff --git a/parser_test.go b/parser_test.go
index d33ddde..7a88055 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -51,12 +51,10 @@
})
}
-// NOTE: from the BurntSushi test suite
-// NOTE: this test is pure evil due to the embedded '.'
-func TestSpecialKV(t *testing.T) {
- tree, err := Load("~!@$^&*()_+-`1234567890[]\\|/?><.,;: = 1")
+func TestNumberInKey(t *testing.T) {
+ tree, err := Load("hello2 = 42")
assertTree(t, tree, err, map[string]interface{}{
- "~!@$^&*()_+-`1234567890[]\\|/?><.,;:": int64(1),
+ "hello2": int64(42),
})
}
@@ -109,6 +107,13 @@
})
}
+func TestSpaceKey(t *testing.T) {
+ tree, err := Load("\"a b\" = \"hello world\"")
+ assertTree(t, tree, err, map[string]interface{}{
+ "a b": "hello world",
+ })
+}
+
func TestStringEscapables(t *testing.T) {
tree, err := Load("a = \"a \\n b\"")
assertTree(t, tree, err, map[string]interface{}{
diff --git a/token.go b/token.go
index 6c0bcc6..f0fbac9 100644
--- a/token.go
+++ b/token.go
@@ -120,7 +120,7 @@
// Keys start with the first character that isn't whitespace or [ and end
// with the last non-whitespace character before the equals sign. Keys
// cannot contain a # character."
- return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '=')
+ return !(r == '\r' || r == '\n' || r == eof || r == '=')
}
func isKeyStartChar(r rune) bool {