all: implement array .any and .all (#9347)
parent
624c1f3bcf
commit
7222ee476b
|
@ -26,7 +26,7 @@ const (
|
|||
valid_comp_if_platforms = ['amd64', 'aarch64', 'x64', 'x32', 'little_endian', 'big_endian']
|
||||
valid_comp_if_other = ['js', 'debug', 'prod', 'test', 'glibc', 'prealloc', 'no_bounds_checking']
|
||||
array_builtin_methods = ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort',
|
||||
'contains', 'index', 'wait']
|
||||
'contains', 'index', 'wait', 'any', 'all']
|
||||
)
|
||||
|
||||
pub struct Checker {
|
||||
|
@ -1318,6 +1318,28 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_e
|
|||
c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`',
|
||||
arg_expr.pos)
|
||||
}
|
||||
} else if arg_expr.kind == .variable {
|
||||
if arg_expr.obj is ast.Var {
|
||||
expr := arg_expr.obj.expr
|
||||
if expr is ast.AnonFn {
|
||||
// copied from above
|
||||
if expr.decl.params.len > 1 {
|
||||
c.error('function needs exactly 1 argument', expr.decl.pos)
|
||||
} else if is_map && (expr.decl.return_type == table.void_type
|
||||
|| expr.decl.params[0].typ != elem_typ) {
|
||||
c.error('type mismatch, should use `fn(a $elem_sym.name) T {...}`',
|
||||
expr.decl.pos)
|
||||
} else if !is_map && (expr.decl.return_type != table.bool_type
|
||||
|| expr.decl.params[0].typ != elem_typ) {
|
||||
c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`',
|
||||
expr.decl.pos)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if !is_map && arg_expr.info.typ != table.bool_type {
|
||||
c.error('type mismatch, should be bool', arg_expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
|
@ -1665,7 +1687,7 @@ fn (mut c Checker) call_array_builtin_method(mut call_expr ast.CallExpr, left_ty
|
|||
}
|
||||
array_info := left_type_sym.info as table.Array
|
||||
elem_typ = array_info.elem_type
|
||||
if method_name in ['filter', 'map'] {
|
||||
if method_name in ['filter', 'map', 'any', 'all'] {
|
||||
// position of `it` doesn't matter
|
||||
scope_register_it(mut call_expr.scope, call_expr.pos, elem_typ)
|
||||
} else if method_name == 'sort' {
|
||||
|
@ -1728,6 +1750,9 @@ fn (mut c Checker) call_array_builtin_method(mut call_expr ast.CallExpr, left_ty
|
|||
} else if method_name == 'filter' {
|
||||
// check fn
|
||||
c.check_map_and_filter(false, elem_typ, call_expr)
|
||||
} else if method_name in ['any', 'all'] {
|
||||
c.check_map_and_filter(false, elem_typ, call_expr)
|
||||
call_expr.return_type = table.bool_type
|
||||
} else if method_name == 'clone' {
|
||||
// need to return `array_xxx` instead of `array`
|
||||
// in ['clone', 'str'] {
|
||||
|
|
|
@ -573,3 +573,131 @@ fn (mut g Gen) gen_array_wait(node ast.CallExpr) {
|
|||
g.expr(node.left)
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_array_any(node ast.CallExpr) {
|
||||
tmp := g.new_tmp_var()
|
||||
s := g.go_before_stmt(0)
|
||||
sym := g.table.get_type_symbol(node.left_type)
|
||||
info := sym.info as table.Array
|
||||
// styp := g.typ(node.return_type)
|
||||
elem_type_str := g.typ(info.elem_type)
|
||||
g.empty_line = true
|
||||
g.write('${g.typ(node.left_type)} ${tmp}_orig = ')
|
||||
g.expr(node.left)
|
||||
g.writeln(';')
|
||||
g.writeln('int ${tmp}_len = ${tmp}_orig.len;')
|
||||
g.writeln('bool $tmp = false;')
|
||||
i := g.new_tmp_var()
|
||||
g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {')
|
||||
g.writeln('\t$elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[$i];')
|
||||
mut is_embed_map_filter := false
|
||||
mut expr := node.args[0].expr
|
||||
match mut expr {
|
||||
ast.AnonFn {
|
||||
g.write('\tif (')
|
||||
g.gen_anon_fn_decl(mut expr)
|
||||
g.write('${expr.decl.name}(it)')
|
||||
}
|
||||
ast.Ident {
|
||||
g.write('\tif (')
|
||||
if expr.kind == .function {
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else if expr.kind == .variable {
|
||||
var_info := expr.var_info()
|
||||
sym_t := g.table.get_type_symbol(var_info.typ)
|
||||
if sym_t.kind == .function {
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
}
|
||||
ast.CallExpr {
|
||||
if expr.name in ['map', 'filter'] {
|
||||
is_embed_map_filter = true
|
||||
g.stmt_path_pos << g.out.len
|
||||
}
|
||||
g.write('\tif (')
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
else {
|
||||
g.write('\tif (')
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
}
|
||||
g.writeln(') {')
|
||||
g.writeln('\t\t$tmp = true;\n\t\t\tbreak;\n\t\t}')
|
||||
g.writeln('}')
|
||||
if !is_embed_map_filter {
|
||||
g.stmt_path_pos << g.out.len
|
||||
}
|
||||
g.write('\n')
|
||||
g.write(s)
|
||||
g.write(tmp)
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_array_all(node ast.CallExpr) {
|
||||
tmp := g.new_tmp_var()
|
||||
s := g.go_before_stmt(0)
|
||||
sym := g.table.get_type_symbol(node.left_type)
|
||||
info := sym.info as table.Array
|
||||
// styp := g.typ(node.return_type)
|
||||
elem_type_str := g.typ(info.elem_type)
|
||||
g.empty_line = true
|
||||
g.write('${g.typ(node.left_type)} ${tmp}_orig = ')
|
||||
g.expr(node.left)
|
||||
g.writeln(';')
|
||||
g.writeln('int ${tmp}_len = ${tmp}_orig.len;')
|
||||
g.writeln('bool $tmp = true;')
|
||||
i := g.new_tmp_var()
|
||||
g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {')
|
||||
g.writeln('\t$elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[$i];')
|
||||
mut is_embed_map_filter := false
|
||||
mut expr := node.args[0].expr
|
||||
match mut expr {
|
||||
ast.AnonFn {
|
||||
g.write('\tif (!(')
|
||||
g.gen_anon_fn_decl(mut expr)
|
||||
g.write('${expr.decl.name}(it)')
|
||||
}
|
||||
ast.Ident {
|
||||
g.write('\tif (!(')
|
||||
if expr.kind == .function {
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else if expr.kind == .variable {
|
||||
var_info := expr.var_info()
|
||||
sym_t := g.table.get_type_symbol(var_info.typ)
|
||||
if sym_t.kind == .function {
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
}
|
||||
ast.CallExpr {
|
||||
if expr.name in ['map', 'filter'] {
|
||||
is_embed_map_filter = true
|
||||
g.stmt_path_pos << g.out.len
|
||||
}
|
||||
g.write('\tif (!(')
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
else {
|
||||
g.write('\tif (!(')
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
}
|
||||
g.writeln(')) {')
|
||||
g.writeln('\t\t$tmp = false;\n\t\t\tbreak;\n\t\t}')
|
||||
g.writeln('}')
|
||||
if !is_embed_map_filter {
|
||||
g.stmt_path_pos << g.out.len
|
||||
}
|
||||
g.write('\n')
|
||||
g.write(s)
|
||||
g.write(tmp)
|
||||
}
|
||||
|
|
|
@ -535,6 +535,14 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
g.gen_array_wait(node)
|
||||
return
|
||||
}
|
||||
'any' {
|
||||
g.gen_array_any(node)
|
||||
return
|
||||
}
|
||||
'all' {
|
||||
g.gen_array_all(node)
|
||||
return
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2111,7 +2111,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
|||
} else {
|
||||
p.name_error = true
|
||||
}
|
||||
is_filter := field_name in ['filter', 'map']
|
||||
is_filter := field_name in ['filter', 'map', 'any', 'all']
|
||||
if is_filter || field_name == 'sort' {
|
||||
p.open_scope()
|
||||
}
|
||||
|
|
|
@ -17,4 +17,14 @@ fn test_array_eval_count() {
|
|||
|
||||
mut a2 := Counter{}
|
||||
assert a2.new_arr('filter() failed').filter(it < 3) == [1, 2]
|
||||
|
||||
mut a3 := Counter{}
|
||||
assert a3.new_arr('any() failed').any(it == 2) == true
|
||||
a3 = Counter{}
|
||||
assert a3.new_arr('any() failed').any(it < 0) == false
|
||||
|
||||
mut a4 := Counter{}
|
||||
assert a4.new_arr('all() failed').all(it > 0) == true
|
||||
a4 = Counter{}
|
||||
assert a4.new_arr('all() failed').all(it == 2) == false
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue