From 182e7071bf2ecdcdece8147bca0e2ed903f3c08a Mon Sep 17 00:00:00 2001 From: Tanel Liiv <204019+dkull@users.noreply.github.com> Date: Fri, 1 May 2020 01:29:54 +0300 Subject: [PATCH] array: map() function --- vlib/builtin/array_test.v | 35 ++++++++++++++--------------------- vlib/v/checker/checker.v | 19 ++++++++++++------- vlib/v/gen/cgen.v | 35 +++++++++++++++++++++++++++++++++++ vlib/v/gen/fn.v | 4 ++++ 4 files changed, 65 insertions(+), 28 deletions(-) diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index 2c4438d40d..654103ab30 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -340,7 +340,7 @@ fn double_up(a mut []int) { } fn double_up_v2(a mut []int) { - for i, val in a { + for i, _ in a { a[i] = a[i]*2 // or val*2, doesn't matter } } @@ -525,26 +525,19 @@ fn test_filter() { } fn test_map() { - // QTODO - /* - println(1) - a := [1, 2, 3, 4, 5, 6] - b := a.map(it * 10) - assert b.len == 6 - assert b[0] == 10 - assert b[1] == 20 - assert b[2] == 30 - c := ['v', 'is', 'awesome'] - d := c.map(it.to_upper()) - assert d[0] == 'V' - assert d[1] == 'IS' - assert d[2] == 'AWESOME' - bools := c.map(it == 'v') - assert bools.len == 3 - assert bools[0] == true - assert bools[1] == false - assert bools[2] == false - */ + nums := [1, 2, 3, 4, 5, 6] + strs := ['v', 'is', 'awesome'] + + assert nums.map(it * 10) == [10, 20, 30, 40, 50, 60] + assert nums.map('$it') == ['1', '2', '3', '4', '5', '6'] + assert nums.map(it % 2 == 0) == [false, true, false, true, false, true] + + assert strs.map(it.to_upper()) == ['V', 'IS', 'AWESOME'] + assert strs.map(it == 'awesome') == [false, false, true] + assert strs.map(7) == [7, 7, 7] + + assert nums == [1, 2, 3, 4, 5, 6] + assert strs == ['v', 'is', 'awesome'] } fn test_array_str() { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 8d18ddaded..97678b2416 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -599,6 +599,7 @@ pub fn (mut c Checker) call_method(call_expr mut ast.CallExpr) table.Type { left_type_sym := c.table.get_type_symbol(left_type) method_name := call_expr.name // TODO: remove this for actual methods, use only for compiler magic + // FIXME: Argument count != 1 will break these if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice'] { if method_name in ['filter', 'map'] { @@ -606,24 +607,28 @@ pub fn (mut c Checker) call_method(call_expr mut ast.CallExpr) table.Type { mut scope := c.file.scope.innermost(call_expr.pos.pos) scope.update_var_type('it', array_info.elem_type) } + + mut arg_type := left_type for arg in call_expr.args { - c.expr(arg.expr) + arg_type = c.expr(arg.expr) } - // need to return `array_xxx` instead of `array` + call_expr.return_type = left_type - if method_name == 'clone' { + call_expr.receiver_type = left_type + if method_name == 'map' && call_expr.args.len == 1 { + call_expr.return_type = c.table.find_or_register_array(arg_type, 1) + } else if method_name == 'clone' { + // need to return `array_xxx` instead of `array` // in ['clone', 'str'] { call_expr.receiver_type = left_type.to_ptr() // call_expr.return_type = call_expr.receiver_type - } else { - call_expr.receiver_type = left_type } - return left_type + return call_expr.return_type } else if left_type_sym.kind == .array && method_name in ['first', 'last'] { info := left_type_sym.info as table.Array call_expr.return_type = info.elem_type call_expr.receiver_type = left_type - return info.elem_type + return call_expr.return_type } if method := c.table.type_find_method(left_type_sym, method_name) { if !method.is_pub && !c.is_builtin_mod && !c.pref.is_test && left_type_sym.mod != c.mod && diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 43c4169e70..c2d55d4d5a 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2494,6 +2494,41 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { g.write(')') } +// `nums.map(it % 2 == 0)` +fn (mut g Gen) gen_map(node ast.CallExpr) { + tmp := g.new_tmp_var() + s := g.out.after(g.stmt_start_pos) // the already generated part of current statement + g.out.go_back(s.len) + // println('filter s="$s"') + ret_typ := g.typ(node.return_type) + //inp_typ := g.typ(node.receiver_type) + ret_sym := g.table.get_type_symbol(node.return_type) + inp_sym := g.table.get_type_symbol(node.receiver_type) + ret_info := ret_sym.info as table.Array + ret_elem_type := g.typ(ret_info.elem_type) + inp_info := inp_sym.info as table.Array + inp_elem_type := g.typ(inp_info.elem_type) + if inp_sym.kind != .array { + verror('map() requires an array') + } + g.writeln('') + g.write('int ${tmp}_len = ') + g.expr(node.left) + g.writeln('.len;') + g.writeln('$ret_typ $tmp = __new_array(0, ${tmp}_len, sizeof($ret_elem_type));') + g.writeln('for (int i = 0; i < ${tmp}_len; i++) {') + g.write('$inp_elem_type it = (($inp_elem_type*) ') + g.expr(node.left) + g.writeln('.data)[i];') + g.write('$ret_elem_type ti = ') + g.expr(node.args[0].expr) // the first arg is the filter condition + g.writeln(';') + g.writeln('array_push(&$tmp, &ti);') + g.writeln('}') + g.write(s) + g.write(tmp) +} + // `nums.filter(it % 2 == 0)` fn (mut g Gen) gen_filter(node ast.CallExpr) { tmp := g.new_tmp_var() diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 163ff5d2bd..f672050da5 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -242,6 +242,10 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.write('._object)') return } + if typ_sym.kind == .array && node.name == 'map' { + g.gen_map(node) + return + } // rec_sym := g.table.get_type_symbol(node.receiver_type) if typ_sym.kind == .array && node.name == 'filter' { g.gen_filter(node)