parser: support `x = a[k] ?` propagation for arrays and maps (#8199)
							parent
							
								
									15cc1cd884
								
							
						
					
					
						commit
						5067046538
					
				|  | @ -1394,33 +1394,45 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr { | ||||||
| 	// [expr]
 | 	// [expr]
 | ||||||
| 	pos := start_pos.extend(p.tok.position()) | 	pos := start_pos.extend(p.tok.position()) | ||||||
| 	p.check(.rsbr) | 	p.check(.rsbr) | ||||||
| 	// a[i] or { ... }
 | 	mut or_kind := ast.OrKind.absent | ||||||
| 	if p.tok.kind == .key_orelse && !p.or_is_handled { | 	mut or_stmts := []ast.Stmt{} | ||||||
| 		was_inside_or_expr := p.inside_or_expr | 	mut or_pos := token.Position{} | ||||||
| 		mut or_pos := p.tok.position() | 	if !p.or_is_handled { | ||||||
| 		p.next() | 		// a[i] or { ... }
 | ||||||
| 		p.open_scope() | 		if p.tok.kind == .key_orelse { | ||||||
| 		or_stmts := p.parse_block_no_scope(false) | 			was_inside_or_expr := p.inside_or_expr | ||||||
| 		or_pos = or_pos.extend(p.prev_tok.position()) | 			or_pos = p.tok.position() | ||||||
| 		p.close_scope() | 			p.next() | ||||||
| 		p.inside_or_expr = was_inside_or_expr | 			p.open_scope() | ||||||
| 		return ast.IndexExpr{ | 			or_stmts = p.parse_block_no_scope(false) | ||||||
| 			left: left | 			or_pos = or_pos.extend(p.prev_tok.position()) | ||||||
| 			index: expr | 			p.close_scope() | ||||||
| 			pos: pos | 			p.inside_or_expr = was_inside_or_expr | ||||||
| 			or_expr: ast.OrExpr{ | 			return ast.IndexExpr{ | ||||||
| 				kind: .block | 				left: left | ||||||
| 				stmts: or_stmts | 				index: expr | ||||||
| 				pos: or_pos | 				pos: pos | ||||||
|  | 				or_expr: ast.OrExpr{ | ||||||
|  | 					kind: .block | ||||||
|  | 					stmts: or_stmts | ||||||
|  | 					pos: or_pos | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		// `a[i] ?`
 | ||||||
|  | 		if p.tok.kind == .question { | ||||||
|  | 			p.next() | ||||||
|  | 			or_kind = .propagate | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	return ast.IndexExpr{ | 	return ast.IndexExpr{ | ||||||
| 		left: left | 		left: left | ||||||
| 		index: expr | 		index: expr | ||||||
| 		pos: pos | 		pos: pos | ||||||
| 		or_expr: ast.OrExpr{ | 		or_expr: ast.OrExpr{ | ||||||
| 			kind: .absent | 			kind: or_kind | ||||||
|  | 			stmts: or_stmts | ||||||
|  | 			pos: or_pos | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | vlib/v/parser/tests/or_default_missing.vv:4:3: error: `or` block must provide a default value of type `int`, or return/exit/continue/break/panic | ||||||
|  |     2 |     m := [3, 4, 5] | ||||||
|  |     3 |     el := m[4] or { | ||||||
|  |     4 |         println('error') | ||||||
|  |       |         ~~~~~~~~~~~~~~~~ | ||||||
|  |     5 |     } | ||||||
|  |     6 |     println(el) | ||||||
|  | vlib/v/parser/tests/or_default_missing.vv:16:16: error: last statement in the `or {}` block should be an expression of type `int` or exit parent scope | ||||||
|  |    14 |     } | ||||||
|  |    15 |     mut testvar := 0 | ||||||
|  |    16 |     el := m['pp'] or { | ||||||
|  |       |                   ~~~~ | ||||||
|  |    17 |         testvar = 12 | ||||||
|  |    18 |     } | ||||||
|  | @ -0,0 +1,20 @@ | ||||||
|  | fn test_array_or() { | ||||||
|  | 	m := [3, 4, 5] | ||||||
|  | 	el := m[4] or { | ||||||
|  | 		println('error') | ||||||
|  | 	} | ||||||
|  | 	println(el) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn test_map_or() { | ||||||
|  | 	m := { | ||||||
|  | 		'as': 3 | ||||||
|  | 		'qw': 4 | ||||||
|  | 		'kl': 5 | ||||||
|  | 	} | ||||||
|  | 	mut testvar := 0 | ||||||
|  | 	el := m['pp'] or { | ||||||
|  | 		testvar = 12 | ||||||
|  | 	} | ||||||
|  | 	println('$el $testvar') | ||||||
|  | } | ||||||
|  | @ -33,3 +33,57 @@ fn test_map_or() { | ||||||
| 	assert el == 7 | 	assert el == 7 | ||||||
| 	assert good == 5 | 	assert good == 5 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | fn get_map_el(key string) ?int { | ||||||
|  | 	m := {'as': 3, 'qw': 4, 'kl': 5} | ||||||
|  | 	r := m[key] ? | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn get_arr_el(i int) ?int { | ||||||
|  | 	m := [3, 4, 5] | ||||||
|  | 	r := m[i] ? | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn test_propagation() { | ||||||
|  | 	mut testvar1 := 12 | ||||||
|  | 	mut testvar2 := 78 | ||||||
|  | 	e := get_map_el('vv') or { | ||||||
|  | 		testvar1 = -34 | ||||||
|  | 		7 | ||||||
|  | 	} | ||||||
|  | 	f := get_map_el('as') or { | ||||||
|  | 		testvar1 = 67 | ||||||
|  | 		23 | ||||||
|  | 	} | ||||||
|  | 	g := get_arr_el(3) or { | ||||||
|  | 		testvar2 = 99 | ||||||
|  | 		12 | ||||||
|  | 	} | ||||||
|  | 	h := get_arr_el(0) or { | ||||||
|  | 		testvar2 = 177 | ||||||
|  | 		int(-67) | ||||||
|  | 	} | ||||||
|  | 	assert testvar1 == -34 | ||||||
|  | 	assert testvar2 == 99 | ||||||
|  | 	assert e == 7 | ||||||
|  | 	assert f == 3 | ||||||
|  | 	assert g == 12 | ||||||
|  | 	assert h == 3 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn get_arr_el_nested(i int) ?int { | ||||||
|  | 	ind := [2, 1, 0, 5] | ||||||
|  | 	m := [3, 4, 5] | ||||||
|  | 	r := m[ind[i]] ? | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn test_nested_array_propagation() { | ||||||
|  | 	g := get_arr_el_nested(3) or { | ||||||
|  | 		12 | ||||||
|  | 	} | ||||||
|  | 	assert g == 12 | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue