toml: fix parsing array of tables (#12388)

pull/12399/head
Larpon 2021-11-05 11:08:40 +01:00 committed by GitHub
parent db65b65f3c
commit 24cd619ff8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 17 deletions

View File

@ -362,7 +362,12 @@ pub fn (mut p Parser) root_table() ? {
t := p.find_table() ?
unsafe {
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'setting "$key.str()" = $val.to_json() in table ${ptr_str(t)}')
t[key.str()] = val
key_str := key.str()
if _ := t[key_str] {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' key "$key" is already initialized with a value. At "$p.tok.kind" "$p.tok.lit" in this (excerpt): "...${p.excerpt()}..."')
}
t[key_str] = val
}
}
}
@ -549,7 +554,11 @@ pub fn (mut p Parser) array_of_tables(mut table map[string]ast.Value) ? {
}
}
p.last_aot = key_str
p.last_aot_index = 0
unsafe {
arr := &(table[p.last_aot] as []ast.Value)
p.last_aot_index = arr.len - 1
}
}
// double_array_of_tables parses next tokens into an array of tables of arrays of `ast.Value`s...
@ -570,6 +579,8 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ? {
p.check(.rsbr) ?
p.check(.rsbr) ?
p.ignore_while(parser.all_formatting)
ks := key_str.split('.')
if ks.len != 2 {
@ -577,24 +588,35 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ? {
' nested array of tables does not support more than 2 levels. (excerpt): "...${p.excerpt()}..."')
}
first := ks[0]
last := ks[1]
first := ks[0] // The array that holds the entries
last := ks[1] // The key the parsed array data should be added to
mut t_arr := &[]ast.Value(0)
mut t_map := ast.Value(ast.Null{})
unsafe {
// NOTE this is starting to get EVEN uglier. TOML is not at all simple at this point...
if p.last_aot != first {
table[first] = []ast.Value{}
p.last_aot = first
mut t_arr := &(table[p.last_aot] as []ast.Value)
t_arr << map[string]ast.Value{}
p.last_aot_index = 0
if first != p.last_aot {
// Implicit allocation
if p.last_aot == '' {
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'implicit allocation of array for nested key `$key_str`.')
table[first] = []ast.Value{}
p.last_aot = first
t_arr = &(table[p.last_aot] as []ast.Value)
t_arr << ast.Value(map[string]ast.Value{})
p.last_aot_index = t_arr.len - 1
} else {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' nested array of tables key "$first" does not match "$p.last_aot". (excerpt): "...${p.excerpt()}..."')
}
}
mut t_arr := &(table[p.last_aot] as []ast.Value)
mut t_map := ast.Value(map[string]ast.Value{})
if t_arr.len > 0 {
t_arr = &(table[p.last_aot] as []ast.Value)
t_map = ast.Value(map[string]ast.Value{})
if p.last_aot_index < t_arr.len {
t_map = t_arr[p.last_aot_index]
}
mut t := &(t_map as map[string]ast.Value)
if last in t.keys() {
@ -617,7 +639,7 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ? {
}
if t_arr.len == 0 {
t_arr << t
p.last_aot_index = 0
p.last_aot_index = t_arr.len - 1
}
}
}

View File

@ -21,7 +21,6 @@ fn test_tables() {
toml_json := toml_doc.to_json()
eprintln(toml_json)
assert toml_json == os.read_file(
os.real_path(os.join_path(os.dir(@FILE), 'testdata', os.file_name(@FILE).all_before_last('.'))) +
'.out') or { panic(err) }

View File

@ -0,0 +1,33 @@
import os
import toml
const (
toml_text = '[[albums]]
name = "Born to Run"
[[albums.songs]]
name = "Jungleland"
[[albums.songs]]
name = "Meeting Across the River"
[[albums]]
name = "Born in the USA"
[[albums.songs]]
name = "Glory Days"
[[albums.songs]]
name = "Dancing in the Dark"'
)
fn test_nested_array_of_tables() {
mut toml_doc := toml.parse(toml_text) or { panic(err) }
toml_json := toml_doc.to_json()
eprintln(toml_json)
assert toml_json == os.read_file(
os.real_path(os.join_path(os.dir(@FILE), 'testdata', os.file_name(@FILE).all_before_last('.'))) +
'.out') or { panic(err) }
}

View File

@ -27,9 +27,7 @@ const (
'datetime/no-leads-with-milli.toml',
'datetime/no-leads.toml',
// Key
'key/duplicate.toml',
'key/after-table.toml',
'key/duplicate-keys.toml',
'key/after-value.toml',
'key/no-eol.toml',
'key/after-array.toml',

View File

@ -0,0 +1 @@
{ "albums": [ { "name": "Born to Run", "songs": [ { "name": "Jungleland" }, { "name": "Meeting Across the River" } ] }, { "name": "Born in the USA", "songs": [ { "name": "Glory Days" }, { "name": "Dancing in the Dark" } ] } ] }