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