cgen: implement generic `array.index` (#7501)

pull/7525/head
yuyi 2020-12-24 02:10:16 +08:00 committed by GitHub
parent f505f5e333
commit 132807d5d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 102 additions and 1 deletions

View File

@ -1226,3 +1226,28 @@ fn test_struct_array_of_multi_type_in() {
println(ivan in people)
assert ivan in people
}
fn test_struct_array_of_multi_type_index() {
ivan := Person{
name: 'ivan'
nums: [1, 2, 3]
kv: {
'aaa': '111'
}
}
people := [Person{
name: 'ivan'
nums: [1, 2, 3]
kv: {
'aaa': '111'
}
}, Person{
name: 'bob'
nums: [2]
kv: {
'bbb': '222'
}
}]
println(people.index(ivan))
assert people.index(ivan) == 0
}

View File

@ -1161,7 +1161,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
// FIXME: Argument count != 1 will break these
if left_type_sym.kind == .array &&
method_name in
['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort', 'contains'] {
['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort', 'contains', 'index'] {
mut elem_typ := table.void_type
is_filter_map := method_name in ['filter', 'map']
is_sort := method_name == 'sort'
@ -1212,6 +1212,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
call_expr.return_type = table.void_type
} else if method_name == 'contains' {
call_expr.return_type = table.bool_type
} else if method_name == 'index' {
call_expr.return_type = table.int_type
}
return call_expr.return_type
} else if left_type_sym.kind == .map && method_name == 'clone' {

View File

@ -5257,6 +5257,76 @@ fn (mut g Gen) gen_array_contains(node ast.CallExpr) {
g.write(')')
}
fn (mut g Gen) gen_array_index_method(left_type table.Type) string {
mut left_sym := g.table.get_type_symbol(left_type)
mut left_type_str := g.typ(left_type).replace('*', '')
left_info := left_sym.info as table.Array
mut elem_type_str := g.typ(left_info.elem_type)
elem_sym := g.table.get_type_symbol(left_info.elem_type)
if elem_sym.kind == .function {
left_type_str = 'array_voidptr'
elem_type_str = 'voidptr'
}
fn_name := '${left_type_str}_index'
if !left_sym.has_method('index') {
g.type_definitions.writeln('static int ${fn_name}($left_type_str a, $elem_type_str v); // auto')
mut fn_builder := strings.new_builder(512)
fn_builder.writeln('static int ${fn_name}($left_type_str a, $elem_type_str v) {')
fn_builder.writeln('\tfor (int i = 0; i < a.len; ++i) {')
match elem_sym.kind {
.string {
fn_builder.writeln('\t\tif (string_eq((*(string*)array_get(a, i)), v)) {')
}
.array {
ptr_typ := g.gen_array_equality_fn(left_info.elem_type)
fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(*($elem_type_str*)array_get(a, i), v)) {')
}
.function {
fn_builder.writeln('\t\tif ((*(voidptr*)array_get(a, i)) == v) {')
}
.map {
ptr_typ := g.gen_map_equality_fn(left_info.elem_type)
fn_builder.writeln('\t\tif (${ptr_typ}_map_eq(*($elem_type_str*)array_get(a, i), v)) {')
}
.struct_ {
ptr_typ := g.gen_struct_equality_fn(left_info.elem_type)
fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(*($elem_type_str*)array_get(a, i), v)) {')
}
else {
fn_builder.writeln('\t\tif ((*($elem_type_str*)array_get(a, i)) == v) {')
}
}
fn_builder.writeln('\t\t\treturn i;')
fn_builder.writeln('\t\t}')
fn_builder.writeln('\t}')
fn_builder.writeln('\treturn -1;')
fn_builder.writeln('}')
g.auto_fn_definitions << fn_builder.str()
left_sym.register_method(&table.Fn{
name: 'index'
params: [table.Param{
typ: left_type
}, table.Param{
typ: left_info.elem_type
}]
})
}
return fn_name
}
// `nums.index(2)`
fn (mut g Gen) gen_array_index(node ast.CallExpr) {
fn_name := g.gen_array_index_method(node.left_type)
g.write('${fn_name}(')
if node.left_type.is_ptr() {
g.write('*')
}
g.expr(node.left)
g.write(', ')
g.expr(node.args[0].expr)
g.write(')')
}
[inline]
fn (g &Gen) nth_stmt_pos(n int) int {
return g.stmt_path_pos[g.stmt_path_pos.len - (1 + n)]

View File

@ -374,6 +374,10 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.gen_array_contains(node)
return
}
'index' {
g.gen_array_index(node)
return
}
else {}
}
}