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
)
132 # `x and y` is replaced with `if x then y else x`
133 redef fun accept_transform_visitor
(v
)
135 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
136 nif
.n_then
.add
(n_expr2
)
137 nif
.n_else
.add
(n_expr
.make_var_read
)
143 redef class AWhileExpr
144 redef fun accept_transform_visitor
(v
)
151 redef fun accept_transform_visitor
(v
)
157 redef class AArrayExpr
158 # `[x,y]` is replaced with
160 # var t = new Array[X].with_capacity(2)
164 redef fun accept_transform_visitor
(v
)
166 var mtype
= self.mtype
.as(MClassType)
167 var nblock
= v
.builder
.make_block
169 var meth
= v
.get_method
(self, "with_capacity", mtype
.mclass
)
170 var nnew
= v
.builder
.make_new
(mtype
, meth
, [v
.builder
.make_int
(n_exprs
.n_exprs
.length
)])
173 var madd
= v
.get_method
(self, "push", mtype
.mclass
)
174 for nexpr
in self.n_exprs
.n_exprs
do
175 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, madd
, [nexpr
])
178 var nres
= nnew
.make_var_read
185 redef class ASuperstringExpr
186 # `"x{y}z"` is replaced with
188 # var t = new Array[Object].with_capacity(3)
193 redef fun accept_transform_visitor
(v
)
195 var nblock
= v
.builder
.make_block
197 var arraytype
= v
.get_class
(self, "Array").get_mtype
([v
.get_class
(self, "Object").mclass_type
])
198 var meth
= v
.get_method
(self, "with_capacity", arraytype
.mclass
)
199 var nnew
= v
.builder
.make_new
(arraytype
, meth
, [v
.builder
.make_int
(n_exprs
.length
)])
202 var madd
= v
.get_method
(self, "add", arraytype
.mclass
)
203 for nexpr
in self.n_exprs
do
204 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, madd
, [nexpr
])
208 var mtos
= v
.get_method
(self, "to_s", arraytype
.mclass
)
209 var ntos
= v
.builder
.make_call
(nnew
.make_var_read
, mtos
, null)
216 redef class ACrangeExpr
217 # `[x..y]` is replaced with `new Range[X](x,y)`
218 redef fun accept_transform_visitor
(v
)
220 var mtype
= self.mtype
.as(MClassType)
221 var meth
= v
.get_method
(self, "init", mtype
.mclass
)
223 replace_with
(v
.builder
.make_new
(mtype
, meth
, [n_expr
, n_expr2
]))
227 redef class AOrangeExpr
228 # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
229 redef fun accept_transform_visitor
(v
)
231 var mtype
= self.mtype
.as(MClassType)
232 var meth
= v
.get_method
(self, "without_last", mtype
.mclass
)
234 replace_with
(v
.builder
.make_new
(mtype
, meth
, [n_expr
, n_expr2
]))
239 # `(x)` is replaced with `x`
240 redef fun accept_transform_visitor
(v
)
246 redef class ASendReassignFormExpr
247 # `x.foo(y)+=z` is replaced with
249 # x.foo(y) = x.foo(y) + z
251 # witch is, in reality:
253 # x."foo="(y, x.foo(y)."+"(z))
254 redef fun accept_transform_visitor
(v
)
256 var nblock
= v
.builder
.make_block
259 var read_args
= new Array[AExpr]
260 var write_args
= new Array[AExpr]
261 for a
in raw_arguments
.as(not null) do
263 read_args
.add
(a
.make_var_read
)
264 write_args
.add
(a
.make_var_read
)
267 var nread
= v
.builder
.make_call
(n_expr
.make_var_read
, callsite
.mproperty
, read_args
)
269 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
271 write_args
.add
(nnewvalue
)
272 var nwrite
= v
.builder
.make_call
(n_expr
.make_var_read
, write_callsite
.mproperty
, write_args
)
279 redef class AVarReassignExpr
280 # `v += z` is replaced with `v = v + z`
281 redef fun accept_transform_visitor
(v
)
283 var variable
= self.variable
.as(not null)
285 var nread
= v
.builder
.make_var_read
(variable
)
286 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
287 var nwrite
= v
.builder
.make_var_assign
(variable
, nnewvalue
)
293 redef class AAttrReassignExpr
294 # `x.a += z` is replaced with `x.a = x.a + z`
295 redef fun accept_transform_visitor
(v
)
297 var nblock
= v
.builder
.make_block
299 var attribute
= self.mproperty
.as(not null)
301 var nread
= v
.builder
.make_attr_read
(n_expr
.make_var_read
, attribute
)
302 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
303 var nwrite
= v
.builder
.make_attr_assign
(n_expr
.make_var_read
, attribute
, nnewvalue
)