Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,437 @@
|
||||
module transform
|
||||
|
||||
import v3.flat
|
||||
|
||||
struct MapIndexInfo {
|
||||
base_id flat.NodeId
|
||||
key_id flat.NodeId
|
||||
base_type string
|
||||
key_type string
|
||||
value_type string
|
||||
}
|
||||
|
||||
fn (mut t Transformer) map_type_parts(map_type string) (string, string) {
|
||||
clean := t.clean_map_type(map_type)
|
||||
if !clean.starts_with('map[') {
|
||||
return '', ''
|
||||
}
|
||||
return t.map_key_type(clean), t.map_value_type(clean)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_new_map_call(map_type string) flat.NodeId {
|
||||
key_type, value_type := t.map_type_parts(map_type)
|
||||
hash_fn, eq_fn, clone_fn, free_fn := map_callback_names(key_type)
|
||||
mut args := []flat.NodeId{}
|
||||
args << t.make_sizeof_type(key_type)
|
||||
args << t.make_sizeof_type(value_type)
|
||||
args << t.make_ident(hash_fn)
|
||||
args << t.make_ident(eq_fn)
|
||||
args << t.make_ident(clone_fn)
|
||||
args << t.make_ident(free_fn)
|
||||
return t.make_call_typed('new_map', args, map_type)
|
||||
}
|
||||
|
||||
fn map_callback_names(key_type string) (string, string, string, string) {
|
||||
if key_type == 'string' {
|
||||
return 'v3_map_hash_string', 'v3_map_eq_string', 'v3_map_clone_string', 'v3_map_free_string'
|
||||
}
|
||||
size_suffix := match key_type {
|
||||
'u8', 'i8', 'bool', 'char' { '1' }
|
||||
'u16', 'i16' { '2' }
|
||||
'i64', 'u64', 'isize', 'usize', 'voidptr' { '8' }
|
||||
else { '4' }
|
||||
}
|
||||
|
||||
return 'v3_map_hash_int_${size_suffix}', 'v3_map_eq_int_${size_suffix}', 'v3_map_clone_int_${size_suffix}', 'v3_map_free_nop'
|
||||
}
|
||||
|
||||
fn (mut t Transformer) map_index_info(index_id flat.NodeId) ?MapIndexInfo {
|
||||
if int(index_id) < 0 {
|
||||
return none
|
||||
}
|
||||
lhs := t.a.nodes[int(index_id)]
|
||||
if lhs.kind != .index || lhs.children_count < 2 || lhs.value == 'range' {
|
||||
return none
|
||||
}
|
||||
base_id := t.a.child(&lhs, 0)
|
||||
key_id := t.a.child(&lhs, 1)
|
||||
base_type := t.node_type(base_id)
|
||||
map_type := t.clean_map_type(base_type)
|
||||
if !map_type.starts_with('map[') {
|
||||
return none
|
||||
}
|
||||
key_type, value_type := t.map_type_parts(map_type)
|
||||
if key_type.len == 0 || value_type.len == 0 {
|
||||
return none
|
||||
}
|
||||
return MapIndexInfo{
|
||||
base_id: base_id
|
||||
key_id: key_id
|
||||
base_type: base_type
|
||||
key_type: key_type
|
||||
value_type: value_type
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_map_get_expr(map_expr flat.NodeId, base_type string, key_name string, zero_name string, value_type string) flat.NodeId {
|
||||
call := t.make_call_typed('map__get', arr3(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp,
|
||||
t.make_ident(key_name)), t.make_prefix(.amp, t.make_ident(zero_name))), 'voidptr')
|
||||
cast := t.make_cast('&${value_type}', call, '&${value_type}')
|
||||
return t.make_prefix(.mul, cast)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_map_get_check_expr(map_expr flat.NodeId, base_type string, key_name string) flat.NodeId {
|
||||
return t.make_call_typed('map__get_check', arr2(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp,
|
||||
t.make_ident(key_name))), 'voidptr')
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_map_exists_expr(map_expr flat.NodeId, base_type string, key_name string) flat.NodeId {
|
||||
return t.make_call_typed('map__exists', arr2(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp,
|
||||
t.make_ident(key_name))), 'bool')
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_map_set_stmt(map_expr flat.NodeId, base_type string, key_name string, value_name string) flat.NodeId {
|
||||
call := t.make_call_typed('map__set', arr3(t.runtime_addr(map_expr, base_type), t.make_prefix(.amp,
|
||||
t.make_ident(key_name)), t.make_prefix(.amp, t.make_ident(value_name))), 'void')
|
||||
return t.make_expr_stmt(call)
|
||||
}
|
||||
|
||||
fn (t &Transformer) const_expr_for_ident(id flat.NodeId) ?flat.NodeId {
|
||||
if int(id) < 0 || isnil(t.tc) {
|
||||
return none
|
||||
}
|
||||
node := t.a.nodes[int(id)]
|
||||
if node.kind != .ident || node.value.len == 0 {
|
||||
return none
|
||||
}
|
||||
if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' {
|
||||
qname := '${t.cur_module}.${node.value}'
|
||||
if expr_id := t.tc.const_exprs[qname] {
|
||||
return expr_id
|
||||
}
|
||||
}
|
||||
if expr_id := t.tc.const_exprs[node.value] {
|
||||
return expr_id
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
fn (mut t Transformer) lower_map_membership_expr(map_id flat.NodeId, key_id flat.NodeId, map_type string) ?flat.NodeId {
|
||||
clean_type := t.clean_map_type(map_type)
|
||||
mut key_type := ''
|
||||
if clean_type.starts_with('map[') {
|
||||
key_type = t.map_key_type(clean_type)
|
||||
}
|
||||
if key_type.len == 0 {
|
||||
key_type = t.node_type(key_id)
|
||||
}
|
||||
if key_type.len == 0 {
|
||||
key := t.a.nodes[int(key_id)]
|
||||
if key.kind == .selector {
|
||||
key_type = t.selector_field_type(key)
|
||||
}
|
||||
}
|
||||
if key_type.len == 0 {
|
||||
return none
|
||||
}
|
||||
map_source_id := t.const_expr_for_ident(map_id) or { map_id }
|
||||
map_expr := t.stable_expr_for_reuse(map_source_id)
|
||||
key_name := t.new_temp('map_key')
|
||||
t.pending_stmts << t.make_decl_assign_typed(key_name, t.transform_expr(key_id), key_type)
|
||||
return t.make_map_exists_expr(map_expr, map_type, key_name)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) try_lower_map_index_expr(_id flat.NodeId, node flat.Node) ?flat.NodeId {
|
||||
if node.kind != .index || node.children_count < 2 || node.value == 'range' {
|
||||
return none
|
||||
}
|
||||
base_id := t.a.child(&node, 0)
|
||||
key_id := t.a.child(&node, 1)
|
||||
base_type := t.node_type(base_id)
|
||||
map_type := t.clean_map_type(base_type)
|
||||
if !map_type.starts_with('map[') {
|
||||
return none
|
||||
}
|
||||
key_type, value_type := t.map_type_parts(map_type)
|
||||
if key_type.len == 0 || value_type.len == 0 {
|
||||
return none
|
||||
}
|
||||
map_source_id := t.const_expr_for_ident(base_id) or { base_id }
|
||||
map_expr := t.stable_expr_for_reuse(map_source_id)
|
||||
key_name := t.new_temp('map_key')
|
||||
zero_name := t.new_temp('map_zero')
|
||||
t.pending_stmts << t.make_decl_assign_typed(key_name, t.transform_expr(key_id), key_type)
|
||||
t.pending_stmts << t.make_decl_assign_typed(zero_name, t.zero_value_for_type(value_type),
|
||||
value_type)
|
||||
return t.make_map_get_expr(map_expr, base_type, key_name, zero_name, value_type)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) is_map_index_or_expr(node flat.Node) bool {
|
||||
if node.kind != .or_expr || node.children_count < 2 {
|
||||
return false
|
||||
}
|
||||
expr := t.a.child_node(&node, 0)
|
||||
if expr.kind != .index || expr.children_count < 2 || expr.value == 'range' {
|
||||
return false
|
||||
}
|
||||
base_id := t.a.child(expr, 0)
|
||||
base_type := t.node_type(base_id)
|
||||
return t.clean_map_type(base_type).starts_with('map[')
|
||||
}
|
||||
|
||||
fn (mut t Transformer) transform_map_index_or_expr(id flat.NodeId, node flat.Node) flat.NodeId {
|
||||
if node.children_count < 2 {
|
||||
return id
|
||||
}
|
||||
expr_id := t.a.child(&node, 0)
|
||||
body_id := t.a.child(&node, 1)
|
||||
info := t.map_index_info(expr_id) or { return id }
|
||||
map_expr := t.stable_expr_for_reuse(info.base_id)
|
||||
key_name := t.new_temp('map_key')
|
||||
ptr_name := t.new_temp('map_ptr')
|
||||
val_name := t.new_temp('map_val')
|
||||
outer_pending := t.pending_stmts.clone()
|
||||
t.pending_stmts.clear()
|
||||
key_expr := t.transform_expr(info.key_id)
|
||||
mut prelude := []flat.NodeId{}
|
||||
t.drain_pending(mut prelude)
|
||||
prelude << t.make_decl_assign_typed(key_name, key_expr, info.key_type)
|
||||
prelude << t.make_decl_assign_typed(ptr_name, t.make_map_get_check_expr(map_expr,
|
||||
info.base_type, key_name), 'voidptr')
|
||||
prelude << t.make_decl_assign_typed(val_name, t.zero_value_for_type(info.value_type),
|
||||
info.value_type)
|
||||
|
||||
ptr_ident := t.make_ident(ptr_name)
|
||||
found_cond := t.make_infix(.ne, ptr_ident, t.a.add(.nil_literal))
|
||||
ptr_value := t.make_prefix(.mul, t.make_cast('&${info.value_type}', t.make_ident(ptr_name),
|
||||
'&${info.value_type}'))
|
||||
then_block := t.make_block(arr1(t.make_assign(t.make_ident(val_name), ptr_value)))
|
||||
else_block := t.make_block(t.lower_map_or_body_to_stmts(body_id, val_name, info.value_type,
|
||||
node.value))
|
||||
t.pending_stmts = outer_pending
|
||||
for stmt in prelude {
|
||||
t.pending_stmts << stmt
|
||||
}
|
||||
t.pending_stmts << t.make_if(found_cond, then_block, else_block)
|
||||
return t.make_ident(val_name)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) lower_map_or_body_to_stmts(body_id flat.NodeId, target_name string, target_type string, mode string) []flat.NodeId {
|
||||
if mode == '!' || mode == '?' {
|
||||
if t.is_optional_type_name(t.cur_fn_ret_type) {
|
||||
return arr1(t.make_none_return_stmt())
|
||||
}
|
||||
return arr1(t.make_panic_stmt('option/result propagation failed'))
|
||||
}
|
||||
if int(body_id) < 0 {
|
||||
return []flat.NodeId{}
|
||||
}
|
||||
body := t.a.nodes[int(body_id)]
|
||||
if body.kind != .block {
|
||||
if body.kind == .none_expr && !t.is_optional_type_name(target_type)
|
||||
&& t.is_optional_type_name(t.cur_fn_ret_type) {
|
||||
return arr1(t.make_none_return_stmt())
|
||||
}
|
||||
return arr1(t.make_assign(t.make_ident(target_name), t.transform_expr(body_id)))
|
||||
}
|
||||
mut result := []flat.NodeId{}
|
||||
for i in 0 .. body.children_count {
|
||||
child_id := t.a.child(&body, i)
|
||||
child := t.a.nodes[int(child_id)]
|
||||
is_last := i == body.children_count - 1
|
||||
if is_last && child.kind == .expr_stmt && child.children_count > 0 {
|
||||
inner_id := t.a.child(&child, 0)
|
||||
inner := t.a.nodes[int(inner_id)]
|
||||
if inner.kind == .none_expr && !t.is_optional_type_name(target_type)
|
||||
&& t.is_optional_type_name(t.cur_fn_ret_type) {
|
||||
result << t.make_none_return_stmt()
|
||||
continue
|
||||
}
|
||||
if t.node_type(inner_id) == 'void' {
|
||||
expanded := t.transform_stmt(child_id)
|
||||
t.drain_pending(mut result)
|
||||
for eid in expanded {
|
||||
result << eid
|
||||
}
|
||||
} else {
|
||||
value := t.transform_expr(inner_id)
|
||||
t.drain_pending(mut result)
|
||||
result << t.make_assign(t.make_ident(target_name), value)
|
||||
}
|
||||
} else {
|
||||
expanded := t.transform_stmt(child_id)
|
||||
t.drain_pending(mut result)
|
||||
for eid in expanded {
|
||||
result << eid
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = target_type
|
||||
return result
|
||||
}
|
||||
|
||||
fn (mut t Transformer) try_lower_map_index_assign(node flat.Node) ?[]flat.NodeId {
|
||||
if node.kind !in [.assign, .index_assign] || node.children_count < 2 {
|
||||
return none
|
||||
}
|
||||
info := t.map_index_info(t.a.child(&node, 0)) or { return none }
|
||||
map_expr := t.stable_expr_for_reuse(info.base_id)
|
||||
key_name := t.new_temp('map_key')
|
||||
mut result := []flat.NodeId{}
|
||||
t.drain_pending(mut result)
|
||||
result << t.make_decl_assign_typed(key_name, t.transform_expr(info.key_id), info.key_type)
|
||||
rhs_id := t.a.child(&node, 1)
|
||||
if node.op == .assign {
|
||||
value_name := t.new_temp('map_val')
|
||||
value := if info.value_type.starts_with('&') && t.is_sum_type_name(info.value_type[1..]) {
|
||||
t.transform_expr_for_type(rhs_id, info.value_type)
|
||||
} else if info.value_type in t.sum_types
|
||||
|| t.resolve_sum_name(info.value_type) in t.sum_types {
|
||||
t.wrap_sum_value(rhs_id, info.value_type)
|
||||
} else {
|
||||
t.transform_expr(rhs_id)
|
||||
}
|
||||
result << t.make_decl_assign_typed(value_name, value, info.value_type)
|
||||
result << t.make_map_set_stmt(map_expr, info.base_type, key_name, value_name)
|
||||
return result
|
||||
}
|
||||
if node.op == .left_shift_assign && info.value_type.starts_with('[]') {
|
||||
t.lower_map_index_append_with_info(info, map_expr, key_name, rhs_id, mut result)
|
||||
return result
|
||||
}
|
||||
op := map_compound_to_infix_op(node.op) or { return none }
|
||||
t.lower_map_index_compound_with_info(info, map_expr, key_name, op, rhs_id, mut result)
|
||||
return result
|
||||
}
|
||||
|
||||
fn map_compound_to_infix_op(op flat.Op) ?flat.Op {
|
||||
match op {
|
||||
.plus_assign { return flat.Op.plus }
|
||||
.minus_assign { return flat.Op.minus }
|
||||
.mul_assign { return flat.Op.mul }
|
||||
.div_assign { return flat.Op.div }
|
||||
.mod_assign { return flat.Op.mod }
|
||||
.amp_assign { return flat.Op.amp }
|
||||
.pipe_assign { return flat.Op.pipe }
|
||||
.xor_assign { return flat.Op.xor }
|
||||
.left_shift_assign { return flat.Op.left_shift }
|
||||
.right_shift_assign { return flat.Op.right_shift }
|
||||
else { return none }
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut t Transformer) load_map_index_current(info MapIndexInfo, map_expr flat.NodeId, key_name string, mut result []flat.NodeId) string {
|
||||
zero_name := t.new_temp('map_zero')
|
||||
current_name := t.new_temp('map_val')
|
||||
result << t.make_decl_assign_typed(zero_name, t.zero_value_for_type(info.value_type),
|
||||
info.value_type)
|
||||
get_expr := t.make_map_get_expr(map_expr, info.base_type, key_name, zero_name, info.value_type)
|
||||
result << t.make_decl_assign_typed(current_name, get_expr, info.value_type)
|
||||
return current_name
|
||||
}
|
||||
|
||||
fn (mut t Transformer) lower_map_index_compound_with_info(info MapIndexInfo, map_expr flat.NodeId, key_name string, op flat.Op, rhs_id flat.NodeId, mut result []flat.NodeId) {
|
||||
current_name := t.load_map_index_current(info, map_expr, key_name, mut result)
|
||||
rhs := t.transform_expr(rhs_id)
|
||||
new_value := if info.value_type == 'string' && op == .plus {
|
||||
t.make_call_typed('string__plus', arr2(t.make_ident(current_name), rhs), 'string')
|
||||
} else {
|
||||
t.make_infix(op, t.make_ident(current_name), rhs)
|
||||
}
|
||||
result << t.make_assign(t.make_ident(current_name), new_value)
|
||||
result << t.make_map_set_stmt(map_expr, info.base_type, key_name, current_name)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) lower_map_index_postfix_with_info(info MapIndexInfo, map_expr flat.NodeId, key_name string, op flat.Op, mut result []flat.NodeId) {
|
||||
current_name := t.load_map_index_current(info, map_expr, key_name, mut result)
|
||||
infix_op := if op == .dec { flat.Op.minus } else { flat.Op.plus }
|
||||
new_value := t.make_infix(infix_op, t.make_ident(current_name), t.make_int_literal(1))
|
||||
result << t.make_assign(t.make_ident(current_name), new_value)
|
||||
result << t.make_map_set_stmt(map_expr, info.base_type, key_name, current_name)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) lower_map_index_append_with_info(info MapIndexInfo, map_expr flat.NodeId, key_name string, rhs_id flat.NodeId, mut result []flat.NodeId) {
|
||||
current_name := t.load_map_index_current(info, map_expr, key_name, mut result)
|
||||
append := t.make_infix(.left_shift, t.make_ident(current_name), t.transform_expr(rhs_id))
|
||||
t.annotate_left_shift(append)
|
||||
result << t.make_expr_stmt(append)
|
||||
result << t.make_map_set_stmt(map_expr, info.base_type, key_name, current_name)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) try_lower_map_index_postfix_stmt(id flat.NodeId) ?[]flat.NodeId {
|
||||
if int(id) < 0 {
|
||||
return none
|
||||
}
|
||||
node := t.a.nodes[int(id)]
|
||||
if node.kind != .postfix || node.children_count == 0 || node.op !in [.inc, .dec] {
|
||||
return none
|
||||
}
|
||||
info := t.map_index_info(t.a.child(&node, 0)) or { return none }
|
||||
map_expr := t.stable_expr_for_reuse(info.base_id)
|
||||
key_name := t.new_temp('map_key')
|
||||
mut result := []flat.NodeId{}
|
||||
t.drain_pending(mut result)
|
||||
result << t.make_decl_assign_typed(key_name, t.transform_expr(info.key_id), info.key_type)
|
||||
t.lower_map_index_postfix_with_info(info, map_expr, key_name, node.op, mut result)
|
||||
return result
|
||||
}
|
||||
|
||||
fn (mut t Transformer) try_lower_map_index_append_stmt(id flat.NodeId) ?[]flat.NodeId {
|
||||
if int(id) < 0 {
|
||||
return none
|
||||
}
|
||||
node := t.a.nodes[int(id)]
|
||||
if node.kind != .infix || node.op != .left_shift || node.children_count < 2 {
|
||||
return none
|
||||
}
|
||||
info := t.map_index_info(t.a.child(&node, 0)) or { return none }
|
||||
if !info.value_type.starts_with('[]') {
|
||||
return none
|
||||
}
|
||||
map_expr := t.stable_expr_for_reuse(info.base_id)
|
||||
key_name := t.new_temp('map_key')
|
||||
mut result := []flat.NodeId{}
|
||||
t.drain_pending(mut result)
|
||||
result << t.make_decl_assign_typed(key_name, t.transform_expr(info.key_id), info.key_type)
|
||||
t.lower_map_index_append_with_info(info, map_expr, key_name, t.a.child(&node, 1), mut result)
|
||||
return result
|
||||
}
|
||||
|
||||
fn (mut t Transformer) lower_map_init_to_runtime(id flat.NodeId, node flat.Node) flat.NodeId {
|
||||
map_type := if node.value.len > 0 {
|
||||
node.value
|
||||
} else if node.typ.len > 0 {
|
||||
node.typ
|
||||
} else {
|
||||
t.node_type(id)
|
||||
}
|
||||
if !map_type.starts_with('map[') {
|
||||
return id
|
||||
}
|
||||
init_call := t.make_new_map_call(map_type)
|
||||
if node.children_count == 0 {
|
||||
return init_call
|
||||
}
|
||||
tmp_name := t.new_temp('map_lit')
|
||||
t.pending_stmts << t.make_decl_assign_typed(tmp_name, init_call, map_type)
|
||||
key_type, value_type := t.map_type_parts(map_type)
|
||||
for i := 0; i + 1 < node.children_count; i += 2 {
|
||||
key_name := t.new_temp('map_key')
|
||||
value_name := t.new_temp('map_val')
|
||||
t.pending_stmts << t.make_decl_assign_typed(key_name,
|
||||
t.transform_expr(t.a.child(&node, i)), key_type)
|
||||
value_id := t.a.child(&node, i + 1)
|
||||
value := if value_type.starts_with('&') && t.is_sum_type_name(value_type[1..]) {
|
||||
t.transform_expr_for_type(value_id, value_type)
|
||||
} else if value_type in t.sum_types || t.resolve_sum_name(value_type) in t.sum_types {
|
||||
t.wrap_sum_value(value_id, value_type)
|
||||
} else {
|
||||
t.transform_expr(value_id)
|
||||
}
|
||||
t.pending_stmts << t.make_decl_assign_typed(value_name, value, value_type)
|
||||
call := t.make_call_typed('map__set', arr3(t.make_prefix(.amp, t.make_ident(tmp_name)), t.make_prefix(.amp,
|
||||
t.make_ident(key_name)), t.make_prefix(.amp, t.make_ident(value_name))), 'void')
|
||||
t.pending_stmts << t.make_expr_stmt(call)
|
||||
}
|
||||
return t.make_ident(tmp_name)
|
||||
}
|
||||
Reference in new issue
Block a user