parser: parse `map{key_expr: val_expr}` (#8608)
							parent
							
								
									db0fc8fbc9
								
							
						
					
					
						commit
						f5f65f929f
					
				| 
						 | 
				
			
			@ -128,13 +128,17 @@ fn test_map() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn test_map_init() {
 | 
			
		||||
	m := {
 | 
			
		||||
		'one': 1
 | 
			
		||||
	one := 'one'
 | 
			
		||||
	three := 'three'
 | 
			
		||||
	m := map{
 | 
			
		||||
		one: 1
 | 
			
		||||
		'two': 2
 | 
			
		||||
		three: 1 + 2
 | 
			
		||||
	}
 | 
			
		||||
	assert m['one'] == 1
 | 
			
		||||
	assert m['two'] == 2
 | 
			
		||||
	assert m['three'] == 0
 | 
			
		||||
	assert m['three'] == 3
 | 
			
		||||
	assert m['unknown'] == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_string_map() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5335,16 +5335,20 @@ pub fn (mut c Checker) check_dup_keys(node &ast.MapInit, i int) {
 | 
			
		|||
	key_i := node.keys[i]
 | 
			
		||||
	if key_i is ast.StringLiteral {
 | 
			
		||||
		for j in 0 .. i {
 | 
			
		||||
			key_j := node.keys[j] as ast.StringLiteral
 | 
			
		||||
			if key_i.val == key_j.val {
 | 
			
		||||
				c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
 | 
			
		||||
			key_j := node.keys[j]
 | 
			
		||||
			if key_j is ast.StringLiteral {
 | 
			
		||||
				if key_i.val == key_j.val {
 | 
			
		||||
					c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if key_i is ast.IntegerLiteral {
 | 
			
		||||
		for j in 0 .. i {
 | 
			
		||||
			key_j := node.keys[j] as ast.IntegerLiteral
 | 
			
		||||
			if key_i.val == key_j.val {
 | 
			
		||||
				c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
 | 
			
		||||
			key_j := node.keys[j]
 | 
			
		||||
			if key_j is ast.IntegerLiteral {
 | 
			
		||||
				if key_i.val == key_j.val {
 | 
			
		||||
					c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,6 +152,7 @@ fn (mut p Parser) array_init() ast.ArrayInit {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parse tokens between braces
 | 
			
		||||
fn (mut p Parser) map_init() ast.MapInit {
 | 
			
		||||
	first_pos := p.prev_tok.position()
 | 
			
		||||
	mut keys := []ast.Expr{}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -128,7 +128,13 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
 | 
			
		|||
			p.next()
 | 
			
		||||
			array_decompose = true
 | 
			
		||||
		}
 | 
			
		||||
		mut e := p.expr(0)
 | 
			
		||||
		mut e := ast.Expr{}
 | 
			
		||||
		if p.tok.kind == .name && p.peek_tok.kind == .colon {
 | 
			
		||||
			// `foo(key:val, key2:val2)`
 | 
			
		||||
			e = p.struct_init(true) // short_syntax:true
 | 
			
		||||
		} else {
 | 
			
		||||
			e = p.expr(0)
 | 
			
		||||
		}
 | 
			
		||||
		if array_decompose {
 | 
			
		||||
			e = ast.ArrayDecompose{
 | 
			
		||||
				expr: e
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1314,6 +1314,16 @@ pub fn (mut p Parser) name_expr() ast.Expr {
 | 
			
		|||
		&& (!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital))
 | 
			
		||||
		&& !p.inside_match_case && (!p.inside_if || p.inside_select)
 | 
			
		||||
		&& (!p.inside_for || p.inside_select) { // && (p.tok.lit[0].is_capital() || p.builtin_mod) {
 | 
			
		||||
		// map.v has struct literal: map{field: expr}
 | 
			
		||||
		if p.peek_tok.kind == .lcbr && !(p.builtin_mod && p.file_base == 'map.v')
 | 
			
		||||
			&& p.tok.lit == 'map' {
 | 
			
		||||
			// map{key_expr: val_expr}
 | 
			
		||||
			p.check(.name)
 | 
			
		||||
			p.check(.lcbr)
 | 
			
		||||
			map_init := p.map_init()
 | 
			
		||||
			p.check(.rcbr)
 | 
			
		||||
			return map_init
 | 
			
		||||
		}
 | 
			
		||||
		return p.struct_init(false) // short_syntax: false
 | 
			
		||||
	} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
 | 
			
		||||
		// T.name
 | 
			
		||||
| 
						 | 
				
			
			@ -1351,11 +1361,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
 | 
			
		|||
			pos: p.tok.position()
 | 
			
		||||
			mod: mod
 | 
			
		||||
		}
 | 
			
		||||
	} else if p.peek_tok.kind == .colon && p.prev_tok.kind != .str_dollar {
 | 
			
		||||
		// `foo(key:val, key2:val2)`
 | 
			
		||||
		return p.struct_init(true) // short_syntax:true
 | 
			
		||||
		// JS. function call with more than 1 dot
 | 
			
		||||
	} else if language == .js && p.peek_tok.kind == .dot && p.peek_tok2.kind == .name {
 | 
			
		||||
		// JS. function call with more than 1 dot
 | 
			
		||||
		node = p.call_expr(language, mod)
 | 
			
		||||
	} else {
 | 
			
		||||
		node = p.parse_ident(language)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -240,6 +240,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
 | 
			
		|||
			// Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
 | 
			
		||||
			p.next()
 | 
			
		||||
			if p.tok.kind in [.chartoken, .number, .string] {
 | 
			
		||||
				// TODO deprecate
 | 
			
		||||
				node = p.map_init()
 | 
			
		||||
			} else {
 | 
			
		||||
				// it should be a struct
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
const (
 | 
			
		||||
	alpha = 'a'
 | 
			
		||||
	beta = 'b'
 | 
			
		||||
	m = map{
 | 
			
		||||
		alpha : 'Alpha'
 | 
			
		||||
		beta : 'Beta'
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
fn test_const_keys() {
 | 
			
		||||
	assert m[alpha] == 'Alpha'
 | 
			
		||||
	assert m[beta] == 'Beta'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum Enum {
 | 
			
		||||
	a b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	m2 = map{
 | 
			
		||||
		Enum.a.str() : 'first'
 | 
			
		||||
		Enum.b.str() : 'second'
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
fn test_method_call() {
 | 
			
		||||
	assert m2.keys() == ['a', 'b']
 | 
			
		||||
	assert m2[Enum.a.str()] == 'first'
 | 
			
		||||
	assert m2[Enum.b.str()] == 'second'
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue