1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 # Thansformations that simplify the AST of expressions
16 # This module transform complex AST `AExpr` nodes into simplier ones
20 import auto_super_init
23 redef class ToolContext
24 var transform_phase
: Phase = new TransformPhase(self, [typing_phase
, auto_super_init_phase
])
27 private class TransformPhase
30 redef fun process_npropdef
(npropdef
: APropdef)
34 var v
= new TransformVisitor(self, npropdef
)
35 v
.enter_visit
(npropdef
)
37 val
= new ASTValidationVisitor
38 val
.enter_visit
(npropdef
)
42 private class TransformVisitor
45 var phase
: TransformPhase
47 var mclassdef
: MClassDef
48 var mpropdef
: MPropDef
49 var builder
: ASTBuilder
51 init(phase
: TransformPhase, npropdef
: APropdef)
54 self.mpropdef
= npropdef
.mpropdef
.as(not null)
55 self.mclassdef
= mpropdef
.mclassdef
56 self.mmodule
= mclassdef
.mmodule
57 self.builder
= new ASTBuilder(mmodule
, mpropdef
.mclassdef
.bound_mtype
)
62 if node
isa AAnnotations then return
64 node
.accept_transform_visitor
(self)
67 # Get a primitive class or display a fatal error on `location`.
68 fun get_class
(location
: AExpr, name
: String): MClass
70 return mmodule
.get_primitive_class
(name
)
73 # Get a primitive method or display a fatal error on `location`.
74 fun get_method
(location
: AExpr, name
: String, recv
: MClass): MMethod
76 return phase
.toolcontext
.modelbuilder
.force_get_primitive_method
(location
, name
, recv
, mmodule
)
81 private fun accept_transform_visitor
(v
: TransformVisitor)
86 redef class AVardeclExpr
87 # `var x = y` is replaced with `x = y`
89 # Declarations are only useful for scope rules
90 # Once names are associated with real objects, ther declaration become useless
91 # Therefore, if there is no initial value, then just detach it
92 # Else, replace it with a simple assignment
93 redef fun accept_transform_visitor
(v
)
99 var nvar
= v
.builder
.make_var_assign
(self.variable
.as(not null), nexpr
)
105 redef class AIfexprExpr
106 # is replaced with `AIfExpr`
107 # Expression if and statement-if use two distinct classes for historical reasons
108 # However, on can replace the `AIfexprExpr` with the simpler `AIfExpr`
109 redef fun accept_transform_visitor
(v
)
111 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
112 nif
.n_then
.add
(n_then
)
113 nif
.n_else
.add
(n_else
)
120 # `x or y` is replaced with `if x then x else y`
121 redef fun accept_transform_visitor
(v
)
123 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
124 nif
.n_then
.add
(n_expr
.make_var_read
)
125 nif
.n_else
.add
(n_expr2
)
131 redef class AImpliesExpr
132 redef fun accept_transform_visitor
(v
)
139 # `x and y` is replaced with `if x then y else x`
140 redef fun accept_transform_visitor
(v
)
142 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
143 nif
.n_then
.add
(n_expr2
)
144 nif
.n_else
.add
(n_expr
.make_var_read
)
150 redef class AWhileExpr
151 redef fun accept_transform_visitor
(v
)
158 redef fun accept_transform_visitor
(v
)
164 redef class AArrayExpr
165 # `[x,y]` is replaced with
167 # var t = new Array[X].with_capacity(2)
171 redef fun accept_transform_visitor
(v
)
173 var mtype
= self.mtype
.as(MClassType)
174 var nblock
= v
.builder
.make_block
176 var meth
= v
.get_method
(self, "with_capacity", mtype
.mclass
)
177 var nnew
= v
.builder
.make_new
(mtype
, meth
, [v
.builder
.make_int
(n_exprs
.n_exprs
.length
)])
180 var madd
= v
.get_method
(self, "push", mtype
.mclass
)
181 for nexpr
in self.n_exprs
.n_exprs
do
182 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, madd
, [nexpr
])
185 var nres
= nnew
.make_var_read
192 redef class ASuperstringExpr
193 # `"x{y}z"` is replaced with
195 # var t = new Array[Object].with_capacity(3)
200 redef fun accept_transform_visitor
(v
)
202 var nblock
= v
.builder
.make_block
204 var arraytype
= v
.get_class
(self, "Array").get_mtype
([v
.get_class
(self, "Object").mclass_type
])
205 var meth
= v
.get_method
(self, "with_capacity", arraytype
.mclass
)
206 var nnew
= v
.builder
.make_new
(arraytype
, meth
, [v
.builder
.make_int
(n_exprs
.length
)])
209 var madd
= v
.get_method
(self, "add", arraytype
.mclass
)
210 for nexpr
in self.n_exprs
do
211 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, madd
, [nexpr
])
215 var mtos
= v
.get_method
(self, "to_s", arraytype
.mclass
)
216 var ntos
= v
.builder
.make_call
(nnew
.make_var_read
, mtos
, null)
223 redef class ACrangeExpr
224 # `[x..y]` is replaced with `new Range[X](x,y)`
225 redef fun accept_transform_visitor
(v
)
227 var mtype
= self.mtype
.as(MClassType)
228 var meth
= v
.get_method
(self, "init", mtype
.mclass
)
230 replace_with
(v
.builder
.make_new
(mtype
, meth
, [n_expr
, n_expr2
]))
234 redef class AOrangeExpr
235 # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
236 redef fun accept_transform_visitor
(v
)
238 var mtype
= self.mtype
.as(MClassType)
239 var meth
= v
.get_method
(self, "without_last", mtype
.mclass
)
241 replace_with
(v
.builder
.make_new
(mtype
, meth
, [n_expr
, n_expr2
]))
246 # `(x)` is replaced with `x`
247 redef fun accept_transform_visitor
(v
)
253 redef class ASendReassignFormExpr
254 # `x.foo(y)+=z` is replaced with
256 # x.foo(y) = x.foo(y) + z
258 # witch is, in reality:
260 # x."foo="(y, x.foo(y)."+"(z))
261 redef fun accept_transform_visitor
(v
)
263 var nblock
= v
.builder
.make_block
266 var read_args
= new Array[AExpr]
267 var write_args
= new Array[AExpr]
268 for a
in raw_arguments
.as(not null) do
270 read_args
.add
(a
.make_var_read
)
271 write_args
.add
(a
.make_var_read
)
274 var nread
= v
.builder
.make_call
(n_expr
.make_var_read
, callsite
.mproperty
, read_args
)
276 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
278 write_args
.add
(nnewvalue
)
279 var nwrite
= v
.builder
.make_call
(n_expr
.make_var_read
, write_callsite
.mproperty
, write_args
)
286 redef class AVarReassignExpr
287 # `v += z` is replaced with `v = v + z`
288 redef fun accept_transform_visitor
(v
)
290 var variable
= self.variable
.as(not null)
292 var nread
= v
.builder
.make_var_read
(variable
)
293 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
294 var nwrite
= v
.builder
.make_var_assign
(variable
, nnewvalue
)
300 redef class AAttrReassignExpr
301 # `x.a += z` is replaced with `x.a = x.a + z`
302 redef fun accept_transform_visitor
(v
)
304 var nblock
= v
.builder
.make_block
306 var attribute
= self.mproperty
.as(not null)
308 var nread
= v
.builder
.make_attr_read
(n_expr
.make_var_read
, attribute
)
309 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
310 var nwrite
= v
.builder
.make_attr_assign
(n_expr
.make_var_read
, attribute
, nnewvalue
)