checker, cgen: implement method map() for fixed arrays (#22644)

This commit is contained in:
yuyi 2024-10-25 16:49:48 +08:00 committed by GitHub
parent 4e9f7c21aa
commit 5ad0186895
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 111 additions and 20 deletions

View 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]!
}

View file

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

View file

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

View file

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