Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,533 @@
|
||||
module transform
|
||||
|
||||
import v3.flat
|
||||
|
||||
fn (t &Transformer) trim_pointer_type(typ string) string {
|
||||
if typ.starts_with('&') {
|
||||
return typ[1..]
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
fn (t &Transformer) resolve_variant(sum_name string, variant string) string {
|
||||
if variant.contains('.') {
|
||||
return variant
|
||||
}
|
||||
resolved_sum := t.resolve_sum_name(sum_name)
|
||||
if resolved_variant := t.sum_variant_name(resolved_sum, variant) {
|
||||
return resolved_variant
|
||||
}
|
||||
if resolved_sum.contains('.') {
|
||||
return '${resolved_sum.all_before_last('.')}.${variant}'
|
||||
}
|
||||
if sum_name.contains('.') {
|
||||
return '${sum_name.all_before_last('.')}.${variant}'
|
||||
}
|
||||
return variant
|
||||
}
|
||||
|
||||
fn (t &Transformer) resolve_sum_name(sum_name string) string {
|
||||
if sum_name.len == 0 {
|
||||
return sum_name
|
||||
}
|
||||
if isnil(t.sum_cache) {
|
||||
return t.resolve_sum_name_uncached(sum_name)
|
||||
}
|
||||
mut c := t.sum_cache
|
||||
if c.module != t.cur_module {
|
||||
c.module = t.cur_module
|
||||
c.entries.clear()
|
||||
}
|
||||
if cached := c.entries[sum_name] {
|
||||
return cached
|
||||
}
|
||||
result := t.resolve_sum_name_uncached(sum_name)
|
||||
c.entries[sum_name] = result
|
||||
return result
|
||||
}
|
||||
|
||||
fn (t &Transformer) resolve_sum_name_uncached(sum_name string) string {
|
||||
if sum_name in t.sum_types {
|
||||
return sum_name
|
||||
}
|
||||
if sum_name.contains('.') {
|
||||
short_sum := sum_name.all_after_last('.')
|
||||
if short_sum in t.sum_types {
|
||||
return short_sum
|
||||
}
|
||||
}
|
||||
if !sum_name.contains('.') && t.cur_module.len > 0 && t.cur_module != 'main'
|
||||
&& t.cur_module != 'builtin' {
|
||||
qsum := '${t.cur_module}.${sum_name}'
|
||||
if qsum in t.sum_types {
|
||||
return qsum
|
||||
}
|
||||
}
|
||||
if !sum_name.contains('.') {
|
||||
mut found := ''
|
||||
for key, _ in t.sum_types {
|
||||
if key.contains('.') && key.all_after_last('.') == sum_name {
|
||||
if found.len > 0 && found != key {
|
||||
found = ''
|
||||
break
|
||||
}
|
||||
found = key
|
||||
}
|
||||
}
|
||||
if found.len > 0 {
|
||||
return found
|
||||
}
|
||||
}
|
||||
if !isnil(t.tc) {
|
||||
if sum_name in t.tc.sum_types {
|
||||
return sum_name
|
||||
}
|
||||
if sum_name.contains('.') {
|
||||
short_sum := sum_name.all_after_last('.')
|
||||
if short_sum in t.tc.sum_types {
|
||||
return short_sum
|
||||
}
|
||||
}
|
||||
if !sum_name.contains('.') && t.cur_module.len > 0 && t.cur_module != 'main'
|
||||
&& t.cur_module != 'builtin' {
|
||||
qsum := '${t.cur_module}.${sum_name}'
|
||||
if qsum in t.tc.sum_types {
|
||||
return qsum
|
||||
}
|
||||
}
|
||||
if !sum_name.contains('.') {
|
||||
mut found := ''
|
||||
for key, _ in t.tc.sum_types {
|
||||
if key.contains('.') && key.all_after_last('.') == sum_name {
|
||||
if found.len > 0 && found != key {
|
||||
found = ''
|
||||
break
|
||||
}
|
||||
found = key
|
||||
}
|
||||
}
|
||||
if found.len > 0 {
|
||||
return found
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum_name
|
||||
}
|
||||
|
||||
fn (t &Transformer) is_sum_type_name(name string) bool {
|
||||
if name.len == 0 {
|
||||
return false
|
||||
}
|
||||
resolved := t.resolve_sum_name(name)
|
||||
return resolved in t.sum_types
|
||||
}
|
||||
|
||||
fn (t &Transformer) is_interface_type_name(name string) bool {
|
||||
if name.len == 0 || isnil(t.tc) {
|
||||
return false
|
||||
}
|
||||
clean := t.trim_pointer_type(t.normalize_type_alias(name))
|
||||
if clean == 'IError' || clean in t.tc.interface_names {
|
||||
return true
|
||||
}
|
||||
if !clean.contains('.') && t.cur_module.len > 0 && t.cur_module != 'main'
|
||||
&& t.cur_module != 'builtin' {
|
||||
return '${t.cur_module}.${clean}' in t.tc.interface_names
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fn (t &Transformer) interface_variant_type(variant string) string {
|
||||
if variant.contains('.') {
|
||||
return variant
|
||||
}
|
||||
if variant in t.structs {
|
||||
return variant
|
||||
}
|
||||
if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' {
|
||||
qvariant := '${t.cur_module}.${variant}'
|
||||
if qvariant in t.structs {
|
||||
return qvariant
|
||||
}
|
||||
}
|
||||
for name, _ in t.structs {
|
||||
if name.contains('.') && name.all_after_last('.') == variant {
|
||||
return name
|
||||
}
|
||||
}
|
||||
return variant
|
||||
}
|
||||
|
||||
fn (t &Transformer) smartcast_target_type(sc SmartcastContext) string {
|
||||
if t.is_interface_type_name(sc.sum_type_name) {
|
||||
return t.interface_variant_type(sc.variant_name)
|
||||
}
|
||||
return t.resolve_variant(sc.sum_type_name, sc.variant_name)
|
||||
}
|
||||
|
||||
fn (t &Transformer) sum_type_index(sum_name string, variant string) int {
|
||||
resolved_sum := t.resolve_sum_name(sum_name)
|
||||
variants := t.sum_types[resolved_sum] or {
|
||||
if !isnil(t.tc) {
|
||||
tc_variants := t.tc.sum_types[resolved_sum] or { return 0 }
|
||||
return sum_type_index_in_variants(tc_variants, variant)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return sum_type_index_in_variants(variants, variant)
|
||||
}
|
||||
|
||||
fn sum_type_index_in_variants(variants []string, variant string) int {
|
||||
short_variant := if variant.contains('.') { variant.all_after_last('.') } else { variant }
|
||||
for i, v in variants {
|
||||
short_v := if v.contains('.') { v.all_after_last('.') } else { v }
|
||||
if v == variant || short_v == short_variant {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fn (mut t Transformer) transform_is_expr(id flat.NodeId, node flat.Node) flat.NodeId {
|
||||
if node.children_count == 0 {
|
||||
return id
|
||||
}
|
||||
expr_id := t.a.child(&node, 0)
|
||||
expr_type := t.node_type(expr_id)
|
||||
clean_type0 := t.trim_pointer_type(expr_type)
|
||||
clean_type := if clean_type0 in t.sum_types {
|
||||
clean_type0
|
||||
} else {
|
||||
t.find_sum_type_for_variant(node.value)
|
||||
}
|
||||
if t.is_interface_type_name(clean_type0) {
|
||||
new_expr := t.transform_expr(expr_id)
|
||||
object := t.make_selector_op(new_expr, '_object', 'voidptr', if expr_type.starts_with('&') {
|
||||
.arrow
|
||||
} else {
|
||||
.dot
|
||||
})
|
||||
return t.make_infix(.ne, object, t.a.add(.nil_literal))
|
||||
}
|
||||
if clean_type.len == 0 || clean_type !in t.sum_types {
|
||||
return t.make_bool_literal(true)
|
||||
}
|
||||
new_expr := t.transform_expr(expr_id)
|
||||
if check := t.make_sum_type_pattern_check(new_expr, expr_type, clean_type, node.value) {
|
||||
return check
|
||||
}
|
||||
return t.make_bool_literal(true)
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_sum_is_check(expr flat.NodeId, expr_type string, sum_name string, variant string) flat.NodeId {
|
||||
tag := t.make_selector_op(expr, 'typ', 'int', if expr_type.starts_with('&') {
|
||||
.arrow
|
||||
} else {
|
||||
.dot
|
||||
})
|
||||
idx := t.make_int_literal(t.sum_type_index(sum_name, variant))
|
||||
return t.make_infix(.eq, tag, idx)
|
||||
}
|
||||
|
||||
fn (t &Transformer) sum_variant_path(sum_name string, variant string) []string {
|
||||
mut visited := map[string]bool{}
|
||||
return t.sum_variant_path_inner(sum_name, variant, mut visited)
|
||||
}
|
||||
|
||||
fn (t &Transformer) sum_variant_path_inner(sum_name string, variant string, mut visited map[string]bool) []string {
|
||||
resolved_sum := t.resolve_sum_name(t.trim_pointer_type(sum_name))
|
||||
if resolved_sum.len == 0 || resolved_sum in visited {
|
||||
return []string{}
|
||||
}
|
||||
visited[resolved_sum] = true
|
||||
if direct := t.sum_variant_name(resolved_sum, variant) {
|
||||
return [direct]
|
||||
}
|
||||
variants := t.sum_types[resolved_sum] or { return []string{} }
|
||||
for direct in variants {
|
||||
direct_sum := t.resolve_sum_name(t.trim_pointer_type(direct))
|
||||
if direct_sum == resolved_sum || direct_sum !in t.sum_types {
|
||||
continue
|
||||
}
|
||||
nested := t.sum_variant_path_inner(direct_sum, variant, mut visited)
|
||||
if nested.len == 0 {
|
||||
continue
|
||||
}
|
||||
mut path := []string{cap: nested.len + 1}
|
||||
path << direct
|
||||
path << nested
|
||||
return path
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_sum_type_pattern_check(expr flat.NodeId, expr_type string, sum_name string, variant string) ?flat.NodeId {
|
||||
resolved_sum := t.resolve_sum_name(t.trim_pointer_type(sum_name))
|
||||
path := t.sum_variant_path(resolved_sum, variant)
|
||||
if path.len == 0 {
|
||||
return none
|
||||
}
|
||||
mut current := expr
|
||||
mut current_type := expr_type
|
||||
mut current_sum := resolved_sum
|
||||
mut chain := flat.empty_node
|
||||
for i, path_variant in path {
|
||||
cmp := t.make_sum_is_check(current, current_type, current_sum, path_variant)
|
||||
if int(chain) < 0 {
|
||||
chain = cmp
|
||||
} else {
|
||||
chain = t.make_infix(.logical_and, chain, cmp)
|
||||
}
|
||||
if i == path.len - 1 {
|
||||
break
|
||||
}
|
||||
qv := t.resolve_variant(current_sum, path_variant)
|
||||
use_ptr := t.variant_references_sum(qv, current_sum)
|
||||
field_type := if use_ptr { '&${qv}' } else { qv }
|
||||
current = t.make_selector_op(current, t.sum_field_name(qv), field_type, if current_type.starts_with('&') {
|
||||
.arrow
|
||||
} else {
|
||||
.dot
|
||||
})
|
||||
current_type = field_type
|
||||
current_sum = t.resolve_sum_name(t.trim_pointer_type(qv))
|
||||
}
|
||||
return chain
|
||||
}
|
||||
|
||||
fn (mut t Transformer) transform_as_expr(id flat.NodeId, node flat.Node) flat.NodeId {
|
||||
if node.children_count == 0 {
|
||||
return id
|
||||
}
|
||||
expr_id := t.a.child(&node, 0)
|
||||
expr_type := t.node_type(expr_id)
|
||||
clean_type0 := t.trim_pointer_type(expr_type)
|
||||
clean_type := if clean_type0 in t.sum_types {
|
||||
clean_type0
|
||||
} else {
|
||||
t.find_sum_type_for_variant(node.value)
|
||||
}
|
||||
if clean_type.len == 0 || clean_type !in t.sum_types {
|
||||
return t.transform_expr(expr_id)
|
||||
}
|
||||
qv := t.resolve_variant(clean_type, node.value)
|
||||
if qv.len > 0 && t.normalize_type_alias(clean_type0) == t.normalize_type_alias(qv) {
|
||||
return t.transform_expr(expr_id)
|
||||
}
|
||||
sc_key := t.expr_key(expr_id)
|
||||
if sc_key.len > 0 {
|
||||
contexts := t.smartcasts_for(sc_key)
|
||||
mut matched_contexts := []SmartcastContext{}
|
||||
for i, sc in contexts {
|
||||
mut sc_variant := sc.variant_name
|
||||
if sc.variant_name.contains('.') {
|
||||
sc_variant = sc.variant_name.all_after_last('.')
|
||||
}
|
||||
mut target_variant := node.value
|
||||
if node.value.contains('.') {
|
||||
target_variant = node.value.all_after_last('.')
|
||||
}
|
||||
if sc_variant == target_variant {
|
||||
end := i + 1
|
||||
matched_contexts = contexts[..end].clone()
|
||||
}
|
||||
}
|
||||
if matched_contexts.len > 0 {
|
||||
base := t.make_plain_expr_for_smartcast(expr_id)
|
||||
return t.apply_smartcast_contexts(base, t.original_expr_type(expr_id), matched_contexts)
|
||||
}
|
||||
}
|
||||
field := t.sum_field_name(qv)
|
||||
new_expr := t.transform_expr(expr_id)
|
||||
use_ptr := t.variant_references_sum(qv, clean_type)
|
||||
field_typ := if use_ptr { '&${qv}' } else { qv }
|
||||
field_sel := t.make_selector_op(new_expr, field, field_typ, if expr_type.starts_with('&') {
|
||||
.arrow
|
||||
} else {
|
||||
.dot
|
||||
})
|
||||
if use_ptr {
|
||||
return t.make_prefix(.mul, field_sel)
|
||||
}
|
||||
return field_sel
|
||||
}
|
||||
|
||||
fn (mut t Transformer) wrap_sum_return_expr(expr_id flat.NodeId) flat.NodeId {
|
||||
was_return_expr := t.in_return_expr
|
||||
t.in_return_expr = true
|
||||
result := if t.cur_fn_ret_type.len == 0 || t.cur_fn_ret_type !in t.sum_types {
|
||||
t.transform_expr(expr_id)
|
||||
} else {
|
||||
t.wrap_sum_value(expr_id, t.cur_fn_ret_type)
|
||||
}
|
||||
t.in_return_expr = was_return_expr
|
||||
return result
|
||||
}
|
||||
|
||||
fn (mut t Transformer) wrap_sum_value(expr_id flat.NodeId, target_sum string) flat.NodeId {
|
||||
resolved_sum := t.resolve_sum_name(target_sum)
|
||||
if resolved_sum.len == 0 || resolved_sum !in t.sum_types {
|
||||
return t.transform_expr(expr_id)
|
||||
}
|
||||
expr := t.a.nodes[int(expr_id)]
|
||||
if expr.kind == .if_expr {
|
||||
branch_type := t.if_expr_branch_result_type(expr)
|
||||
if t.if_expr_branch_overrides_sum_target(branch_type, resolved_sum) {
|
||||
return t.transform_expr(expr_id)
|
||||
}
|
||||
if lowered := t.try_expand_if_expr_value_for_type(expr_id, expr, resolved_sum) {
|
||||
return lowered
|
||||
}
|
||||
}
|
||||
expr_type := t.node_type(expr_id)
|
||||
mut variant := expr_type
|
||||
mut expr_smartcast := SmartcastContext{}
|
||||
key := t.expr_key(expr_id)
|
||||
if key.len > 0 {
|
||||
if sc := t.find_smartcast(key) {
|
||||
expr_smartcast = sc
|
||||
}
|
||||
}
|
||||
has_expr_smartcast := expr_smartcast.expr_name.len > 0
|
||||
if has_expr_smartcast && t.resolve_sum_name(expr_smartcast.sum_type_name) == resolved_sum {
|
||||
variant = t.resolve_variant(expr_smartcast.sum_type_name, expr_smartcast.variant_name)
|
||||
}
|
||||
if expr.kind == .prefix && expr.op == .mul && expr.children_count > 0 {
|
||||
inner_type := t.node_type(t.a.child(&expr, 0))
|
||||
if inner_type.starts_with('&') {
|
||||
variant = inner_type[1..]
|
||||
}
|
||||
}
|
||||
if expr.kind == .struct_init || expr.kind == .cast_expr {
|
||||
variant = expr.value
|
||||
} else if expr.kind == .as_expr && expr.value.len > 0 {
|
||||
variant = expr.value
|
||||
} else if expr.kind == .assoc && expr.value.len > 0 {
|
||||
variant = expr.value
|
||||
} else if expr.kind == .assoc && expr.children_count > 0 {
|
||||
variant = t.node_type(t.a.child(&expr, 0))
|
||||
}
|
||||
if expr.kind !in [.assoc, .as_expr, .prefix] && !has_expr_smartcast
|
||||
&& t.resolve_sum_name(expr_type) == resolved_sum {
|
||||
return t.transform_expr(expr_id)
|
||||
}
|
||||
if expr_type.starts_with('&') && t.resolve_sum_name(expr_type[1..]) == resolved_sum {
|
||||
inner := t.transform_expr(expr_id)
|
||||
deref := t.make_prefix(.mul, inner)
|
||||
t.a.nodes[int(deref)].typ = resolved_sum
|
||||
return deref
|
||||
}
|
||||
if variant.len == 0 {
|
||||
return t.transform_expr(expr_id)
|
||||
}
|
||||
mut clean_variant := if variant.starts_with('&') { variant[1..] } else { variant }
|
||||
if clean_variant.starts_with('ptr') && clean_variant.len > 3 && clean_variant[3..].contains('.') {
|
||||
clean_variant = clean_variant[3..]
|
||||
}
|
||||
if clean_variant.starts_with('ptr') && clean_variant.len > 3
|
||||
&& clean_variant[3..].contains('__') {
|
||||
clean_variant = clean_variant[3..].replace('__', '.')
|
||||
}
|
||||
short_variant := if clean_variant.contains('.') {
|
||||
clean_variant.all_after_last('.')
|
||||
} else {
|
||||
clean_variant
|
||||
}
|
||||
mut matches := false
|
||||
mut matched_variant := clean_variant
|
||||
for v in t.sum_types[resolved_sum] {
|
||||
short_v := if v.contains('.') { v.all_after_last('.') } else { v }
|
||||
if v == clean_variant || short_v == short_variant {
|
||||
matches = true
|
||||
matched_variant = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matches {
|
||||
return t.transform_expr(expr_id)
|
||||
}
|
||||
ref_variant := t.variant_references_sum(matched_variant, resolved_sum)
|
||||
mut pointer_variant_child := flat.empty_node
|
||||
if expr.kind == .prefix && expr.op == .mul && expr.children_count > 0 {
|
||||
pointer_variant_child = t.a.child(&expr, 0)
|
||||
}
|
||||
inner := if int(pointer_variant_child) >= 0 && ref_variant {
|
||||
t.transform_expr(pointer_variant_child)
|
||||
} else {
|
||||
t.transform_expr(expr_id)
|
||||
}
|
||||
if expr_type.starts_with('&') {
|
||||
return t.make_sum_literal(resolved_sum, matched_variant, inner)
|
||||
}
|
||||
if int(pointer_variant_child) >= 0 && ref_variant {
|
||||
return t.make_sum_literal(resolved_sum, matched_variant, inner)
|
||||
}
|
||||
if ref_variant {
|
||||
return t.make_sum_literal(resolved_sum, matched_variant, inner)
|
||||
}
|
||||
start := t.a.children.len
|
||||
t.a.children << inner
|
||||
return t.a.add_node(flat.Node{
|
||||
kind: .cast_expr
|
||||
value: resolved_sum
|
||||
children_start: start
|
||||
children_count: 1
|
||||
typ: resolved_sum
|
||||
})
|
||||
}
|
||||
|
||||
fn (mut t Transformer) ensure_sum_variant_ref(value flat.NodeId, variant string) flat.NodeId {
|
||||
mut value_type := t.node_type(value)
|
||||
if value_type.starts_with('&') {
|
||||
return value
|
||||
}
|
||||
clean_variant := if variant.starts_with('&') { variant[1..] } else { variant }
|
||||
if value_type.len == 0 {
|
||||
value_type = clean_variant
|
||||
}
|
||||
if t.expr_can_take_address(value) || t.a.nodes[int(value)].kind == .struct_init {
|
||||
ref := t.make_prefix(.amp, value)
|
||||
t.a.nodes[int(ref)].typ = '&${clean_variant}'
|
||||
return ref
|
||||
}
|
||||
tmp_name := t.new_temp('sum_val')
|
||||
t.pending_stmts << t.make_decl_assign_typed(tmp_name, value, value_type)
|
||||
ref := t.make_prefix(.amp, t.make_ident(tmp_name))
|
||||
t.a.nodes[int(ref)].typ = '&${clean_variant}'
|
||||
return ref
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_sum_literal(sum_name string, variant string, value flat.NodeId) flat.NodeId {
|
||||
qvariant := t.resolve_variant(sum_name, variant)
|
||||
typ_field := t.make_sum_literal_field('typ', t.make_int_literal(t.sum_type_index(sum_name,
|
||||
qvariant)), 'int')
|
||||
raw_value_type := t.node_type(value)
|
||||
value_type := if raw_value_type.starts_with('&') {
|
||||
raw_value_type
|
||||
} else {
|
||||
qvariant
|
||||
}
|
||||
value_field := t.make_sum_literal_field(t.sum_field_name(qvariant), value, value_type)
|
||||
start := t.a.children.len
|
||||
t.a.children << typ_field
|
||||
t.a.children << value_field
|
||||
return t.a.add_node(flat.Node{
|
||||
kind: .struct_init
|
||||
children_start: start
|
||||
children_count: 2
|
||||
value: sum_name
|
||||
typ: sum_name
|
||||
})
|
||||
}
|
||||
|
||||
fn (mut t Transformer) make_sum_literal_field(name string, value flat.NodeId, typ string) flat.NodeId {
|
||||
start := t.a.children.len
|
||||
t.a.children << value
|
||||
return t.a.add_node(flat.Node{
|
||||
kind: .field_init
|
||||
children_start: start
|
||||
children_count: 1
|
||||
value: name
|
||||
typ: typ
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user