src: update most tools to new constructors
[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
27 # --no-shortcut-range
28 var opt_no_shortcut_range: OptionBool = new OptionBool("Always insantiate a range and its iterator on 'for' loops", "--no-shortcut-range")
29
30 redef init
31 do
32 super
33 self.option_context.add_option(self.opt_no_shortcut_range)
34 end
35 end
36
37 private class TransformPhase
38 super Phase
39
40 redef fun process_npropdef(npropdef: APropdef)
41 do
42 var val
43
44 var v = new TransformVisitor(self, npropdef.mpropdef.as(not null))
45 v.enter_visit(npropdef)
46
47 val = new ASTValidationVisitor
48 val.enter_visit(npropdef)
49 end
50 end
51
52 private class TransformVisitor
53 super Visitor
54
55 var phase: TransformPhase
56 var mmodule: MModule is noinit
57 var mclassdef: MClassDef is noinit
58 var mpropdef: MPropDef
59 var builder: ASTBuilder is noinit
60
61 init
62 do
63 self.mclassdef = mpropdef.mclassdef
64 self.mmodule = mclassdef.mmodule
65 self.builder = new ASTBuilder(mmodule, mpropdef.mclassdef.bound_mtype)
66 end
67
68 redef fun visit(node)
69 do
70 if node isa AAnnotations then return
71 node.visit_all(self)
72 node.accept_transform_visitor(self)
73 end
74
75 # Get a primitive class or display a fatal error on `location`.
76 fun get_class(location: AExpr, name: String): MClass
77 do
78 return mmodule.get_primitive_class(name)
79 end
80
81 # Get a primitive method or display a fatal error on `location`.
82 fun get_method(location: AExpr, name: String, recv: MClass): MMethod
83 do
84 return phase.toolcontext.modelbuilder.force_get_primitive_method(location, name, recv, mmodule)
85 end
86 end
87
88 redef class ANode
89 private fun accept_transform_visitor(v: TransformVisitor)
90 do
91 end
92 end
93
94 redef class AVardeclExpr
95 # `var x = y` is replaced with `x = y`
96 #
97 # Declarations are only useful for scope rules
98 # Once names are associated with real objects, ther declaration become useless
99 # Therefore, if there is no initial value, then just ignore it
100 # Else, replace it with a simple assignment
101 redef fun accept_transform_visitor(v)
102 do
103 var nexpr = n_expr
104 if nexpr == null then
105 # do nothing
106 # note: not detached because the collection is currently under iteration
107 else
108 var nvar = v.builder.make_var_assign(self.variable.as(not null), nexpr)
109 replace_with(nvar)
110 end
111 end
112 end
113
114 redef class AIfexprExpr
115 # is replaced with `AIfExpr`
116 # Expression if and statement-if use two distinct classes for historical reasons
117 # However, on can replace the `AIfexprExpr` with the simpler `AIfExpr`
118 redef fun accept_transform_visitor(v)
119 do
120 var nif = v.builder.make_if(n_expr, self.mtype)
121 nif.n_then.add(n_then)
122 nif.n_else.add(n_else)
123
124 replace_with(nif)
125 end
126 end
127
128 redef class AOrExpr
129 # `x or y` is replaced with `if x then x else y`
130 redef fun accept_transform_visitor(v)
131 do
132 var nif = v.builder.make_if(n_expr, self.mtype)
133 nif.n_then.add(n_expr.make_var_read)
134 nif.n_else.add(n_expr2)
135
136 replace_with(nif)
137 end
138 end
139
140 redef class AImpliesExpr
141 redef fun accept_transform_visitor(v)
142 do
143 # TODO
144 end
145 end
146
147 redef class AAndExpr
148 # `x and y` is replaced with `if x then y else x`
149 redef fun accept_transform_visitor(v)
150 do
151 var nif = v.builder.make_if(n_expr, self.mtype)
152 nif.n_then.add(n_expr2)
153 nif.n_else.add(n_expr.make_var_read)
154
155 replace_with(nif)
156 end
157 end
158
159 redef class AWhileExpr
160 redef fun accept_transform_visitor(v)
161 do
162 var nloop = v.builder.make_loop
163 var nif = v.builder.make_if(n_expr, null)
164 nloop.add nif
165
166 var nblock = n_block
167 if nblock != null then nif.n_then.add nblock
168
169 var escapemark = self.break_mark.as(not null)
170 var nbreak = v.builder.make_break(escapemark)
171 nif.n_else.add nbreak
172
173 nloop.break_mark = self.break_mark
174 nloop.continue_mark = self.continue_mark
175
176 replace_with(nloop)
177 end
178 end
179
180 redef class AForExpr
181 redef fun accept_transform_visitor(v)
182 do
183 var escapemark = self.break_mark
184 assert escapemark != null
185
186 var nblock = v.builder.make_block
187
188 var nexpr = n_expr
189
190 # Shortcut on explicit range
191 # Avoid the instantiation of the range and the iterator
192 if self.variables.length == 1 and nexpr isa ARangeExpr and not v.phase.toolcontext.opt_no_shortcut_range.value then
193 var variable = variables.first
194 nblock.add v.builder.make_var_assign(variable, nexpr.n_expr)
195 var to = nexpr.n_expr2
196 nblock.add to
197
198 var nloop = v.builder.make_loop
199 nloop.break_mark = escapemark
200 nblock.add nloop
201
202 var is_ok = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_lt.as(not null), [to.make_var_read])
203
204 var nif = v.builder.make_if(is_ok, null)
205 nloop.add nif
206
207 var nthen = nif.n_then
208 var ndo = v.builder.make_do
209 ndo.break_mark = escapemark.continue_mark
210 nthen.add ndo
211
212 ndo.add self.n_block.as(not null)
213
214 var one = v.builder.make_int(1)
215 var succ = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_successor.as(not null), [one])
216 nthen.add v.builder.make_var_assign(variable, succ)
217
218 var nbreak = v.builder.make_break(escapemark)
219 nif.n_else.add nbreak
220
221 replace_with(nblock)
222 return
223 end
224
225 nblock.add nexpr
226
227 var iter = v.builder.make_call(nexpr.make_var_read, method_iterator.as(not null), null)
228 nblock.add iter
229
230 var nloop = v.builder.make_loop
231 nloop.break_mark = escapemark
232 nblock.add nloop
233
234 var is_ok = v.builder.make_call(iter.make_var_read, method_is_ok.as(not null), null)
235
236 var nif = v.builder.make_if(is_ok, null)
237 nloop.add nif
238
239 var nthen = nif.n_then
240 var ndo = v.builder.make_do
241 ndo.break_mark = escapemark.continue_mark
242 nthen.add ndo
243
244 if self.variables.length == 1 then
245 var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
246 ndo.add v.builder.make_var_assign(variables.first, item)
247 else if self.variables.length == 2 then
248 var key = v.builder.make_call(iter.make_var_read, method_key.as(not null), null)
249 ndo.add v.builder.make_var_assign(variables[0], key)
250 var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
251 ndo.add v.builder.make_var_assign(variables[1], item)
252 else
253 abort
254 end
255
256 ndo.add self.n_block.as(not null)
257
258 nthen.add v.builder.make_call(iter.make_var_read, method_next.as(not null), null)
259
260 var nbreak = v.builder.make_break(escapemark)
261 nif.n_else.add nbreak
262
263 var method_finish = self.method_finish
264 if method_finish != null then
265 nblock.add v.builder.make_call(iter.make_var_read, method_finish, null)
266 end
267
268 replace_with(nblock)
269 end
270 end
271
272 redef class AArrayExpr
273 # `[x,y]` is replaced with
274 #
275 # var t = new Array[X].with_capacity(2)
276 # t.add(x)
277 # t.add(y)
278 # t
279 redef fun accept_transform_visitor(v)
280 do
281 var nblock = v.builder.make_block
282
283 var nnew = v.builder.make_new(with_capacity_callsite.as(not null), [v.builder.make_int(n_exprs.n_exprs.length)])
284 nblock.add nnew
285
286 for nexpr in self.n_exprs.n_exprs do
287 var nadd = v.builder.make_call(nnew.make_var_read, push_callsite.as(not null), [nexpr])
288 nblock.add nadd
289 end
290 var nres = nnew.make_var_read
291 nblock.add nres
292
293 replace_with(nblock)
294 end
295 end
296
297 redef class ACrangeExpr
298 # `[x..y]` is replaced with `new Range[X](x,y)`
299 redef fun accept_transform_visitor(v)
300 do
301 if parent isa AForExpr then return # to permit shortcut ranges
302 replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
303 end
304 end
305
306 redef class AOrangeExpr
307 # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
308 redef fun accept_transform_visitor(v)
309 do
310 if parent isa AForExpr then return # to permit shortcut ranges
311 replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
312 end
313 end
314
315 redef class AParExpr
316 # `(x)` is replaced with `x`
317 redef fun accept_transform_visitor(v)
318 do
319 replace_with(n_expr)
320 end
321 end
322
323 redef class ASendReassignFormExpr
324 # `x.foo(y)+=z` is replaced with
325 #
326 # x.foo(y) = x.foo(y) + z
327 #
328 # witch is, in reality:
329 #
330 # x."foo="(y, x.foo(y)."+"(z))
331 redef fun accept_transform_visitor(v)
332 do
333 var nblock = v.builder.make_block
334 nblock.add(n_expr)
335
336 var read_args = new Array[AExpr]
337 var write_args = new Array[AExpr]
338 for a in raw_arguments do
339 nblock.add(a)
340 read_args.add(a.make_var_read)
341 write_args.add(a.make_var_read)
342 end
343
344 var nread = v.builder.make_call(n_expr.make_var_read, callsite.as(not null), read_args)
345
346 var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
347
348 write_args.add(nnewvalue)
349 var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.as(not null), write_args)
350 nblock.add(nwrite)
351
352 replace_with(nblock)
353 end
354 end
355
356 redef class AVarReassignExpr
357 # `v += z` is replaced with `v = v + z`
358 redef fun accept_transform_visitor(v)
359 do
360 var variable = self.variable.as(not null)
361
362 var nread = v.builder.make_var_read(variable, read_type.as(not null))
363
364 var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
365 var nwrite = v.builder.make_var_assign(variable, nnewvalue)
366
367 replace_with(nwrite)
368 end
369 end
370
371 redef class AAttrReassignExpr
372 # `x.a += z` is replaced with `x.a = x.a + z`
373 redef fun accept_transform_visitor(v)
374 do
375 var nblock = v.builder.make_block
376 nblock.add(n_expr)
377 var attribute = self.mproperty.as(not null)
378
379 var nread = v.builder.make_attr_read(n_expr.make_var_read, attribute)
380 var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
381 var nwrite = v.builder.make_attr_assign(n_expr.make_var_read, attribute, nnewvalue)
382 nblock.add(nwrite)
383
384 replace_with(nblock)
385 end
386 end