diff --git a/vlib/toml/parser/parser.v b/vlib/toml/parser/parser.v index d1f786b4a8..e8726421fe 100644 --- a/vlib/toml/parser/parser.v +++ b/vlib/toml/parser/parser.v @@ -425,12 +425,7 @@ pub fn (mut p Parser) root_table() ? { peek_tok, _ := p.peek_over(1, parser.keys_and_space_formatting) ? if peek_tok.kind == .period { - p.ignore_while(parser.space_formatting) - dotted_key := p.dotted_key() ? - p.ignore_while(parser.space_formatting) - p.check(.assign) ? - p.ignore_while(parser.space_formatting) - val := p.value() ? + dotted_key, val := p.dotted_key_value() ? sub_table, key := p.sub_table_key(dotted_key) @@ -605,17 +600,11 @@ pub fn (mut p Parser) inline_table(mut tbl map[string]ast.Value) ? { return } .bare, .quoted, .boolean, .number, .underscore { - mut peek_tok := p.peek_tok // Peek forward as far as we can skipping over space formatting tokens. - peek_tok, _ = p.peek_over(1, parser.space_formatting) ? + peek_tok, _ := p.peek_over(1, parser.space_formatting) ? if peek_tok.kind == .period { - p.ignore_while(parser.space_formatting) - dotted_key := p.dotted_key() ? - p.ignore_while(parser.space_formatting) - p.check(.assign) ? - p.ignore_while(parser.space_formatting) - val := p.value() ? + dotted_key, val := p.dotted_key_value() ? sub_table, key := p.sub_table_key(dotted_key) @@ -654,8 +643,12 @@ pub fn (mut p Parser) array_of_tables(mut table map[string]ast.Value) ? { // NOTE this is starting to get ugly. TOML isn't simple at this point p.check(.lsbr) ? // '[' bracket + p.ignore_while(parser.space_formatting) + peek_tok, _ := p.peek_over(1, parser.space_formatting) ? + p.ignore_while(parser.space_formatting) + // [[key.key]] horror - if p.peek_tok.kind == .period { + if peek_tok.kind == .period { p.double_array_of_tables(mut table) ? return } @@ -703,16 +696,16 @@ pub fn (mut p Parser) array_of_tables_contents() ?[]ast.Value { for p.tok.kind != .eof { p.next() ? - util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing token "$p.tok.kind"') p.ignore_while(parser.all_formatting) + util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing token "$p.tok.kind"') match p.tok.kind { .bare, .quoted, .boolean, .number, .underscore { - if p.peek_tok.kind == .period { - dotted_key := p.dotted_key() ? - p.ignore_while(parser.space_formatting) - p.check(.assign) ? - val := p.value() ? + // Peek forward as far as we can skipping over space formatting tokens. + peek_tok, _ := p.peek_over(1, parser.space_formatting) ? + + if peek_tok.kind == .period { + dotted_key, val := p.dotted_key_value() ? sub_table, key := p.sub_table_key(dotted_key) @@ -741,19 +734,9 @@ pub fn (mut p Parser) array_of_tables_contents() ?[]ast.Value { pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ? { util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing array of tables of arrays "$p.tok.kind" "$p.tok.lit"') - mut dotted_key := DottedKey([]string{}) + dotted_key := p.dotted_key() ? + p.ignore_while(parser.space_formatting) - key := p.key() ? - dotted_key << key.str() - for p.peek_tok.kind == .period { - p.next() ? // . - p.check(.period) ? - next_key := p.key() ? - dotted_key << next_key.text - } - util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsed dotted key `$dotted_key` now at "$p.tok.kind" "$p.tok.lit"') - - p.next() ? p.check(.rsbr) ? p.expect(.rsbr) ? @@ -850,11 +833,11 @@ pub fn (mut p Parser) double_array_of_tables_contents(target_key DottedKey) ?[]a match p.tok.kind { .bare, .quoted, .boolean, .number, .underscore { - if p.peek_tok.kind == .period { - mut dotted_key := p.dotted_key() ? - p.ignore_while(parser.space_formatting) - p.check(.assign) ? - val := p.value() ? + // Peek forward as far as we can skipping over space formatting tokens. + peek_tok, _ = p.peek_over(1, parser.space_formatting) ? + + if peek_tok.kind == .period { + mut dotted_key, val := p.dotted_key_value() ? if implicit_allocation_key.len > 0 { dotted_key.insert(0, implicit_allocation_key) @@ -1096,10 +1079,24 @@ pub fn (mut p Parser) key_value() ?(ast.Key, ast.Value) { p.check(.assign) ? // Assignment operator p.ignore_while(parser.space_formatting) value := p.value() ? - util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsed key value pair. "$key" = $value') + util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsed key value pair. `$key = $value`') return key, value } +// dotted_key_value parse and returns a pair `DottedKey` and `ast.Value` type. +// see also `key()` and `value()` +pub fn (mut p Parser) dotted_key_value() ?(DottedKey, ast.Value) { + util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing dotted key value pair...') + p.ignore_while(parser.space_formatting) + dotted_key := p.dotted_key() ? + p.ignore_while(parser.space_formatting) + p.check(.assign) ? + p.ignore_while(parser.space_formatting) + value := p.value() ? + util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsed dotted key value pair `$dotted_key = $value`...') + return dotted_key, value +} + // value parse and returns an `ast.Value` type. // values are the token(s) appearing after an assignment operator (=). pub fn (mut p Parser) value() ?ast.Value { diff --git a/vlib/toml/tests/spaced_keys_test.v b/vlib/toml/tests/spaced_keys_test.v new file mode 100644 index 0000000000..f76efdf3d5 --- /dev/null +++ b/vlib/toml/tests/spaced_keys_test.v @@ -0,0 +1,26 @@ +import toml + +fn test_spaced_keys() { + str_value := 'V rocks!' + + toml_txt := ' + "o" . pq . r = "Yuk" + +[[ a . "b.c" ]] + d . e = "V rocks!" + +[ tube . test . "test.test" ] + h . "i.j." . "k" = "Cryptic" +' + toml_doc := toml.parse(toml_txt) or { panic(err) } + mut value := toml_doc.value('a."b.c"[0].d.e') + assert value == toml.Any(str_value) + assert value as string == str_value + assert value.string() == str_value + + value = toml_doc.value('"o".pq.r') + assert value.string() == 'Yuk' + + value = toml_doc.value('tube.test."test.test".h."i.j."."k"') + assert value.string() == 'Cryptic' +} diff --git a/vlib/toml/toml.v b/vlib/toml/toml.v index 5cc098ee87..b72014e1fb 100644 --- a/vlib/toml/toml.v +++ b/vlib/toml/toml.v @@ -134,7 +134,10 @@ pub fn parse_dotted_key(key string) ?[]string { buf += ch.ascii_str() if !in_string && ch == `.` { if buf != '' && buf != ' ' { - out << buf[..buf.len - 1] + buf = buf[..buf.len - 1] + if buf != '' && buf != ' ' { + out << buf + } } buf = '' continue