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 ignore it
92 # Else, replace it with a simple assignment
93 redef fun accept_transform_visitor
(v
)
98 # note: not detached because the collection is currently under iteration
100 var nvar
= v
.builder
.make_var_assign
(self.variable
.as(not null), nexpr
)
106 redef class AIfexprExpr
107 # is replaced with `AIfExpr`
108 # Expression if and statement-if use two distinct classes for historical reasons
109 # However, on can replace the `AIfexprExpr` with the simpler `AIfExpr`
110 redef fun accept_transform_visitor
(v
)
112 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
113 nif
.n_then
.add
(n_then
)
114 nif
.n_else
.add
(n_else
)
121 # `x or y` is replaced with `if x then x else y`
122 redef fun accept_transform_visitor
(v
)
124 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
125 nif
.n_then
.add
(n_expr
.make_var_read
)
126 nif
.n_else
.add
(n_expr2
)
132 redef class AImpliesExpr
133 redef fun accept_transform_visitor
(v
)
140 # `x and y` is replaced with `if x then y else x`
141 redef fun accept_transform_visitor
(v
)
143 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
144 nif
.n_then
.add
(n_expr2
)
145 nif
.n_else
.add
(n_expr
.make_var_read
)
151 redef class AWhileExpr
152 redef fun accept_transform_visitor
(v
)
159 redef fun accept_transform_visitor
(v
)
165 redef class AArrayExpr
166 # `[x,y]` is replaced with
168 # var t = new Array[X].with_capacity(2)
172 redef fun accept_transform_visitor
(v
)
174 var mtype
= self.mtype
.as(MClassType)
175 var nblock
= v
.builder
.make_block
177 var meth
= v
.get_method
(self, "with_capacity", mtype
.mclass
)
178 var nnew
= v
.builder
.make_new
(mtype
, meth
, [v
.builder
.make_int
(n_exprs
.n_exprs
.length
)])
181 var madd
= v
.get_method
(self, "push", mtype
.mclass
)
182 for nexpr
in self.n_exprs
.n_exprs
do
183 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, madd
, [nexpr
])
186 var nres
= nnew
.make_var_read
193 redef class ASuperstringExpr
194 # `"x{y}z"` is replaced with
196 # var t = new Array[Object].with_capacity(3)
201 redef fun accept_transform_visitor
(v
)
203 var nblock
= v
.builder
.make_block
205 var arraytype
= v
.get_class
(self, "Array").get_mtype
([v
.get_class
(self, "Object").mclass_type
])
206 var meth
= v
.get_method
(self, "with_capacity", arraytype
.mclass
)
207 var nnew
= v
.builder
.make_new
(arraytype
, meth
, [v
.builder
.make_int
(n_exprs
.length
)])
210 var madd
= v
.get_method
(self, "add", arraytype
.mclass
)
211 for nexpr
in self.n_exprs
do
212 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, madd
, [nexpr
])
216 var mtos
= v
.get_method
(self, "to_s", arraytype
.mclass
)
217 var ntos
= v
.builder
.make_call
(nnew
.make_var_read
, mtos
, null)
224 redef class ACrangeExpr
225 # `[x..y]` is replaced with `new Range[X](x,y)`
226 redef fun accept_transform_visitor
(v
)
228 var mtype
= self.mtype
.as(MClassType)
229 replace_with
(v
.builder
.make_new
(mtype
, init_callsite
.mproperty
, [n_expr
, n_expr2
]))
233 redef class AOrangeExpr
234 # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
235 redef fun accept_transform_visitor
(v
)
237 var mtype
= self.mtype
.as(MClassType)
238 replace_with
(v
.builder
.make_new
(mtype
, init_callsite
.mproperty
, [n_expr
, n_expr2
]))
243 # `(x)` is replaced with `x`
244 redef fun accept_transform_visitor
(v
)
250 redef class ASendReassignFormExpr
251 # `x.foo(y)+=z` is replaced with
253 # x.foo(y) = x.foo(y) + z
255 # witch is, in reality:
257 # x."foo="(y, x.foo(y)."+"(z))
258 redef fun accept_transform_visitor
(v
)
260 var nblock
= v
.builder
.make_block
263 var read_args
= new Array[AExpr]
264 var write_args
= new Array[AExpr]
265 for a
in raw_arguments
.as(not null) do
267 read_args
.add
(a
.make_var_read
)
268 write_args
.add
(a
.make_var_read
)
271 var nread
= v
.builder
.make_call
(n_expr
.make_var_read
, callsite
.mproperty
, read_args
)
273 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
275 write_args
.add
(nnewvalue
)
276 var nwrite
= v
.builder
.make_call
(n_expr
.make_var_read
, write_callsite
.mproperty
, write_args
)
283 redef class AVarReassignExpr
284 # `v += z` is replaced with `v = v + z`
285 redef fun accept_transform_visitor
(v
)
287 var variable
= self.variable
.as(not null)
289 var nread
= v
.builder
.make_var_read
(variable
, read_type
.as(not null))
291 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
292 var nwrite
= v
.builder
.make_var_assign
(variable
, nnewvalue
)
298 redef class AAttrReassignExpr
299 # `x.a += z` is replaced with `x.a = x.a + z`
300 redef fun accept_transform_visitor
(v
)
302 var nblock
= v
.builder
.make_block
304 var attribute
= self.mproperty
.as(not null)
306 var nread
= v
.builder
.make_attr_read
(n_expr
.make_var_read
, attribute
)
307 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.mproperty
, [n_value
])
308 var nwrite
= v
.builder
.make_attr_assign
(n_expr
.make_var_read
, attribute
, nnewvalue
)