Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+571
View File
@@ -0,0 +1,571 @@
module transform
import v3.flat
fn (mut t Transformer) transform_field_init_expr(id flat.NodeId, node flat.Node) flat.NodeId {
if node.children_count == 0 {
return id
}
val_id := t.a.child(&node, 0)
val_node := t.a.nodes[int(val_id)]
new_val := if inferred_sum := t.sum_type_for_field_variant(node.value, val_id, val_node) {
t.wrap_sum_value(val_id, inferred_sum)
} else {
t.transform_expr(val_id)
}
start := t.a.children.len
t.a.children << new_val
return t.a.add_node(flat.Node{
kind: .field_init
op: node.op
children_start: start
children_count: 1
pos: node.pos
value: node.value
typ: node.typ
})
}
// transform_struct_fields transforms struct initialization fields with enum resolution.
// For each .field_init child, transforms the value expression. If the struct field type
// is a known enum, resolves shorthand enum values (e.g. `.red` -> `Color.red`).
fn (mut t Transformer) transform_struct_fields(id flat.NodeId, node flat.Node) flat.NodeId {
if node.children_count == 0 {
return t.add_missing_struct_defaults(id, node)
}
info := t.lookup_struct_info(node.value) or {
// Unknown struct: fall back to generic child transform
return t.transform_struct_children(id, node)
}
// Build a field name -> type lookup from the struct definition
mut field_types := map[string]string{}
mut field_order := []string{cap: info.fields.len}
for f in info.fields {
field_types[f.name] = f.typ
field_order << f.name
}
mut field_ids := []flat.NodeId{}
mut promoted_fields := map[string][]flat.NodeId{}
mut promoted_types := map[string]string{}
mut prelude := []flat.NodeId{}
t.drain_pending(mut prelude)
for i in 0 .. node.children_count {
child_id := t.a.child(&node, i)
child := t.a.nodes[int(child_id)]
if child.kind == .field_init && child.children_count > 0 {
val_id := t.a.child(&child, 0)
val_node := t.a.nodes[int(val_id)]
field_name := if child.value.len > 0 {
child.value
} else if i < field_order.len {
field_order[i]
} else {
''
}
mut target_field_name := field_name
mut field_type := field_types[field_name] or { '' }
mut promoted_parent := ''
if field_type.len == 0 {
if embedded := t.embedded_field_for_promoted_field(info, field_name) {
promoted_parent = embedded.name
promoted_types[promoted_parent] = embedded.typ
if embedded_info := t.lookup_struct_info(embedded.typ) {
if promoted_type := t.struct_field_type(embedded_info, field_name) {
field_type = promoted_type
}
}
}
}
if val_node.kind == .array_literal && is_fixed_array_type(field_type) {
t.a.nodes[int(val_id)].typ = field_type
}
value_type := t.node_type(val_id)
sum_field_type := t.struct_field_sum_type(field_type, info.module)
enum_field_type := t.enum_type_name_for_expected(field_type, info.module)
// Check if the value is an enum shorthand and the field type is an enum
mut new_val := if val_node.kind == .enum_val && enum_field_type.len > 0 {
t.transform_enum_shorthand(val_id, val_node, enum_field_type)
} else if field_type.starts_with('[]') && is_fixed_array_type(value_type) {
t.fixed_array_value_to_array(val_id, value_type, field_type)
} else if sum_field_type.len > 0 {
t.wrap_sum_value(val_id, sum_field_type)
} else if inferred_sum := t.sum_type_for_field_variant(field_name, val_id, val_node) {
t.wrap_sum_value(val_id, inferred_sum)
} else if field_type.starts_with('&') {
t.transform_expr_for_type(val_id, field_type)
} else if field_type.len > 0 {
t.transform_expr_for_type(val_id, field_type)
} else {
t.transform_expr(val_id)
}
if sum_field_type.len == 0 && field_type.len > 0 {
new_val = t.coerce_transformed_expr_to_type(new_val, val_id, field_type)
}
t.drain_pending(mut prelude)
fi_start := t.a.children.len
t.a.children << new_val
new_field := t.a.add_node(flat.Node{
kind: .field_init
op: child.op
children_start: fi_start
children_count: 1
pos: child.pos
value: target_field_name
typ: child.typ
})
if promoted_parent.len > 0 {
mut promoted := promoted_fields[promoted_parent] or { []flat.NodeId{} }
promoted << new_field
promoted_fields[promoted_parent] = promoted
} else {
field_ids << new_field
}
} else {
field_ids << child_id
}
}
for parent, promoted in promoted_fields {
promoted_start := t.a.children.len
for fid in promoted {
t.a.children << fid
}
embedded_type := promoted_types[parent] or { parent }
embedded_init := t.a.add_node(flat.Node{
kind: .struct_init
children_start: promoted_start
children_count: flat.child_count(promoted.len)
value: embedded_type
typ: embedded_type
})
fi_start := t.a.children.len
t.a.children << embedded_init
field_ids << t.a.add_node(flat.Node{
kind: .field_init
children_start: fi_start
children_count: 1
value: parent
typ: embedded_type
})
}
start := t.a.children.len
for fid in field_ids {
t.a.children << fid
}
new_id := t.a.add_node(flat.Node{
kind: .struct_init
op: node.op
children_start: start
children_count: flat.child_count(field_ids.len)
pos: node.pos
value: node.value
typ: node.typ
})
final_id := t.add_missing_struct_defaults(new_id, t.a.nodes[int(new_id)])
for stmt in prelude {
t.pending_stmts << stmt
}
return final_id
}
// transform_struct_children is a fallback for struct inits where the struct type is unknown.
// Transforms all field_init value expressions without enum resolution.
fn (mut t Transformer) transform_struct_children(id flat.NodeId, node flat.Node) flat.NodeId {
if node.children_count == 0 {
return id
}
mut field_ids := []flat.NodeId{}
for i in 0 .. node.children_count {
child_id := t.a.child(&node, i)
child := t.a.nodes[int(child_id)]
if child.kind == .field_init && child.children_count > 0 {
val_id := t.a.child(&child, 0)
new_val := t.transform_expr(val_id)
fi_start := t.a.children.len
t.a.children << new_val
field_ids << t.a.add_node(flat.Node{
kind: .field_init
op: child.op
children_start: fi_start
children_count: 1
pos: child.pos
value: child.value
typ: child.typ
})
} else {
field_ids << child_id
}
}
start := t.a.children.len
for fid in field_ids {
t.a.children << fid
}
return t.a.add_node(flat.Node{
kind: .struct_init
op: node.op
children_start: start
children_count: flat.child_count(field_ids.len)
pos: node.pos
value: node.value
typ: node.typ
})
}
// add_missing_struct_defaults checks if any fields with default values are missing
// from the struct initialization. This is a hook point for future default-fill logic.
// Currently returns the node unchanged because StructInfo does not yet store default values.
fn (mut t Transformer) add_missing_struct_defaults(id flat.NodeId, node flat.Node) flat.NodeId {
if node.value.len == 0 {
return id
}
info := t.lookup_struct_info(node.value) or { return id }
mut provided := map[string]bool{}
mut field_ids := []flat.NodeId{cap: int(node.children_count) + info.fields.len}
mut prelude := []flat.NodeId{}
t.drain_pending(mut prelude)
for i in 0 .. node.children_count {
child_id := t.a.child(&node, i)
child := t.a.nodes[int(child_id)]
if child.kind == .field_init {
provided[child.value] = true
}
field_ids << child_id
}
old_module := t.cur_module
if info.module.len > 0 {
t.cur_module = info.module
}
mut added := false
for field in info.fields {
if field.name in provided || int(field.default_expr) < 0 {
continue
}
default_node := t.a.nodes[int(field.default_expr)]
enum_field_type := t.enum_type_name_for_expected(field.typ, info.module)
new_val := if default_node.kind == .enum_val && enum_field_type.len > 0 {
t.transform_enum_shorthand(field.default_expr, default_node, enum_field_type)
} else if t.is_sum_type_name(field.typ) {
// A sum-type field default (e.g. `typ_expr Expr = EmptyExpr{}`) must be
// wrapped into the sum, not emitted as the bare variant. wrap_sum_value
// is a no-op when the value already is the sum type.
t.wrap_sum_value(field.default_expr, field.typ)
} else {
t.transform_expr_for_type(field.default_expr, field.typ)
}
t.drain_pending(mut prelude)
fi_start := t.a.children.len
t.a.children << new_val
field_ids << t.a.add_node(flat.Node{
kind: .field_init
children_start: fi_start
children_count: 1
value: field.name
typ: field.typ
})
provided[field.name] = true
added = true
}
t.cur_module = old_module
if !added {
for stmt in prelude {
t.pending_stmts << stmt
}
return id
}
start := t.a.children.len
for fid in field_ids {
t.a.children << fid
}
final_id := t.a.add_node(flat.Node{
kind: .struct_init
op: node.op
children_start: start
children_count: flat.child_count(field_ids.len)
pos: node.pos
value: node.value
typ: node.typ
})
for stmt in prelude {
t.pending_stmts << stmt
}
return final_id
}
fn (t &Transformer) lookup_struct_info(name string) ?StructInfo {
if name.contains('.') {
if name in t.structs {
return t.structs[name]
}
} else if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' {
qname := '${t.cur_module}.${name}'
if qname in t.structs {
return t.structs[qname]
}
}
if name in t.structs {
return t.structs[name]
}
if name.contains('.') {
short_name := name.all_after_last('.')
if short_name in t.structs {
return t.structs[short_name]
}
}
return none
}
fn (t &Transformer) struct_field_type(info StructInfo, field_name string) ?string {
for field in info.fields {
if field.name == field_name {
return field.typ
}
}
return none
}
fn (t &Transformer) embedded_field_for_promoted_field(info StructInfo, field_name string) ?FieldInfo {
for field in info.fields {
if !t.is_embedded_field(field) {
continue
}
embedded_info := t.lookup_struct_info(field.typ) or { continue }
if _ := t.struct_field_type(embedded_info, field_name) {
return field
}
}
return none
}
fn (t &Transformer) is_embedded_field(field FieldInfo) bool {
if field.name.len == 0 || field.typ.len == 0 {
return false
}
short_typ := if field.typ.contains('.') { field.typ.all_after_last('.') } else { field.typ }
short_name := if field.name.contains('.') { field.name.all_after_last('.') } else { field.name }
return short_name == short_typ
}
fn (mut t Transformer) transform_assoc_expr(id flat.NodeId, node flat.Node) flat.NodeId {
if node.kind != .assoc || node.children_count == 0 {
return id
}
base_id := t.a.child(&node, 0)
base_type := t.node_type(base_id)
mut assoc_type := node.value
if assoc_type.len == 0 {
assoc_type = base_type
}
if assoc_type.starts_with('&') {
assoc_type = assoc_type[1..]
}
mut field_types := map[string]string{}
mut assoc_module := ''
if info := t.lookup_struct_info(assoc_type) {
assoc_module = info.module
for field in info.fields {
field_types[field.name] = field.typ
}
}
tmp_name := t.new_temp('assoc')
outer_pending := t.pending_stmts.clone()
t.pending_stmts.clear()
mut prelude := []flat.NodeId{}
transformed_base := t.transform_expr(base_id)
base := if base_type.starts_with('&') {
t.make_prefix(.mul, transformed_base)
} else {
transformed_base
}
t.drain_pending(mut prelude)
prelude << t.make_decl_assign_typed(tmp_name, base, assoc_type)
for i in 1 .. node.children_count {
field_id := t.a.child(&node, i)
field := t.a.nodes[int(field_id)]
if field.kind != .field_init || field.children_count == 0 {
continue
}
value_id := t.a.child(&field, 0)
value_node := t.a.nodes[int(value_id)]
field_type := field_types[field.value] or { '' }
if value_node.kind == .array_literal && is_fixed_array_type(field_type) {
t.a.nodes[int(value_id)].typ = field_type
}
value_type := t.node_type(value_id)
enum_field_type := t.enum_type_name_for_expected(field_type, assoc_module)
value := if value_node.kind == .enum_val && enum_field_type.len > 0 {
t.transform_enum_shorthand(value_id, value_node, enum_field_type)
} else if field_type.starts_with('[]') && is_fixed_array_type(value_type) {
t.fixed_array_value_to_array(value_id, value_type, field_type)
} else if t.is_sum_type_name(field_type) {
t.wrap_sum_value(value_id, field_type)
} else if field_type.len > 0 {
t.transform_expr_for_type(value_id, field_type)
} else {
t.transform_expr(value_id)
}
t.drain_pending(mut prelude)
prelude << t.make_assign(t.make_selector(t.make_ident(tmp_name), field.value, field_type),
value)
}
t.pending_stmts = outer_pending
for stmt in prelude {
t.pending_stmts << stmt
}
result := t.make_ident(tmp_name)
t.a.nodes[int(result)].typ = assoc_type
return result
}
fn (mut t Transformer) transform_amp_assoc_expr_for_type(_id flat.NodeId, node flat.Node, target_type string) ?flat.NodeId {
if node.kind != .prefix || node.op != .amp || node.children_count != 1 {
return none
}
child_id := t.a.child(&node, 0)
child := t.a.nodes[int(child_id)]
if child.kind != .assoc {
return none
}
value := t.transform_assoc_expr(child_id, child)
mut value_type := t.node_type(value)
if value_type.len == 0 {
value_type = t.node_type(child_id)
}
if value_type.starts_with('&') {
value_type = value_type[1..]
}
if value_type.len == 0 {
return none
}
addr := t.make_prefix(.amp, value)
size := t.make_sizeof_type(value_type)
dup := t.make_call_typed('memdup', arr2(addr, size), 'voidptr')
mut ptr_type := target_type
if ptr_type.len == 0 {
ptr_type = node.typ
}
if !ptr_type.starts_with('&') {
ptr_type = '&${value_type}'
}
cast := t.make_cast(ptr_type, dup, ptr_type)
t.a.nodes[int(cast)].typ = ptr_type
return cast
}
fn (t &Transformer) struct_field_sum_type(field_type string, owner_module string) string {
if t.is_sum_type_name(field_type) {
return field_type
}
if field_type.len == 0 || field_type.contains('.') || owner_module.len == 0 {
return ''
}
qname := '${owner_module}.${field_type}'
if qname in t.sum_types {
return qname
}
return ''
}
fn (t &Transformer) sum_type_for_field_variant(field_name string, val_id flat.NodeId, val_node flat.Node) ?string {
if field_name != 'info' {
return none
}
mut variant := if val_node.kind in [.struct_init, .cast_expr, .assoc] && val_node.value.len > 0 {
val_node.value
} else if val_node.kind == .assoc && val_node.children_count > 0 {
t.node_type(t.a.child(&val_node, 0))
} else {
t.node_type(val_id)
}
if variant.starts_with('&') {
variant = variant[1..]
}
if variant.len == 0 {
return none
}
short_variant := if variant.contains('.') { variant.all_after_last('.') } else { variant }
for sum_name, variants in t.sum_types {
if sum_name != 'TypeInfo' && !sum_name.ends_with('.TypeInfo') {
continue
}
for v in variants {
short_v := if v.contains('.') { v.all_after_last('.') } else { v }
if v == variant || short_v == short_variant {
return sum_name
}
}
}
return none
}
fn (mut t Transformer) fixed_array_value_to_array(value_id flat.NodeId, fixed_type string, array_type string) flat.NodeId {
elem_type := fixed_array_elem_type(fixed_type)
len_expr := t.make_fixed_array_len_expr(fixed_type)
return t.make_call_typed('new_array_from_c_array', [
len_expr,
len_expr,
t.make_sizeof_type(elem_type),
t.transform_expr(value_id),
], array_type)
}
// transform_array_init_expr transforms .array_init nodes (e.g. `[]int{len: n}`).
// Recursively transforms any child expressions (len, cap, init values).
fn (mut t Transformer) transform_array_init_expr(id flat.NodeId, node flat.Node) flat.NodeId {
lowered := t.lower_array_init_to_runtime(id, node)
if lowered != id {
return lowered
}
if node.children_count == 0 {
return id
}
mut new_children := []flat.NodeId{cap: int(node.children_count)}
for i in 0 .. node.children_count {
child_id := t.a.child(&node, i)
new_children << t.transform_expr(child_id)
}
start := t.a.children.len
for nc in new_children {
t.a.children << nc
}
return t.a.add_node(flat.Node{
kind: .array_init
op: node.op
children_start: start
children_count: node.children_count
pos: node.pos
value: node.value
typ: node.typ
})
}
// transform_map_init_expr transforms .map_init nodes.
// Recursively transforms all child key/value expressions.
fn (mut t Transformer) transform_map_init_expr(id flat.NodeId, node flat.Node) flat.NodeId {
if node.value.starts_with('map[') || node.typ.starts_with('map[') {
return t.lower_map_init_to_runtime(id, node)
}
if node.children_count == 0 {
return id
}
mut new_children := []flat.NodeId{cap: int(node.children_count)}
for i in 0 .. node.children_count {
child_id := t.a.child(&node, i)
new_children << t.transform_expr(child_id)
}
start := t.a.children.len
for nc in new_children {
t.a.children << nc
}
return t.a.add_node(flat.Node{
kind: .map_init
op: node.op
children_start: start
children_count: node.children_count
pos: node.pos
value: node.value
typ: node.typ
})
}