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 nblock
= v
.builder
.make_block
176 var nnew
= v
.builder
.make_new
(with_capacity_callsite
.as(not null), [v
.builder
.make_int
(n_exprs
.n_exprs
.length
)])
179 for nexpr
in self.n_exprs
.n_exprs
do
180 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, push_callsite
.as(not null), [nexpr
])
183 var nres
= nnew
.make_var_read
190 redef class ACrangeExpr
191 # `[x..y]` is replaced with `new Range[X](x,y)`
192 redef fun accept_transform_visitor
(v
)
194 replace_with
(v
.builder
.make_new
(init_callsite
.as(not null), [n_expr
, n_expr2
]))
198 redef class AOrangeExpr
199 # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
200 redef fun accept_transform_visitor
(v
)
202 replace_with
(v
.builder
.make_new
(init_callsite
.as(not null), [n_expr
, n_expr2
]))
207 # `(x)` is replaced with `x`
208 redef fun accept_transform_visitor
(v
)
214 redef class ASendReassignFormExpr
215 # `x.foo(y)+=z` is replaced with
217 # x.foo(y) = x.foo(y) + z
219 # witch is, in reality:
221 # x."foo="(y, x.foo(y)."+"(z))
222 redef fun accept_transform_visitor
(v
)
224 var nblock
= v
.builder
.make_block
227 var read_args
= new Array[AExpr]
228 var write_args
= new Array[AExpr]
229 for a
in raw_arguments
do
231 read_args
.add
(a
.make_var_read
)
232 write_args
.add
(a
.make_var_read
)
235 var nread
= v
.builder
.make_call
(n_expr
.make_var_read
, callsite
.as(not null), read_args
)
237 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.as(not null), [n_value
])
239 write_args
.add
(nnewvalue
)
240 var nwrite
= v
.builder
.make_call
(n_expr
.make_var_read
, write_callsite
.as(not null), write_args
)
247 redef class AVarReassignExpr
248 # `v += z` is replaced with `v = v + z`
249 redef fun accept_transform_visitor
(v
)
251 var variable
= self.variable
.as(not null)
253 var nread
= v
.builder
.make_var_read
(variable
, read_type
.as(not null))
255 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.as(not null), [n_value
])
256 var nwrite
= v
.builder
.make_var_assign
(variable
, nnewvalue
)
262 redef class AAttrReassignExpr
263 # `x.a += z` is replaced with `x.a = x.a + z`
264 redef fun accept_transform_visitor
(v
)
266 var nblock
= v
.builder
.make_block
268 var attribute
= self.mproperty
.as(not null)
270 var nread
= v
.builder
.make_attr_read
(n_expr
.make_var_read
, attribute
)
271 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.as(not null), [n_value
])
272 var nwrite
= v
.builder
.make_attr_assign
(n_expr
.make_var_read
, attribute
, nnewvalue
)