From 5067046538f1e9073dadfff3c91c48ea15242664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Tue, 19 Jan 2021 13:46:47 +0100 Subject: [PATCH] parser: support `x = a[k] ?` propagation for arrays and maps (#8199) --- vlib/v/parser/parser.v | 50 ++++++++++++-------- vlib/v/parser/tests/or_default_missing.out | 14 ++++++ vlib/v/parser/tests/or_default_missing.vv | 20 ++++++++ vlib/v/tests/array_map_or_test.v | 54 ++++++++++++++++++++++ 4 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 vlib/v/parser/tests/or_default_missing.out create mode 100644 vlib/v/parser/tests/or_default_missing.vv diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 935261d4f9..6ed3222a19 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -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 } } } diff --git a/vlib/v/parser/tests/or_default_missing.out b/vlib/v/parser/tests/or_default_missing.out new file mode 100644 index 0000000000..a74648b0ea --- /dev/null +++ b/vlib/v/parser/tests/or_default_missing.out @@ -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 | } diff --git a/vlib/v/parser/tests/or_default_missing.vv b/vlib/v/parser/tests/or_default_missing.vv new file mode 100644 index 0000000000..d89db0d72e --- /dev/null +++ b/vlib/v/parser/tests/or_default_missing.vv @@ -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') +} diff --git a/vlib/v/tests/array_map_or_test.v b/vlib/v/tests/array_map_or_test.v index 30e26df42a..d2b5c04772 100644 --- a/vlib/v/tests/array_map_or_test.v +++ b/vlib/v/tests/array_map_or_test.v @@ -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 +}