Skip to content

Commit 614c985

Browse files
authored
v: add a new v.comptime stage COMPTIME, that runs after the checker (CHECK), and before the transformer (TRANSFORM), to simplify the work that later stages do #26068 (#26161)
1 parent 7e3715e commit 614c985

4 files changed

Lines changed: 367 additions & 30 deletions

File tree

‎vlib/v/builder/builder.v‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import v.ast
99
import v.vmod
1010
import v.checker
1111
import v.transformer
12+
import v.comptime
1213
import v.parser
1314
import v.markused
1415
import v.depgraph
@@ -23,6 +24,7 @@ pub:
2324
pub mut:
2425
checker &checker.Checker = unsafe { nil }
2526
transformer &transformer.Transformer = unsafe { nil }
27+
comptime &comptime.Comptime = unsafe { nil }
2628
out_name_c string
2729
out_name_js string
2830
stats_lines int // size of backend generated source code in lines
@@ -82,6 +84,7 @@ pub fn new_builder(pref_ &pref.Preferences) Builder {
8284
table: table
8385
checker: checker.new_checker(table, pref_)
8486
transformer: transformer.new_transformer_with_table(table, pref_)
87+
comptime: comptime.new_comptime_with_table(table, pref_)
8588
compiled_dir: compiled_dir
8689
cached_msvc: msvc
8790
executable_exists: os.is_file(executable_name)
@@ -136,6 +139,11 @@ pub fn (mut b Builder) middle_stages() ! {
136139
println('> t: ${t:10} | s.mod: ${s.mod:-40} | s.name: ${'${s.name#[..30]}':-30} | s.is_builtin: ${s.is_builtin:6} | s.is_pub: ${s.is_pub}')
137140
}
138141
}
142+
143+
util.timing_start('COMPTIME')
144+
b.comptime.solve_files(b.parsed_files)
145+
util.timing_measure('COMPTIME')
146+
139147
if b.pref.dump_defines != '' {
140148
b.dump_defines()
141149
}

‎vlib/v/comptime/comptime.v‎

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
module comptime
2+
3+
import v.pref
4+
import v.ast
5+
6+
pub struct Comptime {
7+
pref &pref.Preferences
8+
pub mut:
9+
table &ast.Table = unsafe { nil }
10+
file &ast.File = unsafe { nil }
11+
}
12+
13+
pub fn new_comptime(pref_ &pref.Preferences) &Comptime {
14+
return &Comptime{
15+
pref: pref_
16+
}
17+
}
18+
19+
pub fn new_comptime_with_table(table &ast.Table, pref_ &pref.Preferences) &Comptime {
20+
mut c := new_comptime(pref_)
21+
c.table = table
22+
return c
23+
}
24+
25+
pub fn (mut c Comptime) solve_files(ast_files []&ast.File) {
26+
for i in 0 .. ast_files.len {
27+
mut file := unsafe { ast_files[i] }
28+
c.solve(mut file)
29+
}
30+
}
31+
32+
pub fn (mut c Comptime) solve(mut ast_file ast.File) {
33+
c.file = ast_file
34+
ast_file.stmts = c.stmts(mut ast_file.stmts)
35+
}
36+
37+
pub fn (mut c Comptime) stmts(mut nodes []ast.Stmt) []ast.Stmt {
38+
for mut stmt in nodes {
39+
stmt = c.stmt(mut stmt)
40+
}
41+
return nodes
42+
}
43+
44+
pub fn (mut c Comptime) stmt(mut node ast.Stmt) ast.Stmt {
45+
match mut node {
46+
ast.EmptyStmt {}
47+
ast.NodeError {}
48+
ast.AsmStmt {}
49+
ast.DebuggerStmt {}
50+
ast.AssertStmt {
51+
node.expr = c.expr(mut node.expr)
52+
}
53+
ast.AssignStmt {
54+
node.right = c.exprs(mut node.right)
55+
node.left = c.exprs(mut node.left)
56+
}
57+
ast.Block {
58+
node.stmts = c.stmts(mut node.stmts)
59+
}
60+
ast.BranchStmt {}
61+
ast.ComptimeFor {
62+
node.stmts = c.stmts(mut node.stmts)
63+
}
64+
ast.ConstDecl {
65+
// node.fields = c.const_decl_fields(mut node.fields)
66+
}
67+
ast.DeferStmt {
68+
node.stmts = c.stmts(mut node.stmts)
69+
}
70+
ast.EnumDecl {
71+
// node.fields = c.enum_decl_fields(mut node.fields)
72+
}
73+
ast.ExprStmt {
74+
res := c.expr_stmt(mut node.expr)
75+
match res {
76+
ast.Expr {
77+
node.expr = res
78+
}
79+
ast.Stmt {
80+
return res
81+
}
82+
}
83+
}
84+
ast.FnDecl {
85+
node.stmts = c.stmts(mut node.stmts)
86+
}
87+
ast.ForCStmt {
88+
if node.has_init && !node.is_multi {
89+
node.init = c.stmt(mut node.init)
90+
}
91+
92+
if node.has_cond {
93+
node.cond = c.expr(mut node.cond)
94+
}
95+
96+
node.stmts = c.stmts(mut node.stmts)
97+
98+
if node.has_inc && !node.is_multi {
99+
node.inc = c.stmt(mut node.inc)
100+
}
101+
}
102+
ast.ForInStmt {
103+
node.stmts = c.stmts(mut node.stmts)
104+
}
105+
ast.ForStmt {
106+
node.cond = c.expr(mut node.cond)
107+
node.stmts = c.stmts(mut node.stmts)
108+
}
109+
ast.GlobalDecl {
110+
// node.fields = c.global_decl_fields(mut node.fields)
111+
}
112+
ast.GotoLabel {}
113+
ast.GotoStmt {}
114+
ast.HashStmt {
115+
// node.ct.conds = c.hashstmt_ct_conds(mut node.ct_conds)
116+
}
117+
ast.Import {}
118+
ast.InterfaceDecl {
119+
// node.fields = c.interface_decl_fields(mut node.fields)
120+
}
121+
ast.Module {}
122+
ast.Return {
123+
node.exprs = c.exprs(mut node.exprs)
124+
}
125+
ast.SemicolonStmt {}
126+
ast.SqlStmt {}
127+
ast.StructDecl {
128+
// node.fields = c.struct_decl_fields(mut node.fields)
129+
}
130+
ast.TypeDecl {}
131+
}
132+
return node
133+
}
134+
135+
type StmtOrExpr = ast.Expr | ast.Stmt
136+
137+
pub fn (mut c Comptime) expr_stmt(mut node ast.Expr) StmtOrExpr {
138+
match mut node {
139+
ast.IfExpr {
140+
if node.is_comptime {
141+
if !node.is_expr && !node.has_else && node.branches.len == 1 {
142+
if node.branches[0].stmts.len == 0 {
143+
// empty ifdef; result of target OS != conditional => skip
144+
return ast.Stmt(ast.Block{
145+
pos: node.pos
146+
scope: ast.empty_scope
147+
})
148+
}
149+
if !c.pref.output_cross_c {
150+
if node.branches[0].cond is ast.Ident {
151+
if c.pref.os == (pref.os_from_string(node.branches[0].cond.name) or {
152+
pref.OS._auto
153+
}) {
154+
// Same target OS as the conditional...
155+
// => skip the #if defined ... #endif wrapper
156+
// and just generate the branch statements:
157+
return ast.Stmt(ast.Block{
158+
stmts: node.branches[0].stmts
159+
scope: node.branches[0].scope
160+
pos: node.pos
161+
})
162+
}
163+
}
164+
}
165+
}
166+
}
167+
return c.expr(mut node)
168+
}
169+
else {
170+
return c.expr(mut node)
171+
}
172+
}
173+
return node
174+
}
175+
176+
pub fn (mut c Comptime) exprs(mut nodes []ast.Expr) []ast.Expr {
177+
for mut e in nodes {
178+
e = c.expr(mut e)
179+
}
180+
return nodes
181+
}
182+
183+
pub fn (mut c Comptime) expr(mut node ast.Expr) ast.Expr {
184+
match mut node {
185+
ast.AnonFn {
186+
node.decl = c.stmt(mut node.decl) as ast.FnDecl
187+
}
188+
ast.ArrayDecompose {
189+
node.expr = c.expr(mut node.expr)
190+
}
191+
ast.ArrayInit {
192+
node.exprs = c.exprs(mut node.exprs)
193+
if node.has_len {
194+
node.len_expr = c.expr(mut node.len_expr)
195+
}
196+
if node.has_cap {
197+
node.cap_expr = c.expr(mut node.cap_expr)
198+
}
199+
if node.has_init {
200+
node.init_expr = c.expr(mut node.init_expr)
201+
}
202+
}
203+
ast.AsCast {
204+
node.expr = c.expr(mut node.expr)
205+
}
206+
ast.CTempVar {
207+
node.orig = c.expr(mut node.orig)
208+
}
209+
ast.CallExpr {
210+
node.left = c.expr(mut node.left)
211+
for mut arg in node.args {
212+
arg.expr = c.expr(mut arg.expr)
213+
}
214+
node.or_block = c.expr(mut node.or_block) as ast.OrExpr
215+
}
216+
ast.CastExpr {
217+
node.arg = c.expr(mut node.arg)
218+
node.expr = c.expr(mut node.expr)
219+
}
220+
ast.ChanInit {
221+
node.cap_expr = c.expr(mut node.cap_expr)
222+
}
223+
ast.ComptimeCall {
224+
for mut arg in node.args {
225+
arg.expr = c.expr(mut arg.expr)
226+
}
227+
}
228+
ast.ComptimeSelector {
229+
node.left = c.expr(mut node.left)
230+
node.field_expr = c.expr(mut node.field_expr)
231+
}
232+
ast.ConcatExpr {
233+
for mut val in node.vals {
234+
val = c.expr(mut val)
235+
}
236+
}
237+
ast.DumpExpr {
238+
node.expr = c.expr(mut node.expr)
239+
}
240+
ast.GoExpr {
241+
node.call_expr = c.expr(mut node.call_expr) as ast.CallExpr
242+
}
243+
ast.IfExpr {
244+
for mut branch in node.branches {
245+
branch.cond = c.expr(mut branch.cond)
246+
branch.stmts = c.stmts(mut branch.stmts)
247+
}
248+
// where we place the result of the if when a := if ...
249+
node.left = c.expr(mut node.left)
250+
}
251+
ast.IfGuardExpr {
252+
node.expr = c.expr(mut node.expr)
253+
}
254+
ast.IndexExpr {
255+
node.left = c.expr(mut node.left)
256+
node.index = c.expr(mut node.index)
257+
node.or_expr = c.expr(mut node.or_expr) as ast.OrExpr
258+
}
259+
ast.InfixExpr {
260+
node.left = c.expr(mut node.left)
261+
node.right = c.expr(mut node.right)
262+
}
263+
ast.IsRefType {
264+
node.expr = c.expr(mut node.expr)
265+
}
266+
ast.Likely {
267+
node.expr = c.expr(mut node.expr)
268+
}
269+
ast.LockExpr {
270+
node.stmts = c.stmts(mut node.stmts)
271+
node.lockeds = c.exprs(mut node.lockeds)
272+
}
273+
ast.MapInit {
274+
node.keys = c.exprs(mut node.keys)
275+
node.vals = c.exprs(mut node.vals)
276+
}
277+
ast.MatchExpr {
278+
node.cond = c.expr(mut node.cond)
279+
for mut branch in node.branches {
280+
branch.exprs = c.exprs(mut branch.exprs)
281+
branch.stmts = c.stmts(mut branch.stmts)
282+
}
283+
}
284+
ast.OrExpr {
285+
node.stmts = c.stmts(mut node.stmts)
286+
}
287+
ast.ParExpr {
288+
node.expr = c.expr(mut node.expr)
289+
}
290+
ast.PostfixExpr {
291+
node.expr = c.expr(mut node.expr)
292+
}
293+
ast.PrefixExpr {
294+
node.right = c.expr(mut node.right)
295+
node.or_block = c.expr(mut node.or_block) as ast.OrExpr
296+
}
297+
ast.RangeExpr {
298+
node.low = c.expr(mut node.low)
299+
node.high = c.expr(mut node.high)
300+
}
301+
ast.SelectExpr {
302+
for mut branch in node.branches {
303+
branch.stmt = c.stmt(mut branch.stmt)
304+
branch.stmts = c.stmts(mut branch.stmts)
305+
}
306+
}
307+
ast.SelectorExpr {
308+
node.expr = c.expr(mut node.expr)
309+
}
310+
ast.SizeOf {
311+
node.expr = c.expr(mut node.expr)
312+
}
313+
ast.SqlExpr {
314+
node.db_expr = c.expr(mut node.db_expr)
315+
if node.has_where {
316+
node.where_expr = c.expr(mut node.where_expr)
317+
}
318+
if node.has_order {
319+
node.order_expr = c.expr(mut node.order_expr)
320+
}
321+
if node.has_limit {
322+
node.limit_expr = c.expr(mut node.limit_expr)
323+
}
324+
if node.has_offset {
325+
node.offset_expr = c.expr(mut node.offset_expr)
326+
}
327+
for mut field in node.fields {
328+
field.default_expr = c.expr(mut field.default_expr)
329+
}
330+
for _, mut sub_struct in node.sub_structs {
331+
sub_struct = c.expr(mut sub_struct) as ast.SqlExpr
332+
}
333+
}
334+
ast.StringInterLiteral {
335+
node.exprs = c.exprs(mut node.exprs)
336+
}
337+
ast.StructInit {
338+
node.update_expr = c.expr(mut node.update_expr)
339+
for mut init_field in node.init_fields {
340+
init_field.expr = c.expr(mut init_field.expr)
341+
}
342+
}
343+
ast.UnsafeExpr {
344+
node.expr = c.expr(mut node.expr)
345+
}
346+
else {}
347+
}
348+
return node
349+
}

0 commit comments

Comments
 (0)