module c import v3.flat import v3.types fn array_like_type(t types.Type) ?types.Array { if t is types.Array { return t } if t is types.Alias { base := t.base_type if base is types.Array { return base } } return none } fn array_fixed_type(t types.Type) ?types.ArrayFixed { if t is types.ArrayFixed { return t } if t is types.Alias { base := t.base_type if base is types.ArrayFixed { return base } } return none } fn (mut g FlatGen) gen_array_literal_value(node flat.Node, elem_type types.Type) { c_elem := g.tc.c_type(elem_type) count := node.children_count if count == 0 { g.write('array_new(sizeof(${c_elem}), 0, 0)') return } g.write('new_array_from_c_array(${count}, ${count}, sizeof(${c_elem}), (${c_elem}[]){') for i in 0 .. count { if i > 0 { g.write(', ') } g.gen_expr(g.a.child(&node, i)) } g.write('})') } fn (mut g FlatGen) gen_fixed_array_data_arg(id flat.NodeId, arr types.ArrayFixed) { node := g.a.nodes[int(id)] if node.kind == .array_literal { c_elem := g.tc.c_type(arr.elem_type) g.write('(${c_elem}[]){') for i in 0 .. node.children_count { if i > 0 { g.write(', ') } g.gen_expr(g.a.child(&node, i)) } g.write('}') return } g.gen_expr(id) } fn (mut g FlatGen) gen_array_push_many_stmt(lhs_id flat.NodeId, rhs_id flat.NodeId) { lhs_is_ptr := g.tc.resolve_type(lhs_id) is types.Pointer amp := if lhs_is_ptr { '' } else { '&' } rhs_type := types.unwrap_pointer(g.tc.resolve_type(rhs_id)) if rhs_fixed := array_fixed_type(rhs_type) { g.write('array_push_many_ptr(${amp}') gen_expr_lvalue(mut g, lhs_id) g.write(', ') g.gen_fixed_array_data_arg(rhs_id, rhs_fixed) len_expr := g.fixed_array_len_value(rhs_fixed) g.writeln(', ${len_expr});') return } g.write('array_push_many(${amp}') gen_expr_lvalue(mut g, lhs_id) g.write(', ') g.gen_expr(rhs_id) g.writeln(');') } fn (mut g FlatGen) gen_slice_expr(node flat.Node, base_id flat.NodeId, base_type types.Type) { start_node := g.a.child_node(&node, 1) has_start := start_node.kind != .empty has_end := node.children_count > 2 base_str := g.expr_to_string(base_id) start_str := if has_start { g.expr_to_string(g.a.child(&node, 1)) } else { '0' } end_str := if has_end { g.expr_to_string(g.a.child(&node, 2)) } else { '${base_str}.len' } if base_type is types.String { g.write('string__substr(${base_str}, ${start_str}, ${end_str})') } else if base_type is types.Array { g.write('array_slice(${base_str}, ${start_str}, ${end_str})') } else { g.write('string__substr(${base_str}, ${start_str}, ${end_str})') } } fn (mut g FlatGen) gen_array_method_call(node flat.Node, fn_node &flat.Node, arr types.Array) { c_elem := g.tc.c_type(arr.elem_type) base_id := g.a.child(fn_node, 0) base_node := g.a.nodes[int(base_id)] is_ptr := if base_node.kind == .ident { g.tc.resolve_type(base_id) is types.Pointer } else { false } dot := if is_ptr { '->' } else { '.' } match fn_node.value { 'clone' { g.write('array_clone(') g.gen_expr(base_id) g.write(')') } 'last' { g.write('*(${c_elem}*)array_get(') g.gen_expr(base_id) g.write(', ') g.gen_expr(base_id) g.write('.len - 1)') } 'first' { g.write('*(${c_elem}*)array_get(') g.gen_expr(base_id) g.write(', 0)') } 'delete_last' { g.gen_expr(base_id) g.write('${dot}len--') } 'pop' { g.write('({ ${c_elem} _pop${g.tmp_count} = *(${c_elem}*)array_get(') g.gen_expr(base_id) g.write(', ') g.gen_expr(base_id) g.write('${dot}len - 1); ') g.gen_expr(base_id) g.write('${dot}len--; _pop${g.tmp_count}; })') g.tmp_count++ } 'clear' { g.gen_expr(base_id) g.write('${dot}len = 0') } 'push_many' { amp := if is_ptr { '' } else { '&' } g.write('array_push_many_ptr(${amp}') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(', ') g.gen_expr(g.a.child(&node, 2)) g.write(')') } 'repeat' { g.write('array__repeat_to_depth(') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(', 0)') } 'repeat_to_depth' { g.write('array__repeat_to_depth(') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(', ') g.gen_expr(g.a.child(&node, 2)) g.write(')') } 'trim' { g.gen_expr(base_id) g.write('${dot}len = ') g.gen_expr(g.a.child(&node, 1)) } 'ensure_cap' { amp := if is_ptr { '' } else { '&' } g.write('array_ensure_cap(${amp}') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(')') } 'delete' { amp := if is_ptr { '' } else { '&' } g.write('array_delete(${amp}') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(')') } 'prepend' { amp := if is_ptr { '' } else { '&' } g.write('array__prepend(${amp}') g.gen_expr(base_id) g.write(', &(${c_elem}[]){') g.gen_expr(g.a.child(&node, 1)) g.write('})') } 'free' { g.write('array__free(') if !is_ptr { g.write('&') } g.gen_expr(base_id) g.write(')') } 'str' { amp := if is_ptr { '' } else { '&' } g.write('strings__Builder__str(${amp}') g.gen_expr(base_id) g.write(')') } 'join' { g.write('array_string_join(') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(')') } 'bytestr' { g.write('u8__vstring_with_len((u8*)') g.gen_expr(base_id) g.write('${dot}data, ') g.gen_expr(base_id) g.write('${dot}len)') } 'contains' { contains_fn := 'array_contains_${array_lookup_suffix(arr.elem_type)}' g.write('${contains_fn}(') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(')') } 'index' { index_fn := 'array_index_${array_lookup_suffix(arr.elem_type)}' g.write('${index_fn}(') g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&node, 1)) g.write(')') } else { best_mname := g.array_method_fallback(fn_node.value) if best_mname.len > 0 { g.write(c_name(best_mname)) g.write('(') ptypes := g.tc.fn_param_types[best_mname] wants_ptr := ptypes.len > 0 && ptypes[0] is types.Pointer if wants_ptr && !is_ptr { g.write('&') } else if !wants_ptr && is_ptr { g.write('*') } g.gen_expr(base_id) for i in 1 .. node.children_count { g.write(', ') g.gen_expr(g.a.child(&node, i)) } g.write(')') } else { g.gen_expr(g.a.child(&node, 0)) g.write('(') g.gen_expr(base_id) g.write(')') } } } } fn array_lookup_suffix(elem_type types.Type) string { if elem_type is types.String { return 'string' } if elem_type is types.Primitive { if elem_type.props.has(.unsigned) && elem_type.size == 8 { return 'u8' } } return 'int' } fn (mut g FlatGen) array_method_fallback(method string) string { if method in g.array_method_cache { return g.array_method_cache[method] } suffix := '.${method}' mut best_mname := '' for mname, _ in g.tc.fn_param_types { if mname.ends_with(suffix) { if best_mname.len == 0 || mname.len > best_mname.len { best_mname = mname } } } g.array_method_cache[method] = best_mname return best_mname } fn (mut g FlatGen) gen_map_ref_arg(base_id flat.NodeId, base_type types.Type) { if base_type is types.Pointer { g.gen_expr(base_id) } else { g.write('&') g.gen_expr(base_id) } } fn (mut g FlatGen) gen_map_delete(node flat.Node, fn_node &flat.Node, m types.Map, base_type types.Type) { c_key := g.tc.c_type(m.key_type) g.write('map__delete(') g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type) g.write(', &(${c_key}[]){') g.gen_expr(g.a.child(&node, 1)) g.write('})') } fn (mut g FlatGen) gen_index_assign(node flat.Node) { lhs_id := g.a.child(&node, 0) lhs := g.a.nodes[int(lhs_id)] if lhs.kind == .index { base_id := g.a.child(&lhs, 0) base_type := g.tc.resolve_type(base_id) clean_base := types.unwrap_pointer(base_type) if clean_base is types.Map { c_key := g.tc.c_type(clean_base.key_type) c_val := g.tc.c_type(clean_base.value_type) is_ptr := base_type is types.Pointer if is_ptr { g.write('map__set(') } else { g.write('map__set(&') } g.gen_expr(base_id) g.write(', &(${c_key}[]){') g.gen_expr_with_expected_type(g.a.child(&lhs, 1), clean_base.key_type) g.write('}, &(${c_val}[]){') g.gen_expr_with_expected_type(g.a.child(&node, 1), clean_base.value_type) g.writeln('});') return } if base_type is types.Pointer { ptr_type := base_type if ptr_type.base_type is types.Void { g.write('((u8*)') g.gen_expr(base_id) g.write(')[') g.gen_expr(g.a.child(&lhs, 1)) g.write('] = ') g.gen_expr(g.a.child(&node, 1)) g.writeln(';') return } } mut arr_type := types.Array{} mut is_array_base := false if base_type is types.Array { arr_type = base_type is_array_base = true } else if base_type is types.Pointer { ptr_type := base_type ptr_base := ptr_type.base_type if ptr_base is types.Array { arr_type = ptr_base is_array_base = true } } if is_array_base { c_elem := g.tc.c_type(arr_type.elem_type) g.write('array_set(') if base_type is types.Pointer { g.write('*') } g.gen_expr(base_id) g.write(', ') g.gen_expr(g.a.child(&lhs, 1)) g.write(', &(${c_elem}[]){') g.gen_expr_with_expected_type(g.a.child(&node, 1), arr_type.elem_type) g.writeln('});') return } } g.gen_assign(node) }