mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
checker, cgen: implement method map() for fixed arrays (#22644)
This commit is contained in:
parent
4e9f7c21aa
commit
5ad0186895
4 changed files with 111 additions and 20 deletions
27
vlib/builtin/fixed_array_map_test.v
Normal file
27
vlib/builtin/fixed_array_map_test.v
Normal file
|
@ -0,0 +1,27 @@
|
|||
fn test_fixed_array_map() {
|
||||
a := [1, 2, 3]!
|
||||
|
||||
b1 := a.map(it * 2)
|
||||
println(b1)
|
||||
assert b1 == [2, 4, 6]!
|
||||
|
||||
b11 := a.map(|x| x * 2)
|
||||
println(b11)
|
||||
assert b11 == [2, 4, 6]!
|
||||
|
||||
b2 := a.map('${it}')
|
||||
println(b2)
|
||||
assert b2 == ['1', '2', '3']!
|
||||
|
||||
b22 := a.map(|x| '${x}')
|
||||
println(b22)
|
||||
assert b22 == ['1', '2', '3']!
|
||||
|
||||
b3 := a.map(it + 2)
|
||||
println(b3)
|
||||
assert b3 == [3, 4, 5]!
|
||||
|
||||
b33 := a.map(|x| x + 2)
|
||||
println(b33)
|
||||
assert b33 == [3, 4, 5]!
|
||||
}
|
|
@ -3498,6 +3498,51 @@ fn (mut c Checker) fixed_array_builtin_method_call(mut node ast.CallExpr, left_t
|
|||
c.error('`${left_sym.name}` has no method `wait()` (only thread handles and arrays of them have)',
|
||||
node.left.pos())
|
||||
}
|
||||
} else if method_name == 'map' {
|
||||
if node.args.len != 1 {
|
||||
c.error('`.${method_name}` expected 1 argument, but got ${node.args.len}',
|
||||
node.pos)
|
||||
return ast.void_type
|
||||
}
|
||||
if mut node.args[0].expr is ast.LambdaExpr {
|
||||
if node.args[0].expr.params.len != 1 {
|
||||
c.error('lambda expressions used in the builtin array methods require exactly 1 parameter',
|
||||
node.args[0].expr.pos)
|
||||
return ast.void_type
|
||||
}
|
||||
c.lambda_expr_fix_type_of_param(mut node.args[0].expr, mut node.args[0].expr.params[0],
|
||||
elem_typ)
|
||||
le_type := c.expr(mut node.args[0].expr.expr)
|
||||
c.support_lambda_expr_one_param(elem_typ, le_type, mut node.args[0].expr)
|
||||
} else {
|
||||
// position of `it` doesn't matter
|
||||
scope_register_it(mut node.scope, node.pos, elem_typ)
|
||||
}
|
||||
|
||||
c.check_map_and_filter(true, elem_typ, node)
|
||||
arg_type := c.check_expr_option_or_result_call(node.args[0].expr, c.expr(mut node.args[0].expr))
|
||||
arg_sym := c.table.sym(arg_type)
|
||||
ret_type := match arg_sym.info {
|
||||
ast.FnType {
|
||||
if node.args[0].expr is ast.SelectorExpr {
|
||||
arg_type
|
||||
} else {
|
||||
arg_sym.info.func.return_type
|
||||
}
|
||||
}
|
||||
else {
|
||||
arg_type
|
||||
}
|
||||
}
|
||||
node.return_type = c.table.find_or_register_array_fixed(c.unwrap_generic(ret_type),
|
||||
array_info.size, array_info.size_expr, false)
|
||||
if node.return_type.has_flag(.shared_f) {
|
||||
node.return_type = node.return_type.clear_flag(.shared_f).deref()
|
||||
}
|
||||
ret_sym := c.table.sym(ret_type)
|
||||
if ret_sym.kind == .multi_return {
|
||||
c.error('returning multiple values is not supported in .map() calls', node.pos)
|
||||
}
|
||||
}
|
||||
return node.return_type
|
||||
}
|
||||
|
|
|
@ -463,15 +463,26 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||
g.past_tmp_var_done(past)
|
||||
}
|
||||
|
||||
ret_typ := g.styp(node.return_type)
|
||||
ret_styp := g.styp(node.return_type)
|
||||
ret_sym := g.table.final_sym(node.return_type)
|
||||
left_is_array := g.table.final_sym(node.left_type).kind == .array
|
||||
inp_sym := g.table.final_sym(node.receiver_type)
|
||||
ret_info := ret_sym.info as ast.Array
|
||||
mut ret_elem_type := g.styp(ret_info.elem_type)
|
||||
inp_info := inp_sym.info as ast.Array
|
||||
inp_elem_type := g.styp(inp_info.elem_type)
|
||||
if inp_sym.kind != .array {
|
||||
verror('map() requires an array')
|
||||
|
||||
ret_elem_type := if left_is_array {
|
||||
(ret_sym.info as ast.Array).elem_type
|
||||
} else {
|
||||
(ret_sym.info as ast.ArrayFixed).elem_type
|
||||
}
|
||||
mut ret_elem_styp := g.styp(ret_elem_type)
|
||||
|
||||
inp_elem_type := if left_is_array {
|
||||
(inp_sym.info as ast.Array).elem_type
|
||||
} else {
|
||||
(inp_sym.info as ast.ArrayFixed).elem_type
|
||||
}
|
||||
inp_elem_styp := g.styp(inp_elem_type)
|
||||
if inp_sym.kind !in [.array, .array_fixed] {
|
||||
verror('map() requires an array or a fixed array')
|
||||
}
|
||||
|
||||
mut expr := node.args[0].expr
|
||||
|
@ -481,16 +492,18 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||
if expr.typ != ast.void_type {
|
||||
var_sym := g.table.sym(expr.typ)
|
||||
if var_sym.info is ast.FnType {
|
||||
ret_elem_type = 'voidptr'
|
||||
ret_elem_styp = 'voidptr'
|
||||
closure_var_decl = g.fn_var_signature(var_sym.info.func.return_type, var_sym.info.func.params.map(it.typ),
|
||||
tmp_map_expr_result_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
noscan := g.check_noscan(ret_info.elem_type)
|
||||
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, ret_typ,
|
||||
noscan := g.check_noscan(ret_elem_type)
|
||||
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, ret_styp,
|
||||
'{0}')
|
||||
g.writeln('${past.tmp_var} = __new_array${noscan}(0, ${past.tmp_var}_len, sizeof(${ret_elem_type}));\n')
|
||||
if left_is_array {
|
||||
g.writeln('${past.tmp_var} = __new_array${noscan}(0, ${past.tmp_var}_len, sizeof(${ret_elem_styp}));\n')
|
||||
}
|
||||
|
||||
mut closure_var := ''
|
||||
if mut expr is ast.AnonFn {
|
||||
|
@ -504,13 +517,12 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||
g.writeln('for (int ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
|
||||
g.indent++
|
||||
var_name := g.get_array_expr_param_name(mut expr)
|
||||
g.write_prepared_var(var_name, inp_info.elem_type, inp_elem_type, past.tmp_var, i,
|
||||
true)
|
||||
g.write_prepared_var(var_name, inp_elem_type, inp_elem_styp, past.tmp_var, i, left_is_array)
|
||||
g.set_current_pos_as_last_stmt_pos()
|
||||
mut is_embed_map_filter := false
|
||||
match mut expr {
|
||||
ast.AnonFn {
|
||||
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
|
||||
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
|
||||
if expr.inherited_vars.len > 0 {
|
||||
g.write_closure_fn(mut expr, var_name, closure_var)
|
||||
} else {
|
||||
|
@ -519,7 +531,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||
}
|
||||
}
|
||||
ast.Ident {
|
||||
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
|
||||
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
|
||||
if expr.kind == .function {
|
||||
if expr.obj is ast.Var && expr.obj.is_inherited {
|
||||
g.write(closure_ctx + '->')
|
||||
|
@ -545,7 +557,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||
is_embed_map_filter = true
|
||||
g.set_current_pos_as_last_stmt_pos()
|
||||
}
|
||||
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
|
||||
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
|
||||
g.expr(expr)
|
||||
}
|
||||
ast.CastExpr {
|
||||
|
@ -557,23 +569,27 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||
expr.expr_type = g.table.value_type(ctyp)
|
||||
}
|
||||
}
|
||||
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
|
||||
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
|
||||
g.expr(expr)
|
||||
}
|
||||
ast.LambdaExpr {
|
||||
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
|
||||
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
|
||||
g.expr(expr.expr)
|
||||
}
|
||||
else {
|
||||
if closure_var_decl != '' {
|
||||
g.write('${closure_var_decl} = ')
|
||||
} else {
|
||||
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
|
||||
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
|
||||
}
|
||||
g.expr(expr)
|
||||
}
|
||||
}
|
||||
if left_is_array {
|
||||
g.writeln2(';', 'array_push${noscan}((array*)&${past.tmp_var}, &${tmp_map_expr_result_name});')
|
||||
} else {
|
||||
g.writeln2(';', '${past.tmp_var}[${i}] = ${tmp_map_expr_result_name};')
|
||||
}
|
||||
g.indent--
|
||||
g.writeln('}')
|
||||
if !is_embed_map_filter {
|
||||
|
|
|
@ -1201,6 +1201,9 @@ fn (mut g Gen) gen_fixed_array_method_call(node ast.CallExpr, left_type ast.Type
|
|||
'all' {
|
||||
g.gen_array_all(node)
|
||||
}
|
||||
'map' {
|
||||
g.gen_array_map(node)
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue