icode: generate closure for 'for'
[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 escapable.break_seq = v.return_seq
351 escapable.break_value = v.return_value
352 n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null)
353
354 if n_expr != null then
355 v.generate_stmt(n_expr)
356 v.iroutine.closure_decls[position].default = iclos
357
358 # Add a final break in case of break block witout value
359 if variable.closure.is_break and v.return_value == null then
360 v.add_escape(v.return_seq.as(not null))
361 end
362 end
363 v.seq = old_seq
364 end
365 end
366
367 redef class AConcreteMethPropdef
368 redef fun fill_iroutine(v, method)
369 do
370 var params = v.iroutine.params.to_a
371 var selfreg = v.variable(self_var)
372 v.stmt(new IMove(selfreg, params[0]))
373 params.shift
374
375 var orig_meth: MMLocalProperty = method.global.intro
376 var orig_sig = orig_meth.signature_for(method.signature.recv)
377 if n_signature != null then
378 n_signature.fill_iroutine_parameters(v, orig_sig, params, v.iroutine.closure_decls)
379 end
380
381 if self isa AConcreteInitPropdef then
382 v.invoke_super_init_calls_after(null)
383 end
384
385 if n_block != null then
386 v.generate_stmt(n_block)
387 end
388 end
389 end
390
391 redef class ADeferredMethPropdef
392 redef fun fill_iroutine(v, method)
393 do
394 v.add_abort("Deferred method called")
395 end
396 end
397
398 redef class AExternMethPropdef
399 redef fun fill_iroutine(v, method)
400 do
401 var params = v.iroutine.params
402 var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
403 if n_extern != null then
404 ename = n_extern.text
405 ename = ename.substring(1, ename.length-2)
406 end
407 var sig = method.signature
408 assert params.length == sig.arity + 1
409 var args = new Array[String]
410 args.add(sig.recv.unboxtype("@@@"))
411 for i in [0..sig.arity[ do
412 args.add(sig[i].unboxtype("@@@"))
413 end
414 var s = "{ename}({args.join(", ")})"
415 var rtype = sig.return_type
416 if rtype != null then
417 s = rtype.boxtype(s)
418 v.add_return_value(v.expr(new INative(s, params), rtype))
419 else
420 v.stmt(new INative(s, params))
421 end
422 end
423 end
424
425 redef class AInternMethPropdef
426 redef fun fill_iroutine(v, method)
427 do
428 var p = v.iroutine.params.to_a
429 var c = method.local_class.name
430 var n = method.name
431 var s: nullable String = null
432 if c == once "Int".to_symbol then
433 if n == once "object_id".to_symbol then
434 s = "@@@"
435 else if n == once "unary -".to_symbol then
436 s = "TAG_Int(-UNTAG_Int(@@@))"
437 else if n == once "output".to_symbol then
438 s = "printf(\"%ld\\n\", UNTAG_Int(@@@));"
439 else if n == once "ascii".to_symbol then
440 s = "TAG_Char(UNTAG_Int(@@@))"
441 else if n == once "succ".to_symbol then
442 s = "TAG_Int(UNTAG_Int(@@@)+1)"
443 else if n == once "prec".to_symbol then
444 s = "TAG_Int(UNTAG_Int(@@@)-1)"
445 else if n == once "to_f".to_symbol then
446 s = "BOX_Float((float)UNTAG_Int(@@@))"
447 else if n == once "+".to_symbol then
448 s = "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))"
449 else if n == once "-".to_symbol then
450 s = "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))"
451 else if n == once "*".to_symbol then
452 s = "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))"
453 else if n == once "/".to_symbol then
454 s = "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
455 else if n == once "%".to_symbol then
456 s = "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))"
457 else if n == once "<".to_symbol then
458 s = "TAG_Bool(UNTAG_Int(@@@)<UNTAG_Int(@@@))"
459 else if n == once ">".to_symbol then
460 s = "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))"
461 else if n == once "<=".to_symbol then
462 s = "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
463 else if n == once ">=".to_symbol then
464 s = "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
465 else if n == once "lshift".to_symbol then
466 s = "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
467 else if n == once "rshift".to_symbol then
468 s = "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
469 else if n == once "==".to_symbol then
470 s = "TAG_Bool((@@@)==(@@@))"
471 else if n == once "!=".to_symbol then
472 s = "TAG_Bool((@@@)!=(@@@))"
473 end
474 else if c == once "Float".to_symbol then
475 if n == once "object_id".to_symbol then
476 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
477 else if n == once "unary -".to_symbol then
478 s = "BOX_Float(-UNBOX_Float(@@@))"
479 else if n == once "output".to_symbol then
480 s = "printf(\"%f\\n\", UNBOX_Float(@@@));"
481 else if n == once "to_i".to_symbol then
482 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
483 else if n == once "+".to_symbol then
484 s = "BOX_Float(UNBOX_Float(@@@)+UNBOX_Float(@@@))"
485 else if n == once "-".to_symbol then
486 s = "BOX_Float(UNBOX_Float(@@@)-UNBOX_Float(@@@))"
487 else if n == once "*".to_symbol then
488 s = "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
489 else if n == once "/".to_symbol then
490 s = "BOX_Float(UNBOX_Float(@@@)/UNBOX_Float(@@@))"
491 else if n == once "<".to_symbol then
492 s = "TAG_Bool(UNBOX_Float(@@@)<UNBOX_Float(@@@))"
493 else if n == once ">".to_symbol then
494 s = "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))"
495 else if n == once "<=".to_symbol then
496 s = "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
497 else if n == once ">=".to_symbol then
498 s = "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
499 end
500 else if c == once "Char".to_symbol then
501 if n == once "object_id".to_symbol then
502 s = "TAG_Int(UNTAG_Char(@@@))"
503 else if n == once "unary -".to_symbol then
504 s = "TAG_Char(-UNTAG_Char(@@@))"
505 else if n == once "output".to_symbol then
506 s = "printf(\"%c\", (unsigned char)UNTAG_Char(@@@));"
507 else if n == once "ascii".to_symbol then
508 s = "TAG_Int((unsigned char)UNTAG_Char(@@@))"
509 else if n == once "succ".to_symbol then
510 s = "TAG_Char(UNTAG_Char(@@@)+1)"
511 else if n == once "prec".to_symbol then
512 s = "TAG_Char(UNTAG_Char(@@@)-1)"
513 else if n == once "to_i".to_symbol then
514 s = "TAG_Int(UNTAG_Char(@@@)-'0')"
515 else if n == once "+".to_symbol then
516 s = "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))"
517 else if n == once "-".to_symbol then
518 s = "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))"
519 else if n == once "*".to_symbol then
520 s = "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))"
521 else if n == once "/".to_symbol then
522 s = "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
523 else if n == once "%".to_symbol then
524 s = "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))"
525 else if n == once "<".to_symbol then
526 s = "TAG_Bool(UNTAG_Char(@@@)<UNTAG_Char(@@@))"
527 else if n == once ">".to_symbol then
528 s = "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))"
529 else if n == once "<=".to_symbol then
530 s = "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
531 else if n == once ">=".to_symbol then
532 s = "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
533 else if n == once "==".to_symbol then
534 s = "TAG_Bool((@@@)==(@@@))"
535 else if n == once "!=".to_symbol then
536 s = "TAG_Bool((@@@)!=(@@@))"
537 end
538 else if c == once "Bool".to_symbol then
539 if n == once "object_id".to_symbol then
540 s = "TAG_Int(UNTAG_Bool(@@@))"
541 else if n == once "unary -".to_symbol then
542 s = "TAG_Bool(-UNTAG_Bool(@@@))"
543 else if n == once "output".to_symbol then
544 s = "(void)printf(UNTAG_Bool(@@@)?\"true\\n\":\"false\\n\");"
545 else if n == once "ascii".to_symbol then
546 s = "TAG_Bool(UNTAG_Bool(@@@))"
547 else if n == once "to_i".to_symbol then
548 s = "TAG_Int(UNTAG_Bool(@@@))"
549 else if n == once "==".to_symbol then
550 s = "TAG_Bool((@@@)==(@@@))"
551 else if n == once "!=".to_symbol then
552 s = "TAG_Bool((@@@)!=(@@@))"
553 end
554 else if c == once "NativeArray".to_symbol then
555 if n == once "object_id".to_symbol then
556 s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
557 else if n == once "[]".to_symbol then
558 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
559 else if n == once "[]=".to_symbol then
560 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
561 else if n == once "copy_to".to_symbol then
562 var t = p[0]
563 p[0] = p[1]
564 p[1] = t
565 s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
566 end
567 else if c == once "NativeString".to_symbol then
568 if n == once "object_id".to_symbol then
569 s = "TAG_Int(UNBOX_NativeString(@@@))"
570 else if n == once "atoi".to_symbol then
571 s = "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
572 else if n == once "[]".to_symbol then
573 s = "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
574 else if n == once "[]=".to_symbol then
575 s = "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
576 else if n == once "copy_to".to_symbol then
577 var t = p[0]
578 p[0] = p[1]
579 p[1] = p[4]
580 p[4] = p[2]
581 p[2] = t
582 s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
583 end
584 else if n == once "object_id".to_symbol then
585 s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
586 else if n == once "sys".to_symbol then
587 s = "(G_sys)"
588 else if n == once "is_same_type".to_symbol then
589 s = "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
590 else if n == once "exit".to_symbol then
591 p[0] = p[1]
592 s = "exit(UNTAG_Int(@@@));"
593 else if n == once "calloc_array".to_symbol then
594 p[0] = p[1]
595 s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
596 else if n == once "calloc_string".to_symbol then
597 p[0] = p[1]
598 s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
599 end
600 if s == null then
601 v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
602 s = "NIT_NULL"
603 end
604 var rtype = method.signature.return_type
605 if rtype != null then
606 v.add_return_value(v.expr(new INative(s, p), rtype))
607 else
608 v.stmt(new INative(s, p))
609 end
610 end
611 end
612
613 ###############################################################################
614
615 redef class AExpr
616 redef fun accept_icode_generation(v) do end
617
618 # Generate icode sequence in the current A2IContext
619 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
620 protected fun generate_icode(v: A2IContext): nullable IRegister is abstract
621 end
622
623 redef class AVardeclExpr
624 redef fun generate_icode(v)
625 do
626 var reg = v.variable(variable)
627 var ne = n_expr
628 if ne != null then
629 v.add_assignment(reg, v.generate_expr(ne))
630 end
631 return null
632 end
633 end
634
635 redef class ABlockExpr
636 redef fun generate_icode(v)
637 do
638 for ne in n_expr do v.generate_stmt(ne)
639 return null
640 end
641 end
642
643 redef class ADoExpr
644 redef fun generate_icode(v)
645 do
646 var seq_old = v.seq
647 var seq = new ISeq
648 v.stmt(seq)
649 escapable.break_seq = seq
650 v.seq = seq
651
652 v.generate_stmt(n_block)
653
654 v.seq = seq_old
655 return null
656 end
657 end
658
659 redef class AReturnExpr
660 redef fun generate_icode(v)
661 do
662 var ne = n_expr
663 if ne != null then
664 v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
665 end
666 v.add_escape(v.return_seq.as(not null))
667 return null
668 end
669 end
670
671 redef class ABreakExpr
672 redef fun generate_icode(v)
673 do
674 var ne = n_expr
675 if ne != null then
676 v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
677 end
678 v.add_escape(escapable.break_seq.as(not null))
679 return null
680 end
681 end
682
683 redef class AContinueExpr
684 redef fun generate_icode(v)
685 do
686 var ne = n_expr
687 if ne != null then
688 v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
689 end
690 v.add_escape(escapable.continue_seq.as(not null))
691 return null
692 end
693 end
694
695 redef class AAbortExpr
696 redef fun generate_icode(v)
697 do
698 v.add_abort("Aborted")
699 return null
700 end
701 end
702
703 redef class AIfExpr
704 redef fun generate_icode(v)
705 do
706 var iif = new IIf(v.generate_expr(n_expr))
707 v.stmt(iif)
708 var seq_old = v.seq
709
710 if n_then != null then
711 v.seq = iif.then_seq
712 v.generate_stmt(n_then)
713 end
714
715 if n_else != null then
716 v.seq = iif.else_seq
717 v.generate_stmt(n_else)
718 end
719
720 v.seq = seq_old
721 return null
722 end
723 end
724
725 redef class AWhileExpr
726 redef fun generate_icode(v)
727 do
728 var seq_old = v.seq
729 var iloop = new ILoop
730 v.stmt(iloop)
731 escapable.break_seq = iloop
732 v.seq = iloop
733
734 # Process condition
735 var iif = new IIf(v.generate_expr(n_expr))
736 v.stmt(iif)
737
738 # Process inside (condition is true)
739 if n_block != null then
740 v.seq = iif.then_seq
741 escapable.continue_seq = iif.then_seq
742 v.generate_stmt(n_block)
743 end
744
745 # Process escape (condition is false)
746 v.seq = iif.else_seq
747 v.add_escape(iloop)
748
749 v.seq = seq_old
750 return null
751 end
752 end
753
754 redef class ALoopExpr
755 redef fun generate_icode(v)
756 do
757 var seq_old = v.seq
758 var iloop = new ILoop
759 v.stmt(iloop)
760 escapable.break_seq = iloop
761 v.seq = iloop
762
763 # Process inside
764 if n_block != null then
765 var seq = new ISeq
766 v.stmt(seq)
767 v.seq = seq
768 escapable.continue_seq = seq
769 v.generate_stmt(n_block)
770 end
771
772 v.seq = seq_old
773 return null
774 end
775 end
776
777 redef class AForExpr
778 redef fun generate_icode(v)
779 do
780 var expr_type = n_expr.stype
781
782 # Get iterate
783 var meth_iterate = v.visitor.get_method(expr_type, once "iterate".to_symbol)
784
785 # Build closure
786 var iclos = meth_iterate.signature.closures.first.signature.generate_empty_iclosuredef(v)
787 var old_seq = v.seq
788
789 var seq = new ISeq
790 v.stmt(seq)
791 v.seq = seq
792 escapable.break_seq = seq
793 escapable.break_value = null
794
795 v.seq = iclos.body
796 escapable.continue_seq = iclos.body
797 escapable.continue_value = null
798 v.stmt(new IMove(v.variable(variable), iclos.params.first))
799 v.generate_stmt(n_block)
800
801 # Call closure
802 v.seq = seq
803 v.add_call(meth_iterate, [v.generate_expr(n_expr)], [iclos])
804
805 v.seq = old_seq
806 return null
807 end
808 end
809
810 redef class AAssertExpr
811 redef fun generate_icode(v)
812 do
813 var e = v.generate_expr(n_expr)
814 var iif = new IIf(e)
815 v.stmt(iif)
816 var seq_old = v.seq
817 v.seq = iif.else_seq
818 v.generate_stmt(n_else)
819 var id = n_id
820 if id == null then
821 v.add_abort("Assert failed")
822 else
823 v.add_abort("Assert %s failed", id.to_s)
824 end
825 v.seq = seq_old
826 return null
827 end
828 end
829
830 redef class AVarExpr
831 redef fun generate_icode(v)
832 do
833 return v.variable(variable)
834 end
835 end
836
837 redef class AVarAssignExpr
838 redef fun generate_icode(v)
839 do
840 var e = v.generate_expr(n_value)
841 v.add_assignment(v.variable(variable), e)
842 return null
843 end
844 end
845
846 redef class AVarReassignExpr
847 redef fun generate_icode(v)
848 do
849 var e1 = v.variable(variable)
850 var e2 = v.generate_expr(n_value)
851 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
852 v.add_assignment(e1, e3)
853 return null
854 end
855 end
856
857 redef class ASelfExpr
858 redef fun generate_icode(v)
859 do
860 return v.variable(variable)
861 end
862 end
863
864 redef class AIfexprExpr
865 redef fun generate_icode(v)
866 do
867 # Process condition
868 var iif = new IIf(v.generate_expr(n_expr))
869 v.stmt(iif)
870 var seq_old = v.seq
871
872 # Prepare result
873 var reg = v.new_register(stype)
874
875 # Process 'then'
876 v.seq = iif.then_seq
877 v.add_assignment(reg, v.generate_expr(n_then))
878
879 # Process 'else'
880 v.seq = iif.else_seq
881 v.add_assignment(reg, v.generate_expr(n_else))
882
883 v.seq = seq_old
884 return reg
885 end
886 end
887
888 redef class AEeExpr
889 redef fun generate_icode(v)
890 do
891 var e = v.generate_expr(n_expr)
892 var e2 = v.generate_expr(n_expr2)
893 return v.expr(new IIs(e, e2), stype)
894 end
895 end
896
897 redef class AOrExpr
898 redef fun generate_icode(v)
899 do
900 # Prepare result
901 var reg = v.new_register(stype)
902
903 # Process left operand (in a if/then)
904 var iif = new IIf(v.generate_expr(n_expr))
905 v.stmt(iif)
906 var seq_old = v.seq
907 v.seq = iif.then_seq
908 v.add_assignment(reg, v.lit_true_reg)
909
910 # Process right operand (in the else)
911 v.seq = iif.else_seq
912 v.add_assignment(reg, v.generate_expr(n_expr2))
913
914 v.seq = seq_old
915 return reg
916 end
917 end
918
919 redef class AAndExpr
920 redef fun generate_icode(v)
921 do
922 # Prepare result
923 var reg = v.new_register(stype)
924
925 # Process left operand (in a if/else)
926 var iif = new IIf(v.generate_expr(n_expr))
927 v.stmt(iif)
928 var seq_old = v.seq
929 v.seq = iif.else_seq
930 v.add_assignment(reg, v.lit_false_reg)
931
932 # Process right operand (in the then)
933 v.seq = iif.then_seq
934 v.add_assignment(reg, v.generate_expr(n_expr2))
935
936 v.seq = seq_old
937 return reg
938 end
939 end
940
941 redef class ANotExpr
942 redef fun generate_icode(v)
943 do
944 var e = v.generate_expr(n_expr)
945 return v.expr(new INot(e), stype)
946 end
947 end
948
949 redef class AIsaExpr
950 redef fun generate_icode(v)
951 do
952 var e = v.generate_expr(n_expr)
953 return v.expr(new ITypeCheck(e, n_type.stype), stype)
954 end
955 end
956
957 redef class AAsCastExpr
958 redef fun generate_icode(v)
959 do
960 var e = v.generate_expr(n_expr)
961 v.add_type_cast(e, stype)
962 return e
963 end
964 end
965
966 redef class AAsNotnullExpr
967 redef fun generate_icode(v)
968 do
969 var e = v.generate_expr(n_expr)
970 v.add_type_cast(e, stype)
971 return e
972 end
973 end
974
975 redef class ATrueExpr
976 redef fun generate_icode(v)
977 do
978 return v.lit_true_reg
979 end
980 end
981
982 redef class AFalseExpr
983 redef fun generate_icode(v)
984 do
985 return v.lit_false_reg
986 end
987 end
988
989 redef class AIntExpr
990 redef fun generate_icode(v)
991 do
992 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
993 end
994 end
995
996 redef class AFloatExpr
997 redef fun generate_icode(v)
998 do
999 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
1000 end
1001 end
1002
1003 redef class ACharExpr
1004 redef fun generate_icode(v)
1005 do
1006 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
1007 end
1008 end
1009
1010 redef class AStringFormExpr
1011 redef fun generate_icode(v)
1012 do
1013 compute_string_infos
1014 var old_seq = v.seq
1015 var ionce = new IOnce
1016 var reg = v.expr(ionce, stype)
1017 v.seq = ionce.body
1018 var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring)
1019 var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int)
1020 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
1021 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
1022 v.add_assignment(reg, e)
1023 v.seq = old_seq
1024 return reg
1025 end
1026
1027 # The raw string value
1028 protected fun string_text: String is abstract
1029
1030 # The string in a C native format
1031 protected var _cstring: nullable String
1032
1033 # The string length in bytes
1034 protected var _cstring_length: nullable Int
1035
1036 # Compute _cstring and _cstring_length using string_text
1037 protected fun compute_string_infos
1038 do
1039 var len = 0
1040 var str = string_text
1041 var res = new Buffer
1042 var i = 0
1043 while i < str.length do
1044 var c = str[i]
1045 if c == '\\' then
1046 i = i + 1
1047 var c2 = str[i]
1048 if c2 != '{' and c2 != '}' then
1049 res.add(c)
1050 end
1051 c = c2
1052 end
1053 len = len + 1
1054 res.add(c)
1055 i = i + 1
1056 end
1057 _cstring = res.to_s
1058 _cstring_length = len
1059 end
1060 end
1061
1062 redef class AStringExpr
1063 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1064 end
1065 redef class AStartStringExpr
1066 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1067 end
1068 redef class AMidStringExpr
1069 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1070 end
1071 redef class AEndStringExpr
1072 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1073 end
1074
1075 redef class ASuperstringExpr
1076 redef fun generate_icode(v)
1077 do
1078 var array = v.add_new_array(atype, n_exprs.length)
1079 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
1080 for ne in n_exprs do
1081 var e = v.generate_expr(ne)
1082 if ne.stype != stype then
1083 e = v.expr(new ICall(prop_to_s, [e]), stype)
1084 end
1085 v.add_call_array_add(array, e)
1086 end
1087 return v.expr(new ICall(prop_to_s, [array]), stype)
1088 end
1089 end
1090
1091 redef class ANullExpr
1092 redef fun generate_icode(v)
1093 do
1094 return v.lit_null_reg
1095 end
1096 end
1097
1098 redef class AArrayExpr
1099 redef fun generate_icode(v)
1100 do
1101 var recv = v.add_new_array(stype, n_exprs.length)
1102 for ne in n_exprs do
1103 var e = v.generate_expr(ne)
1104 v.add_call_array_add(recv, e)
1105 end
1106 return recv
1107 end
1108 end
1109
1110 redef class ACrangeExpr
1111 redef fun generate_icode(v)
1112 do
1113 var e = v.generate_expr(n_expr)
1114 var e2 = v.generate_expr(n_expr2)
1115 var prop = v.visitor.get_method(stype, once "init".to_symbol)
1116 return v.expr(new INew(stype, prop, [e, e2]), stype)
1117 end
1118 end
1119
1120 redef class AOrangeExpr
1121 redef fun generate_icode(v)
1122 do
1123 var e = v.generate_expr(n_expr)
1124 var e2 = v.generate_expr(n_expr2)
1125 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1126 return v.expr(new INew(stype, prop, [e, e2]), stype)
1127 end
1128 end
1129
1130 redef class ASuperExpr
1131 redef fun generate_icode(v)
1132 do
1133 var arity = v.iroutine.params.length - 1
1134 if init_in_superclass != null then
1135 arity = init_in_superclass.signature.arity
1136 end
1137 var args = new Array[IRegister].with_capacity(arity + 1)
1138 args.add(v.iroutine.params[0])
1139 if n_args.length != arity then
1140 for i in [0..arity[ do
1141 args.add(v.iroutine.params[i + 1])
1142 end
1143 else
1144 for na in n_args do
1145 args.add(v.generate_expr(na))
1146 end
1147 end
1148 var p = init_in_superclass
1149 if p != null then
1150 var rtype = p.signature.return_type
1151 if rtype != null then
1152 return v.expr(new ICall(p, args), rtype)
1153 else
1154 v.stmt(new ICall(p, args))
1155 return null
1156 end
1157 else
1158 p = prop
1159 var rtype = p.signature.return_type
1160 if rtype == null then
1161 v.stmt(new ISuper(p, args))
1162 return null
1163 else
1164 return v.expr(new ISuper(p, args), rtype)
1165 end
1166 end
1167 end
1168 end
1169
1170 redef class AAttrExpr
1171 redef fun generate_icode(v)
1172 do
1173 var e = v.generate_expr(n_expr)
1174 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1175 return v.add_attr_read(prop, e)
1176 end
1177 end
1178
1179 redef class AAttrAssignExpr
1180 redef fun generate_icode(v)
1181 do
1182 var e = v.generate_expr(n_expr)
1183 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1184 var e2 = v.generate_expr(n_value)
1185 v.stmt(new IAttrWrite(prop, e, e2))
1186 return null
1187 end
1188 end
1189 redef class AAttrReassignExpr
1190 redef fun generate_icode(v)
1191 do
1192 var e1 = v.generate_expr(n_expr)
1193 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1194 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1195 var e3 = v.generate_expr(n_value)
1196 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1197 v.stmt(new IAttrWrite(prop, e1, e4))
1198 return null
1199 end
1200 end
1201
1202 redef class AIssetAttrExpr
1203 redef fun generate_icode(v)
1204 do
1205 var e = v.generate_expr(n_expr)
1206 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1207 return v.expr(new IAttrIsset(prop, e), stype)
1208 end
1209 end
1210
1211 redef class AAbsAbsSendExpr
1212 # Compile each argument and add them to the array
1213 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1214 do
1215 var par_arity = signature.arity
1216 var par_vararg = signature.vararg_rank
1217 var raw_args = raw_arguments
1218 var raw_arity = raw_args.length
1219 var arg_idx = 0
1220 for par_idx in [0..par_arity[ do
1221 var a: AExpr
1222 var par_type = signature[par_idx]
1223 if par_idx == par_vararg then
1224 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1225 for i in [0..(raw_arity-par_arity)] do
1226 a = raw_args[arg_idx]
1227 v.add_call_array_add(arr, v.generate_expr(a))
1228 arg_idx = arg_idx + 1
1229 end
1230 args.add(arr)
1231 else
1232 a = raw_args[arg_idx]
1233 args.add(v.generate_expr(a))
1234 arg_idx = arg_idx + 1
1235 end
1236 end
1237 end
1238 end
1239
1240 redef class ASendExpr
1241 redef fun generate_icode(v)
1242 do
1243 var recv = v.generate_expr(n_expr)
1244 var args = new Array[IRegister]
1245 args.add(recv)
1246 var prop = prop
1247 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1248 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1249 var r2: nullable IRegister # The raw result of the call
1250
1251 # Prepare closures
1252 var seq_old = v.seq
1253 var closcns: nullable Array[nullable IClosureDef] = null
1254 if not prop_signature.closures.is_empty then
1255 var rtype = prop_signature.return_type
1256 if rtype != null then
1257 r = v.new_register(rtype)
1258 end
1259 var seq = new ISeq
1260 v.stmt(seq)
1261 v.seq = seq
1262 closcns = new Array[nullable IClosureDef]
1263 var cdarity = 0
1264 if closure_defs != null then cdarity = closure_defs.length
1265 var closure_defs = closure_defs
1266 for mmc in prop_signature.closures do
1267 var found = false
1268 var name = mmc.name
1269 if closure_defs != null then
1270 for cd in closure_defs do
1271 if cd.n_id.to_symbol != name then continue
1272 assert found == false
1273 found = true
1274 cd.escapable.break_seq = seq
1275 cd.escapable.break_value = r
1276 var cn = cd.generate_iclosuredef(v)
1277 closcns.add(cn)
1278 end
1279 end
1280 if not found then
1281 closcns.add(null)
1282 end
1283 end
1284 end
1285
1286 r2 = v.add_call(prop, args, closcns)
1287
1288 # Closure work
1289 if not prop_signature.closures.is_empty then
1290 if r != null and r2 != null then v.add_assignment(r, r2)
1291 v.seq = seq_old
1292 else
1293 r = r2
1294 end
1295
1296 if prop.global.is_init then
1297 v.invoke_super_init_calls_after(prop)
1298 end
1299 return r
1300 end
1301 end
1302
1303 redef class ASendReassignExpr
1304 redef fun generate_icode(v)
1305 do
1306 var recv = v.generate_expr(n_expr)
1307 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1308 var args = new Array[IRegister]
1309 args.add(recv)
1310 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1311
1312 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1313 var e3 = v.generate_expr(n_value)
1314 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1315 var args2 = args.to_a
1316 args2.add(e4)
1317 v.stmt(new ICall(prop, args2))
1318 return null
1319 end
1320 end
1321
1322 redef class ANewExpr
1323 redef fun generate_icode(v)
1324 do
1325 var args = new Array[IRegister]
1326 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1327 return v.expr(new INew(stype, prop, args), stype)
1328 end
1329 end
1330
1331 redef class AProxyExpr
1332 redef fun generate_icode(v)
1333 do
1334 return v.generate_expr(n_expr)
1335 end
1336 end
1337
1338 redef class AOnceExpr
1339 redef fun generate_icode(v)
1340 do
1341 var ionce = new IOnce
1342 var reg = v.expr(ionce, stype)
1343 var old_seq = v.seq
1344 v.seq = ionce.body
1345
1346 var e = v.generate_expr(n_expr)
1347 v.add_assignment(reg, e)
1348
1349 v.seq = old_seq
1350 return reg
1351 end
1352 end
1353
1354
1355 redef class AClosureDef
1356 var _iclosure_def: nullable IClosureDef
1357
1358 fun generate_iclosuredef(v: A2IContext): IClosureDef
1359 do
1360 # Prepare signature
1361 var args = new Array[IRegister]
1362 var sig = closure.signature
1363 for i in [0..sig.arity[ do
1364 args.add(v.new_register(sig[i]))
1365 end
1366 var ret: nullable IRegister = null
1367 var rtype = sig.return_type
1368 if rtype != null then
1369 ret = v.new_register(rtype)
1370 end
1371
1372 var iclos = new IClosureDef(args, ret)
1373 iclos.location = location
1374
1375 # Prepare env
1376 var seq_old = v.seq
1377 v.seq = iclos.body
1378 escapable.continue_seq = iclos.body
1379 escapable.continue_value = iclos.result
1380
1381 # Assign parameters
1382 for i in [0..variables.length[ do
1383 var res = v.variable(variables[i])
1384 v.add_assignment(res, iclos.params[i])
1385 end
1386
1387 v.generate_stmt(n_expr)
1388
1389 # Add a final break in case of break block witout value
1390 if closure.is_break and escapable.break_value == null then
1391 v.add_escape(escapable.break_seq.as(not null))
1392 end
1393
1394 v.seq = seq_old
1395 _iclosure_def = iclos
1396 return iclos
1397 end
1398 end
1399
1400 redef class AClosureCallExpr
1401 redef fun generate_icode(v)
1402 do
1403 # Geneate arguments
1404 var args = new Array[IRegister]
1405 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1406
1407 # Prepare icall
1408 var closdecl = v.closurevariables[variable]
1409 var icall = new IClosCall(closdecl, args)
1410 var seq_old = v.seq
1411
1412 # Fill break of ical
1413 if n_closure_defs.length == 1 then do
1414 var iseq = new ISeq
1415 icall.break_seq = iseq
1416 v.seq = iseq
1417 v.generate_stmt(n_closure_defs.first.n_expr)
1418 v.seq = seq_old
1419 end
1420
1421 # Prepare in case of default block
1422 var iif: nullable IIf = null # The iif of default block
1423 var closdecl_default = closdecl.default # The default (if any)
1424 if closdecl_default != null then
1425 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1426 v.stmt(iif)
1427 v.seq = iif.then_seq
1428 end
1429
1430 # Add the icall
1431 var r2: nullable IRegister = null # the result of the icall
1432 var rtype = variable.closure.signature.return_type
1433 if rtype == null then
1434 v.stmt(icall)
1435 else
1436 r2 = v.expr(icall, rtype)
1437 end
1438
1439 # Process the case of default block
1440 var r: nullable IRegister = null # the real result
1441 if closdecl_default != null then
1442 assert iif != null
1443 if r2 != null then
1444 assert rtype != null
1445 r = v.new_register(rtype)
1446 v.add_assignment(r, r2)
1447 end
1448 v.seq = iif.else_seq
1449 var r3 = v.inline_routine(closdecl_default, args, null)
1450 if r != null then
1451 assert r3 != null
1452 v.add_assignment(r, r3)
1453 end
1454 v.seq = seq_old
1455 else
1456 r = r2
1457 end
1458 return r
1459 end
1460 end