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 # Instantiation and transformation of semantic nodes in the AST of expressions and statements
18 intrude import semantize
::typing
19 intrude import literal
21 intrude import semantize
::scope
23 # General factory to build semantic nodes in the AST of expressions
25 # The module used as reference for the building
26 # It is used to gather types and other stuff
29 # The anchor used for some mechanism relying on types
30 var anchor
: nullable MClassType
32 # Make a new Int literal
33 fun make_int
(value
: Int): AIntegerExpr
35 return new AIntegerExpr.make
(value
, mmodule
.int_type
)
38 # Make a new instantiation
39 fun make_new
(callsite
: CallSite, args
: nullable Array[AExpr]): ANewExpr
41 return new ANewExpr.make
(callsite
, args
)
44 # Make a new message send
45 fun make_call
(recv
: AExpr, callsite
: CallSite, args
: nullable Array[AExpr]): ACallExpr
47 return new ACallExpr.make
(recv
, callsite
, args
)
50 # Make a new, empty, sequence of statements
51 fun make_block
: ABlockExpr
53 return new ABlockExpr.make
56 # Make a new, empty, loop of statements
57 fun make_loop
: ALoopExpr
59 return new ALoopExpr.make
62 # Make a new variable read
63 fun make_var_read
(variable
: Variable, mtype
: MType): AVarExpr
65 return new AVarExpr.make
(variable
, mtype
)
68 # Make a new variable assignment
69 fun make_var_assign
(variable
: Variable, value
: AExpr): AVarAssignExpr
71 return new AVarAssignExpr.make
(variable
, value
)
74 # Make a new attribute read
75 fun make_attr_read
(recv
: AExpr, attribute
: MAttribute): AAttrExpr
77 var mtype
= attribute
.intro
.static_mtype
.resolve_for
(recv
.mtype
.as(not null), anchor
, mmodule
, true)
78 return new AAttrExpr.make
(recv
, attribute
, mtype
)
81 # Make a new attribute assignment
82 fun make_attr_assign
(recv
: AExpr, attribute
: MAttribute, value
: AExpr): AAttrAssignExpr
84 return new AAttrAssignExpr.make
(recv
, attribute
, value
)
87 # Make a new escapable block
90 return new ADoExpr.make
93 # Make a new break for a given escapemark
94 fun make_break
(escapemark
: EscapeMark): ABreakExpr
96 return new ABreakExpr.make
(escapemark
)
99 # Make a new conditional
100 # `mtype` is the return type of the whole if, in case of a ternary operator.
101 fun make_if
(condition
: AExpr, mtype
: nullable MType): AIfExpr
103 return new AIfExpr.make
(condition
, mtype
)
108 # Return a new variable read that contains the value of the expression
109 # This method take care efficiently of creating and initalising an anonymous local variable
111 # Note: since this method do side-effects (AST replacement), there could be unexpected effects when used as
112 # argument of other methods related to AST transformations.
113 fun make_var_read
: AVarExpr
115 var variable
= self.variable_cache
116 if variable
== null then
117 assert parent
!= null
118 var place
= detach_with_placeholder
119 variable
= new Variable("")
120 variable
.declared_type
= self.mtype
121 var nvar
= new AVarAssignExpr.make
(variable
, self)
122 place
.replace_with
(nvar
)
123 self.variable_cache
= variable
125 return new AVarExpr.make
(variable
, variable
.declared_type
.as(not null))
128 private var variable_cache
: nullable Variable
130 # The `detach` method completely remove the node in the parent.
131 # However, sometime, it is useful to keep the emplacement of the removed child.
133 # The standard use case is the insertion of a node between a parent `p` and a child `p.c`.
134 # To create the new node `n`, we need to attach the child to it.
135 # But, to put `n` where `c` was in `p`, the place has to be remembered.
140 # var h = c.detach_with_placeholder
141 # var n = astbuilder.make_XXX(c)
144 fun detach_with_placeholder
: AExpr
146 var h
= new APlaceholderExpr.make
152 # Add `expr` at the end of the block
154 # REQUIRE: self isa ABlockExpr
156 # Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
159 print
"add not implemented in {inspect}"
163 redef fun accept_ast_validation
(v
)
166 if mtype
== null and not is_typed
then
167 #debug "TYPING: untyped expression"
172 # A placeholder for a `AExpr` node
173 # Instances are transiantly used to mark some specific emplacements in the AST
174 # during complex transformations.
176 # Their must not appear in a valid AST
178 # @see AExpr::detach_with_placeholder
179 class APlaceholderExpr
185 redef fun accept_ast_validation
(v
)
188 debug
"PARENT: remaining placeholder"
192 redef class ABlockExpr
204 redef class ALoopExpr
207 _n_kwloop
= new TKwloop
209 n_block
= new ABlockExpr
210 n_block
.is_typed
= true
224 n_block
= new ABlockExpr
225 n_block
.is_typed
= true
228 # Make a new break expression of the given do
229 fun make_break
: ABreakExpr
231 var escapemark
= self.break_mark
232 if escapemark
== null then
233 escapemark
= new EscapeMark(null)
234 self.break_mark
= escapemark
236 return new ABreakExpr.make
(escapemark
)
245 redef class ABreakExpr
246 private init make
(escapemark
: EscapeMark)
248 _n_kwbreak
= new TKwbreak
249 self.escapemark
= escapemark
250 escapemark
.escapes
.add
self
256 private init make
(condition
: AExpr, mtype
: nullable MType)
260 _n_expr
.parent
= self
261 _n_kwthen
= new TKwthen
262 _n_then
= new ABlockExpr.make
263 _n_kwelse
= new TKwelse
264 _n_else
= new ABlockExpr.make
273 var n_id
= new TClassid
274 var n_qid
= new AQclassid
280 redef class AIntegerExpr
281 private init make
(value
: Int, t
: MType)
284 self._n_integer
= new TInteger # dummy
290 private init make
(callsite
: CallSite, args
: nullable Array[AExpr])
292 _n_kwnew
= new TKwnew
293 _n_type
= new AType.make
294 _n_args
= new AListExprs
296 n_args
.n_exprs
.add_all
(args
)
298 self.callsite
= callsite
299 self.recvtype
= callsite
.recv
.as(MClassType)
300 if callsite
.mproperty
.is_new
then
301 self.mtype
= callsite
.msignature
.return_mtype
303 self.mtype
= callsite
.recv
309 redef class ACallExpr
310 private init make
(recv
: AExpr, callsite
: CallSite, args
: nullable Array[AExpr])
313 _n_args
= new AListExprs
315 _n_qid
.n_id
= new TId
317 self.n_args
.n_exprs
.add_all
(args
)
319 self.callsite
= callsite
320 self.mtype
= callsite
.msignature
.return_mtype
325 redef class AAttrExpr
326 private init make
(recv
: AExpr, attribute
: MAttribute, t
: MType)
331 mproperty
= attribute
336 redef class AAttrAssignExpr
337 private init make
(recv
: AExpr, attribute
: MAttribute, value
: AExpr)
344 _n_assign
= new TAssign
345 mproperty
= attribute
351 private init make
(v
: Variable, mtype
: MType)
359 redef class AVarAssignExpr
360 private init make
(v
: Variable, value
: AExpr)
365 _n_assign
= new TAssign
371 # Check the consitency of AST
372 class ASTValidationVisitor
374 redef fun visit
(node
)
376 node
.accept_ast_validation
(self)
378 private var path
= new CircularArray[ANode]
379 private var seen
= new HashSet[ANode]
383 # Recursively validate a AST node.
384 # This ensure that location and parenting are defined and coherent.
386 # After complex low-level AST manipulation and construction,
387 # it is recommended to call it.
389 # Note: this just instantiate and run an `ASTValidationVisitor`.
392 (new ASTValidationVisitor).enter_visit
(self)
395 private fun accept_ast_validation
(v
: ASTValidationVisitor)
397 var parent
= self.parent
400 if path
.length
> 0 then
401 var path_parent
= v
.path
.first
402 if parent
== null then
403 self.parent
= path_parent
404 #debug "PARENT: expected parent: {path_parent}"
406 else if parent
!= path_parent
then
407 self.parent
= path_parent
408 if v
.seen
.has
(self) then
409 debug
"DUPLICATE (NOTATREE): already seen node with parent {parent} now with {path_parent}."
412 debug
"PARENT: expected parent: {path_parent}, got {parent}"
417 if not isset _location
then
418 #debug "LOCATION: unlocated node {v.path.join(", ")}"
419 _location
= self.parent
.location
428 redef class AAnnotation
429 redef fun accept_ast_validation
(v
)
431 # Do not enter in annotations