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 {