Files
agila_open_tool/tools/v/vlib/v3/gen/c/array.v
T

393 lines
9.3 KiB
V

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)
}