transform: transforms `while` and `for`
[nit.git] / src / transform.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Thansformations that simplify the AST of expressions
16 # This module transform complex AST `AExpr` nodes into simplier ones
17 module transform
18
19 import astbuilder
20 import astvalidation
21 import semantize
22 intrude import semantize::scope
23
24 redef class ToolContext
25 var transform_phase: Phase = new TransformPhase(self, [typing_phase, auto_super_init_phase])
26 end
27
28 private class TransformPhase
29 super Phase
30
31 redef fun process_npropdef(npropdef: APropdef)
32 do
33 var val
34
35 var v = new TransformVisitor(self, npropdef)
36 v.enter_visit(npropdef)
37
38 val = new ASTValidationVisitor
39 val.enter_visit(npropdef)
40 end
41 end
42
43 private class TransformVisitor
44 super Visitor
45
46 var phase: TransformPhase
47 var mmodule: MModule
48 var mclassdef: MClassDef
49 var mpropdef: MPropDef
50 var builder: ASTBuilder
51
52 init(phase: TransformPhase, npropdef: APropdef)
53 do
54 self.phase = phase
55 self.mpropdef = npropdef.mpropdef.as(not null)
56 self.mclassdef = mpropdef.mclassdef
57 self.mmodule = mclassdef.mmodule
58 self.builder = new ASTBuilder(mmodule, mpropdef.mclassdef.bound_mtype)
59 end
60
61 redef fun visit(node)
62 do
63 if node isa AAnnotations then return
64 node.visit_all(self)
65 node.accept_transform_visitor(self)
66 end
67
68 # Get a primitive class or display a fatal error on `location`.
69 fun get_class(location: AExpr, name: String): MClass
70 do
71 return mmodule.get_primitive_class(name)
72 end
73
74 # Get a primitive method or display a fatal error on `location`.
75 fun get_method(location: AExpr, name: String, recv: MClass): MMethod
76 do
77 return phase.toolcontext.modelbuilder.force_get_primitive_method(location, name, recv, mmodule)
78 end
79 end
80
81 redef class ANode
82 private fun accept_transform_visitor(v: TransformVisitor)
83 do
84 end
85 end
86
87 redef class AVardeclExpr
88 # `var x = y` is replaced with `x = y`
89 #
90 # Declarations are only useful for scope rules
91 # Once names are associated with real objects, ther declaration become useless
92 # Therefore, if there is no initial value, then just ignore it
93 # Else, replace it with a simple assignment
94 redef fun accept_transform_visitor(v)
95 do
96 var nexpr = n_expr
97 if nexpr == null then
98 # do nothing
99 # note: not detached because the collection is currently under iteration
100 else
101 var nvar = v.builder.make_var_assign(self.variable.as(not null), nexpr)
102 replace_with(nvar)
103 end
104 end
105 end
106
107 redef class AIfexprExpr
108 # is replaced with `AIfExpr`
109 # Expression if and statement-if use two distinct classes for historical reasons
110 # However, on can replace the `AIfexprExpr` with the simpler `AIfExpr`
111 redef fun accept_transform_visitor(v)
112 do
113 var nif = v.builder.make_if(n_expr, self.mtype)
114 nif.n_then.add(n_then)
115 nif.n_else.add(n_else)
116
117 replace_with(nif)
118 end
119 end
120
121 redef class AOrExpr
122 # `x or y` is replaced with `if x then x else y`
123 redef fun accept_transform_visitor(v)
124 do
125 var nif = v.builder.make_if(n_expr, self.mtype)
126 nif.n_then.add(n_expr.make_var_read)
127 nif.n_else.add(n_expr2)
128
129 replace_with(nif)
130 end
131 end
132
133 redef class AImpliesExpr
134 redef fun accept_transform_visitor(v)
135 do
136 # TODO
137 end
138 end
139
140 redef class AAndExpr
141 # `x and y` is replaced with `if x then y else x`
142 redef fun accept_transform_visitor(v)
143 do
144 var nif = v.builder.make_if(n_expr, self.mtype)
145 nif.n_then.add(n_expr2)
146 nif.n_else.add(n_expr.make_var_read)
147
148 replace_with(nif)
149 end
150 end
151
152 redef class AWhileExpr
153 redef fun accept_transform_visitor(v)
154 do
155 var nloop = v.builder.make_loop
156 var nif = v.builder.make_if(n_expr, null)
157 nloop.add nif
158
159 var nblock = n_block
160 if nblock != null then nif.n_then.add nblock
161
162 var escapemark = self.break_mark.as(not null)
163 var nbreak = v.builder.make_break(escapemark)
164 nif.n_else.add nbreak
165
166 nloop.break_mark = self.break_mark
167 nloop.continue_mark = self.continue_mark
168
169 replace_with(nloop)
170 end
171 end
172
173 redef class AForExpr
174 redef fun accept_transform_visitor(v)
175 do
176 var escapemark = self.break_mark
177 assert escapemark != null
178
179 var nblock = v.builder.make_block
180
181 var nexpr = n_expr
182
183 nblock.add nexpr
184
185 var iter = v.builder.make_call(nexpr.make_var_read, method_iterator.as(not null), null)
186 nblock.add iter
187
188 var nloop = v.builder.make_loop
189 nloop.break_mark = escapemark
190 nblock.add nloop
191
192 var is_ok = v.builder.make_call(iter.make_var_read, method_is_ok.as(not null), null)
193
194 var nif = v.builder.make_if(is_ok, null)
195 nloop.add nif
196
197 var nthen = nif.n_then
198 var ndo = v.builder.make_do
199 ndo.break_mark = escapemark.continue_mark
200 nthen.add ndo
201
202 if self.variables.length == 1 then
203 var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
204 ndo.add v.builder.make_var_assign(variables.first, item)
205 else if self.variables.length == 2 then
206 var key = v.builder.make_call(iter.make_var_read, method_key.as(not null), null)
207 ndo.add v.builder.make_var_assign(variables[0], key)
208 var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
209 ndo.add v.builder.make_var_assign(variables[1], item)
210 else
211 abort
212 end
213
214 ndo.add self.n_block.as(not null)
215
216 nthen.add v.builder.make_call(iter.make_var_read, method_next.as(not null), null)
217
218 var nbreak = v.builder.make_break(escapemark)
219 nif.n_else.add nbreak
220
221 var method_finish = self.method_finish
222 if method_finish != null then
223 nblock.add v.builder.make_call(iter.make_var_read, method_finish, null)
224 end
225
226 replace_with(nblock)
227 end
228 end
229
230 redef class AArrayExpr
231 # `[x,y]` is replaced with
232 #
233 # var t = new Array[X].with_capacity(2)
234 # t.add(x)
235 # t.add(y)
236 # t
237 redef fun accept_transform_visitor(v)
238 do
239 var nblock = v.builder.make_block
240
241 var nnew = v.builder.make_new(with_capacity_callsite.as(not null), [v.builder.make_int(n_exprs.n_exprs.length)])
242 nblock.add nnew
243
244 for nexpr in self.n_exprs.n_exprs do
245 var nadd = v.builder.make_call(nnew.make_var_read, push_callsite.as(not null), [nexpr])
246 nblock.add nadd
247 end
248 var nres = nnew.make_var_read
249 nblock.add nres
250
251 replace_with(nblock)
252 end
253 end
254
255 redef class ACrangeExpr
256 # `[x..y]` is replaced with `new Range[X](x,y)`
257 redef fun accept_transform_visitor(v)
258 do
259 if parent isa AForExpr then return # to permit shortcut ranges
260 replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
261 end
262 end
263
264 redef class AOrangeExpr
265 # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
266 redef fun accept_transform_visitor(v)
267 do
268 if parent isa AForExpr then return # to permit shortcut ranges
269 replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
270 end
271 end
272
273 redef class AParExpr
274 # `(x)` is replaced with `x`
275 redef fun accept_transform_visitor(v)
276 do
277 replace_with(n_expr)
278 end
279 end
280
281 redef class ASendReassignFormExpr
282 # `x.foo(y)+=z` is replaced with
283 #
284 # x.foo(y) = x.foo(y) + z
285 #
286 # witch is, in reality:
287 #
288 # x."foo="(y, x.foo(y)."+"(z))
289 redef fun accept_transform_visitor(v)
290 do
291 var nblock = v.builder.make_block
292 nblock.add(n_expr)
293
294 var read_args = new Array[AExpr]
295 var write_args = new Array[AExpr]
296 for a in raw_arguments do
297 nblock.add(a)
298 read_args.add(a.make_var_read)
299 write_args.add(a.make_var_read)
300 end
301
302 var nread = v.builder.make_call(n_expr.make_var_read, callsite.as(not null), read_args)
303
304 var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
305
306 write_args.add(nnewvalue)
307 var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.as(not null), write_args)
308 nblock.add(nwrite)
309
310 replace_with(nblock)
311 end
312 end
313
314 redef class AVarReassignExpr
315 # `v += z` is replaced with `v = v + z`
316 redef fun accept_transform_visitor(v)
317 do
318 var variable = self.variable.as(not null)
319
320 var nread = v.builder.make_var_read(variable, read_type.as(not null))
321
322 var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
323 var nwrite = v.builder.make_var_assign(variable, nnewvalue)
324
325 replace_with(nwrite)
326 end
327 end
328
329 redef class AAttrReassignExpr
330 # `x.a += z` is replaced with `x.a = x.a + z`
331 redef fun accept_transform_visitor(v)
332 do
333 var nblock = v.builder.make_block
334 nblock.add(n_expr)
335 var attribute = self.mproperty.as(not null)
336
337 var nread = v.builder.make_attr_read(n_expr.make_var_read, attribute)
338 var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
339 var nwrite = v.builder.make_attr_assign(n_expr.make_var_read, attribute, nnewvalue)
340 nblock.add(nwrite)
341
342 replace_with(nblock)
343 end
344 end