toml: fix parsing array of tables (#12388)
							parent
							
								
									db65b65f3c
								
							
						
					
					
						commit
						24cd619ff8
					
				|  | @ -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 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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) } | ||||
|  |  | |||
|  | @ -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) } | ||||
| } | ||||
|  | @ -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', | ||||
|  |  | |||
|  | @ -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" } ] } ] } | ||||
		Loading…
	
		Reference in New Issue