// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. // Use of this source code is governed by an MIT license that can be found in the LICENSE file. module c import strings import v.ast fn (mut g Gen) array_init(node ast.ArrayInit) { array_type := g.unwrap(node.typ) mut array_styp := '' elem_type := g.unwrap(node.elem_type) mut shared_styp := '' // only needed for shared &[]{...} is_amp := g.is_amp g.is_amp = false if is_amp { g.out.go_back(1) // delete the `&` already generated in `prefix_expr() } if g.is_shared { shared_styp = g.typ(array_type.typ.set_flag(.shared_f)) g.writeln('($shared_styp*)__dup_shared_array(&($shared_styp){.mtx = {0}, .val =') } else if is_amp { array_styp = g.typ(array_type.typ) g.write('HEAP($array_styp, ') } if array_type.unaliased_sym.kind == .array_fixed { if node.has_it { g.inside_lambda = true tmp := g.new_tmp_var() mut s := g.go_before_stmt(0) s_ends_with_ln := s.ends_with('\n') s = s.trim_space() ret_typ := g.typ(node.typ) elem_typ := g.typ(node.elem_type) g.empty_line = true g.write('$ret_typ $tmp =') g.write('{') if node.has_val { for i, expr in node.exprs { if expr.is_auto_deref_var() { g.write('*') } g.write('0') if i != node.exprs.len - 1 { g.write(', ') } } } else if node.has_default { g.write('0') info := array_type.unaliased_sym.info as ast.ArrayFixed for _ in 1 .. info.size { g.write(', ') g.write('0') } } else { g.write('0') } g.write('}') g.writeln(';') g.writeln('{') g.indent++ g.writeln('$elem_typ* pelem = ($elem_typ*)$tmp;') g.writeln('int _len = (int)sizeof($tmp) / sizeof($elem_typ);') g.writeln('for(int it=0; it<_len; it++, pelem++) {') g.indent++ g.write('*pelem = ') g.expr(node.default_expr) g.writeln(';') g.indent-- g.writeln('}') g.indent-- g.writeln('}') if s_ends_with_ln { g.writeln(s) } else { g.write(s) } g.write(tmp) g.inside_lambda = false return } g.write('{') if node.has_val { for i, expr in node.exprs { if expr.is_auto_deref_var() { g.write('*') } g.expr(expr) if i != node.exprs.len - 1 { g.write(', ') } } } else if node.has_default { g.expr(node.default_expr) info := array_type.unaliased_sym.info as ast.ArrayFixed for _ in 1 .. info.size { g.write(', ') g.expr(node.default_expr) } } else { g.write('0') } g.write('}') return } elem_styp := g.typ(elem_type.typ) noscan := g.check_noscan(elem_type.typ) if node.exprs.len == 0 { is_default_array := elem_type.unaliased_sym.kind == .array && node.has_default if node.has_it { // []int{len: 6, init: it * it} when variable it is used in init expression g.inside_lambda = true tmp := g.new_tmp_var() mut s := g.go_before_stmt(0) s_ends_with_ln := s.ends_with('\n') s = s.trim_space() ret_typ := g.typ(node.typ) elem_typ := g.typ(node.elem_type) g.empty_line = true g.write('$ret_typ $tmp =') if is_default_array { g.write('__new_array_with_array_default${noscan}(') } else { g.write('__new_array_with_default${noscan}(') } if node.has_len { g.expr(node.len_expr) g.write(', ') } else { g.write('0, ') } if node.has_cap { g.expr(node.cap_expr) g.write(', ') } else { g.write('0, ') } if elem_type.unaliased_sym.kind == .function { g.write('sizeof(voidptr), ') } else { g.write('sizeof($elem_styp), ') } if is_default_array { g.write('($elem_styp[]){') g.expr(node.default_expr) g.write('}[0])') } else if node.has_len && node.elem_type == ast.string_type { g.write('&($elem_styp[]){') g.write('_SLIT("")') g.write('})') } else if node.has_len && elem_type.unaliased_sym.kind in [.array, .map] { g.write('(voidptr)&($elem_styp[]){') g.write(g.type_default(node.elem_type)) g.write('}[0])') } else { g.write('0)') } if g.is_shared { g.write('}, sizeof($shared_styp))') } else if is_amp { g.write(')') } g.writeln(';') g.writeln('{') g.indent++ g.writeln('$elem_typ* pelem = ($elem_typ*)${tmp}.data;') g.writeln('for(int it=0; it<${tmp}.len; it++, pelem++) {') g.indent++ g.write('*pelem = ') g.expr(node.default_expr) g.writeln(';') g.indent-- g.writeln('}') g.indent-- g.writeln('}') if s_ends_with_ln { g.writeln(s) } else { g.write(s) } g.write(tmp) g.inside_lambda = false return } if is_default_array { g.write('__new_array_with_array_default${noscan}(') } else { g.write('__new_array_with_default${noscan}(') } if node.has_len { g.expr(node.len_expr) g.write(', ') } else { g.write('0, ') } if node.has_cap { g.expr(node.cap_expr) g.write(', ') } else { g.write('0, ') } if elem_type.unaliased_sym.kind == .function { g.write('sizeof(voidptr), ') } else { g.write('sizeof($elem_styp), ') } if is_default_array { g.write('($elem_styp[]){') g.expr(node.default_expr) g.write('}[0])') } else if node.has_default { g.write('&($elem_styp[]){') g.expr(node.default_expr) g.write('})') } else if node.has_len && node.elem_type == ast.string_type { g.write('&($elem_styp[]){') g.write('_SLIT("")') g.write('})') } else if node.has_len && elem_type.unaliased_sym.kind in [.array, .map] { g.write('(voidptr)&($elem_styp[]){') g.write(g.type_default(node.elem_type)) g.write('}[0])') } else { g.write('0)') } if g.is_shared { g.write('}, sizeof($shared_styp))') } else if is_amp { g.write(')') } return } len := node.exprs.len if elem_type.unaliased_sym.kind == .function { g.write('new_array_from_c_array($len, $len, sizeof(voidptr), _MOV((voidptr[$len]){') } else { g.write('new_array_from_c_array${noscan}($len, $len, sizeof($elem_styp), _MOV(($elem_styp[$len]){') } if len > 8 { g.writeln('') g.write('\t\t') } for i, expr in node.exprs { if node.expr_types[i] == ast.string_type && expr !is ast.StringLiteral && expr !is ast.StringInterLiteral { g.write('string_clone(') g.expr(expr) g.write(')') } else { g.expr_with_cast(expr, node.expr_types[i], node.elem_type) } if i != len - 1 { if i > 0 && i & 7 == 0 { // i > 0 && i % 8 == 0 g.writeln(',') g.write('\t\t') } else { g.write(', ') } } } g.write('}))') if g.is_shared { g.write('}, sizeof($shared_styp))') } else if is_amp { g.write(')') } } // `nums.map(it % 2 == 0)` fn (mut g Gen) gen_array_map(node ast.CallExpr) { g.inside_lambda = true tmp := g.new_tmp_var() mut s := g.go_before_stmt(0) s_ends_with_ln := s.ends_with('\n') s = s.trim_space() // println('filter s="$s"') ret_typ := g.typ(node.return_type) // inp_typ := g.typ(node.receiver_type) ret_sym := g.table.get_type_symbol(node.return_type) inp_sym := g.table.get_type_symbol(node.receiver_type) ret_info := ret_sym.info as ast.Array ret_elem_type := g.typ(ret_info.elem_type) inp_info := inp_sym.info as ast.Array inp_elem_type := g.typ(inp_info.elem_type) if inp_sym.kind != .array { verror('map() requires an array') } g.empty_line = true noscan := g.check_noscan(ret_info.elem_type) g.writeln('$ret_typ $tmp = __new_array${noscan}(0, 0, sizeof($ret_elem_type));') has_infix_left_var_name := g.infix_left_var_name.len > 0 if has_infix_left_var_name { g.writeln('if ($g.infix_left_var_name) {') g.infix_left_var_name = '' g.indent++ } 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('$tmp = __new_array${noscan}(0, ${tmp}_len, sizeof($ret_elem_type));\n') i := g.new_tmp_var() g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {') g.indent++ g.writeln('$inp_elem_type it = (($inp_elem_type*) ${tmp}_orig.data)[$i];') g.set_current_pos_as_last_stmt_pos() mut is_embed_map_filter := false mut expr := node.args[0].expr match mut expr { ast.AnonFn { g.write('$ret_elem_type ti = ') g.gen_anon_fn_decl(mut expr) g.write('${expr.decl.name}(it)') } ast.Ident { g.write('$ret_elem_type ti = ') if expr.kind == .function { g.write('${c_name(expr.name)}(it)') } else if expr.kind == .variable { var_info := expr.var_info() sym := g.table.get_type_symbol(var_info.typ) if sym.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', 'all', 'any'] { is_embed_map_filter = true g.set_current_pos_as_last_stmt_pos() } g.write('$ret_elem_type ti = ') g.expr(node.args[0].expr) } else { g.write('$ret_elem_type ti = ') g.expr(node.args[0].expr) } } g.writeln(';') g.writeln('array_push${noscan}((array*)&$tmp, &ti);') g.indent-- g.writeln('}') if !is_embed_map_filter { g.set_current_pos_as_last_stmt_pos() } if has_infix_left_var_name { g.indent-- g.writeln('}') } if s_ends_with_ln { g.writeln(s) } else { g.write(s) } g.write(tmp) g.inside_lambda = false } // `users.sort(a.age < b.age)` fn (mut g Gen) gen_array_sort(node ast.CallExpr) { // println('filter s="$s"') rec_sym := g.table.get_type_symbol(node.receiver_type) if rec_sym.kind != .array { println(node.name) println(g.typ(node.receiver_type)) // println(rec_sym.kind) verror('.sort() is an array method') } if g.pref.is_bare { g.writeln('bare_panic(_SLIT("sort does not work with -freestanding"))') return } info := rec_sym.info as ast.Array // `users.sort(a.age > b.age)` // Generate a comparison function for a custom type elem_stype := g.typ(info.elem_type) mut compare_fn := 'compare_${elem_stype.replace('*', '_ptr')}' mut comparison_type := g.unwrap(ast.void_type) mut left_expr, mut right_expr := '', '' // the only argument can only be an infix expression like `a < b` or `b.field > a.field` if node.args.len == 0 { comparison_type = g.unwrap(info.elem_type.set_nr_muls(0)) shared a := g.array_sort_fn array_sort_fn := a.clone() if compare_fn in array_sort_fn { g.gen_array_sort_call(node, compare_fn) return } left_expr = '*a' right_expr = '*b' } else { infix_expr := node.args[0].expr as ast.InfixExpr comparison_type = g.unwrap(infix_expr.left_type.set_nr_muls(0)) left_name := infix_expr.left.str() if left_name.len > 1 { compare_fn += '_by' + left_name[1..].replace_each(['.', '_', '[', '_', ']', '_']) } // is_reverse is `true` for `.sort(a > b)` and `.sort(b < a)` is_reverse := (left_name.starts_with('a') && infix_expr.op == .gt) || (left_name.starts_with('b') && infix_expr.op == .lt) if is_reverse { compare_fn += '_reverse' } shared a := g.array_sort_fn array_sort_fn := a.clone() if compare_fn in array_sort_fn { g.gen_array_sort_call(node, compare_fn) return } if left_name.starts_with('a') != is_reverse { left_expr = g.expr_string(infix_expr.left) right_expr = g.expr_string(infix_expr.right) if infix_expr.left is ast.Ident { left_expr = '*' + left_expr } if infix_expr.right is ast.Ident { right_expr = '*' + right_expr } } else { left_expr = g.expr_string(infix_expr.right) right_expr = g.expr_string(infix_expr.left) if infix_expr.left is ast.Ident { right_expr = '*' + right_expr } if infix_expr.right is ast.Ident { left_expr = '*' + left_expr } } } // Register a new custom `compare_xxx` function for qsort() // TODO: move to checker lock g.array_sort_fn { g.array_sort_fn << compare_fn } stype_arg := g.typ(info.elem_type) g.definitions.writeln('int ${compare_fn}($stype_arg* a, $stype_arg* b) {') c_condition := if comparison_type.sym.has_method('<') { '${g.typ(comparison_type.typ)}__lt($left_expr, $right_expr)' } else if comparison_type.unaliased_sym.has_method('<') { '${g.typ(comparison_type.unaliased)}__lt($left_expr, $right_expr)' } else { '$left_expr < $right_expr' } g.definitions.writeln('\tif ($c_condition) return -1;') g.definitions.writeln('\telse return 1;') g.definitions.writeln('}\n') // write call to the generated function g.gen_array_sort_call(node, compare_fn) } fn (mut g Gen) gen_array_sort_call(node ast.CallExpr, compare_fn string) { deref_field := if node.left_type.is_ptr() || node.left_type.is_pointer() { '->' } else { '.' } // eprintln('> qsort: pointer $node.left_type | deref: `$deref`') g.empty_line = true g.write('qsort(') g.expr(node.left) g.write('${deref_field}data, ') g.expr(node.left) g.write('${deref_field}len, ') g.expr(node.left) g.write('${deref_field}element_size, (int (*)(const void *, const void *))&$compare_fn)') } // `nums.filter(it % 2 == 0)` fn (mut g Gen) gen_array_filter(node ast.CallExpr) { tmp := g.new_tmp_var() mut s := g.go_before_stmt(0) s_ends_with_ln := s.ends_with('\n') s = s.trim_space() // println('filter s="$s"') sym := g.table.get_type_symbol(node.return_type) if sym.kind != .array { verror('filter() requires an array') } info := sym.info as ast.Array styp := g.typ(node.return_type) elem_type_str := g.typ(info.elem_type) g.empty_line = true noscan := g.check_noscan(info.elem_type) g.writeln('$styp $tmp = __new_array${noscan}(0, 0, sizeof($elem_type_str));') has_infix_left_var_name := g.infix_left_var_name.len > 0 if has_infix_left_var_name { g.writeln('if ($g.infix_left_var_name) {') g.infix_left_var_name = '' g.indent++ } 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('$tmp = __new_array${noscan}(0, ${tmp}_len, sizeof($elem_type_str));\n') i := g.new_tmp_var() g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {') g.indent++ g.writeln('$elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[$i];') g.set_current_pos_as_last_stmt_pos() mut is_embed_map_filter := false mut expr := node.args[0].expr match mut expr { ast.AnonFn { g.write('if (') g.gen_anon_fn_decl(mut expr) g.write('${expr.decl.name}(it)') } ast.Ident { g.write('if (') 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', 'all', 'any'] { is_embed_map_filter = true g.set_current_pos_as_last_stmt_pos() } g.write('if (') g.expr(node.args[0].expr) } else { g.write('if (') g.expr(node.args[0].expr) } } g.writeln(') {') g.writeln('\tarray_push${noscan}((array*)&$tmp, &it);') g.writeln('}') g.indent-- g.writeln('}') if !is_embed_map_filter { g.set_current_pos_as_last_stmt_pos() } if has_infix_left_var_name { g.indent-- g.writeln('}') } if s_ends_with_ln { g.writeln(s) } else { g.write(s) } g.write(tmp) } // `nums.insert(0, 2)` `nums.insert(0, [2,3,4])` fn (mut g Gen) gen_array_insert(node ast.CallExpr) { left_sym := g.table.get_type_symbol(node.left_type) left_info := left_sym.info as ast.Array elem_type_str := g.typ(left_info.elem_type) arg2_sym := g.table.get_type_symbol(node.args[1].typ) is_arg2_array := arg2_sym.kind == .array && node.args[1].typ == node.left_type noscan := g.check_noscan(left_info.elem_type) if is_arg2_array { g.write('array_insert_many${noscan}(&') } else { g.write('array_insert${noscan}(&') } g.expr(node.left) g.write(', ') g.expr(node.args[0].expr) if is_arg2_array { g.write(', ') g.expr(node.args[1].expr) g.write('.data, ') g.expr(node.args[1].expr) g.write('.len)') } else { g.write(', &($elem_type_str[]){') if left_info.elem_type == ast.string_type { g.write('string_clone(') } g.expr_with_cast(node.args[1].expr, node.args[1].typ, left_info.elem_type) if left_info.elem_type == ast.string_type { g.write(')') } g.write('})') } } // `nums.prepend(2)` `nums.prepend([2,3,4])` fn (mut g Gen) gen_array_prepend(node ast.CallExpr) { left_sym := g.table.get_type_symbol(node.left_type) left_info := left_sym.info as ast.Array elem_type_str := g.typ(left_info.elem_type) arg_sym := g.table.get_type_symbol(node.args[0].typ) is_arg_array := arg_sym.kind == .array && node.args[0].typ == node.left_type noscan := g.check_noscan(left_info.elem_type) if is_arg_array { g.write('array_prepend_many${noscan}(&') } else { g.write('array_prepend${noscan}(&') } g.expr(node.left) if is_arg_array { g.write(', ') g.expr(node.args[0].expr) g.write('.data, ') g.expr(node.args[0].expr) g.write('.len)') } else { g.write(', &($elem_type_str[]){') g.expr_with_cast(node.args[0].expr, node.args[0].typ, left_info.elem_type) g.write('})') } } fn (mut g Gen) get_array_contains_method(typ ast.Type) string { t := g.table.get_final_type_symbol(g.unwrap_generic(typ).set_nr_muls(0)).idx g.array_contains_types << t return g.typ(t) + '_contains' } fn (mut g Gen) gen_array_contains_methods() { mut done := []ast.Type{} for t in g.array_contains_types { left_final_sym := g.table.get_final_type_symbol(t) if left_final_sym.idx in done || g.table.get_type_symbol(t).has_method('contains') { continue } done << t mut left_type_str := g.typ(t) fn_name := '${left_type_str}_contains' left_info := left_final_sym.info as ast.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' } g.type_definitions.writeln('static bool ${fn_name}($left_type_str a, $elem_type_str v); // auto') mut fn_builder := strings.new_builder(512) fn_builder.writeln('static bool ${fn_name}($left_type_str a, $elem_type_str v) {') fn_builder.writeln('\tfor (int i = 0; i < a.len; ++i) {') if elem_sym.kind == .string { fn_builder.writeln('\t\tif (fast_string_eq(((string*)a.data)[i], v)) {') } else if elem_sym.kind == .array && left_info.elem_type.nr_muls() == 0 { ptr_typ := g.equality_fn(left_info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq((($elem_type_str*)a.data)[i], v)) {') } else if elem_sym.kind == .function { fn_builder.writeln('\t\tif (((voidptr*)a.data)[i] == v) {') } else if elem_sym.kind == .map && left_info.elem_type.nr_muls() == 0 { ptr_typ := g.equality_fn(left_info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((($elem_type_str*)a.data)[i], v)) {') } else if elem_sym.kind == .struct_ && left_info.elem_type.nr_muls() == 0 { ptr_typ := g.equality_fn(left_info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq((($elem_type_str*)a.data)[i], v)) {') } else if elem_sym.kind == .interface_ && left_info.elem_type.nr_muls() == 0 { ptr_typ := g.equality_fn(left_info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq((($elem_type_str*)a.data)[i], v)) {') } else if elem_sym.kind == .sum_type && left_info.elem_type.nr_muls() == 0 { ptr_typ := g.equality_fn(left_info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq((($elem_type_str*)a.data)[i], v)) {') } else { fn_builder.writeln('\t\tif ((($elem_type_str*)a.data)[i] == v) {') } fn_builder.writeln('\t\t\treturn true;') fn_builder.writeln('\t\t}') fn_builder.writeln('\t}') fn_builder.writeln('\treturn false;') fn_builder.writeln('}') g.auto_fn_definitions << fn_builder.str() } } // `nums.contains(2)` fn (mut g Gen) gen_array_contains(typ ast.Type, left ast.Expr, right ast.Expr) { fn_name := g.get_array_contains_method(typ) g.write('${fn_name}(') g.write(strings.repeat(`*`, typ.nr_muls())) if typ.share() == .shared_t { g.out.go_back(1) } g.expr(left) if typ.share() == .shared_t { g.write('->val') } g.write(', ') g.expr(right) g.write(')') } fn (mut g Gen) get_array_index_method(typ ast.Type) string { t := g.unwrap_generic(typ).set_nr_muls(0) g.array_index_types << t return g.typ(t) + '_index' } fn (mut g Gen) gen_array_index_methods() { mut done := []ast.Type{} for t in g.array_index_types { if t in done || g.table.get_type_symbol(t).has_method('index') { continue } done << t final_left_sym := g.table.get_final_type_symbol(t) mut left_type_str := g.typ(t) fn_name := '${left_type_str}_index' info := final_left_sym.info as ast.Array mut elem_type_str := g.typ(info.elem_type) elem_sym := g.table.get_type_symbol(info.elem_type) if elem_sym.kind == .function { left_type_str = 'Array_voidptr' elem_type_str = 'voidptr' } 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('\t$elem_type_str* pelem = a.data;') fn_builder.writeln('\tfor (int i = 0; i < a.len; ++i, ++pelem) {') if elem_sym.kind == .string { fn_builder.writeln('\t\tif (fast_string_eq(*pelem, v)) {') } else if elem_sym.kind == .array && !info.elem_type.is_ptr() { ptr_typ := g.equality_fn(info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(*pelem, v)) {') } else if elem_sym.kind == .function && !info.elem_type.is_ptr() { fn_builder.writeln('\t\tif ( pelem == v) {') } else if elem_sym.kind == .map && !info.elem_type.is_ptr() { ptr_typ := g.equality_fn(info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((*pelem, v))) {') } else if elem_sym.kind == .struct_ && !info.elem_type.is_ptr() { ptr_typ := g.equality_fn(info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(*pelem, v)) {') } else if elem_sym.kind == .interface_ { ptr_typ := g.equality_fn(info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_interface_eq(*pelem, v)) {') } else if elem_sym.kind == .sum_type { ptr_typ := g.equality_fn(info.elem_type) fn_builder.writeln('\t\tif (${ptr_typ}_sumtype_eq(*pelem, v)) {') } else { fn_builder.writeln('\t\tif (*pelem == 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() } } // `nums.index(2)` fn (mut g Gen) gen_array_index(node ast.CallExpr) { fn_name := g.get_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(')') } fn (mut g Gen) gen_array_wait(node ast.CallExpr) { arr := g.table.get_type_symbol(node.receiver_type) thread_type := arr.array_info().elem_type thread_sym := g.table.get_type_symbol(thread_type) thread_ret_type := thread_sym.thread_info().return_type eltyp := g.table.get_type_symbol(thread_ret_type).cname fn_name := g.register_thread_array_wait_call(eltyp) g.write('${fn_name}(') g.expr(node.left) g.write(')') } fn (mut g Gen) gen_array_any(node ast.CallExpr) { tmp := g.new_tmp_var() mut s := g.go_before_stmt(0) s_ends_with_ln := s.ends_with('\n') s = s.trim_space() sym := g.table.get_type_symbol(node.left_type) info := sym.info as ast.Array // styp := g.typ(node.return_type) elem_type_str := g.typ(info.elem_type) g.empty_line = true g.writeln('bool $tmp = false;') has_infix_left_var_name := g.infix_left_var_name.len > 0 if has_infix_left_var_name { g.writeln('if ($g.infix_left_var_name) {') g.infix_left_var_name = '' g.indent++ } g.write('${g.typ(node.left_type)} ${tmp}_orig = ') g.expr(node.left) g.writeln(';') g.writeln('int ${tmp}_len = ${tmp}_orig.len;') i := g.new_tmp_var() g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {') g.indent++ g.writeln('$elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[$i];') g.set_current_pos_as_last_stmt_pos() mut is_embed_map_filter := false mut expr := node.args[0].expr match mut expr { ast.AnonFn { g.write('if (') g.gen_anon_fn_decl(mut expr) g.write('${expr.decl.name}(it)') } ast.Ident { g.write('if (') 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', 'all', 'any'] { is_embed_map_filter = true g.set_current_pos_as_last_stmt_pos() } g.write('if (') g.expr(node.args[0].expr) } else { g.write('if (') g.expr(node.args[0].expr) } } g.writeln(') {') g.writeln('\t$tmp = true;') g.writeln('\tbreak;') g.writeln('}') g.indent-- g.writeln('}') if !is_embed_map_filter { g.set_current_pos_as_last_stmt_pos() } if has_infix_left_var_name { g.indent-- g.writeln('}') } if s_ends_with_ln { g.writeln(s) } else { g.write(s) } g.write(tmp) } fn (mut g Gen) gen_array_all(node ast.CallExpr) { tmp := g.new_tmp_var() mut s := g.go_before_stmt(0) s_ends_with_ln := s.ends_with('\n') s = s.trim_space() sym := g.table.get_type_symbol(node.left_type) info := sym.info as ast.Array // styp := g.typ(node.return_type) elem_type_str := g.typ(info.elem_type) g.empty_line = true g.writeln('bool $tmp = true;') has_infix_left_var_name := g.infix_left_var_name.len > 0 if has_infix_left_var_name { g.writeln('if ($g.infix_left_var_name) {') g.infix_left_var_name = '' g.indent++ } g.write('${g.typ(node.left_type)} ${tmp}_orig = ') g.expr(node.left) g.writeln(';') g.writeln('int ${tmp}_len = ${tmp}_orig.len;') i := g.new_tmp_var() g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {') g.indent++ g.writeln('$elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[$i];') g.empty_line = true g.set_current_pos_as_last_stmt_pos() mut is_embed_map_filter := false mut expr := node.args[0].expr match mut expr { ast.AnonFn { g.write('if (!(') g.gen_anon_fn_decl(mut expr) g.write('${expr.decl.name}(it)') } ast.Ident { g.write('if (!(') 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', 'all', 'any'] { is_embed_map_filter = true g.set_current_pos_as_last_stmt_pos() } g.write('if (!(') g.expr(node.args[0].expr) } else { g.write('if (!(') g.expr(node.args[0].expr) } } g.writeln(')) {') g.writeln('\t$tmp = false;') g.writeln('\tbreak;') g.writeln('}') g.indent-- g.writeln('}') if !is_embed_map_filter { g.set_current_pos_as_last_stmt_pos() } if has_infix_left_var_name { g.indent-- g.writeln('}') } if s_ends_with_ln { g.writeln(s) } else { g.write(s) } g.write(tmp) }