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)',
|
c.error('`${left_sym.name}` has no method `wait()` (only thread handles and arrays of them have)',
|
||||||
node.left.pos())
|
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
|
return node.return_type
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,15 +463,26 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
||||||
g.past_tmp_var_done(past)
|
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)
|
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)
|
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)
|
ret_elem_type := if left_is_array {
|
||||||
inp_info := inp_sym.info as ast.Array
|
(ret_sym.info as ast.Array).elem_type
|
||||||
inp_elem_type := g.styp(inp_info.elem_type)
|
} else {
|
||||||
if inp_sym.kind != .array {
|
(ret_sym.info as ast.ArrayFixed).elem_type
|
||||||
verror('map() requires an array')
|
}
|
||||||
|
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
|
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 {
|
if expr.typ != ast.void_type {
|
||||||
var_sym := g.table.sym(expr.typ)
|
var_sym := g.table.sym(expr.typ)
|
||||||
if var_sym.info is ast.FnType {
|
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),
|
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)
|
tmp_map_expr_result_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
noscan := g.check_noscan(ret_info.elem_type)
|
noscan := g.check_noscan(ret_elem_type)
|
||||||
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, ret_typ,
|
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, ret_styp,
|
||||||
'{0}')
|
'{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 := ''
|
mut closure_var := ''
|
||||||
if mut expr is ast.AnonFn {
|
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.writeln('for (int ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
|
||||||
g.indent++
|
g.indent++
|
||||||
var_name := g.get_array_expr_param_name(mut expr)
|
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,
|
g.write_prepared_var(var_name, inp_elem_type, inp_elem_styp, past.tmp_var, i, left_is_array)
|
||||||
true)
|
|
||||||
g.set_current_pos_as_last_stmt_pos()
|
g.set_current_pos_as_last_stmt_pos()
|
||||||
mut is_embed_map_filter := false
|
mut is_embed_map_filter := false
|
||||||
match mut expr {
|
match mut expr {
|
||||||
ast.AnonFn {
|
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 {
|
if expr.inherited_vars.len > 0 {
|
||||||
g.write_closure_fn(mut expr, var_name, closure_var)
|
g.write_closure_fn(mut expr, var_name, closure_var)
|
||||||
} else {
|
} else {
|
||||||
|
@ -519,7 +531,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.Ident {
|
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.kind == .function {
|
||||||
if expr.obj is ast.Var && expr.obj.is_inherited {
|
if expr.obj is ast.Var && expr.obj.is_inherited {
|
||||||
g.write(closure_ctx + '->')
|
g.write(closure_ctx + '->')
|
||||||
|
@ -545,7 +557,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
||||||
is_embed_map_filter = true
|
is_embed_map_filter = true
|
||||||
g.set_current_pos_as_last_stmt_pos()
|
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)
|
g.expr(expr)
|
||||||
}
|
}
|
||||||
ast.CastExpr {
|
ast.CastExpr {
|
||||||
|
@ -557,23 +569,27 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
||||||
expr.expr_type = g.table.value_type(ctyp)
|
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)
|
g.expr(expr)
|
||||||
}
|
}
|
||||||
ast.LambdaExpr {
|
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)
|
g.expr(expr.expr)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if closure_var_decl != '' {
|
if closure_var_decl != '' {
|
||||||
g.write('${closure_var_decl} = ')
|
g.write('${closure_var_decl} = ')
|
||||||
} else {
|
} else {
|
||||||
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
|
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
|
||||||
}
|
}
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln2(';', 'array_push${noscan}((array*)&${past.tmp_var}, &${tmp_map_expr_result_name});')
|
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.indent--
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
if !is_embed_map_filter {
|
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' {
|
'all' {
|
||||||
g.gen_array_all(node)
|
g.gen_array_all(node)
|
||||||
}
|
}
|
||||||
|
'map' {
|
||||||
|
g.gen_array_map(node)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue