parser: support `x = a[k] ?` propagation for arrays and maps (#8199)

pull/8202/head
Uwe Krüger 2021-01-19 13:46:47 +01:00 committed by GitHub
parent 15cc1cd884
commit 5067046538
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 19 deletions

View File

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

View File

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

View File

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

View File

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