toml: clean up and improve spaced and dotted key parsing (#12576)

pull/12580/head
Larpon 2021-11-25 15:51:54 +01:00 committed by GitHub
parent f584e70cf2
commit a59eabc4ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 40 deletions

View File

@ -425,12 +425,7 @@ pub fn (mut p Parser) root_table() ? {
peek_tok, _ := p.peek_over(1, parser.keys_and_space_formatting) ? peek_tok, _ := p.peek_over(1, parser.keys_and_space_formatting) ?
if peek_tok.kind == .period { if peek_tok.kind == .period {
p.ignore_while(parser.space_formatting) dotted_key, val := p.dotted_key_value() ?
dotted_key := p.dotted_key() ?
p.ignore_while(parser.space_formatting)
p.check(.assign) ?
p.ignore_while(parser.space_formatting)
val := p.value() ?
sub_table, key := p.sub_table_key(dotted_key) 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 return
} }
.bare, .quoted, .boolean, .number, .underscore { .bare, .quoted, .boolean, .number, .underscore {
mut peek_tok := p.peek_tok
// Peek forward as far as we can skipping over space formatting tokens. // 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 { if peek_tok.kind == .period {
p.ignore_while(parser.space_formatting) dotted_key, val := p.dotted_key_value() ?
dotted_key := p.dotted_key() ?
p.ignore_while(parser.space_formatting)
p.check(.assign) ?
p.ignore_while(parser.space_formatting)
val := p.value() ?
sub_table, key := p.sub_table_key(dotted_key) 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 // NOTE this is starting to get ugly. TOML isn't simple at this point
p.check(.lsbr) ? // '[' bracket 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 // [[key.key]] horror
if p.peek_tok.kind == .period { if peek_tok.kind == .period {
p.double_array_of_tables(mut table) ? p.double_array_of_tables(mut table) ?
return return
} }
@ -703,16 +696,16 @@ pub fn (mut p Parser) array_of_tables_contents() ?[]ast.Value {
for p.tok.kind != .eof { for p.tok.kind != .eof {
p.next() ? p.next() ?
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing token "$p.tok.kind"')
p.ignore_while(parser.all_formatting) p.ignore_while(parser.all_formatting)
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing token "$p.tok.kind"')
match p.tok.kind { match p.tok.kind {
.bare, .quoted, .boolean, .number, .underscore { .bare, .quoted, .boolean, .number, .underscore {
if p.peek_tok.kind == .period { // Peek forward as far as we can skipping over space formatting tokens.
dotted_key := p.dotted_key() ? peek_tok, _ := p.peek_over(1, parser.space_formatting) ?
p.ignore_while(parser.space_formatting)
p.check(.assign) ? if peek_tok.kind == .period {
val := p.value() ? dotted_key, val := p.dotted_key_value() ?
sub_table, key := p.sub_table_key(dotted_key) 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) ? { 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"') 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.check(.rsbr) ?
p.expect(.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 { match p.tok.kind {
.bare, .quoted, .boolean, .number, .underscore { .bare, .quoted, .boolean, .number, .underscore {
if p.peek_tok.kind == .period { // Peek forward as far as we can skipping over space formatting tokens.
mut dotted_key := p.dotted_key() ? peek_tok, _ = p.peek_over(1, parser.space_formatting) ?
p.ignore_while(parser.space_formatting)
p.check(.assign) ? if peek_tok.kind == .period {
val := p.value() ? mut dotted_key, val := p.dotted_key_value() ?
if implicit_allocation_key.len > 0 { if implicit_allocation_key.len > 0 {
dotted_key.insert(0, implicit_allocation_key) 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.check(.assign) ? // Assignment operator
p.ignore_while(parser.space_formatting) p.ignore_while(parser.space_formatting)
value := p.value() ? 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 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. // value parse and returns an `ast.Value` type.
// values are the token(s) appearing after an assignment operator (=). // values are the token(s) appearing after an assignment operator (=).
pub fn (mut p Parser) value() ?ast.Value { pub fn (mut p Parser) value() ?ast.Value {

View File

@ -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'
}

View File

@ -134,7 +134,10 @@ pub fn parse_dotted_key(key string) ?[]string {
buf += ch.ascii_str() buf += ch.ascii_str()
if !in_string && ch == `.` { if !in_string && ch == `.` {
if buf != '' && buf != ' ' { if buf != '' && buf != ' ' {
out << buf[..buf.len - 1] buf = buf[..buf.len - 1]
if buf != '' && buf != ' ' {
out << buf
}
} }
buf = '' buf = ''
continue continue