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
22 intrude import semantize
::scope
24 redef class ToolContext
25 var transform_phase
: Phase = new TransformPhase(self, [typing_phase
, auto_super_init_phase
])
28 private class TransformPhase
31 redef fun process_npropdef
(npropdef
: APropdef)
35 var v
= new TransformVisitor(self, npropdef
)
36 v
.enter_visit
(npropdef
)
38 val
= new ASTValidationVisitor
39 val
.enter_visit
(npropdef
)
43 private class TransformVisitor
46 var phase
: TransformPhase
48 var mclassdef
: MClassDef
49 var mpropdef
: MPropDef
50 var builder
: ASTBuilder
52 init(phase
: TransformPhase, npropdef
: APropdef)
55 self.mpropdef
= npropdef
.mpropdef
.as(not null)
56 self.mclassdef
= mpropdef
.mclassdef
57 self.mmodule
= mclassdef
.mmodule
58 self.builder
= new ASTBuilder(mmodule
, mpropdef
.mclassdef
.bound_mtype
)
63 if node
isa AAnnotations then return
65 node
.accept_transform_visitor
(self)
68 # Get a primitive class or display a fatal error on `location`.
69 fun get_class
(location
: AExpr, name
: String): MClass
71 return mmodule
.get_primitive_class
(name
)
74 # Get a primitive method or display a fatal error on `location`.
75 fun get_method
(location
: AExpr, name
: String, recv
: MClass): MMethod
77 return phase
.toolcontext
.modelbuilder
.force_get_primitive_method
(location
, name
, recv
, mmodule
)
82 private fun accept_transform_visitor
(v
: TransformVisitor)
87 redef class AVardeclExpr
88 # `var x = y` is replaced with `x = y`
90 # Declarations are only useful for scope rules
91 # Once names are associated with real objects, ther declaration become useless
92 # Therefore, if there is no initial value, then just ignore it
93 # Else, replace it with a simple assignment
94 redef fun accept_transform_visitor
(v
)
99 # note: not detached because the collection is currently under iteration
101 var nvar
= v
.builder
.make_var_assign
(self.variable
.as(not null), nexpr
)
107 redef class AIfexprExpr
108 # is replaced with `AIfExpr`
109 # Expression if and statement-if use two distinct classes for historical reasons
110 # However, on can replace the `AIfexprExpr` with the simpler `AIfExpr`
111 redef fun accept_transform_visitor
(v
)
113 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
114 nif
.n_then
.add
(n_then
)
115 nif
.n_else
.add
(n_else
)
122 # `x or y` is replaced with `if x then x else y`
123 redef fun accept_transform_visitor
(v
)
125 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
126 nif
.n_then
.add
(n_expr
.make_var_read
)
127 nif
.n_else
.add
(n_expr2
)
133 redef class AImpliesExpr
134 redef fun accept_transform_visitor
(v
)
141 # `x and y` is replaced with `if x then y else x`
142 redef fun accept_transform_visitor
(v
)
144 var nif
= v
.builder
.make_if
(n_expr
, self.mtype
)
145 nif
.n_then
.add
(n_expr2
)
146 nif
.n_else
.add
(n_expr
.make_var_read
)
152 redef class AWhileExpr
153 redef fun accept_transform_visitor
(v
)
155 var nloop
= v
.builder
.make_loop
156 var nif
= v
.builder
.make_if
(n_expr
, null)
160 if nblock
!= null then nif
.n_then
.add nblock
162 var escapemark
= self.break_mark
.as(not null)
163 var nbreak
= v
.builder
.make_break
(escapemark
)
164 nif
.n_else
.add nbreak
166 nloop
.break_mark
= self.break_mark
167 nloop
.continue_mark
= self.continue_mark
174 redef fun accept_transform_visitor
(v
)
176 var escapemark
= self.break_mark
177 assert escapemark
!= null
179 var nblock
= v
.builder
.make_block
185 var iter
= v
.builder
.make_call
(nexpr
.make_var_read
, method_iterator
.as(not null), null)
188 var nloop
= v
.builder
.make_loop
189 nloop
.break_mark
= escapemark
192 var is_ok
= v
.builder
.make_call
(iter
.make_var_read
, method_is_ok
.as(not null), null)
194 var nif
= v
.builder
.make_if
(is_ok
, null)
197 var nthen
= nif
.n_then
198 var ndo
= v
.builder
.make_do
199 ndo
.break_mark
= escapemark
.continue_mark
202 if self.variables
.length
== 1 then
203 var item
= v
.builder
.make_call
(iter
.make_var_read
, method_item
.as(not null), null)
204 ndo
.add v
.builder
.make_var_assign
(variables
.first
, item
)
205 else if self.variables
.length
== 2 then
206 var key
= v
.builder
.make_call
(iter
.make_var_read
, method_key
.as(not null), null)
207 ndo
.add v
.builder
.make_var_assign
(variables
[0], key
)
208 var item
= v
.builder
.make_call
(iter
.make_var_read
, method_item
.as(not null), null)
209 ndo
.add v
.builder
.make_var_assign
(variables
[1], item
)
214 ndo
.add
self.n_block
.as(not null)
216 nthen
.add v
.builder
.make_call
(iter
.make_var_read
, method_next
.as(not null), null)
218 var nbreak
= v
.builder
.make_break
(escapemark
)
219 nif
.n_else
.add nbreak
221 var method_finish
= self.method_finish
222 if method_finish
!= null then
223 nblock
.add v
.builder
.make_call
(iter
.make_var_read
, method_finish
, null)
230 redef class AArrayExpr
231 # `[x,y]` is replaced with
233 # var t = new Array[X].with_capacity(2)
237 redef fun accept_transform_visitor
(v
)
239 var nblock
= v
.builder
.make_block
241 var nnew
= v
.builder
.make_new
(with_capacity_callsite
.as(not null), [v
.builder
.make_int
(n_exprs
.n_exprs
.length
)])
244 for nexpr
in self.n_exprs
.n_exprs
do
245 var nadd
= v
.builder
.make_call
(nnew
.make_var_read
, push_callsite
.as(not null), [nexpr
])
248 var nres
= nnew
.make_var_read
255 redef class ACrangeExpr
256 # `[x..y]` is replaced with `new Range[X](x,y)`
257 redef fun accept_transform_visitor
(v
)
259 if parent
isa AForExpr then return # to permit shortcut ranges
260 replace_with
(v
.builder
.make_new
(init_callsite
.as(not null), [n_expr
, n_expr2
]))
264 redef class AOrangeExpr
265 # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
266 redef fun accept_transform_visitor
(v
)
268 if parent
isa AForExpr then return # to permit shortcut ranges
269 replace_with
(v
.builder
.make_new
(init_callsite
.as(not null), [n_expr
, n_expr2
]))
274 # `(x)` is replaced with `x`
275 redef fun accept_transform_visitor
(v
)
281 redef class ASendReassignFormExpr
282 # `x.foo(y)+=z` is replaced with
284 # x.foo(y) = x.foo(y) + z
286 # witch is, in reality:
288 # x."foo="(y, x.foo(y)."+"(z))
289 redef fun accept_transform_visitor
(v
)
291 var nblock
= v
.builder
.make_block
294 var read_args
= new Array[AExpr]
295 var write_args
= new Array[AExpr]
296 for a
in raw_arguments
do
298 read_args
.add
(a
.make_var_read
)
299 write_args
.add
(a
.make_var_read
)
302 var nread
= v
.builder
.make_call
(n_expr
.make_var_read
, callsite
.as(not null), read_args
)
304 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.as(not null), [n_value
])
306 write_args
.add
(nnewvalue
)
307 var nwrite
= v
.builder
.make_call
(n_expr
.make_var_read
, write_callsite
.as(not null), write_args
)
314 redef class AVarReassignExpr
315 # `v += z` is replaced with `v = v + z`
316 redef fun accept_transform_visitor
(v
)
318 var variable
= self.variable
.as(not null)
320 var nread
= v
.builder
.make_var_read
(variable
, read_type
.as(not null))
322 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.as(not null), [n_value
])
323 var nwrite
= v
.builder
.make_var_assign
(variable
, nnewvalue
)
329 redef class AAttrReassignExpr
330 # `x.a += z` is replaced with `x.a = x.a + z`
331 redef fun accept_transform_visitor
(v
)
333 var nblock
= v
.builder
.make_block
335 var attribute
= self.mproperty
.as(not null)
337 var nread
= v
.builder
.make_attr_read
(n_expr
.make_var_read
, attribute
)
338 var nnewvalue
= v
.builder
.make_call
(nread
, reassign_callsite
.as(not null), [n_value
])
339 var nwrite
= v
.builder
.make_attr_assign
(n_expr
.make_var_read
, attribute
, nnewvalue
)