toml: clean up and improve spaced and dotted key parsing (#12576)
							parent
							
								
									f584e70cf2
								
							
						
					
					
						commit
						a59eabc4ab
					
				| 
						 | 
				
			
			@ -425,12 +425,7 @@ pub fn (mut p Parser) root_table() ? {
 | 
			
		|||
				peek_tok, _ := p.peek_over(1, parser.keys_and_space_formatting) ?
 | 
			
		||||
 | 
			
		||||
				if peek_tok.kind == .period {
 | 
			
		||||
					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)
 | 
			
		||||
					val := p.value() ?
 | 
			
		||||
					dotted_key, val := p.dotted_key_value() ?
 | 
			
		||||
 | 
			
		||||
					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
 | 
			
		||||
			}
 | 
			
		||||
			.bare, .quoted, .boolean, .number, .underscore {
 | 
			
		||||
				mut peek_tok := p.peek_tok
 | 
			
		||||
				// 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 {
 | 
			
		||||
					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)
 | 
			
		||||
					val := p.value() ?
 | 
			
		||||
					dotted_key, val := p.dotted_key_value() ?
 | 
			
		||||
 | 
			
		||||
					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
 | 
			
		||||
	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
 | 
			
		||||
	if p.peek_tok.kind == .period {
 | 
			
		||||
	if peek_tok.kind == .period {
 | 
			
		||||
		p.double_array_of_tables(mut table) ?
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -703,16 +696,16 @@ pub fn (mut p Parser) array_of_tables_contents() ?[]ast.Value {
 | 
			
		|||
 | 
			
		||||
	for p.tok.kind != .eof {
 | 
			
		||||
		p.next() ?
 | 
			
		||||
		util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing token "$p.tok.kind"')
 | 
			
		||||
		p.ignore_while(parser.all_formatting)
 | 
			
		||||
		util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing token "$p.tok.kind"')
 | 
			
		||||
 | 
			
		||||
		match p.tok.kind {
 | 
			
		||||
			.bare, .quoted, .boolean, .number, .underscore {
 | 
			
		||||
				if p.peek_tok.kind == .period {
 | 
			
		||||
					dotted_key := p.dotted_key() ?
 | 
			
		||||
					p.ignore_while(parser.space_formatting)
 | 
			
		||||
					p.check(.assign) ?
 | 
			
		||||
					val := p.value() ?
 | 
			
		||||
				// Peek forward as far as we can skipping over space formatting tokens.
 | 
			
		||||
				peek_tok, _ := p.peek_over(1, parser.space_formatting) ?
 | 
			
		||||
 | 
			
		||||
				if peek_tok.kind == .period {
 | 
			
		||||
					dotted_key, val := p.dotted_key_value() ?
 | 
			
		||||
 | 
			
		||||
					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) ? {
 | 
			
		||||
	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.expect(.rsbr) ?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -850,11 +833,11 @@ pub fn (mut p Parser) double_array_of_tables_contents(target_key DottedKey) ?[]a
 | 
			
		|||
 | 
			
		||||
		match p.tok.kind {
 | 
			
		||||
			.bare, .quoted, .boolean, .number, .underscore {
 | 
			
		||||
				if p.peek_tok.kind == .period {
 | 
			
		||||
					mut dotted_key := p.dotted_key() ?
 | 
			
		||||
					p.ignore_while(parser.space_formatting)
 | 
			
		||||
					p.check(.assign) ?
 | 
			
		||||
					val := p.value() ?
 | 
			
		||||
				// Peek forward as far as we can skipping over space formatting tokens.
 | 
			
		||||
				peek_tok, _ = p.peek_over(1, parser.space_formatting) ?
 | 
			
		||||
 | 
			
		||||
				if peek_tok.kind == .period {
 | 
			
		||||
					mut dotted_key, val := p.dotted_key_value() ?
 | 
			
		||||
 | 
			
		||||
					if implicit_allocation_key.len > 0 {
 | 
			
		||||
						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.ignore_while(parser.space_formatting)
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
// values are the token(s) appearing after an assignment operator (=).
 | 
			
		||||
pub fn (mut p Parser) value() ?ast.Value {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +134,10 @@ pub fn parse_dotted_key(key string) ?[]string {
 | 
			
		|||
		buf += ch.ascii_str()
 | 
			
		||||
		if !in_string && ch == `.` {
 | 
			
		||||
			if buf != '' && buf != ' ' {
 | 
			
		||||
				out << buf[..buf.len - 1]
 | 
			
		||||
				buf = buf[..buf.len - 1]
 | 
			
		||||
				if buf != '' && buf != ' ' {
 | 
			
		||||
					out << buf
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			buf = ''
 | 
			
		||||
			continue
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue