Skip to content

Commit 12f04b5

Browse files
authored
toml: fix remaining invalid exceptions for table/* (#26189)
1 parent 39ef9b2 commit 12f04b5

3 files changed

Lines changed: 59 additions & 24 deletions

File tree

‎vlib/toml/parser/parser.v‎

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,28 @@ pub fn (mut p Parser) find_in_table(mut table map[string]ast.Value, key DottedKe
397397
return t
398398
}
399399

400+
// is_all_tables returns `true` if *all* entries in `dotted_key` (`a.b.c`) are tables (`map[string]ast.Value`), `false` otherwise.
401+
fn is_all_tables(table map[string]ast.Value, dotted_key DottedKey) bool {
402+
if dotted_key.len == 0 {
403+
return false
404+
}
405+
unsafe {
406+
mut t := &table
407+
for key in dotted_key {
408+
if val := t[key] {
409+
if val is map[string]ast.Value {
410+
t = &val
411+
} else {
412+
return false
413+
}
414+
} else {
415+
return false
416+
}
417+
}
418+
}
419+
return true
420+
}
421+
400422
// find_array_of_tables returns an array if found in the root table based on the parser's
401423
// last encountered "Array Of Tables" key.
402424
// If the state key does not exist find_array_in_table will return an error.
@@ -495,6 +517,11 @@ pub fn (mut p Parser) root_table() ! {
495517

496518
sub_table, key := p.sub_table_key(dotted_key)
497519

520+
if is_all_tables(p.root_map, dotted_key) {
521+
return error(@MOD + '.' + @STRUCT + '.' + @FN +
522+
' key `${dotted_key.str()}` is already declared. Unexpected redeclaration at "${p.tok.kind}" "${p.tok.lit}" in this (excerpt): "...${p.excerpt()}..."')
523+
}
524+
498525
// NOTE these are *relatively* costly checks. In general - and by specification,
499526
// TOML documents are expected to be "small" so this shouldn't be a problem. Famous last words.
500527
for explicit_key in p.explicit_declared {
@@ -631,14 +658,16 @@ pub fn (mut p Parser) root_table() ! {
631658
}
632659
}
633660
}
634-
// Disallow re-declaring the key
635-
p.check_explicitly_declared(dotted_key)!
661+
662+
// Disallow re-defining
663+
// This check also covers *implicit* table allocations from "dotted" keys, so no need for e.g: `p.check_implicitly_declared(dotted_key)!`
664+
if is_all_tables(p.root_map, dotted_key) {
665+
return error(@MOD + '.' + @STRUCT + '.' + @FN +
666+
' key `${dotted_key.str()}` is already declared. Unexpected redeclaration at "${p.tok.kind}" "${p.tok.lit}" in this (excerpt): "...${p.excerpt()}..."')
667+
}
636668
p.explicit_declared << dotted_key
637-
// ... also check implicitly declared keys
638-
p.check_implicitly_declared(dotted_key)!
639669

640670
p.ignore_while(space_formatting)
641-
642671
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'setting root map key to `${dotted_key}` at "${p.tok.kind}" "${p.tok.lit}"')
643672
p.root_map_key = dotted_key
644673
p.allocate_table(p.root_map_key)!
@@ -886,7 +915,6 @@ pub fn (mut p Parser) array_of_tables(mut table map[string]ast.Value) ! {
886915

887916
// Disallow re-declaring the key
888917
p.check_explicitly_declared(dotted_key)!
889-
890918
unsafe {
891919
if val := table[dotted_key_str] {
892920
if val is []ast.Value {
@@ -936,17 +964,18 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ! {
936964
p.ignore_while(all_formatting)
937965

938966
p.check_explicitly_declared(dotted_key)!
939-
940-
first := DottedKey([dotted_key[0]]) // The array that holds the entries
941-
last := DottedKey([dotted_key[1]]) // The key the parsed array data should be added to
942-
943-
// Disallow re-declaring last part
944-
p.check_explicitly_declared(last)!
967+
if is_all_tables(p.root_map, dotted_key) {
968+
return error(@MOD + '.' + @STRUCT + '.' + @FN +
969+
' key `${dotted_key.str()}` is already declared. Unexpected redeclaration at "${p.tok.kind}" "${p.tok.lit}" in this (excerpt): "...${p.excerpt()}..."')
970+
}
945971

946972
if !p.explicit_declared_array_of_tables.has(dotted_key) {
947973
p.explicit_declared_array_of_tables << dotted_key
948974
}
949975

976+
first := DottedKey([dotted_key[0]]) // The array that holds the entries
977+
last := DottedKey([dotted_key[1]]) // The key the parsed array data should be added to
978+
950979
mut t_arr := &[]ast.Value(unsafe { nil })
951980
mut t_map := ast.Value(ast.Null{})
952981

@@ -960,7 +989,12 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ! {
960989
mut nm := &p.root_map
961990
if first.str() in table.keys() {
962991
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'adding to existing table entry at `${first}`.')
963-
nm = &(table[first.str()] as map[string]ast.Value)
992+
table_first := table[first.str()]
993+
if table_first !is map[string]ast.Value {
994+
return error(@MOD + '.' + @STRUCT + '.' + @FN +
995+
' expected a table at "${first.str()}" but got "${table_first.type_name()}" instead. (excerpt): "...${p.excerpt()}..."')
996+
}
997+
nm = &(table_first as map[string]ast.Value)
964998
} else {
965999
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'implicit allocation of map for `${first}` in dotted key `${dotted_key}`.')
9661000
nm = &map[string]ast.Value{}
@@ -983,8 +1017,9 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ! {
9831017
}
9841018
}
9851019

1020+
array_of_tables := table[p.last_aot.str()]
9861021
if first == p.last_aot {
987-
if table[p.last_aot.str()] is map[string]ast.Value {
1022+
if array_of_tables is map[string]ast.Value {
9881023
// NOTE: Here we "undo" the implicit-explicit special case declaration for:
9891024
// https://github.com/toml-lang/toml-test/blob/576db852/tests/invalid/table/array-implicit.toml
9901025
// ... to make the following test pass:
@@ -996,16 +1031,20 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ! {
9961031
}
9971032

9981033
// Give a nicer error if the `as` cast below can not be done
999-
if table[p.last_aot.str()] !is []ast.Value {
1034+
if array_of_tables !is []ast.Value {
10001035
return error(@MOD + '.' + @STRUCT + '.' + @FN +
10011036
' nested array of tables "${p.last_aot}" expected an array but got "${table[p.last_aot.str()].type_name()}". Re-definition is not allowed. (excerpt): "...${p.excerpt()}..."')
10021037
}
1003-
t_arr = &(table[p.last_aot.str()] as []ast.Value)
1038+
t_arr = &(array_of_tables as []ast.Value)
10041039
t_map = ast.Value(map[string]ast.Value{})
10051040
if p.last_aot_index < t_arr.len {
10061041
t_map = t_arr[p.last_aot_index]
10071042
}
10081043

1044+
if t_map !is map[string]ast.Value {
1045+
return error(@MOD + '.' + @STRUCT + '.' + @FN +
1046+
' expected a table but got "${t_map.type_name()}". (excerpt): "...${p.excerpt()}..."')
1047+
}
10091048
mut t := &(t_map as map[string]ast.Value)
10101049

10111050
if val := t[last.str()] {

‎vlib/toml/tests/nested_test.v‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ enabled = true
1717
[servers.alpha.tricky]
1818
ip = "10.0.0.100"
1919
20-
[firewall.rules.limit]
21-
ip = "10.0.0.101"
22-
23-
[firewall.rules]
20+
[firewall.rules]
2421
block = true
22+
23+
[firewall.rules.limit]
24+
ip = "10.0.0.101"
2525
'
2626

2727
fn test_parse() {

‎vlib/toml/tests/toml_lang_test.v‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ const invalid_exceptions = [
2626
'do_not_remove',
2727
'string/multiline-escape-space-02.toml',
2828
'string/missing-quotes-array.toml',
29-
'table/append-with-dotted-keys-05.toml',
30-
'table/duplicate-key-03.toml',
31-
'table/duplicate-key-10.toml',
32-
'table/redefine-02.toml',
3329
]
3430
const valid_value_exceptions = [
3531
'do_not_remove',

0 commit comments

Comments
 (0)