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]
|
||||
pos := start_pos.extend(p.tok.position())
|
||||
p.check(.rsbr)
|
||||
// a[i] or { ... }
|
||||
if p.tok.kind == .key_orelse && !p.or_is_handled {
|
||||
was_inside_or_expr := p.inside_or_expr
|
||||
mut or_pos := p.tok.position()
|
||||
p.next()
|
||||
p.open_scope()
|
||||
or_stmts := p.parse_block_no_scope(false)
|
||||
or_pos = or_pos.extend(p.prev_tok.position())
|
||||
p.close_scope()
|
||||
p.inside_or_expr = was_inside_or_expr
|
||||
return ast.IndexExpr{
|
||||
left: left
|
||||
index: expr
|
||||
pos: pos
|
||||
or_expr: ast.OrExpr{
|
||||
kind: .block
|
||||
stmts: or_stmts
|
||||
pos: or_pos
|
||||
mut or_kind := ast.OrKind.absent
|
||||
mut or_stmts := []ast.Stmt{}
|
||||
mut or_pos := token.Position{}
|
||||
if !p.or_is_handled {
|
||||
// a[i] or { ... }
|
||||
if p.tok.kind == .key_orelse {
|
||||
was_inside_or_expr := p.inside_or_expr
|
||||
or_pos = p.tok.position()
|
||||
p.next()
|
||||
p.open_scope()
|
||||
or_stmts = p.parse_block_no_scope(false)
|
||||
or_pos = or_pos.extend(p.prev_tok.position())
|
||||
p.close_scope()
|
||||
p.inside_or_expr = was_inside_or_expr
|
||||
return ast.IndexExpr{
|
||||
left: left
|
||||
index: expr
|
||||
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{
|
||||
left: left
|
||||
index: expr
|
||||
pos: pos
|
||||
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 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