Rename REAMDE to README.md
[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 semantize::literal
20 intrude import semantize::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 stufs
27 var mmodule: MModule
28
29 # The anchor used for some mechanism relying on types
30 var anchor: nullable MClassType
31
32 # Make a new Int literal
33 fun make_int(value: Int): AIntExpr
34 do
35 return new ADecIntExpr.make(value, mmodule.int_type)
36 end
37
38 # Make a new instatiation
39 fun make_new(callsite: CallSite, args: nullable Array[AExpr]): ANewExpr
40 do
41 return new ANewExpr.make(callsite, args)
42 end
43
44 # Make a new message send
45 fun make_call(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr]): ACallExpr
46 do
47 return new ACallExpr.make(recv, callsite, args)
48 end
49
50 # Make a new, empty, sequence of statements
51 fun make_block: ABlockExpr
52 do
53 return new ABlockExpr.make
54 end
55
56 # Make a new, empty, loop of statements
57 fun make_loop: ALoopExpr
58 do
59 return new ALoopExpr.make
60 end
61
62 # Make a new variable read
63 fun make_var_read(variable: Variable, mtype: MType): AVarExpr
64 do
65 return new AVarExpr.make(variable, mtype)
66 end
67
68 # Make a new variable assignment
69 fun make_var_assign(variable: Variable, value: AExpr): AVarAssignExpr
70 do
71 return new AVarAssignExpr.make(variable, value)
72 end
73
74 # Make a new attribute read
75 fun make_attr_read(recv: AExpr, attribute: MAttribute): AAttrExpr
76 do
77 var mtype = attribute.intro.static_mtype.resolve_for(recv.mtype.as(not null), anchor, mmodule, true)
78 return new AAttrExpr.make(recv, attribute, mtype)
79 end
80
81 # Make a new attribute assignment
82 fun make_attr_assign(recv: AExpr, attribute: MAttribute, value: AExpr): AAttrAssignExpr
83 do
84 return new AAttrAssignExpr.make(recv, attribute, value)
85 end
86
87 # Make a new escapable block
88 fun make_do: ADoExpr
89 do
90 return new ADoExpr.make
91 end
92
93 # Make a new break for a given escapemark
94 fun make_break(escapemark: EscapeMark): ABreakExpr
95 do
96 return new ABreakExpr.make(escapemark)
97 end
98
99 # Make a new condinionnal
100 # `mtype` is the return type of the whole if, in case of a ternary operator.
101 fun make_if(condition: AExpr, mtype: nullable MType): AIfExpr
102 do
103 return new AIfExpr.make(condition, mtype)
104 end
105 end
106
107 redef class AExpr
108 # Return a new variable read that contains the value of the expression
109 # This method take care efficiently of creating and initalising an anonymous local variable
110 #
111 # Note: since this method do side-effects (AST replacement), there could be unexpected effects when used as
112 # argument of other methods related to AST transformations.
113 fun make_var_read: AVarExpr
114 do
115 var variable = self.variable_cache
116 if variable == null then
117 assert parent != null
118 var place = detach_with_placeholder
119 variable = new Variable("")
120 variable.declared_type = self.mtype
121 var nvar = new AVarAssignExpr.make(variable, self)
122 place.replace_with(nvar)
123 self.variable_cache = variable
124 end
125 return new AVarExpr.make(variable, variable.declared_type.as(not null))
126 end
127
128 private var variable_cache: nullable Variable
129
130 # The `detach` method completely remove the node in the parent.
131 # Owever, sometime, it is useful to keep the emplacement of the removed child.
132 #
133 # The standard usecase is the insertion of a node beetwen a parent `p` and a child `p.c`.
134 # To create the new node `n`, we need to attach the child to it.
135 # But, to put `n` where `c` was in `p`, the place has to be remembered.
136 #
137 # ~~~nitish
138 # var p: AExpr
139 # var c = p.c
140 # var h = c.detach_with_placeholder
141 # var n = astbuilder.make_XXX(c)
142 # h.replace_with(n)
143 # ~~~
144 fun detach_with_placeholder: AExpr
145 do
146 var h = new APlaceholderExpr.make
147 self.replace_with(h)
148 return h
149 end
150
151
152 # Add `expr` at the end of the block
153 #
154 # REQUIRE: self isa ABlockExpr
155 #
156 # Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
157 fun add(expr: AExpr)
158 do
159 print "add not implemented in {inspect}"
160 abort
161 end
162 end
163
164 # A placeholder for a `AExpr` node
165 # Instances are transiantly used to mark some specific emplacments in the AST
166 # during complex transformations.
167 #
168 # Their must not appear in a valid AST
169 #
170 # @see AExpr::detach_with_placeholder
171 class APlaceholderExpr
172 super AExpr
173 private init make
174 do
175 end
176 end
177
178 redef class ABlockExpr
179 private init make
180 do
181 self.is_typed = true
182 end
183
184 redef fun add(expr: AExpr)
185 do
186 n_expr.add expr
187 end
188 end
189
190 redef class ALoopExpr
191 private init make
192 do
193 _n_kwloop = new TKwloop
194 self.is_typed = true
195 n_block = new ABlockExpr
196 n_block.is_typed = true
197 end
198
199 redef fun add(expr: AExpr)
200 do
201 n_block.add expr
202 end
203 end
204
205 redef class ADoExpr
206 private init make
207 do
208 _n_kwdo = new TKwdo
209 self.is_typed = true
210 n_block = new ABlockExpr
211 n_block.is_typed = true
212 end
213
214 # Make a new break expression of the given do
215 fun make_break: ABreakExpr
216 do
217 var escapemark = self.break_mark
218 if escapemark == null then
219 escapemark = new EscapeMark(null)
220 self.break_mark = escapemark
221 end
222 return new ABreakExpr.make(escapemark)
223 end
224
225 redef fun add(expr: AExpr)
226 do
227 n_block.add expr
228 end
229 end
230
231 redef class ABreakExpr
232 private init make(escapemark: EscapeMark)
233 do
234 _n_kwbreak = new TKwbreak
235 self.escapemark = escapemark
236 escapemark.escapes.add self
237 self.is_typed = true
238 end
239 end
240
241 redef class AIfExpr
242 private init make(condition: AExpr, mtype: nullable MType)
243 do
244 _n_kwif = new TKwif
245 _n_expr = condition
246 _n_expr.parent = self
247 _n_kwthen = new TKwthen
248 _n_then = new ABlockExpr.make
249 _n_kwelse = new TKwelse
250 _n_else = new ABlockExpr.make
251 self.mtype = mtype
252 self.is_typed = true
253 end
254 end
255
256 redef class AType
257 private init make
258 do
259 _n_id = new TClassid
260 end
261 end
262
263 redef class ADecIntExpr
264 private init make(value: Int, t: MType)
265 do
266 self.value = value
267 self._n_number = new TNumber # dummy
268 self.mtype = t
269 end
270 end
271
272 redef class ANewExpr
273 private init make(callsite: CallSite, args: nullable Array[AExpr])
274 do
275 _n_kwnew = new TKwnew
276 _n_type = new AType.make
277 _n_args = new AListExprs
278 if args != null then
279 n_args.n_exprs.add_all(args)
280 end
281 self.callsite = callsite
282 self.recvtype = callsite.recv.as(MClassType)
283 if callsite.mproperty.is_new then
284 self.mtype = callsite.msignature.return_mtype
285 else
286 self.mtype = callsite.recv
287 end
288 self.is_typed = true
289 end
290 end
291
292 redef class ACallExpr
293 private init make(recv: AExpr, callsite: CallSite, args: nullable Array[AExpr])
294 do
295 self._n_expr = recv
296 _n_args = new AListExprs
297 _n_id = new TId
298 if args != null then
299 self.n_args.n_exprs.add_all(args)
300 end
301 self.callsite = callsite
302 self.mtype = callsite.msignature.return_mtype
303 self.is_typed = true
304 end
305 end
306
307 redef class AAttrExpr
308 private init make(recv: AExpr, attribute: MAttribute, t: MType)
309 do
310 _n_expr = recv
311 recv.parent = self
312 _n_id = new TAttrid
313 mproperty = attribute
314 mtype = t
315 end
316 end
317
318 redef class AAttrAssignExpr
319 private init make(recv: AExpr, attribute: MAttribute, value: AExpr)
320 do
321 _n_expr = recv
322 recv.parent = self
323 _n_id = new TAttrid
324 _n_value = value
325 value.parent = self
326 _n_assign = new TAssign
327 mproperty = attribute
328 mtype = value.mtype
329 end
330 end
331
332 redef class AVarExpr
333 private init make(v: Variable, mtype: MType)
334 do
335 _n_id = new TId
336 variable = v
337 self.mtype = mtype
338 end
339 end
340
341 redef class AVarAssignExpr
342 private init make(v: Variable, value: AExpr)
343 do
344 _n_id = new TId
345 _n_value = value
346 value.parent = self
347 _n_assign = new TAssign
348 variable = v
349 mtype = value.mtype
350 end
351 end
352