diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index cb09bb441e..7b992f7ec4 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -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 +} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 720011fc6d..7cf5e4f7f9 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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' { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index e20aea89c5..aef163b1e3 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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)] diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index d1955caf2b..9f95f8698b 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -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 {} } }