d81ac6b6816bff9281318242fd03b74b4d6ded3d
[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
23 # General factory to build semantic nodes in the AST of expressions
24 class ASTBuilder
25 # The module used as reference for the building
26 # It is used to gather types and other stuff
27 var mmodule: MModule
28
29 # The anchor used for some mechanism relying on types
30 var anchor: nullable MClassType
31
32 # Check mmodule to avoid a new instantiation of ASTBuilder
33 fun check_mmodule(mmodule: MModule)
34 do
35 if self.mmodule != mmodule then self.mmodule = mmodule
36 end
37
38 # Make a new Int literal
39 fun make_int(value: Int): AIntegerExpr
40 do
41 return new AIntegerExpr.make(value, mmodule.int_type)
42 end
43
44 # Make a new instantiation
45 fun make_new(callsite: CallSite, args: nullable Array[AExpr]): ANewExpr
46 do
47 return new ANewExpr.make(callsite, args)
48 end
49
50 # Make a new message send
51 fun make_call(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr]): ACallExpr
52 do
53 return new ACallExpr.make(recv, callsite, args)
54 end
55
56 # Make a new, empty, sequence of statements
57 fun make_block: ABlockExpr
58 do
59 return new ABlockExpr.make
60 end
61
62 # Make a new, empty, loop of statements
63 fun make_loop: ALoopExpr
64 do
65 return new ALoopExpr.make
66 end
67
68 # Make a new variable read
69 fun make_var_read(variable: Variable, mtype: MType): AVarExpr
70 do
71 return new AVarExpr.make(variable, mtype)
72 end
73
74 # Make a new variable assignment
75 fun make_var_assign(variable: Variable, value: AExpr): AVarAssignExpr
76 do
77 return new AVarAssignExpr.make(variable, value)
78 end
79
80 # Make a new attribute read
81 fun make_attr_read(recv: AExpr, attribute: MAttribute): AAttrExpr
82 do
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)
85 end
86
87 # Make a new attribute assignment
88 fun make_attr_assign(recv: AExpr, attribute: MAttribute, value: AExpr): AAttrAssignExpr
89 do
90 return new AAttrAssignExpr.make(recv, attribute, value)
91 end
92
93 # Make a new escapable block
94 fun make_do: ADoExpr
95 do
96 return new ADoExpr.make
97 end
98
99 # Make a new break for a given escapemark
100 fun make_break(escapemark: EscapeMark): ABreakExpr
101 do
102 return new ABreakExpr.make(escapemark)
103 end
104
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
108 do
109 return new AIfExpr.make(condition, mtype)
110 end
111
112 # Make a new assert
113 fun make_assert(n_id : nullable TId , n_expr : AExpr , n_else : nullable AExpr): AAssertExpr
114 do
115 return new AAssertExpr.make(n_id , n_expr , n_else)
116 end
117
118 # Make a new method
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
127 do
128 return new AMethPropdef.make(n_visibility, tk_redef, mmethoddef, n_signature, n_annotations, n_extern_calls, n_extern_code_block, n_block)
129 end
130
131 # Make a new or with two expr
132 fun make_or(right_expr: AExpr, left_expr: AExpr): AOrExpr
133 do
134 return new AOrExpr.make(right_expr,left_expr)
135 end
136
137 # Make a new and with two expr
138 fun make_and(right_expr: AExpr, left_expr: AExpr): AAndExpr
139 do
140 return new AAndExpr.make(right_expr,left_expr)
141 end
142
143 # Make a new parenthesis expr
144 fun make_parenthesis(expr: AExpr, annotations: nullable AAnnotations): AParExpr
145 do
146 return new AParExpr.make(expr,annotations)
147 end
148
149 # Make a new message super
150 fun make_super_call(args: nullable Array[AExpr], n_qualified: nullable AQualified): ASuperExpr
151 do
152 return new ASuperExpr.make(args,n_qualified)
153 end
154
155 # Make a new return
156 fun make_return(expr: nullable AExpr): AReturnExpr
157 do
158 return new AReturnExpr.make(expr)
159 end
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
162 do
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
166 return callsite
167 end
168 end
169
170 redef class AExpr
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
173 #
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
177 do
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
187 end
188 return new AVarExpr.make(variable, variable.declared_type.as(not null))
189 end
190
191 private var variable_cache: nullable Variable
192
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.
195 #
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.
199 #
200 # ~~~nitish
201 # var p: AExpr
202 # var c = p.c
203 # var h = c.detach_with_placeholder
204 # var n = astbuilder.make_XXX(c)
205 # h.replace_with(n)
206 # ~~~
207 fun detach_with_placeholder: AExpr
208 do
209 var h = new APlaceholderExpr.make
210 self.replace_with(h)
211 return h
212 end
213
214
215 # Add `expr` at the end of the block
216 #
217 # REQUIRE: self isa ABlockExpr
218 #
219 # Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
220 fun add(expr: AExpr)
221 do
222 print "add not implemented in {inspect}"
223 abort
224 end
225
226 redef fun accept_ast_validation(v)
227 do
228 super
229 if mtype == null and not is_typed then
230 #debug "TYPING: untyped expression"
231 end
232 end
233 end
234
235 # A placeholder for a `AExpr` node
236 # Instances are transiantly used to mark some specific emplacements in the AST
237 # during complex transformations.
238 #
239 # Their must not appear in a valid AST
240 #
241 # @see AExpr::detach_with_placeholder
242 class APlaceholderExpr
243 super AExpr
244 private init make
245 do
246 end
247
248 redef fun accept_ast_validation(v)
249 do
250 super
251 debug "PARENT: remaining placeholder"
252 end
253 end
254
255 redef class AReturnExpr
256 private init make(expr: nullable AExpr)
257 do
258 self.init_areturnexpr(null, expr)
259 end
260 end
261
262 redef class ASuperExpr
263 private init make(args: nullable Array[AExpr], n_qualified: nullable AQualified)
264 do
265 var n_args = new AListExprs
266 if args != null then
267 n_args.n_exprs.add_all(args)
268 end
269 self.init_asuperexpr(n_qualified, new TKwsuper, n_args)
270 end
271 end
272
273 redef class AParExpr
274 private init make(expr: AExpr, annotations: nullable AAnnotations)
275 do
276 self.location = expr.location
277 self.init_aparexpr(new TOpar, expr, new TCpar, annotations)
278 end
279 end
280
281 redef class AOrExpr
282 private init make(right_expr: AExpr, left_expr: AExpr)
283 do
284 self.init_aorexpr(right_expr,new TKwor,left_expr)
285 end
286 end
287
288 redef class AAndExpr
289 private init make(right_expr: AExpr, left_expr: AExpr)
290 do
291 self.init_aandexpr(right_expr,new TKwand ,left_expr)
292 end
293 end
294
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)
304 do
305 var n_tid = new TId
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)
310
311 if mmethoddef != null then
312 self.n_methid.as(AIdMethid).n_id.text = mmethoddef.name
313 self.mpropdef = mmethoddef
314 end
315 end
316 end
317
318 redef class AAssertExpr
319 private init make(n_id : nullable TId , n_expr : nullable AExpr , n_else : nullable AExpr)
320 do
321 n_kwassert = new TKwassert
322 n_kwelse = null
323 if n_else != null then n_kwelse = new TKwelse
324 self.init_aassertexpr(n_kwassert, n_id , n_expr , n_kwelse , n_else)
325 end
326 end
327
328 redef class ABlockExpr
329 private init make
330 do
331 self.is_typed = true
332 end
333
334 redef fun add(expr)
335 do
336 n_expr.add expr
337 end
338 end
339
340 redef class ALoopExpr
341 private init make
342 do
343 _n_kwloop = new TKwloop
344 self.is_typed = true
345 n_block = new ABlockExpr
346 n_block.is_typed = true
347 end
348
349 redef fun add(expr)
350 do
351 n_block.add expr
352 end
353 end
354
355 redef class ADoExpr
356 private init make
357 do
358 _n_kwdo = new TKwdo
359 self.is_typed = true
360 n_block = new ABlockExpr
361 n_block.is_typed = true
362 end
363
364 # Make a new break expression of the given do
365 fun make_break: ABreakExpr
366 do
367 var escapemark = self.break_mark
368 if escapemark == null then
369 escapemark = new EscapeMark(null)
370 self.break_mark = escapemark
371 end
372 return new ABreakExpr.make(escapemark)
373 end
374
375 redef fun add(expr)
376 do
377 n_block.add expr
378 end
379 end
380
381 redef class ABreakExpr
382 private init make(escapemark: EscapeMark)
383 do
384 _n_kwbreak = new TKwbreak
385 self.escapemark = escapemark
386 escapemark.escapes.add self
387 self.is_typed = true
388 end
389 end
390
391 redef class AIfExpr
392 private init make(condition: AExpr, mtype: nullable MType)
393 do
394 _n_kwif = new TKwif
395 _n_expr = condition
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
401 self.mtype = mtype
402 self.is_typed = true
403 end
404 end
405
406 redef class AType
407 private init make
408 do
409 var n_id = new TClassid
410 var n_qid = new AQclassid
411 n_qid.n_id = n_id
412 _n_qid = n_qid
413 end
414 end
415
416 redef class AIntegerExpr
417 private init make(value: Int, t: MType)
418 do
419 self.value = value
420 self._n_integer = new TInteger # dummy
421 self.mtype = t
422 end
423 end
424
425 redef class ANewExpr
426 private init make(callsite: CallSite, args: nullable Array[AExpr])
427 do
428 _n_kwnew = new TKwnew
429 _n_type = new AType.make
430 _n_args = new AListExprs
431 if args != null then
432 n_args.n_exprs.add_all(args)
433 end
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
438 else
439 self.mtype = callsite.recv
440 end
441 self.is_typed = true
442 end
443 end
444
445 redef class ACallExpr
446 private init make(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr])
447 do
448 self._n_expr = recv
449 _n_args = new AListExprs
450 _n_qid = new AQid
451 _n_qid.n_id = new TId
452 _n_qid.n_id.text = callsite.mproperty.name
453 if args != null then
454 self.n_args.n_exprs.add_all(args)
455 end
456 self.callsite = callsite
457 self.mtype = callsite.msignature.return_mtype
458 self.is_typed = true
459 end
460 end
461
462 redef class AAttrExpr
463 private init make(recv: AExpr, attribute: MAttribute, t: MType)
464 do
465 _n_expr = recv
466 recv.parent = self
467 _n_id = new TAttrid
468 mproperty = attribute
469 mtype = t
470 end
471 end
472
473 redef class AAttrAssignExpr
474 private init make(recv: AExpr, attribute: MAttribute, value: AExpr)
475 do
476 _n_expr = recv
477 recv.parent = self
478 _n_id = new TAttrid
479 _n_value = value
480 value.parent = self
481 _n_assign = new TAssign
482 mproperty = attribute
483 mtype = value.mtype
484 end
485 end
486
487 redef class AVarExpr
488 private init make(v: Variable, mtype: MType)
489 do
490 _n_id = new TId
491 variable = v
492 self.mtype = mtype
493 end
494 end
495
496 redef class AVarAssignExpr
497 private init make(v: Variable, value: AExpr)
498 do
499 _n_id = new TId
500 _n_value = value
501 value.parent = self
502 _n_assign = new TAssign
503 variable = v
504 mtype = value.mtype
505 end
506 end
507
508 # Check the consitency of AST
509 class ASTValidationVisitor
510 super Visitor
511 redef fun visit(node)
512 do
513 node.accept_ast_validation(self)
514 end
515 private var path = new CircularArray[ANode]
516 private var seen = new HashSet[ANode]
517 end
518
519 redef class ANode
520 # Recursively validate a AST node.
521 # This ensure that location and parenting are defined and coherent.
522 #
523 # After complex low-level AST manipulation and construction,
524 # it is recommended to call it.
525 #
526 # Note: this just instantiate and run an `ASTValidationVisitor`.
527 fun validate
528 do
529 (new ASTValidationVisitor).enter_visit(self)
530 end
531
532 private fun accept_ast_validation(v: ASTValidationVisitor)
533 do
534 var parent = self.parent
535 var path = v.path
536
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}"
542 v.seen.add(self)
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}."
547 else
548 v.seen.add(self)
549 debug "PARENT: expected parent: {path_parent}, got {parent}"
550 end
551 end
552 end
553
554 if not isset _location then
555 #debug "LOCATION: unlocated node {v.path.join(", ")}"
556 _location = self.parent.location
557 end
558
559 path.unshift(self)
560 visit_all(v)
561 path.shift
562 end
563 end
564
565 redef class AAnnotation
566 redef fun accept_ast_validation(v)
567 do
568 # Do not enter in annotations
569 end
570 end