Skip to content

Commit d10c662

Browse files
committed
v2: transform
1 parent f665055 commit d10c662

1 file changed

Lines changed: 245 additions & 0 deletions

File tree

‎vlib/v2/transform/transform.v‎

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2+
// Use of this source code is governed by an MIT license
3+
// that can be found in the LICENSE file.
4+
5+
// The transform module provides AST-level transformations that lower
6+
// complex language constructs into simpler forms. This avoids duplicating
7+
// lowering logic across multiple backends (C, x64, arm64, etc).
8+
module transform
9+
10+
import v2.ast
11+
12+
pub struct Transformer {
13+
mut:
14+
// Track array literals that need lowering
15+
array_temps int
16+
}
17+
18+
pub fn Transformer.new() &Transformer {
19+
return &Transformer{}
20+
}
21+
22+
// transform processes an entire file, lowering complex constructs
23+
// Returns a new file with transformed statements
24+
pub fn (mut t Transformer) transform(file ast.File) ast.File {
25+
mut new_stmts := []ast.Stmt{cap: file.stmts.len}
26+
for stmt in file.stmts {
27+
new_stmts << t.stmt(stmt)
28+
}
29+
return ast.File{
30+
attributes: file.attributes
31+
mod: file.mod
32+
name: file.name
33+
stmts: new_stmts
34+
imports: file.imports
35+
}
36+
}
37+
38+
fn (mut t Transformer) stmt(node ast.Stmt) ast.Stmt {
39+
match node {
40+
ast.AssignStmt {
41+
return t.assign_stmt(node)
42+
}
43+
ast.FnDecl {
44+
return t.fn_decl(node)
45+
}
46+
ast.ForStmt {
47+
return t.for_stmt(node)
48+
}
49+
ast.BlockStmt {
50+
return t.block_stmt(node)
51+
}
52+
ast.ReturnStmt {
53+
return t.return_stmt(node)
54+
}
55+
ast.ExprStmt {
56+
return ast.ExprStmt{
57+
expr: t.expr(node.expr)
58+
}
59+
}
60+
else {
61+
return node
62+
}
63+
}
64+
}
65+
66+
fn (mut t Transformer) assign_stmt(node ast.AssignStmt) ast.Stmt {
67+
// Transform RHS expressions
68+
mut new_rhs := []ast.Expr{cap: node.rhs.len}
69+
for rhs_expr in node.rhs {
70+
new_rhs << t.expr(rhs_expr)
71+
}
72+
return ast.AssignStmt{
73+
op: node.op
74+
lhs: node.lhs
75+
rhs: new_rhs
76+
pos: node.pos
77+
}
78+
}
79+
80+
fn (mut t Transformer) fn_decl(node ast.FnDecl) ast.Stmt {
81+
mut new_stmts := []ast.Stmt{cap: node.stmts.len}
82+
for stmt in node.stmts {
83+
new_stmts << t.stmt(stmt)
84+
}
85+
return ast.FnDecl{
86+
attributes: node.attributes
87+
is_public: node.is_public
88+
is_method: node.is_method
89+
is_static: node.is_static
90+
receiver: node.receiver
91+
language: node.language
92+
name: node.name
93+
typ: node.typ
94+
stmts: new_stmts
95+
pos: node.pos
96+
}
97+
}
98+
99+
fn (mut t Transformer) for_stmt(node ast.ForStmt) ast.Stmt {
100+
mut new_stmts := []ast.Stmt{cap: node.stmts.len}
101+
for stmt in node.stmts {
102+
new_stmts << t.stmt(stmt)
103+
}
104+
return ast.ForStmt{
105+
init: t.stmt(node.init)
106+
cond: t.expr(node.cond)
107+
post: t.stmt(node.post)
108+
stmts: new_stmts
109+
}
110+
}
111+
112+
fn (mut t Transformer) block_stmt(node ast.BlockStmt) ast.Stmt {
113+
mut new_stmts := []ast.Stmt{cap: node.stmts.len}
114+
for stmt in node.stmts {
115+
new_stmts << t.stmt(stmt)
116+
}
117+
return ast.BlockStmt{
118+
stmts: new_stmts
119+
}
120+
}
121+
122+
fn (mut t Transformer) return_stmt(node ast.ReturnStmt) ast.Stmt {
123+
mut new_exprs := []ast.Expr{cap: node.exprs.len}
124+
for expr in node.exprs {
125+
new_exprs << t.expr(expr)
126+
}
127+
return ast.ReturnStmt{
128+
exprs: new_exprs
129+
}
130+
}
131+
132+
fn (mut t Transformer) expr(node ast.Expr) ast.Expr {
133+
match node {
134+
ast.ArrayInitExpr {
135+
return t.lower_array_init(node)
136+
}
137+
ast.StringInterLiteral {
138+
return t.lower_string_inter(node)
139+
}
140+
ast.InfixExpr {
141+
return ast.InfixExpr{
142+
op: node.op
143+
lhs: t.expr(node.lhs)
144+
rhs: t.expr(node.rhs)
145+
pos: node.pos
146+
}
147+
}
148+
ast.PrefixExpr {
149+
return ast.PrefixExpr{
150+
op: node.op
151+
expr: t.expr(node.expr)
152+
pos: node.pos
153+
}
154+
}
155+
ast.CallExpr {
156+
return t.call_expr(node)
157+
}
158+
ast.IndexExpr {
159+
return ast.IndexExpr{
160+
lhs: t.expr(node.lhs)
161+
expr: t.expr(node.expr)
162+
is_gated: node.is_gated
163+
}
164+
}
165+
ast.IfExpr {
166+
return t.if_expr(node)
167+
}
168+
else {
169+
return node
170+
}
171+
}
172+
}
173+
174+
fn (mut t Transformer) call_expr(node ast.CallExpr) ast.Expr {
175+
mut new_args := []ast.Expr{cap: node.args.len}
176+
for arg in node.args {
177+
new_args << t.expr(arg)
178+
}
179+
return ast.CallExpr{
180+
lhs: node.lhs
181+
args: new_args
182+
pos: node.pos
183+
}
184+
}
185+
186+
fn (mut t Transformer) if_expr(node ast.IfExpr) ast.Expr {
187+
mut new_stmts := []ast.Stmt{cap: node.stmts.len}
188+
for stmt in node.stmts {
189+
new_stmts << t.stmt(stmt)
190+
}
191+
return ast.IfExpr{
192+
cond: t.expr(node.cond)
193+
stmts: new_stmts
194+
else_expr: t.expr(node.else_expr)
195+
}
196+
}
197+
198+
// lower_array_init transforms ArrayInitExpr into a lowered form.
199+
// For literal arrays like [1, 2, 3], we keep the ArrayInitExpr but ensure
200+
// all element expressions are transformed.
201+
// The SSA builder handles the actual lowering to alloca + stores.
202+
fn (mut t Transformer) lower_array_init(node ast.ArrayInitExpr) ast.Expr {
203+
// Transform all element expressions
204+
mut new_exprs := []ast.Expr{cap: node.exprs.len}
205+
for expr in node.exprs {
206+
new_exprs << t.expr(expr)
207+
}
208+
209+
// Transform len/cap/init expressions if present
210+
new_len := t.expr(node.len)
211+
new_cap := t.expr(node.cap)
212+
new_init := t.expr(node.init)
213+
214+
return ast.ArrayInitExpr{
215+
typ: node.typ
216+
exprs: new_exprs
217+
init: new_init
218+
cap: new_cap
219+
len: new_len
220+
pos: node.pos
221+
}
222+
}
223+
224+
// lower_string_inter transforms StringInterLiteral.
225+
// For now, we just transform the interpolated expressions.
226+
// The SSA builder handles the actual lowering to sprintf calls.
227+
// Later, this can be transformed into strconv function calls.
228+
fn (mut t Transformer) lower_string_inter(node ast.StringInterLiteral) ast.Expr {
229+
// Transform all interpolated expressions
230+
mut new_inters := []ast.StringInter{cap: node.inters.len}
231+
for inter in node.inters {
232+
new_inters << ast.StringInter{
233+
format: inter.format
234+
width: inter.width
235+
precision: inter.precision
236+
expr: t.expr(inter.expr)
237+
format_expr: t.expr(inter.format_expr)
238+
}
239+
}
240+
return ast.StringInterLiteral{
241+
kind: node.kind
242+
values: node.values
243+
inters: new_inters
244+
}
245+
}

0 commit comments

Comments
 (0)