astbuilder: Make the construction of the `AMethPropdef` more generic
[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 end
161
162 redef class AExpr
163 # Return a new variable read that contains the value of the expression
164 # This method take care efficiently of creating and initalising an anonymous local variable
165 #
166 # Note: since this method do side-effects (AST replacement), there could be unexpected effects when used as
167 # argument of other methods related to AST transformations.
168 fun make_var_read: AVarExpr
169 do
170 var variable = self.variable_cache
171 if variable == null then
172 assert parent != null
173 var place = detach_with_placeholder
174 variable = new Variable("")
175 variable.declared_type = self.mtype
176 var nvar = new AVarAssignExpr.make(variable, self)
177 place.replace_with(nvar)
178 self.variable_cache = variable
179 end
180 return new AVarExpr.make(variable, variable.declared_type.as(not null))
181 end
182
183 private var variable_cache: nullable Variable
184
185 # The `detach` method completely remove the node in the parent.
186 # However, sometime, it is useful to keep the emplacement of the removed child.
187 #
188 # The standard use case is the insertion of a node between a parent `p` and a child `p.c`.
189 # To create the new node `n`, we need to attach the child to it.
190 # But, to put `n` where `c` was in `p`, the place has to be remembered.
191 #
192 # ~~~nitish
193 # var p: AExpr
194 # var c = p.c
195 # var h = c.detach_with_placeholder
196 # var n = astbuilder.make_XXX(c)
197 # h.replace_with(n)
198 # ~~~
199 fun detach_with_placeholder: AExpr
200 do
201 var h = new APlaceholderExpr.make
202 self.replace_with(h)
203 return h
204 end
205
206
207 # Add `expr` at the end of the block
208 #
209 # REQUIRE: self isa ABlockExpr
210 #
211 # Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
212 fun add(expr: AExpr)
213 do
214 print "add not implemented in {inspect}"
215 abort
216 end
217
218 redef fun accept_ast_validation(v)
219 do
220 super
221 if mtype == null and not is_typed then
222 #debug "TYPING: untyped expression"
223 end
224 end
225 end
226
227 # A placeholder for a `AExpr` node
228 # Instances are transiantly used to mark some specific emplacements in the AST
229 # during complex transformations.
230 #
231 # Their must not appear in a valid AST
232 #
233 # @see AExpr::detach_with_placeholder
234 class APlaceholderExpr
235 super AExpr
236 private init make
237 do
238 end
239
240 redef fun accept_ast_validation(v)
241 do
242 super
243 debug "PARENT: remaining placeholder"
244 end
245 end
246
247 redef class AReturnExpr
248 private init make(expr: nullable AExpr)
249 do
250 self.init_areturnexpr(null, expr)
251 end
252 end
253
254 redef class ASuperExpr
255 private init make(args: nullable Array[AExpr], n_qualified: nullable AQualified)
256 do
257 var n_args = new AListExprs
258 if args != null then
259 n_args.n_exprs.add_all(args)
260 end
261 self.init_asuperexpr(n_qualified, new TKwsuper, n_args)
262 end
263 end
264
265 redef class AParExpr
266 private init make(expr: AExpr, annotations: nullable AAnnotations)
267 do
268 self.location = expr.location
269 self.init_aparexpr(new TOpar, expr, new TCpar, annotations)
270 end
271 end
272
273 redef class AOrExpr
274 private init make(right_expr: AExpr, left_expr: AExpr)
275 do
276 self.init_aorexpr(right_expr,new TKwor,left_expr)
277 end
278 end
279
280 redef class AAndExpr
281 private init make(right_expr: AExpr, left_expr: AExpr)
282 do
283 self.init_aandexpr(right_expr,new TKwand ,left_expr)
284 end
285 end
286
287 redef class AMethPropdef
288 private init make(n_visibility: nullable AVisibility,
289 tk_redef: nullable TKwredef,
290 mmethoddef: nullable MMethodDef,
291 n_signature: nullable ASignature,
292 n_annotations: nullable AAnnotations,
293 n_extern_calls: nullable AExternCalls,
294 n_extern_code_block: nullable AExternCodeBlock,
295 n_block: nullable AExpr)
296 do
297 var n_tid = new TId
298 var n_methid = new AIdMethid.init_aidmethid(n_tid)
299 if n_signature == null then n_signature = new ASignature
300 if n_visibility == null then n_visibility = new APublicVisibility
301 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)
302
303 if mmethoddef != null then
304 self.n_methid.as(AIdMethid).n_id.text = mmethoddef.name
305 self.mpropdef = mmethoddef
306 end
307 end
308 end
309
310 redef class AAssertExpr
311 private init make(n_id : nullable TId , n_expr : nullable AExpr , n_else : nullable AExpr)
312 do
313 n_kwassert = new TKwassert
314 n_kwelse = null
315 if n_else != null then n_kwelse = new TKwelse
316 self.init_aassertexpr(n_kwassert, n_id , n_expr , n_kwelse , n_else)
317 end
318 end
319
320 redef class ABlockExpr
321 private init make
322 do
323 self.is_typed = true
324 end
325
326 redef fun add(expr)
327 do
328 n_expr.add expr
329 end
330 end
331
332 redef class ALoopExpr
333 private init make
334 do
335 _n_kwloop = new TKwloop
336 self.is_typed = true
337 n_block = new ABlockExpr
338 n_block.is_typed = true
339 end
340
341 redef fun add(expr)
342 do
343 n_block.add expr
344 end
345 end
346
347 redef class ADoExpr
348 private init make
349 do
350 _n_kwdo = new TKwdo
351 self.is_typed = true
352 n_block = new ABlockExpr
353 n_block.is_typed = true
354 end
355
356 # Make a new break expression of the given do
357 fun make_break: ABreakExpr
358 do
359 var escapemark = self.break_mark
360 if escapemark == null then
361 escapemark = new EscapeMark(null)
362 self.break_mark = escapemark
363 end
364 return new ABreakExpr.make(escapemark)
365 end
366
367 redef fun add(expr)
368 do
369 n_block.add expr
370 end
371 end
372
373 redef class ABreakExpr
374 private init make(escapemark: EscapeMark)
375 do
376 _n_kwbreak = new TKwbreak
377 self.escapemark = escapemark
378 escapemark.escapes.add self
379 self.is_typed = true
380 end
381 end
382
383 redef class AIfExpr
384 private init make(condition: AExpr, mtype: nullable MType)
385 do
386 _n_kwif = new TKwif
387 _n_expr = condition
388 _n_expr.parent = self
389 _n_kwthen = new TKwthen
390 _n_then = new ABlockExpr.make
391 _n_kwelse = new TKwelse
392 _n_else = new ABlockExpr.make
393 self.mtype = mtype
394 self.is_typed = true
395 end
396 end
397
398 redef class AType
399 private init make
400 do
401 var n_id = new TClassid
402 var n_qid = new AQclassid
403 n_qid.n_id = n_id
404 _n_qid = n_qid
405 end
406 end
407
408 redef class AIntegerExpr
409 private init make(value: Int, t: MType)
410 do
411 self.value = value
412 self._n_integer = new TInteger # dummy
413 self.mtype = t
414 end
415 end
416
417 redef class ANewExpr
418 private init make(callsite: CallSite, args: nullable Array[AExpr])
419 do
420 _n_kwnew = new TKwnew
421 _n_type = new AType.make
422 _n_args = new AListExprs
423 if args != null then
424 n_args.n_exprs.add_all(args)
425 end
426 self.callsite = callsite
427 self.recvtype = callsite.recv.as(MClassType)
428 if callsite.mproperty.is_new then
429 self.mtype = callsite.msignature.return_mtype
430 else
431 self.mtype = callsite.recv
432 end
433 self.is_typed = true
434 end
435 end
436
437 redef class ACallExpr
438 private init make(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr])
439 do
440 self._n_expr = recv
441 _n_args = new AListExprs
442 _n_qid = new AQid
443 _n_qid.n_id = new TId
444 _n_qid.n_id.text = callsite.mproperty.name
445 if args != null then
446 self.n_args.n_exprs.add_all(args)
447 end
448 self.callsite = callsite
449 self.mtype = callsite.msignature.return_mtype
450 self.is_typed = true
451 end
452 end
453
454 redef class AAttrExpr
455 private init make(recv: AExpr, attribute: MAttribute, t: MType)
456 do
457 _n_expr = recv
458 recv.parent = self
459 _n_id = new TAttrid
460 mproperty = attribute
461 mtype = t
462 end
463 end
464
465 redef class AAttrAssignExpr
466 private init make(recv: AExpr, attribute: MAttribute, value: AExpr)
467 do
468 _n_expr = recv
469 recv.parent = self
470 _n_id = new TAttrid
471 _n_value = value
472 value.parent = self
473 _n_assign = new TAssign
474 mproperty = attribute
475 mtype = value.mtype
476 end
477 end
478
479 redef class AVarExpr
480 private init make(v: Variable, mtype: MType)
481 do
482 _n_id = new TId
483 variable = v
484 self.mtype = mtype
485 end
486 end
487
488 redef class AVarAssignExpr
489 private init make(v: Variable, value: AExpr)
490 do
491 _n_id = new TId
492 _n_value = value
493 value.parent = self
494 _n_assign = new TAssign
495 variable = v
496 mtype = value.mtype
497 end
498 end
499
500 # Check the consitency of AST
501 class ASTValidationVisitor
502 super Visitor
503 redef fun visit(node)
504 do
505 node.accept_ast_validation(self)
506 end
507 private var path = new CircularArray[ANode]
508 private var seen = new HashSet[ANode]
509 end
510
511 redef class ANode
512 # Recursively validate a AST node.
513 # This ensure that location and parenting are defined and coherent.
514 #
515 # After complex low-level AST manipulation and construction,
516 # it is recommended to call it.
517 #
518 # Note: this just instantiate and run an `ASTValidationVisitor`.
519 fun validate
520 do
521 (new ASTValidationVisitor).enter_visit(self)
522 end
523
524 private fun accept_ast_validation(v: ASTValidationVisitor)
525 do
526 var parent = self.parent
527 var path = v.path
528
529 if path.length > 0 then
530 var path_parent = v.path.first
531 if parent == null then
532 self.parent = path_parent
533 #debug "PARENT: expected parent: {path_parent}"
534 v.seen.add(self)
535 else if parent != path_parent then
536 self.parent = path_parent
537 if v.seen.has(self) then
538 debug "DUPLICATE (NOTATREE): already seen node with parent {parent} now with {path_parent}."
539 else
540 v.seen.add(self)
541 debug "PARENT: expected parent: {path_parent}, got {parent}"
542 end
543 end
544 end
545
546 if not isset _location then
547 #debug "LOCATION: unlocated node {v.path.join(", ")}"
548 _location = self.parent.location
549 end
550
551 path.unshift(self)
552 visit_all(v)
553 path.shift
554 end
555 end
556
557 redef class AAnnotation
558 redef fun accept_ast_validation(v)
559 do
560 # Do not enter in annotations
561 end
562 end