diff --git a/vlib/toml/parser/parser.v b/vlib/toml/parser/parser.v index c5f1acd5bc..dd242ba145 100644 --- a/vlib/toml/parser/parser.v +++ b/vlib/toml/parser/parser.v @@ -575,8 +575,8 @@ pub fn (mut p Parser) root_table() ? { // // `table.key` now shape shifts into being a *double array of tables* key... // ... but with a different set of rules - making it hard to reuse the code we already have for that ... - // See `testdata/array_of_tables_edge_case_1_test.toml` for the type of construct parsed. - if p.last_aot.len == 1 && dotted_key.len == 2 + // See `testdata/array_of_tables_edge_case__test.toml` for the type of constructs parsed. + if p.last_aot.len == 1 && dotted_key.len > 1 && dotted_key[0] == p.last_aot.str() { // Disallow re-declaring the key p.check_explicitly_declared_array_of_tables(dotted_key) ? @@ -589,7 +589,20 @@ pub fn (mut p Parser) root_table() ? { p.table_contents(mut m) ? unsafe { mut mut_val := &val - mut_val[dotted_key[1].str()] = m + if dotted_key.len == 2 { + // [table.key] + mut_val[dotted_key[1].str()] = m + } else { + // [table.key.key.etc] + mut dotted_key_copy := dotted_key.clone() + dotted_key_copy.delete(0) + new_key := todo_msvc_astring2dkey(dotted_key_copy) + sub_table, key := p.sub_table_key(new_key) + t := p.find_in_table(mut mut_val, sub_table) ? + util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, + 'setting "$key" = $val in table ${ptr_str(t)}') + t[new_key.last().str()] = m + } } } else { return error(@MOD + '.' + @STRUCT + '.' + @FN + @@ -606,6 +619,7 @@ pub fn (mut p Parser) root_table() ? { p.check_implicitly_declared(dotted_key) ? p.ignore_while(parser.space_formatting) + util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'setting root map key to `$dotted_key` at "$p.tok.kind" "$p.tok.lit"') p.root_map_key = dotted_key p.allocate_table(p.root_map_key) ? @@ -628,6 +642,9 @@ pub fn (mut p Parser) root_table() ? { ' key `$dotted_key` has already been explicitly declared. Unexpected redeclaration at "$p.tok.kind" "$p.tok.lit" in this (excerpt): "...${p.excerpt()}..."') } + // Allow [ key ] + p.ignore_while(parser.space_formatting) + util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'setting root map key to `$dotted_key` at "$p.tok.kind" "$p.tok.lit"') p.root_map_key = dotted_key p.allocate_table(p.root_map_key) ? @@ -805,6 +822,7 @@ 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 + // Allow [[ key]] p.ignore_while(parser.space_formatting) peek_tok, _ := p.peek_over(1, parser.space_formatting) ? p.ignore_while(parser.space_formatting) @@ -817,6 +835,10 @@ pub fn (mut p Parser) array_of_tables(mut table map[string]ast.Value) ? { key := p.key() ? p.next() ? + + // Allow [[key ]] + p.ignore_while(parser.space_formatting) + p.check(.rsbr) ? p.peek_for_correct_line_ending_or_fail() ? p.expect(.rsbr) ? diff --git a/vlib/toml/tests/alexcrichton.toml-rs-tests_test.v b/vlib/toml/tests/alexcrichton.toml-rs-tests_test.v index 2a9f075394..46b3eac844 100644 --- a/vlib/toml/tests/alexcrichton.toml-rs-tests_test.v +++ b/vlib/toml/tests/alexcrichton.toml-rs-tests_test.v @@ -13,7 +13,6 @@ const ( 'valid/example-v0.3.0.toml', 'valid/example-v0.4.0.toml', 'valid/datetime-truncate.toml', // Not considered valid since RFC 3339 doesn't permit > 6 ms digits ?? - 'valid/table-array-nest-no-keys.toml', ] invalid_exceptions = [ 'invalid/string-bad-line-ending-escape.toml', @@ -31,6 +30,7 @@ const ( 'valid/table-array-many.toml', 'valid/table-array-one.toml', 'valid/table-array-nest.toml', + 'valid/table-array-nest-no-keys.toml', ] jq = os.find_abs_path_of_executable('jq') or { '' } diff --git a/vlib/toml/tests/array_of_tables_edge_case_2_test.v b/vlib/toml/tests/array_of_tables_edge_case_2_test.v new file mode 100644 index 0000000000..f4f18dac29 --- /dev/null +++ b/vlib/toml/tests/array_of_tables_edge_case_2_test.v @@ -0,0 +1,18 @@ +import os +import toml +import toml.to + +fn test_array_of_tables_edge_case_file() { + toml_file := + os.real_path(os.join_path(os.dir(@FILE), 'testdata', os.file_name(@FILE).all_before_last('.'))) + + '.toml' + toml_doc := toml.parse(toml_file) or { panic(err) } + + toml_json := to.json(toml_doc) + out_file := + os.real_path(os.join_path(os.dir(@FILE), 'testdata', os.file_name(@FILE).all_before_last('.'))) + + '.out' + out_file_json := os.read_file(out_file) or { panic(err) } + println(toml_json) + assert toml_json == out_file_json +} diff --git a/vlib/toml/tests/testdata/array_of_tables_edge_case_2_test.out b/vlib/toml/tests/testdata/array_of_tables_edge_case_2_test.out new file mode 100644 index 0000000000..ecd307a20b --- /dev/null +++ b/vlib/toml/tests/testdata/array_of_tables_edge_case_2_test.out @@ -0,0 +1 @@ +{ "albums": [ { "songs": [ { }, { } ] } ], "artists": [ { "home": { "address": { } } } ] } \ No newline at end of file diff --git a/vlib/toml/tests/testdata/array_of_tables_edge_case_2_test.toml b/vlib/toml/tests/testdata/array_of_tables_edge_case_2_test.toml new file mode 100644 index 0000000000..ad6eb10630 --- /dev/null +++ b/vlib/toml/tests/testdata/array_of_tables_edge_case_2_test.toml @@ -0,0 +1,6 @@ +[[ albums ]] + [[ albums.songs ]] + [[ albums.songs ]] + +[[ artists ]] + [ artists.home.address ]