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
22 intrude import modelbuilder_base
24 # General factory to build semantic nodes in the AST of expressions
26 # The module used as reference for the building
27 # It is used to gather types and other stuff
30 # The anchor used for some mechanism relying on types
31 var anchor
: nullable MClassType
33 # Check mmodule to avoid a new instantiation of ASTBuilder
34 fun check_mmodule
(mmodule
: MModule)
36 if self.mmodule
!= mmodule
then self.mmodule
= mmodule
39 # Make a new Int literal
40 fun make_int
(value
: Int): AIntegerExpr
42 return new AIntegerExpr.make
(value
, mmodule
.int_type
)
45 # Make a new instantiation
46 fun make_new
(callsite
: CallSite, args
: nullable Array[AExpr]): ANewExpr
48 return new ANewExpr.make
(callsite
, args
)
51 # Make a new message send
52 fun make_call
(recv
: AExpr, callsite
: CallSite, args
: nullable Array[AExpr]): ACallExpr
54 return new ACallExpr.make
(recv
, callsite
, args
)
57 # Make a new, empty, sequence of statements
58 fun make_block
: ABlockExpr
60 return new ABlockExpr.make
63 # Make a new, empty, loop of statements
64 fun make_loop
: ALoopExpr
66 return new ALoopExpr.make
69 # Make a new variable read
70 fun make_var_read
(variable
: Variable, mtype
: MType): AVarExpr
72 return new AVarExpr.make
(variable
, mtype
)
75 # Make a new variable assignment
76 fun make_var_assign
(variable
: Variable, value
: AExpr): AVarAssignExpr
78 return new AVarAssignExpr.make
(variable
, value
)
81 # Make a new attribute read
82 fun make_attr_read
(recv
: AExpr, attribute
: MAttribute): AAttrExpr
84 var mtype
= attribute
.intro
.static_mtype
.resolve_for
(recv
.mtype
.as(not null), anchor
, mmodule
, true)
85 return new AAttrExpr.make
(recv
, attribute
, mtype
)
88 # Make a new attribute assignment
89 fun make_attr_assign
(recv
: AExpr, attribute
: MAttribute, value
: AExpr): AAttrAssignExpr
91 return new AAttrAssignExpr.make
(recv
, attribute
, value
)
94 # Make a new escapable block
97 return new ADoExpr.make
100 # Make a new break for a given escapemark
101 fun make_break
(escapemark
: EscapeMark): ABreakExpr
103 return new ABreakExpr.make
(escapemark
)
106 # Make a new conditional
107 # `mtype` is the return type of the whole if, in case of a ternary operator.
108 fun make_if
(condition
: AExpr, mtype
: nullable MType): AIfExpr
110 return new AIfExpr.make
(condition
, mtype
)
114 fun make_assert
(n_id
: nullable TId , n_expr
: AExpr , n_else
: nullable AExpr): AAssertExpr
116 return new AAssertExpr.make
(n_id
, n_expr
, n_else
)
120 fun make_method
(n_visibility
: nullable AVisibility,
121 tk_redef
: nullable TKwredef,
122 mmethoddef
: nullable MMethodDef,
123 n_signature
: nullable ASignature,
124 n_annotations
: nullable AAnnotations,
125 n_extern_calls
: nullable AExternCalls,
126 n_extern_code_block
: nullable AExternCodeBlock,
127 n_block
: nullable AExpr): AMethPropdef
129 return new AMethPropdef.make
(n_visibility
, tk_redef
, mmethoddef
, n_signature
, n_annotations
, n_extern_calls
, n_extern_code_block
, n_block
)
132 # Make a new or with two expr
133 fun make_or
(right_expr
: AExpr, left_expr
: AExpr): AOrExpr
135 return new AOrExpr.make
(right_expr
,left_expr
)
138 # Make a new and with two expr
139 fun make_and
(right_expr
: AExpr, left_expr
: AExpr): AAndExpr
141 return new AAndExpr.make
(right_expr
,left_expr
)
144 # Make a new parenthesis expr
145 fun make_parenthesis
(expr
: AExpr, annotations
: nullable AAnnotations): AParExpr
147 return new AParExpr.make
(expr
,annotations
)
150 # Make a new message super
151 fun make_super_call
(args
: nullable Array[AExpr], n_qualified
: nullable AQualified): ASuperExpr
153 return new ASuperExpr.make
(args
,n_qualified
)
157 fun make_return
(expr
: nullable AExpr): AReturnExpr
159 return new AReturnExpr.make
(expr
)
163 fun make_not
(expr
: AExpr): ANotExpr
165 return new ANotExpr.make
(expr
)
168 # Build a callsite to call the `mproperty` in the current method `caller_method`.
169 # `is_self_call` indicate if the method caller is a property of `self`
170 fun create_callsite
(modelbuilder
: ModelBuilder, caller_method
: AMethPropdef, mproperty
: MMethod, is_self_call
: Bool): CallSite
172 # FIXME It's not the better solution to call `TypeVisitor` here to build a model entity, but some make need to have a callsite
173 var type_visitor
= new TypeVisitor(modelbuilder
, caller_method
.mpropdef
.as(not null))
174 var callsite
= type_visitor
.build_callsite_by_property
(caller_method
, mproperty
.intro_mclassdef
.bound_mtype
, mproperty
, is_self_call
)
175 assert callsite
!= null
181 # Return a new variable read that contains the value of the expression
182 # This method take care efficiently of creating and initalising an anonymous local variable
184 # Note: since this method do side-effects (AST replacement), there could be unexpected effects when used as
185 # argument of other methods related to AST transformations.
186 fun make_var_read
: AVarExpr
188 var variable
= self.variable_cache
189 if variable
== null then
190 assert parent
!= null
191 var place
= detach_with_placeholder
192 variable
= new Variable("")
193 variable
.declared_type
= self.mtype
194 var nvar
= new AVarAssignExpr.make
(variable
, self)
195 place
.replace_with
(nvar
)
196 self.variable_cache
= variable
198 return new AVarExpr.make
(variable
, variable
.declared_type
.as(not null))
201 private var variable_cache
: nullable Variable
203 # The `detach` method completely remove the node in the parent.
204 # However, sometime, it is useful to keep the emplacement of the removed child.
206 # The standard use case is the insertion of a node between a parent `p` and a child `p.c`.
207 # To create the new node `n`, we need to attach the child to it.
208 # But, to put `n` where `c` was in `p`, the place has to be remembered.
213 # var h = c.detach_with_placeholder
214 # var n = astbuilder.make_XXX(c)
217 fun detach_with_placeholder
: AExpr
219 var h
= new APlaceholderExpr.make
225 # Add `expr` at the end of the block
227 # REQUIRE: self isa ABlockExpr
229 # Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
232 print
"add not implemented in {inspect}"
236 redef fun accept_ast_validation
(v
)
239 if mtype
== null and not is_typed
then
240 #debug "TYPING: untyped expression"
245 # A placeholder for a `AExpr` node
246 # Instances are transiantly used to mark some specific emplacements in the AST
247 # during complex transformations.
249 # Their must not appear in a valid AST
251 # @see AExpr::detach_with_placeholder
252 class APlaceholderExpr
258 redef fun accept_ast_validation
(v
)
261 debug
"PARENT: remaining placeholder"
266 private init make
(expr
: AExpr)
268 self.init_anotexpr
(new TKwnot, expr
)
272 redef class AReturnExpr
273 private init make
(expr
: nullable AExpr)
275 self.init_areturnexpr
(null, expr
)
279 redef class ASuperExpr
280 private init make
(args
: nullable Array[AExpr], n_qualified
: nullable AQualified, mpropdef
: nullable MMethodDef)
282 var n_args
= new AListExprs
284 n_args
.n_exprs
.add_all
(args
)
287 self.init_asuperexpr
(n_qualified
, new TKwsuper, n_args
)
292 private init make
(right_expr
: AExpr, left_expr
: AExpr)
294 self.init_aorexpr
(right_expr
,new TKwor,left_expr
)
299 private init make
(right_expr
: AExpr, left_expr
: AExpr)
301 self.init_aandexpr
(right_expr
,new TKwand ,left_expr
)
305 redef class AMethPropdef
306 private init make
(n_visibility
: nullable AVisibility,
307 tk_redef
: nullable TKwredef,
308 mmethoddef
: nullable MMethodDef,
309 n_signature
: nullable ASignature,
310 n_annotations
: nullable AAnnotations,
311 n_extern_calls
: nullable AExternCalls,
312 n_extern_code_block
: nullable AExternCodeBlock,
313 n_block
: nullable AExpr)
316 var n_methid
= new AIdMethid.init_aidmethid
(n_tid
)
317 if n_signature
== null then n_signature
= new ASignature
318 if n_visibility
== null then n_visibility
= new APublicVisibility
319 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)
320 self.mpropdef
= mmethoddef
324 redef class AAssertExpr
325 private init make
(n_id
: nullable TId , n_expr
: nullable AExpr , n_else
: nullable AExpr)
327 n_kwassert
= new TKwassert
329 if n_else
!= null then n_kwelse
= new TKwelse
330 self.init_aassertexpr
(n_kwassert
, n_id
, n_expr
, n_kwelse
, n_else
)
334 redef class ALoopExpr
337 _n_kwloop
= new TKwloop
339 n_block
= new ABlockExpr
340 n_block
.is_typed
= true
354 n_block
= new ABlockExpr
355 n_block
.is_typed
= true
358 # Make a new break expression of the given do
359 fun make_break
: ABreakExpr
361 var escapemark
= self.break_mark
362 if escapemark
== null then
363 escapemark
= new EscapeMark(null)
364 self.break_mark
= escapemark
366 return new ABreakExpr.make
(escapemark
)
375 redef class ABreakExpr
376 private init make
(escapemark
: EscapeMark)
378 _n_kwbreak
= new TKwbreak
379 self.escapemark
= escapemark
380 escapemark
.escapes
.add
self
386 private init make
(condition
: AExpr, mtype
: nullable MType)
390 _n_expr
.parent
= self
391 _n_kwthen
= new TKwthen
392 _n_then
= new ABlockExpr.make
393 _n_kwelse
= new TKwelse
394 _n_else
= new ABlockExpr.make
396 if mtype
!= null then self.is_typed
= true
402 private init make
(t
: nullable MType)
404 var n_id
= new TClassid
405 var n_qid
= new AQclassid
411 redef fun clone
: SELF
413 return new AType.make
(mtype
)
419 redef class AIntegerExpr
421 private init make
(value
: nullable Numeric, t
: nullable MType)
424 if t
!= null then self.is_typed
= true
426 _n_integer
= new TInteger # dummy
429 redef fun clone
: SELF
431 return new AIntegerExpr.make
(value
, mtype
)
435 redef class AFloatExpr
437 private init make
(value
: nullable Float, t
: nullable MType)
440 if t
!= null then self.is_typed
= true
442 _n_float
= new TFloat # dummy
445 redef fun clone
: SELF
447 return new AFloatExpr.make
(value
, mtype
)
451 redef class ATrueExpr
453 private init make
(t
: nullable MType)
455 init_atrueexpr
(new TKwtrue, null)
457 if t
!= null then self.is_typed
= true
460 redef fun clone
: SELF
462 return new ATrueExpr.make
(mtype
)
466 redef class AFalseExpr
468 private init make
(t
: nullable MType)
470 init_afalseexpr
(new TKwfalse, null)
472 if t
!= null then self.is_typed
= true
475 redef fun clone
: SELF
477 return new AFalseExpr.make
(mtype
)
481 redef class ACharExpr
483 # `token_text` represent the real value as it's present in a file not only the char.
484 # `token_text` is needed if you want to use some methods (for exemple: `prefix`, `suffix` or `is_code_point methods`)
485 private init make
(value
: nullable Char, t
: nullable MType, token_text
: nullable String)
490 if token_text
!= null then n_char
.text
= token_text
491 if t
!= null then self.is_typed
= true
494 redef fun clone
: SELF
496 var self_clone
= new ACharExpr.make
(self.value
, mtype
, n_char
.text
)
502 private init make
(callsite
: CallSite, args
: nullable Array[AExpr])
504 _n_kwnew
= new TKwnew
505 _n_type
= new AType.make
506 _n_args
= new AListExprs
508 n_args
.n_exprs
.add_all
(args
)
510 self.callsite
= callsite
511 self.recvtype
= callsite
.recv
.as(MClassType)
512 if callsite
.mproperty
.is_new
then
513 self.mtype
= callsite
.msignature
.return_mtype
515 self.mtype
= callsite
.recv
521 redef class ACallExpr
522 private init make
(recv
: AExpr, callsite
: nullable CallSite, args
: nullable Array[AExpr])
525 _n_args
= new AListExprs
527 _n_qid
.n_id
= new TId
528 _n_qid
.n_id
.text
= callsite
.mproperty
.name
530 self.n_args
.n_exprs
.add_all
(args
)
533 if callsite
!= null then
534 self.callsite
= callsite
535 self.mtype
= callsite
.msignature
.return_mtype
541 redef class AAsCastExpr
542 private init make
(n_expr
: AExpr, n_type
: AType)
544 init_aascastexpr
(n_expr
, new TKwas , null , n_type
, null)
548 redef class AAsNotnullExpr
549 private init make
(n_expr
: AExpr, t
: nullable MType)
551 init_aasnotnullexpr
(n_expr
, new TKwas, null, new TKwnot, new TKwnull, null)
553 if t
!= null then _is_typed
= true
557 redef class ANullExpr
559 private init make
(t
: nullable MType)
561 init_anullexpr
(new TKwnull, null)
563 if t
!= null then self.is_typed
= true
567 redef class ASelfExpr
569 private init make
(v
: nullable Variable, t
: nullable MType)
571 init_aselfexpr
(new TKwself, null)
573 if t
!= null then is_typed
=true
576 redef fun clone
: SELF
578 return new ASelfExpr.make
(self.variable
, self.mtype
)
582 redef class AImplicitSelfExpr
584 redef fun clone
: SELF
586 var self_clone
= new AImplicitSelfExpr.make
(variable
, mtype
)
587 self_clone
.is_sys
= is_sys
593 redef class AAttrExpr
594 private init make
(recv
: AExpr, attribute
: nullable MAttribute, t
: nullable MType)
599 _mproperty
= attribute
601 if t
!= null then _is_typed
= true
605 redef class AAttrAssignExpr
606 private init make
(recv
: AExpr, attribute
: nullable MAttribute, value
: AExpr)
613 _n_assign
= new TAssign
614 _mproperty
= attribute
620 private init make
(v
: nullable Variable, t
: nullable MType)
623 if v
!= null then _n_id
.text
= v
.name
626 if t
!= null then is_typed
= true
630 redef class AVarAssignExpr
631 private init make
(v
: nullable Variable, value
: AExpr)
634 if v
!= null then _n_id
.text
= v
.name
637 _n_assign
= new TAssign
640 if _mtype
!= null then _is_typed
= true
644 redef class ASignature
645 redef fun clone
: SELF
648 if ntype
!= null then ntype
= n_type
.clone
649 return new ASignature.init_asignature
(null, n_params
.clone
, null, ntype
)
655 private init make
(v
: nullable Variable, t
: nullable AType)
662 redef fun clone
: SELF
665 if ntype
!= null then ntype
= n_type
.clone
666 return new AParam.make
(variable
, ntype
)
670 redef class ABlockExpr
671 private init make
(t
: nullable MType)
685 fun add_all
(exprs
: Array[AExpr])
692 redef fun clone
: SELF
694 var clone
= new ABlockExpr.make
(mtype
)
695 for expr
in self.n_expr
do
696 clone
.add
(expr
.clone
)
702 redef class AQclassid
703 redef fun clone
: SELF
705 return new AQclassid.init_aqclassid
(n_qualified
.clone
, n_id
)
709 redef class AQualified
710 redef fun clone
: SELF
712 return new AQualified.init_aqualified
(n_id
.clone
, n_classid
)
717 redef fun clone
: SELF
719 var clone_n_qualified
= n_qualified
720 if n_qualified
!= null then clone_n_qualified
= n_qualified
.clone
721 return new AQid.init_aqid
(clone_n_qualified
, n_id
.clone
)
726 redef fun clone
: SELF
728 return new TId.init_tk
(location
)
733 private init make
(expr
: AExpr, annotations
: nullable AAnnotations)
735 self.init_aparexpr
(new TOpar, expr
, new TCpar, annotations
)
739 # Check the consitency of AST
740 class ASTValidationVisitor
742 redef fun visit
(node
)
744 node
.accept_ast_validation
(self)
746 private var path
= new CircularArray[ANode]
747 private var seen
= new HashSet[ANode]
753 redef fun clone
: SELF
755 var clone_anodes
= new ANodes[E
](self.parent
)
757 clone_anodes
.add
(node
.clone
)
766 redef fun clone
: SELF
768 # By default the clone abort to avoid surprises
769 print
"The clone method is not implemented for the `{self.class_name}` class"
772 # Recursively validate a AST node.
773 # This ensure that location and parenting are defined and coherent.
775 # After complex low-level AST manipulation and construction,
776 # it is recommended to call it.
778 # Note: this just instantiate and run an `ASTValidationVisitor`.
781 (new ASTValidationVisitor).enter_visit
(self)
784 private fun accept_ast_validation
(v
: ASTValidationVisitor)
786 var parent
= self.parent
789 if path
.length
> 0 then
790 var path_parent
= v
.path
.first
791 if parent
== null then
792 self.parent
= path_parent
793 #debug "PARENT: expected parent: {path_parent}"
795 else if parent
!= path_parent
then
796 self.parent
= path_parent
797 if v
.seen
.has
(self) then
798 debug
"DUPLICATE (NOTATREE): already seen node with parent {parent} now with {path_parent}."
801 debug
"PARENT: expected parent: {path_parent}, got {parent}"
806 if not isset _location
then
807 #debug "LOCATION: unlocated node {v.path.join(", ")}"
808 _location
= self.parent
.location
817 redef class AAnnotation
819 redef fun accept_ast_validation
(v
)
821 # Do not enter in annotations
824 private init make
(n_args
: ANodes[AExpr])
826 _n_visibility
= new APublicVisibility