fb4a801f59827644a788e8a40d7f2823fa61fa69
[nit.git] / src / syntax / icode_generation.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2009 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Things needed by typing.nit to generate intermediate code from AST
18 package icode_generation
19
20 import icode
21 import syntax_base
22 private import typing
23 private import primitive_info
24
25 # An AST2ICode context stores the currently built icode informations
26 class A2IContext
27 special ICodeBuilder
28 redef fun stmt(s: ICode)
29 do
30 if _current_node != null then
31 current_location = _current_node.location
32 else if visitor.current_node != null then
33 current_location = visitor.current_node.location
34 end
35 super
36 end
37
38 # Prepare a new array of length item
39 fun add_new_array(stype: MMType, length: Int): IRegister
40 do
41 var prop = visitor.get_method(stype, once "with_capacity".to_symbol)
42 var ni = expr(new INative("TAG_Int({length})", null), visitor.type_int)
43 return expr(new INew(stype, prop, [ni]), stype)
44 end
45
46 # Add an array add
47 fun add_call_array_add(recv, item: IRegister)
48 do
49 var stype = recv.stype
50 var prop = visitor.get_method(stype, once "add".to_symbol)
51 stmt(new ICall(prop, [recv, item]))
52 end
53
54 # Get the iregister associated with a variable
55 # Or assign one if none exists
56 fun variable(v: Variable): IRegister
57 do
58 if _variables.has_key(v) then
59 return _variables[v]
60 else
61 var t = v.stype
62 if t == null then t = visitor.type_object.as_nullable
63 var reg = new_register(t)
64 _variables[v] = reg
65 return reg
66 end
67 end
68
69 # Current registered variable
70 var _variables: HashMap[Variable, IRegister] = new HashMap[Variable, IRegister]
71
72 # Current registered closurevariables
73 readable var _closurevariables: HashMap[ClosureVariable, IClosureDecl] = new HashMap[ClosureVariable, IClosureDecl]
74
75 # The current syntax visitor
76 readable var _visitor: AbsSyntaxVisitor
77
78 # Where a nit return must branch
79 readable writable var _return_seq: nullable ISeq
80
81 # Register where a functionnal nit return must store its value
82 readable writable var _return_value: nullable IRegister
83
84 # The method associated to the iroutine (if any)
85 readable var _method: nullable MMMethod
86
87 init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod)
88 do
89 super(visitor.module, r)
90 _visitor = visitor
91 _return_seq = r.body
92 _return_value = r.result
93 _method = m
94 end
95
96 # Insert implicit super init calls
97 fun invoke_super_init_calls_after(start_prop: nullable MMMethod)
98 do
99 var p = method
100 assert p isa MMSrcMethod
101 var n = p.node
102 assert n isa AConcreteInitPropdef
103
104 if n.super_init_calls.is_empty then return
105 var i = 0
106 var j = 0
107 if start_prop != null then
108 while n.super_init_calls[i] != start_prop do
109 i += 1
110 end
111 i += 1
112
113 while n.explicit_super_init_calls[j] != start_prop do
114 j += 1
115 end
116 j += 1
117 end
118 var stop_prop: nullable MMMethod = null
119 if j < n.explicit_super_init_calls.length then
120 stop_prop = n.explicit_super_init_calls[j]
121 end
122 var l = n.super_init_calls.length
123 while i < l do
124 var sp = n.super_init_calls[i]
125 if sp == stop_prop then break
126 var cargs = new Array[IRegister]
127 if sp.signature.arity == 0 then
128 cargs.add(iroutine.params.first)
129 else
130 for va in iroutine.params do
131 cargs.add(va)
132 end
133 end
134 stmt(new ICall(sp, cargs))
135 i += 1
136 end
137 end
138
139 # The current AExpr
140 var _current_node: nullable AExpr = null
141
142 # Generate icode in the current sequence from a statement
143 fun generate_stmt(n: nullable AExpr)
144 do
145 if n == null then return
146 var old = _current_node
147 _current_node = n
148 n.generate_icode(self)
149 _current_node = old
150 end
151
152 # Generate icode in the current sequence from an expression
153 fun generate_expr(n: AExpr): IRegister
154 do
155 var old = _current_node
156 _current_node = n
157 var reg = n.generate_icode(self).as(not null)
158 _current_node = old
159 return reg
160 end
161 end
162
163 redef class EscapableBlock
164 # Where a nit break must branch
165 readable writable var _break_seq: nullable ISeq
166
167 # Where a nit continue must branch
168 readable writable var _continue_seq: nullable ISeq
169
170 # Register where a functionnal nit break must store its value
171 readable writable var _break_value: nullable IRegister
172
173 # Register where a functionnal nit continue must store its value
174 readable writable var _continue_value: nullable IRegister
175 end
176
177 redef class MMSrcModule
178 # Generate icode for method bodies
179 fun generate_icode(tc: ToolContext)
180 do
181 var v = new A2IVisitor(tc, self)
182 for c in src_local_classes do
183 for p in c.src_local_properties do
184 if p isa MMSrcMethod then
185 p.generate_iroutine(v)
186 else if p isa MMSrcAttribute then
187 p.generate_iroutine(v)
188 end
189 end
190 end
191 end
192 end
193
194 redef class MMSrcAttribute
195 redef readable writable var _iroutine: nullable IRoutine
196
197 # Generate the initialization iroutine
198 fun generate_iroutine(visitor: A2IVisitor)
199 do
200 if node.n_expr != null then
201 var iroutine = signature.generate_empty_iroutine
202 iroutine.location = node.location
203 var v = new A2IContext(visitor, iroutine, null)
204 visitor.icode_ctx = v
205 visitor.enter_visit(node)
206 visitor.icode_ctx = null
207 _iroutine = iroutine
208 end
209 end
210 end
211
212 redef class MMSrcMethod
213 redef readable writable var _iroutine: nullable IRoutine
214
215 # Generate the body iroutine
216 fun generate_iroutine(visitor: A2IVisitor)
217 do
218 var iroutine = signature.generate_empty_iroutine
219 if node != null then
220 iroutine.location = node.location
221 end
222 var v = new A2IContext(visitor, iroutine, self)
223 visitor.icode_ctx = v
224 inner_generate_iroutine(v)
225 visitor.icode_ctx = null
226 _iroutine = iroutine
227 end
228
229 # Generate the body iroutine (specific part)
230 fun inner_generate_iroutine(v: A2IContext) is abstract
231 end
232
233 redef class MMReadImplementationMethod
234 redef fun inner_generate_iroutine(v)
235 do
236 var e = v.add_attr_read(node.prop, v.iroutine.params.first)
237 v.add_return_value(e)
238 end
239 end
240
241 redef class MMWriteImplementationMethod
242 redef fun inner_generate_iroutine(v)
243 do
244 var params = v.iroutine.params
245 v.stmt(new IAttrWrite(node.prop, params[0], params[1]))
246 end
247 end
248
249 redef class MMMethSrcMethod
250 redef fun inner_generate_iroutine(v)
251 do
252 v.visitor.enter_visit(node)
253 end
254 end
255
256 redef class MMImplicitInit
257 redef fun inner_generate_iroutine(v)
258 do
259 var params = v.iroutine.params
260 var f = params.length - unassigned_attributes.length
261 var recv = params.first
262 for sp in super_inits do
263 assert sp isa MMMethod
264 var args_recv = [recv]
265 if sp == super_init then
266 var args = new Array[IRegister].with_capacity(f)
267 args.add(recv)
268 for i in [1..f[ do
269 args.add(params[i])
270 end
271 v.stmt(new ICall(sp, args))
272 else
273 v.stmt(new ICall(sp, args_recv))
274 end
275 end
276 for i in [f..params.length[ do
277 var attribute = unassigned_attributes[i-f]
278 v.stmt(new IAttrWrite(attribute, recv, params[i]))
279 end
280 end
281 end
282
283 class A2IVisitor
284 special AbsSyntaxVisitor
285 writable var _icode_ctx: nullable A2IContext
286 fun icode_ctx: A2IContext do return _icode_ctx.as(not null)
287 redef fun visit(n) do n.accept_icode_generation(self)
288 init(tc, m) do super
289 end
290
291
292 ###############################################################################
293
294 redef class ANode
295 fun accept_icode_generation(v: A2IVisitor) do accept_abs_syntax_visitor(v) end
296 end
297
298 redef class AAttrPropdef
299 redef fun accept_icode_generation(vv)
300 do
301 var v = vv.icode_ctx
302 v.stmt(new IMove(v.variable(self_var), v.iroutine.params.first))
303 super
304 var ne = n_expr
305 if ne != null then
306 v.stmt(new IMove(v.iroutine.result.as(not null), v.generate_expr(ne)))
307 end
308 end
309 end
310
311 redef class AMethPropdef
312 redef fun accept_icode_generation(vv)
313 do
314 super
315 fill_iroutine(vv.icode_ctx, method)
316 end
317
318 # Compile the method body common preambule (before specific body stuff if any)
319 fun fill_iroutine(v: A2IContext, method: MMSrcMethod) is abstract
320 end
321
322 redef class ASignature
323 fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: Sequence[IRegister], closdecls: nullable Sequence[IClosureDecl])
324 do
325 for ap in n_params do
326 var reg = v.variable(ap.variable)
327 var orig_type = orig_sig[ap.position]
328 var apst = ap.variable.stype.as(not null)
329 if not orig_type < apst then
330 v.add_type_cast(params[ap.position], apst)
331 end
332 v.stmt(new IMove(reg, params[ap.position]))
333 end
334 for i in [0..n_closure_decls.length[ do
335 var wd = n_closure_decls[i]
336 v.closurevariables[wd.variable] = closdecls[i]
337 end
338 end
339 end
340
341 redef class AClosureDecl
342 redef fun accept_icode_generation(vv)
343 do
344 var v = vv.icode_ctx
345 var iclos = variable.closure.signature.generate_empty_iclosuredef(v)
346 var old_seq = v.seq
347 v.seq = iclos.body
348 escapable.continue_seq = iclos.body
349 escapable.continue_value = iclos.result
350 n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null)
351
352 if n_expr != null then
353 v.generate_stmt(n_expr)
354 v.iroutine.closure_decls[position].default = iclos
355 end
356 v.seq = old_seq
357 end
358 end
359
360 redef class AConcreteMethPropdef
361 redef fun fill_iroutine(v, method)
362 do
363 var params = v.iroutine.params.to_a
364 var selfreg = v.variable(self_var)
365 v.stmt(new IMove(selfreg, params[0]))
366 params.shift
367
368 var orig_meth: MMLocalProperty = method.global.intro
369 var orig_sig = orig_meth.signature_for(method.signature.recv)
370 if n_signature != null then
371 n_signature.fill_iroutine_parameters(v, orig_sig, params, v.iroutine.closure_decls)
372 end
373
374 if self isa AConcreteInitPropdef then
375 v.invoke_super_init_calls_after(null)
376 end
377
378 if n_block != null then
379 v.generate_stmt(n_block)
380 end
381 end
382 end
383
384 redef class ADeferredMethPropdef
385 redef fun fill_iroutine(v, method)
386 do
387 v.add_abort("Deferred method called")
388 end
389 end
390
391 redef class AExternMethPropdef
392 redef fun fill_iroutine(v, method)
393 do
394 var params = v.iroutine.params
395 var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
396 if n_extern != null then
397 ename = n_extern.text
398 ename = ename.substring(1, ename.length-2)
399 end
400 var sig = method.signature
401 assert params.length == sig.arity + 1
402 var args = new Array[String]
403 args.add(sig.recv.unboxtype("@@@"))
404 for i in [0..sig.arity[ do
405 args.add(sig[i].unboxtype("@@@"))
406 end
407 var s = "{ename}({args.join(", ")})"
408 var rtype = sig.return_type
409 if rtype != null then
410 s = rtype.boxtype(s)
411 v.add_return_value(v.expr(new INative(s, params), rtype))
412 else
413 v.stmt(new INative(s, params))
414 end
415 end
416 end
417
418 redef class AInternMethPropdef
419 redef fun fill_iroutine(v, method)
420 do
421 var p = v.iroutine.params.to_a
422 var c = method.local_class.name
423 var n = method.name
424 var s: nullable String = null
425 if c == once "Int".to_symbol then
426 if n == once "object_id".to_symbol then
427 s = "@@@"
428 else if n == once "unary -".to_symbol then
429 s = "TAG_Int(-UNTAG_Int(@@@))"
430 else if n == once "output".to_symbol then
431 s = "printf(\"%ld\\n\", UNTAG_Int(@@@));"
432 else if n == once "ascii".to_symbol then
433 s = "TAG_Char(UNTAG_Int(@@@))"
434 else if n == once "succ".to_symbol then
435 s = "TAG_Int(UNTAG_Int(@@@)+1)"
436 else if n == once "prec".to_symbol then
437 s = "TAG_Int(UNTAG_Int(@@@)-1)"
438 else if n == once "to_f".to_symbol then
439 s = "BOX_Float((float)UNTAG_Int(@@@))"
440 else if n == once "+".to_symbol then
441 s = "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))"
442 else if n == once "-".to_symbol then
443 s = "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))"
444 else if n == once "*".to_symbol then
445 s = "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))"
446 else if n == once "/".to_symbol then
447 s = "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
448 else if n == once "%".to_symbol then
449 s = "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))"
450 else if n == once "<".to_symbol then
451 s = "TAG_Bool(UNTAG_Int(@@@)<UNTAG_Int(@@@))"
452 else if n == once ">".to_symbol then
453 s = "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))"
454 else if n == once "<=".to_symbol then
455 s = "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
456 else if n == once ">=".to_symbol then
457 s = "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
458 else if n == once "lshift".to_symbol then
459 s = "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
460 else if n == once "rshift".to_symbol then
461 s = "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
462 else if n == once "==".to_symbol then
463 s = "TAG_Bool((@@@)==(@@@))"
464 else if n == once "!=".to_symbol then
465 s = "TAG_Bool((@@@)!=(@@@))"
466 end
467 else if c == once "Float".to_symbol then
468 if n == once "object_id".to_symbol then
469 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
470 else if n == once "unary -".to_symbol then
471 s = "BOX_Float(-UNBOX_Float(@@@))"
472 else if n == once "output".to_symbol then
473 s = "printf(\"%f\\n\", UNBOX_Float(@@@));"
474 else if n == once "to_i".to_symbol then
475 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
476 else if n == once "+".to_symbol then
477 s = "BOX_Float(UNBOX_Float(@@@)+UNBOX_Float(@@@))"
478 else if n == once "-".to_symbol then
479 s = "BOX_Float(UNBOX_Float(@@@)-UNBOX_Float(@@@))"
480 else if n == once "*".to_symbol then
481 s = "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
482 else if n == once "/".to_symbol then
483 s = "BOX_Float(UNBOX_Float(@@@)/UNBOX_Float(@@@))"
484 else if n == once "<".to_symbol then
485 s = "TAG_Bool(UNBOX_Float(@@@)<UNBOX_Float(@@@))"
486 else if n == once ">".to_symbol then
487 s = "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))"
488 else if n == once "<=".to_symbol then
489 s = "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
490 else if n == once ">=".to_symbol then
491 s = "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
492 end
493 else if c == once "Char".to_symbol then
494 if n == once "object_id".to_symbol then
495 s = "TAG_Int(UNTAG_Char(@@@))"
496 else if n == once "unary -".to_symbol then
497 s = "TAG_Char(-UNTAG_Char(@@@))"
498 else if n == once "output".to_symbol then
499 s = "printf(\"%c\", (unsigned char)UNTAG_Char(@@@));"
500 else if n == once "ascii".to_symbol then
501 s = "TAG_Int((unsigned char)UNTAG_Char(@@@))"
502 else if n == once "succ".to_symbol then
503 s = "TAG_Char(UNTAG_Char(@@@)+1)"
504 else if n == once "prec".to_symbol then
505 s = "TAG_Char(UNTAG_Char(@@@)-1)"
506 else if n == once "to_i".to_symbol then
507 s = "TAG_Int(UNTAG_Char(@@@)-'0')"
508 else if n == once "+".to_symbol then
509 s = "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))"
510 else if n == once "-".to_symbol then
511 s = "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))"
512 else if n == once "*".to_symbol then
513 s = "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))"
514 else if n == once "/".to_symbol then
515 s = "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
516 else if n == once "%".to_symbol then
517 s = "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))"
518 else if n == once "<".to_symbol then
519 s = "TAG_Bool(UNTAG_Char(@@@)<UNTAG_Char(@@@))"
520 else if n == once ">".to_symbol then
521 s = "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))"
522 else if n == once "<=".to_symbol then
523 s = "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
524 else if n == once ">=".to_symbol then
525 s = "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
526 else if n == once "==".to_symbol then
527 s = "TAG_Bool((@@@)==(@@@))"
528 else if n == once "!=".to_symbol then
529 s = "TAG_Bool((@@@)!=(@@@))"
530 end
531 else if c == once "Bool".to_symbol then
532 if n == once "object_id".to_symbol then
533 s = "TAG_Int(UNTAG_Bool(@@@))"
534 else if n == once "unary -".to_symbol then
535 s = "TAG_Bool(-UNTAG_Bool(@@@))"
536 else if n == once "output".to_symbol then
537 s = "(void)printf(UNTAG_Bool(@@@)?\"true\\n\":\"false\\n\");"
538 else if n == once "ascii".to_symbol then
539 s = "TAG_Bool(UNTAG_Bool(@@@))"
540 else if n == once "to_i".to_symbol then
541 s = "TAG_Int(UNTAG_Bool(@@@))"
542 else if n == once "==".to_symbol then
543 s = "TAG_Bool((@@@)==(@@@))"
544 else if n == once "!=".to_symbol then
545 s = "TAG_Bool((@@@)!=(@@@))"
546 end
547 else if c == once "NativeArray".to_symbol then
548 if n == once "object_id".to_symbol then
549 s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
550 else if n == once "[]".to_symbol then
551 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
552 else if n == once "[]=".to_symbol then
553 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
554 else if n == once "copy_to".to_symbol then
555 var t = p[0]
556 p[0] = p[1]
557 p[1] = t
558 s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
559 end
560 else if c == once "NativeString".to_symbol then
561 if n == once "object_id".to_symbol then
562 s = "TAG_Int(UNBOX_NativeString(@@@))"
563 else if n == once "atoi".to_symbol then
564 s = "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
565 else if n == once "[]".to_symbol then
566 s = "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
567 else if n == once "[]=".to_symbol then
568 s = "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
569 else if n == once "copy_to".to_symbol then
570 var t = p[0]
571 p[0] = p[1]
572 p[1] = p[4]
573 p[4] = p[2]
574 p[2] = t
575 s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
576 end
577 else if n == once "object_id".to_symbol then
578 s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
579 else if n == once "sys".to_symbol then
580 s = "(G_sys)"
581 else if n == once "is_same_type".to_symbol then
582 s = "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
583 else if n == once "exit".to_symbol then
584 p[0] = p[1]
585 s = "exit(UNTAG_Int(@@@));"
586 else if n == once "calloc_array".to_symbol then
587 p[0] = p[1]
588 s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
589 else if n == once "calloc_string".to_symbol then
590 p[0] = p[1]
591 s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
592 end
593 if s == null then
594 v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
595 s = "NIT_NULL"
596 end
597 var rtype = method.signature.return_type
598 if rtype != null then
599 v.add_return_value(v.expr(new INative(s, p), rtype))
600 else
601 v.stmt(new INative(s, p))
602 end
603 end
604 end
605
606 ###############################################################################
607
608 redef class AExpr
609 redef fun accept_icode_generation(v) do end
610
611 # Generate icode sequence in the current A2IContext
612 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
613 protected fun generate_icode(v: A2IContext): nullable IRegister is abstract
614 end
615
616 redef class AVardeclExpr
617 redef fun generate_icode(v)
618 do
619 var reg = v.variable(variable)
620 var ne = n_expr
621 if ne != null then
622 v.add_assignment(reg, v.generate_expr(ne))
623 end
624 return null
625 end
626 end
627
628 redef class ABlockExpr
629 redef fun generate_icode(v)
630 do
631 for ne in n_expr do v.generate_stmt(ne)
632 return null
633 end
634 end
635
636 redef class ADoExpr
637 redef fun generate_icode(v)
638 do
639 var seq_old = v.seq
640 var seq = new ISeq
641 v.stmt(seq)
642 escapable.break_seq = seq
643 v.seq = seq
644
645 v.generate_stmt(n_block)
646
647 v.seq = seq_old
648 return null
649 end
650 end
651
652 redef class AReturnExpr
653 redef fun generate_icode(v)
654 do
655 var ne = n_expr
656 if ne != null then
657 v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
658 end
659 v.stmt(new IEscape(v.return_seq.as(not null)))
660 return null
661 end
662 end
663
664 redef class ABreakExpr
665 redef fun generate_icode(v)
666 do
667 var ne = n_expr
668 if ne != null then
669 v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
670 end
671 v.stmt(new IEscape(escapable.break_seq.as(not null)))
672 return null
673 end
674 end
675
676 redef class AContinueExpr
677 redef fun generate_icode(v)
678 do
679 var ne = n_expr
680 if ne != null then
681 v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
682 end
683 v.stmt(new IEscape(escapable.continue_seq.as(not null)))
684 return null
685 end
686 end
687
688 redef class AAbortExpr
689 redef fun generate_icode(v)
690 do
691 v.add_abort("Aborted")
692 return null
693 end
694 end
695
696 redef class AIfExpr
697 redef fun generate_icode(v)
698 do
699 var iif = new IIf(v.generate_expr(n_expr))
700 v.stmt(iif)
701 var seq_old = v.seq
702
703 if n_then != null then
704 v.seq = iif.then_seq
705 v.generate_stmt(n_then)
706 end
707
708 if n_else != null then
709 v.seq = iif.else_seq
710 v.generate_stmt(n_else)
711 end
712
713 v.seq = seq_old
714 return null
715 end
716 end
717
718 redef class AWhileExpr
719 redef fun generate_icode(v)
720 do
721 var seq_old = v.seq
722 var iloop = new ILoop
723 v.stmt(iloop)
724 escapable.break_seq = iloop
725 v.seq = iloop
726
727 # Process condition
728 var iif = new IIf(v.generate_expr(n_expr))
729 v.stmt(iif)
730
731 # Process inside (condition is true)
732 if n_block != null then
733 v.seq = iif.then_seq
734 escapable.continue_seq = iif.then_seq
735 v.generate_stmt(n_block)
736 end
737
738 # Process escape (condition is false)
739 v.seq = iif.else_seq
740 v.stmt(new IEscape(iloop))
741
742 v.seq = seq_old
743 return null
744 end
745 end
746
747 redef class ALoopExpr
748 redef fun generate_icode(v)
749 do
750 var seq_old = v.seq
751 var iloop = new ILoop
752 v.stmt(iloop)
753 escapable.break_seq = iloop
754 v.seq = iloop
755
756 # Process inside
757 if n_block != null then
758 var seq = new ISeq
759 v.stmt(seq)
760 v.seq = seq
761 escapable.continue_seq = seq
762 v.generate_stmt(n_block)
763 end
764
765 v.seq = seq_old
766 return null
767 end
768 end
769
770 redef class AForExpr
771 redef fun generate_icode(v)
772 do
773 var expr_type = n_expr.stype
774
775 # Get iterator
776 var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol)
777
778 var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null)
779 var ireg_iter = v.expr(new ICall(meth_iterator, [v.generate_expr(n_expr)]), iter_type)
780
781 # Enter loop
782 var seq_old = v.seq
783 var iloop = new ILoop
784 v.stmt(iloop)
785 escapable.break_seq = iloop
786 v.seq = iloop
787
788 # Condition evaluation
789 var meth_is_ok = v.visitor.get_method(iter_type, once ("is_ok".to_symbol))
790 var ireg_isok = v.expr(new ICall(meth_is_ok, [ireg_iter]), v.visitor.type_bool)
791 var iif = new IIf(ireg_isok)
792
793 # Process insite the loop (condition is true)
794 v.stmt(iif)
795 v.seq = iif.then_seq
796 escapable.continue_seq = iif.then_seq
797
798 # Automatic variable assignment
799 var meth_item = v.visitor.get_method(iter_type, once ("item".to_symbol))
800 var va_stype = variable.stype.as(not null)
801 var ireg_item = v.expr(new ICall(meth_item, [ireg_iter]), va_stype)
802 var ireg_va = v.variable(variable)
803 v.add_assignment(ireg_va, ireg_item)
804
805 # Body evaluation
806 v.generate_stmt(n_block)
807
808 # Exit contition (condition is false)
809 v.seq = iif.else_seq
810 v.stmt(new IEscape(iloop))
811
812 # Next step
813 var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol))
814 v.seq = iloop
815 v.stmt(new ICall(meth_next, [ireg_iter]))
816
817 v.seq = seq_old
818 return null
819 end
820 end
821
822 redef class AAssertExpr
823 redef fun generate_icode(v)
824 do
825 var e = v.generate_expr(n_expr)
826 var iif = new IIf(e)
827 v.stmt(iif)
828 var seq_old = v.seq
829 v.seq = iif.else_seq
830 v.generate_stmt(n_else)
831 var id = n_id
832 if id == null then
833 v.add_abort("Assert failed")
834 else
835 v.add_abort("Assert %s failed", id.to_s)
836 end
837 v.seq = seq_old
838 return null
839 end
840 end
841
842 redef class AVarExpr
843 redef fun generate_icode(v)
844 do
845 return v.variable(variable)
846 end
847 end
848
849 redef class AVarAssignExpr
850 redef fun generate_icode(v)
851 do
852 var e = v.generate_expr(n_value)
853 v.add_assignment(v.variable(variable), e)
854 return null
855 end
856 end
857
858 redef class AVarReassignExpr
859 redef fun generate_icode(v)
860 do
861 var e1 = v.variable(variable)
862 var e2 = v.generate_expr(n_value)
863 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
864 v.add_assignment(e1, e3)
865 return null
866 end
867 end
868
869 redef class ASelfExpr
870 redef fun generate_icode(v)
871 do
872 return v.variable(variable)
873 end
874 end
875
876 redef class AIfexprExpr
877 redef fun generate_icode(v)
878 do
879 # Process condition
880 var iif = new IIf(v.generate_expr(n_expr))
881 v.stmt(iif)
882 var seq_old = v.seq
883
884 # Prepare result
885 var reg = v.new_register(stype)
886
887 # Process 'then'
888 v.seq = iif.then_seq
889 v.add_assignment(reg, v.generate_expr(n_then))
890
891 # Process 'else'
892 v.seq = iif.else_seq
893 v.add_assignment(reg, v.generate_expr(n_else))
894
895 v.seq = seq_old
896 return reg
897 end
898 end
899
900 redef class AEeExpr
901 redef fun generate_icode(v)
902 do
903 var e = v.generate_expr(n_expr)
904 var e2 = v.generate_expr(n_expr2)
905 return v.expr(new IIs(e, e2), stype)
906 end
907 end
908
909 redef class AOrExpr
910 redef fun generate_icode(v)
911 do
912 # Prepare result
913 var reg = v.new_register(stype)
914
915 # Process left operand (in a if/then)
916 var iif = new IIf(v.generate_expr(n_expr))
917 v.stmt(iif)
918 var seq_old = v.seq
919 v.seq = iif.then_seq
920 v.add_assignment(reg, v.lit_true_reg)
921
922 # Process right operand (in the else)
923 v.seq = iif.else_seq
924 v.add_assignment(reg, v.generate_expr(n_expr2))
925
926 v.seq = seq_old
927 return reg
928 end
929 end
930
931 redef class AAndExpr
932 redef fun generate_icode(v)
933 do
934 # Prepare result
935 var reg = v.new_register(stype)
936
937 # Process left operand (in a if/else)
938 var iif = new IIf(v.generate_expr(n_expr))
939 v.stmt(iif)
940 var seq_old = v.seq
941 v.seq = iif.else_seq
942 v.add_assignment(reg, v.lit_false_reg)
943
944 # Process right operand (in the then)
945 v.seq = iif.then_seq
946 v.add_assignment(reg, v.generate_expr(n_expr2))
947
948 v.seq = seq_old
949 return reg
950 end
951 end
952
953 redef class ANotExpr
954 redef fun generate_icode(v)
955 do
956 var e = v.generate_expr(n_expr)
957 return v.expr(new INot(e), stype)
958 end
959 end
960
961 redef class AIsaExpr
962 redef fun generate_icode(v)
963 do
964 var e = v.generate_expr(n_expr)
965 return v.expr(new ITypeCheck(e, n_type.stype), stype)
966 end
967 end
968
969 redef class AAsCastExpr
970 redef fun generate_icode(v)
971 do
972 var e = v.generate_expr(n_expr)
973 v.add_type_cast(e, stype)
974 return e
975 end
976 end
977
978 redef class AAsNotnullExpr
979 redef fun generate_icode(v)
980 do
981 var e = v.generate_expr(n_expr)
982 v.add_type_cast(e, stype)
983 return e
984 end
985 end
986
987 redef class ATrueExpr
988 redef fun generate_icode(v)
989 do
990 return v.lit_true_reg
991 end
992 end
993
994 redef class AFalseExpr
995 redef fun generate_icode(v)
996 do
997 return v.lit_false_reg
998 end
999 end
1000
1001 redef class AIntExpr
1002 redef fun generate_icode(v)
1003 do
1004 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
1005 end
1006 end
1007
1008 redef class AFloatExpr
1009 redef fun generate_icode(v)
1010 do
1011 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
1012 end
1013 end
1014
1015 redef class ACharExpr
1016 redef fun generate_icode(v)
1017 do
1018 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
1019 end
1020 end
1021
1022 redef class AStringFormExpr
1023 redef fun generate_icode(v)
1024 do
1025 compute_string_infos
1026 var old_seq = v.seq
1027 var ionce = new IOnce
1028 var reg = v.expr(ionce, stype)
1029 v.seq = ionce.body
1030 var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring)
1031 var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int)
1032 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
1033 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
1034 v.add_assignment(reg, e)
1035 v.seq = old_seq
1036 return reg
1037 end
1038
1039 # The raw string value
1040 protected fun string_text: String is abstract
1041
1042 # The string in a C native format
1043 protected var _cstring: nullable String
1044
1045 # The string length in bytes
1046 protected var _cstring_length: nullable Int
1047
1048 # Compute _cstring and _cstring_length using string_text
1049 protected fun compute_string_infos
1050 do
1051 var len = 0
1052 var str = string_text
1053 var res = new Buffer
1054 var i = 0
1055 while i < str.length do
1056 var c = str[i]
1057 if c == '\\' then
1058 i = i + 1
1059 var c2 = str[i]
1060 if c2 != '{' and c2 != '}' then
1061 res.add(c)
1062 end
1063 c = c2
1064 end
1065 len = len + 1
1066 res.add(c)
1067 i = i + 1
1068 end
1069 _cstring = res.to_s
1070 _cstring_length = len
1071 end
1072 end
1073
1074 redef class AStringExpr
1075 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1076 end
1077 redef class AStartStringExpr
1078 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1079 end
1080 redef class AMidStringExpr
1081 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1082 end
1083 redef class AEndStringExpr
1084 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1085 end
1086
1087 redef class ASuperstringExpr
1088 redef fun generate_icode(v)
1089 do
1090 var array = v.add_new_array(atype, n_exprs.length)
1091 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
1092 for ne in n_exprs do
1093 var e = v.generate_expr(ne)
1094 if ne.stype != stype then
1095 e = v.expr(new ICall(prop_to_s, [e]), stype)
1096 end
1097 v.add_call_array_add(array, e)
1098 end
1099 return v.expr(new ICall(prop_to_s, [array]), stype)
1100 end
1101 end
1102
1103 redef class ANullExpr
1104 redef fun generate_icode(v)
1105 do
1106 return v.lit_null_reg
1107 end
1108 end
1109
1110 redef class AArrayExpr
1111 redef fun generate_icode(v)
1112 do
1113 var recv = v.add_new_array(stype, n_exprs.length)
1114 for ne in n_exprs do
1115 var e = v.generate_expr(ne)
1116 v.add_call_array_add(recv, e)
1117 end
1118 return recv
1119 end
1120 end
1121
1122 redef class ACrangeExpr
1123 redef fun generate_icode(v)
1124 do
1125 var e = v.generate_expr(n_expr)
1126 var e2 = v.generate_expr(n_expr2)
1127 var prop = v.visitor.get_method(stype, once "init".to_symbol)
1128 return v.expr(new INew(stype, prop, [e, e2]), stype)
1129 end
1130 end
1131
1132 redef class AOrangeExpr
1133 redef fun generate_icode(v)
1134 do
1135 var e = v.generate_expr(n_expr)
1136 var e2 = v.generate_expr(n_expr2)
1137 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1138 return v.expr(new INew(stype, prop, [e, e2]), stype)
1139 end
1140 end
1141
1142 redef class ASuperExpr
1143 redef fun generate_icode(v)
1144 do
1145 var arity = v.iroutine.params.length - 1
1146 if init_in_superclass != null then
1147 arity = init_in_superclass.signature.arity
1148 end
1149 var args = new Array[IRegister].with_capacity(arity + 1)
1150 args.add(v.iroutine.params[0])
1151 if n_args.length != arity then
1152 for i in [0..arity[ do
1153 args.add(v.iroutine.params[i + 1])
1154 end
1155 else
1156 for na in n_args do
1157 args.add(v.generate_expr(na))
1158 end
1159 end
1160 var p = init_in_superclass
1161 if p != null then
1162 var rtype = p.signature.return_type
1163 if rtype != null then
1164 return v.expr(new ICall(p, args), rtype)
1165 else
1166 v.stmt(new ICall(p, args))
1167 return null
1168 end
1169 else
1170 p = prop
1171 var rtype = p.signature.return_type
1172 if rtype == null then
1173 v.stmt(new ISuper(p, args))
1174 return null
1175 else
1176 return v.expr(new ISuper(p, args), rtype)
1177 end
1178 end
1179 end
1180 end
1181
1182 redef class AAttrExpr
1183 redef fun generate_icode(v)
1184 do
1185 var e = v.generate_expr(n_expr)
1186 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1187 return v.add_attr_read(prop, e)
1188 end
1189 end
1190
1191 redef class AAttrAssignExpr
1192 redef fun generate_icode(v)
1193 do
1194 var e = v.generate_expr(n_expr)
1195 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1196 var e2 = v.generate_expr(n_value)
1197 v.stmt(new IAttrWrite(prop, e, e2))
1198 return null
1199 end
1200 end
1201 redef class AAttrReassignExpr
1202 redef fun generate_icode(v)
1203 do
1204 var e1 = v.generate_expr(n_expr)
1205 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1206 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1207 var e3 = v.generate_expr(n_value)
1208 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1209 v.stmt(new IAttrWrite(prop, e1, e4))
1210 return null
1211 end
1212 end
1213
1214 redef class AIssetAttrExpr
1215 redef fun generate_icode(v)
1216 do
1217 var e = v.generate_expr(n_expr)
1218 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1219 return v.expr(new IAttrIsset(prop, e), stype)
1220 end
1221 end
1222
1223 redef class AAbsAbsSendExpr
1224 # Compile each argument and add them to the array
1225 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1226 do
1227 var par_arity = signature.arity
1228 var par_vararg = signature.vararg_rank
1229 var raw_args = raw_arguments
1230 var raw_arity = raw_args.length
1231 var arg_idx = 0
1232 for par_idx in [0..par_arity[ do
1233 var a: AExpr
1234 var par_type = signature[par_idx]
1235 if par_idx == par_vararg then
1236 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1237 for i in [0..(raw_arity-par_arity)] do
1238 a = raw_args[arg_idx]
1239 v.add_call_array_add(arr, v.generate_expr(a))
1240 arg_idx = arg_idx + 1
1241 end
1242 args.add(arr)
1243 else
1244 a = raw_args[arg_idx]
1245 args.add(v.generate_expr(a))
1246 arg_idx = arg_idx + 1
1247 end
1248 end
1249 end
1250 end
1251
1252 redef class ASendExpr
1253 redef fun generate_icode(v)
1254 do
1255 var recv = v.generate_expr(n_expr)
1256 var args = new Array[IRegister]
1257 args.add(recv)
1258 var prop = prop
1259 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1260 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1261 var r2: nullable IRegister # The raw result of the call
1262
1263 # Prepare closures
1264 var seq_old = v.seq
1265 var closcns: nullable Array[nullable IClosureDef] = null
1266 if not prop_signature.closures.is_empty then
1267 var rtype = prop_signature.return_type
1268 if rtype != null then
1269 r = v.new_register(rtype)
1270 end
1271 var seq = new ISeq
1272 v.stmt(seq)
1273 v.seq = seq
1274 closcns = new Array[nullable IClosureDef]
1275 var cdarity = 0
1276 if closure_defs != null then cdarity = closure_defs.length
1277 var closure_defs = closure_defs
1278 for mmc in prop_signature.closures do
1279 var found = false
1280 var name = mmc.name
1281 if closure_defs != null then
1282 for cd in closure_defs do
1283 if cd.n_id.to_symbol != name then continue
1284 assert found == false
1285 found = true
1286 cd.escapable.break_seq = seq
1287 cd.escapable.break_value = r
1288 var cn = cd.generate_iclosuredef(v)
1289 closcns.add(cn)
1290 end
1291 end
1292 if not found then
1293 closcns.add(null)
1294 end
1295 end
1296 end
1297
1298 r2 = v.add_call(prop, args, closcns)
1299
1300 # Closure work
1301 if not prop_signature.closures.is_empty then
1302 if r != null and r2 != null then v.add_assignment(r, r2)
1303 v.seq = seq_old
1304 else
1305 r = r2
1306 end
1307
1308 if prop.global.is_init then
1309 v.invoke_super_init_calls_after(prop)
1310 end
1311 return r
1312 end
1313 end
1314
1315 redef class ASendReassignExpr
1316 redef fun generate_icode(v)
1317 do
1318 var recv = v.generate_expr(n_expr)
1319 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1320 var args = new Array[IRegister]
1321 args.add(recv)
1322 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1323
1324 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1325 var e3 = v.generate_expr(n_value)
1326 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1327 var args2 = args.to_a
1328 args2.add(e4)
1329 v.stmt(new ICall(prop, args2))
1330 return null
1331 end
1332 end
1333
1334 redef class ANewExpr
1335 redef fun generate_icode(v)
1336 do
1337 var args = new Array[IRegister]
1338 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1339 return v.expr(new INew(stype, prop, args), stype)
1340 end
1341 end
1342
1343 redef class AProxyExpr
1344 redef fun generate_icode(v)
1345 do
1346 return v.generate_expr(n_expr)
1347 end
1348 end
1349
1350 redef class AOnceExpr
1351 redef fun generate_icode(v)
1352 do
1353 var ionce = new IOnce
1354 var reg = v.expr(ionce, stype)
1355 var old_seq = v.seq
1356 v.seq = ionce.body
1357
1358 var e = v.generate_expr(n_expr)
1359 v.add_assignment(reg, e)
1360
1361 v.seq = old_seq
1362 return reg
1363 end
1364 end
1365
1366
1367 redef class AClosureDef
1368 var _iclosure_def: nullable IClosureDef
1369
1370 fun generate_iclosuredef(v: A2IContext): IClosureDef
1371 do
1372 # Prepare signature
1373 var args = new Array[IRegister]
1374 var sig = closure.signature
1375 for i in [0..sig.arity[ do
1376 args.add(v.new_register(sig[i]))
1377 end
1378 var ret: nullable IRegister = null
1379 var rtype = sig.return_type
1380 if rtype != null then
1381 ret = v.new_register(rtype)
1382 end
1383
1384 var iclos = new IClosureDef(args, ret)
1385 iclos.location = location
1386
1387 # Prepare env
1388 var seq_old = v.seq
1389 v.seq = iclos.body
1390 escapable.continue_seq = iclos.body
1391 escapable.continue_value = iclos.result
1392
1393 # Assign parameters
1394 for i in [0..variables.length[ do
1395 var res = v.variable(variables[i])
1396 v.add_assignment(res, iclos.params[i])
1397 end
1398
1399 v.generate_stmt(n_expr)
1400
1401 v.seq = seq_old
1402 _iclosure_def = iclos
1403 return iclos
1404 end
1405 end
1406
1407 redef class AClosureCallExpr
1408 redef fun generate_icode(v)
1409 do
1410 # Geneate arguments
1411 var args = new Array[IRegister]
1412 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1413
1414 # Prepare icall
1415 var closdecl = v.closurevariables[variable]
1416 var icall = new IClosCall(closdecl, args)
1417 var seq_old = v.seq
1418
1419 # Fill break of ical
1420 if n_closure_defs.length == 1 then do
1421 var iseq = new ISeq
1422 icall.break_seq = iseq
1423 v.seq = iseq
1424 v.generate_stmt(n_closure_defs.first.n_expr)
1425 v.seq = seq_old
1426 end
1427
1428 # Prepare in case of default block
1429 var iif: nullable IIf = null # The iif of default block
1430 var closdecl_default = closdecl.default # The default (if any)
1431 if closdecl_default != null then
1432 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1433 v.stmt(iif)
1434 v.seq = iif.then_seq
1435 end
1436
1437 # Add the icall
1438 var r2: nullable IRegister = null # the result of the icall
1439 var rtype = variable.closure.signature.return_type
1440 if rtype == null then
1441 v.stmt(icall)
1442 else
1443 r2 = v.expr(icall, rtype)
1444 end
1445
1446 # Process the case of default block
1447 var r: nullable IRegister = null # the real result
1448 if closdecl_default != null then
1449 assert iif != null
1450 if r2 != null then
1451 assert rtype != null
1452 r = v.new_register(rtype)
1453 v.add_assignment(r, r2)
1454 end
1455 v.seq = iif.else_seq
1456 var r3 = v.inline_routine(closdecl_default, args, null)
1457 if r != null then
1458 assert r3 != null
1459 v.add_assignment(r, r3)
1460 end
1461 v.seq = seq_old
1462 else
1463 r = r2
1464 end
1465 return r
1466 end
1467 end