astbuilder: First implementation of clonable for ast nodes
[nit.git] / src / astbuilder.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Instantiation and transformation of semantic nodes in the AST of expressions and statements
16 module astbuilder
17
18 intrude import semantize::typing
19 intrude import literal
20 intrude import parser
21 intrude import semantize::scope
22 intrude import modelbuilder_base
23
24 # General factory to build semantic nodes in the AST of expressions
25 class ASTBuilder
26 # The module used as reference for the building
27 # It is used to gather types and other stuff
28 var mmodule: MModule
29
30 # The anchor used for some mechanism relying on types
31 var anchor: nullable MClassType
32
33 # Check mmodule to avoid a new instantiation of ASTBuilder
34 fun check_mmodule(mmodule: MModule)
35 do
36 if self.mmodule != mmodule then self.mmodule = mmodule
37 end
38
39 # Make a new Int literal
40 fun make_int(value: Int): AIntegerExpr
41 do
42 return new AIntegerExpr.make(value, mmodule.int_type)
43 end
44
45 # Make a new instantiation
46 fun make_new(callsite: CallSite, args: nullable Array[AExpr]): ANewExpr
47 do
48 return new ANewExpr.make(callsite, args)
49 end
50
51 # Make a new message send
52 fun make_call(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr]): ACallExpr
53 do
54 return new ACallExpr.make(recv, callsite, args)
55 end
56
57 # Make a new, empty, sequence of statements
58 fun make_block: ABlockExpr
59 do
60 return new ABlockExpr.make
61 end
62
63 # Make a new, empty, loop of statements
64 fun make_loop: ALoopExpr
65 do
66 return new ALoopExpr.make
67 end
68
69 # Make a new variable read
70 fun make_var_read(variable: Variable, mtype: MType): AVarExpr
71 do
72 return new AVarExpr.make(variable, mtype)
73 end
74
75 # Make a new variable assignment
76 fun make_var_assign(variable: Variable, value: AExpr): AVarAssignExpr
77 do
78 return new AVarAssignExpr.make(variable, value)
79 end
80
81 # Make a new attribute read
82 fun make_attr_read(recv: AExpr, attribute: MAttribute): AAttrExpr
83 do
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)
86 end
87
88 # Make a new attribute assignment
89 fun make_attr_assign(recv: AExpr, attribute: MAttribute, value: AExpr): AAttrAssignExpr
90 do
91 return new AAttrAssignExpr.make(recv, attribute, value)
92 end
93
94 # Make a new escapable block
95 fun make_do: ADoExpr
96 do
97 return new ADoExpr.make
98 end
99
100 # Make a new break for a given escapemark
101 fun make_break(escapemark: EscapeMark): ABreakExpr
102 do
103 return new ABreakExpr.make(escapemark)
104 end
105
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
109 do
110 return new AIfExpr.make(condition, mtype)
111 end
112
113 # Make a new assert
114 fun make_assert(n_id : nullable TId , n_expr : AExpr , n_else : nullable AExpr): AAssertExpr
115 do
116 return new AAssertExpr.make(n_id , n_expr , n_else)
117 end
118
119 # Make a new method
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
128 do
129 return new AMethPropdef.make(n_visibility, tk_redef, mmethoddef, n_signature, n_annotations, n_extern_calls, n_extern_code_block, n_block)
130 end
131
132 # Make a new or with two expr
133 fun make_or(right_expr: AExpr, left_expr: AExpr): AOrExpr
134 do
135 return new AOrExpr.make(right_expr,left_expr)
136 end
137
138 # Make a new and with two expr
139 fun make_and(right_expr: AExpr, left_expr: AExpr): AAndExpr
140 do
141 return new AAndExpr.make(right_expr,left_expr)
142 end
143
144 # Make a new parenthesis expr
145 fun make_parenthesis(expr: AExpr, annotations: nullable AAnnotations): AParExpr
146 do
147 return new AParExpr.make(expr,annotations)
148 end
149
150 # Make a new message super
151 fun make_super_call(args: nullable Array[AExpr], n_qualified: nullable AQualified): ASuperExpr
152 do
153 return new ASuperExpr.make(args,n_qualified)
154 end
155
156 # Make a new return
157 fun make_return(expr: nullable AExpr): AReturnExpr
158 do
159 return new AReturnExpr.make(expr)
160 end
161
162 # Make a new not
163 fun make_not(expr: AExpr): ANotExpr
164 do
165 return new ANotExpr.make(expr)
166 end
167
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
171 do
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
176 return callsite
177 end
178 end
179
180 redef class AExpr
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
183 #
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
187 do
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
197 end
198 return new AVarExpr.make(variable, variable.declared_type.as(not null))
199 end
200
201 private var variable_cache: nullable Variable
202
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.
205 #
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.
209 #
210 # ~~~nitish
211 # var p: AExpr
212 # var c = p.c
213 # var h = c.detach_with_placeholder
214 # var n = astbuilder.make_XXX(c)
215 # h.replace_with(n)
216 # ~~~
217 fun detach_with_placeholder: AExpr
218 do
219 var h = new APlaceholderExpr.make
220 self.replace_with(h)
221 return h
222 end
223
224
225 # Add `expr` at the end of the block
226 #
227 # REQUIRE: self isa ABlockExpr
228 #
229 # Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
230 fun add(expr: AExpr)
231 do
232 print "add not implemented in {inspect}"
233 abort
234 end
235
236 redef fun accept_ast_validation(v)
237 do
238 super
239 if mtype == null and not is_typed then
240 #debug "TYPING: untyped expression"
241 end
242 end
243 end
244
245 # A placeholder for a `AExpr` node
246 # Instances are transiantly used to mark some specific emplacements in the AST
247 # during complex transformations.
248 #
249 # Their must not appear in a valid AST
250 #
251 # @see AExpr::detach_with_placeholder
252 class APlaceholderExpr
253 super AExpr
254 private init make
255 do
256 end
257
258 redef fun accept_ast_validation(v)
259 do
260 super
261 debug "PARENT: remaining placeholder"
262 end
263 end
264
265 redef class ANotExpr
266 private init make(expr: AExpr)
267 do
268 self.init_anotexpr(new TKwnot, expr)
269 end
270 end
271
272 redef class AReturnExpr
273 private init make(expr: nullable AExpr)
274 do
275 self.init_areturnexpr(null, expr)
276 end
277 end
278
279 redef class ASuperExpr
280 private init make(args: nullable Array[AExpr], n_qualified: nullable AQualified, mpropdef: nullable MMethodDef)
281 do
282 var n_args = new AListExprs
283 if args != null then
284 n_args.n_exprs.add_all(args)
285 end
286 _mpropdef = mpropdef
287 self.init_asuperexpr(n_qualified, new TKwsuper, n_args)
288 end
289 end
290
291 redef class AOrExpr
292 private init make(right_expr: AExpr, left_expr: AExpr)
293 do
294 self.init_aorexpr(right_expr,new TKwor,left_expr)
295 end
296 end
297
298 redef class AAndExpr
299 private init make(right_expr: AExpr, left_expr: AExpr)
300 do
301 self.init_aandexpr(right_expr,new TKwand ,left_expr)
302 end
303 end
304
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)
314 do
315 var n_tid = new TId
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
321 end
322 end
323
324 redef class AAssertExpr
325 private init make(n_id : nullable TId , n_expr : nullable AExpr , n_else : nullable AExpr)
326 do
327 n_kwassert = new TKwassert
328 n_kwelse = null
329 if n_else != null then n_kwelse = new TKwelse
330 self.init_aassertexpr(n_kwassert, n_id , n_expr , n_kwelse , n_else)
331 end
332 end
333
334 redef class ALoopExpr
335 private init make
336 do
337 _n_kwloop = new TKwloop
338 self.is_typed = true
339 n_block = new ABlockExpr
340 n_block.is_typed = true
341 end
342
343 redef fun add(expr)
344 do
345 n_block.add expr
346 end
347 end
348
349 redef class ADoExpr
350 private init make
351 do
352 _n_kwdo = new TKwdo
353 self.is_typed = true
354 n_block = new ABlockExpr
355 n_block.is_typed = true
356 end
357
358 # Make a new break expression of the given do
359 fun make_break: ABreakExpr
360 do
361 var escapemark = self.break_mark
362 if escapemark == null then
363 escapemark = new EscapeMark(null)
364 self.break_mark = escapemark
365 end
366 return new ABreakExpr.make(escapemark)
367 end
368
369 redef fun add(expr)
370 do
371 n_block.add expr
372 end
373 end
374
375 redef class ABreakExpr
376 private init make(escapemark: EscapeMark)
377 do
378 _n_kwbreak = new TKwbreak
379 self.escapemark = escapemark
380 escapemark.escapes.add self
381 self.is_typed = true
382 end
383 end
384
385 redef class AIfExpr
386 private init make(condition: AExpr, mtype: nullable MType)
387 do
388 _n_kwif = new TKwif
389 _n_expr = condition
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
395 self.mtype = mtype
396 if mtype != null then self.is_typed = true
397 end
398 end
399
400 redef class AType
401
402 private init make(t: nullable MType)
403 do
404 var n_id = new TClassid
405 var n_qid = new AQclassid
406 n_qid.n_id = n_id
407 _n_qid = n_qid
408 _mtype = t
409 end
410
411 redef fun clone: SELF
412 do
413 return new AType.make(mtype)
414 end
415 end
416
417 # Primitive type
418
419 redef class AIntegerExpr
420
421 private init make(value: nullable Numeric, t: nullable MType)
422 do
423 _mtype = t
424 if t != null then self.is_typed = true
425 _value = value
426 _n_integer = new TInteger # dummy
427 end
428
429 redef fun clone: SELF
430 do
431 return new AIntegerExpr.make(value, mtype)
432 end
433 end
434
435 redef class AFloatExpr
436
437 private init make(value: nullable Float, t: nullable MType)
438 do
439 _mtype = t
440 if t != null then self.is_typed = true
441 _value = value
442 _n_float = new TFloat # dummy
443 end
444
445 redef fun clone: SELF
446 do
447 return new AFloatExpr.make(value, mtype)
448 end
449 end
450
451 redef class ATrueExpr
452
453 private init make(t: nullable MType)
454 do
455 init_atrueexpr(new TKwtrue, null)
456 _mtype = t
457 if t != null then self.is_typed = true
458 end
459
460 redef fun clone: SELF
461 do
462 return new ATrueExpr.make(mtype)
463 end
464 end
465
466 redef class AFalseExpr
467
468 private init make(t: nullable MType)
469 do
470 init_afalseexpr(new TKwfalse, null)
471 _mtype = t
472 if t != null then self.is_typed = true
473 end
474
475 redef fun clone: SELF
476 do
477 return new AFalseExpr.make(mtype)
478 end
479 end
480
481 redef class ACharExpr
482
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)
486 do
487 _value = value
488 _mtype = t
489 _n_char = new TChar
490 if token_text != null then n_char.text = token_text
491 if t != null then self.is_typed = true
492 end
493
494 redef fun clone: SELF
495 do
496 var self_clone = new ACharExpr.make(self.value, mtype, n_char.text)
497 return self_clone
498 end
499 end
500
501 redef class ANewExpr
502 private init make(callsite: CallSite, args: nullable Array[AExpr])
503 do
504 _n_kwnew = new TKwnew
505 _n_type = new AType.make
506 _n_args = new AListExprs
507 if args != null then
508 n_args.n_exprs.add_all(args)
509 end
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
514 else
515 self.mtype = callsite.recv
516 end
517 self.is_typed = true
518 end
519 end
520
521 redef class ACallExpr
522 private init make(recv: AExpr, callsite: nullable CallSite, args: nullable Array[AExpr])
523 do
524 self._n_expr = recv
525 _n_args = new AListExprs
526 _n_qid = new AQid
527 _n_qid.n_id = new TId
528 _n_qid.n_id.text = callsite.mproperty.name
529 if args != null then
530 self.n_args.n_exprs.add_all(args)
531 end
532
533 if callsite != null then
534 self.callsite = callsite
535 self.mtype = callsite.msignature.return_mtype
536 self.is_typed = true
537 end
538 end
539 end
540
541 redef class AAsCastExpr
542 private init make(n_expr: AExpr, n_type: AType)
543 do
544 init_aascastexpr(n_expr, new TKwas , null , n_type, null)
545 end
546 end
547
548 redef class AAsNotnullExpr
549 private init make(n_expr: AExpr, t: nullable MType)
550 do
551 init_aasnotnullexpr(n_expr, new TKwas, null, new TKwnot, new TKwnull, null)
552 _mtype = t
553 if t != null then _is_typed = true
554 end
555 end
556
557 redef class ANullExpr
558
559 private init make(t: nullable MType)
560 do
561 init_anullexpr(new TKwnull, null)
562 _mtype = t
563 if t != null then self.is_typed = true
564 end
565 end
566
567 redef class ASelfExpr
568
569 private init make(v: nullable Variable, t: nullable MType)
570 do
571 init_aselfexpr(new TKwself, null)
572 _mtype = t
573 if t != null then is_typed =true
574 end
575
576 redef fun clone: SELF
577 do
578 return new ASelfExpr.make(self.variable, self.mtype)
579 end
580 end
581
582 redef class AImplicitSelfExpr
583
584 redef fun clone: SELF
585 do
586 var self_clone = new AImplicitSelfExpr.make(variable, mtype)
587 self_clone.is_sys = is_sys
588 return self_clone
589 end
590 end
591
592
593 redef class AAttrExpr
594 private init make(recv: AExpr, attribute: nullable MAttribute, t: nullable MType)
595 do
596 _n_expr = recv
597 recv.parent = self
598 _n_id = new TAttrid
599 _mproperty = attribute
600 _mtype = t
601 if t != null then _is_typed = true
602 end
603 end
604
605 redef class AAttrAssignExpr
606 private init make(recv: AExpr, attribute: nullable MAttribute, value: AExpr)
607 do
608 _n_expr = recv
609 recv.parent = self
610 _n_id = new TAttrid
611 _n_value = value
612 value.parent = self
613 _n_assign = new TAssign
614 _mproperty = attribute
615 _mtype = value.mtype
616 end
617 end
618
619 redef class AVarExpr
620 private init make(v: nullable Variable, t: nullable MType)
621 do
622 _n_id = new TId
623 if v != null then _n_id.text = v.name
624 _variable = v
625 _mtype = t
626 if t != null then is_typed = true
627 end
628 end
629
630 redef class AVarAssignExpr
631 private init make(v: nullable Variable, value: AExpr)
632 do
633 _n_id = new TId
634 if v != null then _n_id.text = v.name
635 _n_value = value
636 value.parent = self
637 _n_assign = new TAssign
638 _variable = v
639 _mtype = value.mtype
640 if _mtype != null then _is_typed = true
641 end
642 end
643
644 redef class ASignature
645 redef fun clone: SELF
646 do
647 var ntype = n_type
648 if ntype != null then ntype = n_type.clone
649 return new ASignature.init_asignature(null, n_params.clone, null, ntype)
650 end
651 end
652
653 redef class AParam
654
655 private init make(v: nullable Variable, t: nullable AType)
656 do
657 _n_id = new TId
658 _variable = v
659 _n_type = t
660 end
661
662 redef fun clone: SELF
663 do
664 var ntype = n_type
665 if ntype != null then ntype = n_type.clone
666 return new AParam.make(variable, ntype)
667 end
668 end
669
670 redef class ABlockExpr
671 private init make(t: nullable MType)
672 do
673 if t != null then
674 _mtype = t
675 _is_typed = true
676 end
677 end
678
679 redef fun add(expr)
680 do
681 n_expr.add expr
682 expr.parent = self
683 end
684
685 fun add_all(exprs: Array[AExpr])
686 do
687 for expr in exprs do
688 add(expr)
689 end
690 end
691
692 redef fun clone: SELF
693 do
694 var clone = new ABlockExpr.make(mtype)
695 for expr in self.n_expr do
696 clone.add(expr.clone)
697 end
698 return clone
699 end
700 end
701
702 redef class AQclassid
703 redef fun clone: SELF
704 do
705 return new AQclassid.init_aqclassid(n_qualified.clone, n_id)
706 end
707 end
708
709 redef class AQualified
710 redef fun clone: SELF
711 do
712 return new AQualified.init_aqualified(n_id.clone, n_classid)
713 end
714 end
715
716 redef class AQid
717 redef fun clone: SELF
718 do
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)
722 end
723 end
724
725 redef class TId
726 redef fun clone: SELF
727 do
728 return new TId.init_tk(location)
729 end
730 end
731
732 redef class AParExpr
733 private init make(expr: AExpr, annotations: nullable AAnnotations)
734 do
735 self.init_aparexpr(new TOpar, expr, new TCpar, annotations)
736 end
737 end
738
739 # Check the consitency of AST
740 class ASTValidationVisitor
741 super Visitor
742 redef fun visit(node)
743 do
744 node.accept_ast_validation(self)
745 end
746 private var path = new CircularArray[ANode]
747 private var seen = new HashSet[ANode]
748 end
749
750 redef class ANodes
751 super Cloneable
752
753 redef fun clone: SELF
754 do
755 var clone_anodes = new ANodes[E](self.parent)
756 for node in self do
757 clone_anodes.add(node.clone)
758 end
759 return clone_anodes
760 end
761 end
762
763 redef class ANode
764 super Cloneable
765
766 redef fun clone: SELF
767 do
768 # By default the clone abort to avoid surprises
769 print "The clone method is not implemented for the `{self.class_name}` class"
770 abort
771 end
772 # Recursively validate a AST node.
773 # This ensure that location and parenting are defined and coherent.
774 #
775 # After complex low-level AST manipulation and construction,
776 # it is recommended to call it.
777 #
778 # Note: this just instantiate and run an `ASTValidationVisitor`.
779 fun validate
780 do
781 (new ASTValidationVisitor).enter_visit(self)
782 end
783
784 private fun accept_ast_validation(v: ASTValidationVisitor)
785 do
786 var parent = self.parent
787 var path = v.path
788
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}"
794 v.seen.add(self)
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}."
799 else
800 v.seen.add(self)
801 debug "PARENT: expected parent: {path_parent}, got {parent}"
802 end
803 end
804 end
805
806 if not isset _location then
807 #debug "LOCATION: unlocated node {v.path.join(", ")}"
808 _location = self.parent.location
809 end
810
811 path.unshift(self)
812 visit_all(v)
813 path.shift
814 end
815 end
816
817 redef class AAnnotation
818
819 redef fun accept_ast_validation(v)
820 do
821 # Do not enter in annotations
822 end
823
824 private init make(n_args : ANodes[AExpr])
825 do
826 _n_visibility = new APublicVisibility
827 _n_args = n_args
828 end
829 end