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 # Check mmodule to avoid a new instantiation of ASTBuilder
33 fun check_mmodule
(mmodule
: MModule)
35 if self.mmodule
!= mmodule
then self.mmodule
= mmodule
38 # Make a new Int literal
39 fun make_int
(value
: Int): AIntegerExpr
41 return new AIntegerExpr.make
(value
, mmodule
.int_type
)
44 # Make a new instantiation
45 fun make_new
(callsite
: CallSite, args
: nullable Array[AExpr]): ANewExpr
47 return new ANewExpr.make
(callsite
, args
)
50 # Make a new message send
51 fun make_call
(recv
: AExpr, callsite
: CallSite, args
: nullable Array[AExpr]): ACallExpr
53 return new ACallExpr.make
(recv
, callsite
, args
)
56 # Make a new, empty, sequence of statements
57 fun make_block
: ABlockExpr
59 return new ABlockExpr.make
62 # Make a new, empty, loop of statements
63 fun make_loop
: ALoopExpr
65 return new ALoopExpr.make
68 # Make a new variable read
69 fun make_var_read
(variable
: Variable, mtype
: MType): AVarExpr
71 return new AVarExpr.make
(variable
, mtype
)
74 # Make a new variable assignment
75 fun make_var_assign
(variable
: Variable, value
: AExpr): AVarAssignExpr
77 return new AVarAssignExpr.make
(variable
, value
)
80 # Make a new attribute read
81 fun make_attr_read
(recv
: AExpr, attribute
: MAttribute): AAttrExpr
83 var mtype
= attribute
.intro
.static_mtype
.resolve_for
(recv
.mtype
.as(not null), anchor
, mmodule
, true)
84 return new AAttrExpr.make
(recv
, attribute
, mtype
)
87 # Make a new attribute assignment
88 fun make_attr_assign
(recv
: AExpr, attribute
: MAttribute, value
: AExpr): AAttrAssignExpr
90 return new AAttrAssignExpr.make
(recv
, attribute
, value
)
93 # Make a new escapable block
96 return new ADoExpr.make
99 # Make a new break for a given escapemark
100 fun make_break
(escapemark
: EscapeMark): ABreakExpr
102 return new ABreakExpr.make
(escapemark
)
105 # Make a new conditional
106 # `mtype` is the return type of the whole if, in case of a ternary operator.
107 fun make_if
(condition
: AExpr, mtype
: nullable MType): AIfExpr
109 return new AIfExpr.make
(condition
, mtype
)
113 fun make_assert
(n_id
: nullable TId , n_expr
: AExpr , n_else
: nullable AExpr): AAssertExpr
115 return new AAssertExpr.make
(n_id
, n_expr
, n_else
)
119 fun make_method
(n_visibility
: nullable AVisibility,
120 tk_redef
: nullable TKwredef,
121 mmethoddef
: nullable MMethodDef,
122 n_signature
: nullable ASignature,
123 n_annotations
: nullable AAnnotations,
124 n_extern_calls
: nullable AExternCalls,
125 n_extern_code_block
: nullable AExternCodeBlock,
126 n_block
: nullable AExpr): AMethPropdef
128 return new AMethPropdef.make
(n_visibility
, tk_redef
, mmethoddef
, n_signature
, n_annotations
, n_extern_calls
, n_extern_code_block
, n_block
)
131 # Make a new or with two expr
132 fun make_or
(right_expr
: AExpr, left_expr
: AExpr): AOrExpr
134 return new AOrExpr.make
(right_expr
,left_expr
)
137 # Make a new and with two expr
138 fun make_and
(right_expr
: AExpr, left_expr
: AExpr): AAndExpr
140 return new AAndExpr.make
(right_expr
,left_expr
)
143 # Make a new parenthesis expr
144 fun make_parenthesis
(expr
: AExpr, annotations
: nullable AAnnotations): AParExpr
146 return new AParExpr.make
(expr
,annotations
)
149 # Make a new message super
150 fun make_super_call
(args
: nullable Array[AExpr], n_qualified
: nullable AQualified): ASuperExpr
152 return new ASuperExpr.make
(args
,n_qualified
)
156 fun make_return
(expr
: nullable AExpr): AReturnExpr
158 return new AReturnExpr.make
(expr
)
160 # Create a callsite with the given `mproperty`. Take the current method `actual_method` as a context
161 fun create_callsite
(modelbuilder
: ModelBuilder, actual_method
: AMethPropdef, mproperty
: MMethod, is_self_call
: Bool): CallSite
163 var type_visitor
= new TypeVisitor(modelbuilder
, actual_method
.mpropdef
.as(not null))
164 var callsite
= type_visitor
.build_callsite_by_property
(actual_method
, mproperty
.intro_mclassdef
.bound_mtype
, mproperty
, is_self_call
)
165 assert callsite
!= null
171 # Return a new variable read that contains the value of the expression
172 # This method take care efficiently of creating and initalising an anonymous local variable
174 # Note: since this method do side-effects (AST replacement), there could be unexpected effects when used as
175 # argument of other methods related to AST transformations.
176 fun make_var_read
: AVarExpr
178 var variable
= self.variable_cache
179 if variable
== null then
180 assert parent
!= null
181 var place
= detach_with_placeholder
182 variable
= new Variable("")
183 variable
.declared_type
= self.mtype
184 var nvar
= new AVarAssignExpr.make
(variable
, self)
185 place
.replace_with
(nvar
)
186 self.variable_cache
= variable
188 return new AVarExpr.make
(variable
, variable
.declared_type
.as(not null))
191 private var variable_cache
: nullable Variable
193 # The `detach` method completely remove the node in the parent.
194 # However, sometime, it is useful to keep the emplacement of the removed child.
196 # The standard use case is the insertion of a node between a parent `p` and a child `p.c`.
197 # To create the new node `n`, we need to attach the child to it.
198 # But, to put `n` where `c` was in `p`, the place has to be remembered.
203 # var h = c.detach_with_placeholder
204 # var n = astbuilder.make_XXX(c)
207 fun detach_with_placeholder
: AExpr
209 var h
= new APlaceholderExpr.make
215 # Add `expr` at the end of the block
217 # REQUIRE: self isa ABlockExpr
219 # Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
222 print
"add not implemented in {inspect}"
226 redef fun accept_ast_validation
(v
)
229 if mtype
== null and not is_typed
then
230 #debug "TYPING: untyped expression"
235 # A placeholder for a `AExpr` node
236 # Instances are transiantly used to mark some specific emplacements in the AST
237 # during complex transformations.
239 # Their must not appear in a valid AST
241 # @see AExpr::detach_with_placeholder
242 class APlaceholderExpr
248 redef fun accept_ast_validation
(v
)
251 debug
"PARENT: remaining placeholder"
255 redef class AReturnExpr
256 private init make
(expr
: nullable AExpr)
258 self.init_areturnexpr
(null, expr
)
262 redef class ASuperExpr
263 private init make
(args
: nullable Array[AExpr], n_qualified
: nullable AQualified)
265 var n_args
= new AListExprs
267 n_args
.n_exprs
.add_all
(args
)
269 self.init_asuperexpr
(n_qualified
, new TKwsuper, n_args
)
274 private init make
(expr
: AExpr, annotations
: nullable AAnnotations)
276 self.location
= expr
.location
277 self.init_aparexpr
(new TOpar, expr
, new TCpar, annotations
)
282 private init make
(right_expr
: AExpr, left_expr
: AExpr)
284 self.init_aorexpr
(right_expr
,new TKwor,left_expr
)
289 private init make
(right_expr
: AExpr, left_expr
: AExpr)
291 self.init_aandexpr
(right_expr
,new TKwand ,left_expr
)
295 redef class AMethPropdef
296 private init make
(n_visibility
: nullable AVisibility,
297 tk_redef
: nullable TKwredef,
298 mmethoddef
: nullable MMethodDef,
299 n_signature
: nullable ASignature,
300 n_annotations
: nullable AAnnotations,
301 n_extern_calls
: nullable AExternCalls,
302 n_extern_code_block
: nullable AExternCodeBlock,
303 n_block
: nullable AExpr)
306 var n_methid
= new AIdMethid.init_aidmethid
(n_tid
)
307 if n_signature
== null then n_signature
= new ASignature
308 if n_visibility
== null then n_visibility
= new APublicVisibility
309 self.init_amethpropdef
(null,tk_redef
,n_visibility
,new TKwmeth,null,null,null,n_methid
,n_signature
,n_annotations
,n_extern_calls
,n_extern_code_block
,new TKwdo,n_block
,new TKwend)
311 if mmethoddef
!= null then
312 self.n_methid
.as(AIdMethid).n_id
.text
= mmethoddef
.name
313 self.mpropdef
= mmethoddef
318 redef class AAssertExpr
319 private init make
(n_id
: nullable TId , n_expr
: nullable AExpr , n_else
: nullable AExpr)
321 n_kwassert
= new TKwassert
323 if n_else
!= null then n_kwelse
= new TKwelse
324 self.init_aassertexpr
(n_kwassert
, n_id
, n_expr
, n_kwelse
, n_else
)
328 redef class ABlockExpr
340 redef class ALoopExpr
343 _n_kwloop
= new TKwloop
345 n_block
= new ABlockExpr
346 n_block
.is_typed
= true
360 n_block
= new ABlockExpr
361 n_block
.is_typed
= true
364 # Make a new break expression of the given do
365 fun make_break
: ABreakExpr
367 var escapemark
= self.break_mark
368 if escapemark
== null then
369 escapemark
= new EscapeMark(null)
370 self.break_mark
= escapemark
372 return new ABreakExpr.make
(escapemark
)
381 redef class ABreakExpr
382 private init make
(escapemark
: EscapeMark)
384 _n_kwbreak
= new TKwbreak
385 self.escapemark
= escapemark
386 escapemark
.escapes
.add
self
392 private init make
(condition
: AExpr, mtype
: nullable MType)
396 _n_expr
.parent
= self
397 _n_kwthen
= new TKwthen
398 _n_then
= new ABlockExpr.make
399 _n_kwelse
= new TKwelse
400 _n_else
= new ABlockExpr.make
409 var n_id
= new TClassid
410 var n_qid
= new AQclassid
416 redef class AIntegerExpr
417 private init make
(value
: Int, t
: MType)
420 self._n_integer
= new TInteger # dummy
426 private init make
(callsite
: CallSite, args
: nullable Array[AExpr])
428 _n_kwnew
= new TKwnew
429 _n_type
= new AType.make
430 _n_args
= new AListExprs
432 n_args
.n_exprs
.add_all
(args
)
434 self.callsite
= callsite
435 self.recvtype
= callsite
.recv
.as(MClassType)
436 if callsite
.mproperty
.is_new
then
437 self.mtype
= callsite
.msignature
.return_mtype
439 self.mtype
= callsite
.recv
445 redef class ACallExpr
446 private init make
(recv
: AExpr, callsite
: CallSite, args
: nullable Array[AExpr])
449 _n_args
= new AListExprs
451 _n_qid
.n_id
= new TId
452 _n_qid
.n_id
.text
= callsite
.mproperty
.name
454 self.n_args
.n_exprs
.add_all
(args
)
456 self.callsite
= callsite
457 self.mtype
= callsite
.msignature
.return_mtype
462 redef class AAttrExpr
463 private init make
(recv
: AExpr, attribute
: MAttribute, t
: MType)
468 mproperty
= attribute
473 redef class AAttrAssignExpr
474 private init make
(recv
: AExpr, attribute
: MAttribute, value
: AExpr)
481 _n_assign
= new TAssign
482 mproperty
= attribute
488 private init make
(v
: Variable, mtype
: MType)
496 redef class AVarAssignExpr
497 private init make
(v
: Variable, value
: AExpr)
502 _n_assign
= new TAssign
508 # Check the consitency of AST
509 class ASTValidationVisitor
511 redef fun visit
(node
)
513 node
.accept_ast_validation
(self)
515 private var path
= new CircularArray[ANode]
516 private var seen
= new HashSet[ANode]
520 # Recursively validate a AST node.
521 # This ensure that location and parenting are defined and coherent.
523 # After complex low-level AST manipulation and construction,
524 # it is recommended to call it.
526 # Note: this just instantiate and run an `ASTValidationVisitor`.
529 (new ASTValidationVisitor).enter_visit
(self)
532 private fun accept_ast_validation
(v
: ASTValidationVisitor)
534 var parent
= self.parent
537 if path
.length
> 0 then
538 var path_parent
= v
.path
.first
539 if parent
== null then
540 self.parent
= path_parent
541 #debug "PARENT: expected parent: {path_parent}"
543 else if parent
!= path_parent
then
544 self.parent
= path_parent
545 if v
.seen
.has
(self) then
546 debug
"DUPLICATE (NOTATREE): already seen node with parent {parent} now with {path_parent}."
549 debug
"PARENT: expected parent: {path_parent}, got {parent}"
554 if not isset _location
then
555 #debug "LOCATION: unlocated node {v.path.join(", ")}"
556 _location
= self.parent
.location
565 redef class AAnnotation
566 redef fun accept_ast_validation
(v
)
568 # Do not enter in annotations