syntax: vararg arguments are processed by icode
[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: IndexedCollection[IRegister], closdecls: nullable IndexedCollection[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 AForExpr
742 redef fun generate_icode(v)
743 do
744 var expr_type = n_expr.stype
745
746 # Get iterator
747 var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol)
748
749 var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null)
750 var ireg_iter = v.expr(new ICall(meth_iterator, [v.generate_expr(n_expr)]), iter_type)
751
752 # Enter loop
753 var seq_old = v.seq
754 var iloop = new ILoop
755 v.stmt(iloop)
756 escapable.break_seq = iloop
757 v.seq = iloop
758
759 # Condition evaluation
760 var meth_is_ok = v.visitor.get_method(iter_type, once ("is_ok".to_symbol))
761 var ireg_isok = v.expr(new ICall(meth_is_ok, [ireg_iter]), v.visitor.type_bool)
762 var iif = new IIf(ireg_isok)
763
764 # Process insite the loop (condition is true)
765 v.stmt(iif)
766 v.seq = iif.then_seq
767 escapable.continue_seq = iif.then_seq
768
769 # Automatic variable assignment
770 var meth_item = v.visitor.get_method(iter_type, once ("item".to_symbol))
771 var va_stype = variable.stype.as(not null)
772 var ireg_item = v.expr(new ICall(meth_item, [ireg_iter]), va_stype)
773 var ireg_va = v.variable(variable)
774 v.add_assignment(ireg_va, ireg_item)
775
776 # Body evaluation
777 v.generate_stmt(n_block)
778
779 # Exit contition (condition is false)
780 v.seq = iif.else_seq
781 v.stmt(new IEscape(iloop))
782
783 # Next step
784 var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol))
785 v.seq = iloop
786 v.stmt(new ICall(meth_next, [ireg_iter]))
787
788 v.seq = seq_old
789 return null
790 end
791 end
792
793 redef class AAssertExpr
794 redef fun generate_icode(v)
795 do
796 var e = v.generate_expr(n_expr)
797 var iif = new IIf(e)
798 v.stmt(iif)
799 var seq_old = v.seq
800 v.seq = iif.else_seq
801 var id = n_id
802 if id == null then
803 v.add_abort("Assert failed")
804 else
805 v.add_abort("Assert %s failed", id.to_s)
806 end
807 v.seq = seq_old
808 return null
809 end
810 end
811
812 redef class AVarExpr
813 redef fun generate_icode(v)
814 do
815 return v.variable(variable)
816 end
817 end
818
819 redef class AVarAssignExpr
820 redef fun generate_icode(v)
821 do
822 var e = v.generate_expr(n_value)
823 v.add_assignment(v.variable(variable), e)
824 return null
825 end
826 end
827
828 redef class AVarReassignExpr
829 redef fun generate_icode(v)
830 do
831 var e1 = v.variable(variable)
832 var e2 = v.generate_expr(n_value)
833 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
834 v.add_assignment(e1, e3)
835 return null
836 end
837 end
838
839 redef class ASelfExpr
840 redef fun generate_icode(v)
841 do
842 return v.variable(variable)
843 end
844 end
845
846 redef class AIfexprExpr
847 redef fun generate_icode(v)
848 do
849 # Process condition
850 var iif = new IIf(v.generate_expr(n_expr))
851 v.stmt(iif)
852 var seq_old = v.seq
853
854 # Prepare result
855 var reg = v.new_register(stype)
856
857 # Process 'then'
858 v.seq = iif.then_seq
859 v.add_assignment(reg, v.generate_expr(n_then))
860
861 # Process 'else'
862 v.seq = iif.else_seq
863 v.add_assignment(reg, v.generate_expr(n_else))
864
865 v.seq = seq_old
866 return reg
867 end
868 end
869
870 redef class AEeExpr
871 redef fun generate_icode(v)
872 do
873 var e = v.generate_expr(n_expr)
874 var e2 = v.generate_expr(n_expr2)
875 return v.expr(new IIs(e, e2), stype)
876 end
877 end
878
879 redef class AOrExpr
880 redef fun generate_icode(v)
881 do
882 # Prepare result
883 var reg = v.new_register(stype)
884
885 # Process left operand (in a if/then)
886 var iif = new IIf(v.generate_expr(n_expr))
887 v.stmt(iif)
888 var seq_old = v.seq
889 v.seq = iif.then_seq
890 v.add_assignment(reg, v.lit_true_reg)
891
892 # Process right operand (in the else)
893 v.seq = iif.else_seq
894 v.add_assignment(reg, v.generate_expr(n_expr2))
895
896 v.seq = seq_old
897 return reg
898 end
899 end
900
901 redef class AAndExpr
902 redef fun generate_icode(v)
903 do
904 # Prepare result
905 var reg = v.new_register(stype)
906
907 # Process left operand (in a if/else)
908 var iif = new IIf(v.generate_expr(n_expr))
909 v.stmt(iif)
910 var seq_old = v.seq
911 v.seq = iif.else_seq
912 v.add_assignment(reg, v.lit_false_reg)
913
914 # Process right operand (in the then)
915 v.seq = iif.then_seq
916 v.add_assignment(reg, v.generate_expr(n_expr2))
917
918 v.seq = seq_old
919 return reg
920 end
921 end
922
923 redef class ANotExpr
924 redef fun generate_icode(v)
925 do
926 var e = v.generate_expr(n_expr)
927 return v.expr(new INot(e), stype)
928 end
929 end
930
931 redef class AIsaExpr
932 redef fun generate_icode(v)
933 do
934 var e = v.generate_expr(n_expr)
935 return v.expr(new ITypeCheck(e, n_type.stype), stype)
936 end
937 end
938
939 redef class AAsCastExpr
940 redef fun generate_icode(v)
941 do
942 var e = v.generate_expr(n_expr)
943 v.add_type_cast(e, stype)
944 return e
945 end
946 end
947
948 redef class AAsNotnullExpr
949 redef fun generate_icode(v)
950 do
951 var e = v.generate_expr(n_expr)
952 v.add_type_cast(e, stype)
953 return e
954 end
955 end
956
957 redef class ATrueExpr
958 redef fun generate_icode(v)
959 do
960 return v.lit_true_reg
961 end
962 end
963
964 redef class AFalseExpr
965 redef fun generate_icode(v)
966 do
967 return v.lit_false_reg
968 end
969 end
970
971 redef class AIntExpr
972 redef fun generate_icode(v)
973 do
974 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
975 end
976 end
977
978 redef class AFloatExpr
979 redef fun generate_icode(v)
980 do
981 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
982 end
983 end
984
985 redef class ACharExpr
986 redef fun generate_icode(v)
987 do
988 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
989 end
990 end
991
992 redef class AStringFormExpr
993 redef fun generate_icode(v)
994 do
995 compute_string_infos
996 var old_seq = v.seq
997 var ionce = new IOnce
998 var reg = v.expr(ionce, stype)
999 v.seq = ionce.body
1000 var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring)
1001 var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int)
1002 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
1003 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
1004 v.add_assignment(reg, e)
1005 v.seq = old_seq
1006 return reg
1007 end
1008
1009 # The raw string value
1010 protected fun string_text: String is abstract
1011
1012 # The string in a C native format
1013 protected var _cstring: nullable String
1014
1015 # The string length in bytes
1016 protected var _cstring_length: nullable Int
1017
1018 # Compute _cstring and _cstring_length using string_text
1019 protected fun compute_string_infos
1020 do
1021 var len = 0
1022 var str = string_text
1023 var res = new Buffer
1024 var i = 0
1025 while i < str.length do
1026 var c = str[i]
1027 if c == '\\' then
1028 i = i + 1
1029 var c2 = str[i]
1030 if c2 != '{' and c2 != '}' then
1031 res.add(c)
1032 end
1033 c = c2
1034 end
1035 len = len + 1
1036 res.add(c)
1037 i = i + 1
1038 end
1039 _cstring = res.to_s
1040 _cstring_length = len
1041 end
1042 end
1043
1044 redef class AStringExpr
1045 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1046 end
1047 redef class AStartStringExpr
1048 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1049 end
1050 redef class AMidStringExpr
1051 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1052 end
1053 redef class AEndStringExpr
1054 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1055 end
1056
1057 redef class ASuperstringExpr
1058 redef fun generate_icode(v)
1059 do
1060 var array = v.add_new_array(atype, n_exprs.length)
1061 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
1062 for ne in n_exprs do
1063 var e = v.generate_expr(ne)
1064 if ne.stype != stype then
1065 e = v.expr(new ICall(prop_to_s, [e]), stype)
1066 end
1067 v.add_call_array_add(array, e)
1068 end
1069 return v.expr(new ICall(prop_to_s, [array]), stype)
1070 end
1071 end
1072
1073 redef class ANullExpr
1074 redef fun generate_icode(v)
1075 do
1076 return v.lit_null_reg
1077 end
1078 end
1079
1080 redef class AArrayExpr
1081 redef fun generate_icode(v)
1082 do
1083 var recv = v.add_new_array(stype, n_exprs.length)
1084 for ne in n_exprs do
1085 var e = v.generate_expr(ne)
1086 v.add_call_array_add(recv, e)
1087 end
1088 return recv
1089 end
1090 end
1091
1092 redef class ACrangeExpr
1093 redef fun generate_icode(v)
1094 do
1095 var e = v.generate_expr(n_expr)
1096 var e2 = v.generate_expr(n_expr2)
1097 var prop = v.visitor.get_method(stype, once "init".to_symbol)
1098 return v.expr(new INew(stype, prop, [e, e2]), stype)
1099 end
1100 end
1101
1102 redef class AOrangeExpr
1103 redef fun generate_icode(v)
1104 do
1105 var e = v.generate_expr(n_expr)
1106 var e2 = v.generate_expr(n_expr2)
1107 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1108 return v.expr(new INew(stype, prop, [e, e2]), stype)
1109 end
1110 end
1111
1112 redef class ASuperExpr
1113 redef fun generate_icode(v)
1114 do
1115 var arity = v.iroutine.params.length - 1
1116 if init_in_superclass != null then
1117 arity = init_in_superclass.signature.arity
1118 end
1119 var args = new Array[IRegister].with_capacity(arity + 1)
1120 args.add(v.iroutine.params[0])
1121 if n_args.length != arity then
1122 for i in [0..arity[ do
1123 args.add(v.iroutine.params[i + 1])
1124 end
1125 else
1126 for na in n_args do
1127 args.add(v.generate_expr(na))
1128 end
1129 end
1130 var p = init_in_superclass
1131 if p != null then
1132 var rtype = p.signature.return_type
1133 if rtype != null then
1134 return v.expr(new ICall(p, args), rtype)
1135 else
1136 v.stmt(new ICall(p, args))
1137 return null
1138 end
1139 else
1140 var p = prop
1141 var rtype = p.signature.return_type
1142 if rtype == null then
1143 v.stmt(new ISuper(p, args))
1144 return null
1145 else
1146 return v.expr(new ISuper(p, args), rtype)
1147 end
1148 end
1149 end
1150 end
1151
1152 redef class AAttrExpr
1153 redef fun generate_icode(v)
1154 do
1155 var e = v.generate_expr(n_expr)
1156 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1157 return v.add_attr_read(prop, e)
1158 end
1159 end
1160
1161 redef class AAttrAssignExpr
1162 redef fun generate_icode(v)
1163 do
1164 var e = v.generate_expr(n_expr)
1165 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1166 var e2 = v.generate_expr(n_value)
1167 v.stmt(new IAttrWrite(prop, e, e2))
1168 return null
1169 end
1170 end
1171 redef class AAttrReassignExpr
1172 redef fun generate_icode(v)
1173 do
1174 var e1 = v.generate_expr(n_expr)
1175 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1176 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1177 var e3 = v.generate_expr(n_value)
1178 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1179 v.stmt(new IAttrWrite(prop, e1, e4))
1180 return null
1181 end
1182 end
1183
1184 redef class AIssetAttrExpr
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 return v.expr(new IAttrIsset(prop, e), stype)
1190 end
1191 end
1192
1193 redef class AAbsAbsSendExpr
1194 # Compile each argument and add them to the array
1195 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1196 do
1197 var par_arity = signature.arity
1198 var par_vararg = signature.vararg_rank
1199 var raw_args = raw_arguments
1200 var raw_arity = raw_args.length
1201 var arg_idx = 0
1202 for par_idx in [0..par_arity[ do
1203 var a: AExpr
1204 var par_type = signature[par_idx]
1205 if par_idx == par_vararg then
1206 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1207 for i in [0..(raw_arity-par_arity)] do
1208 a = raw_args[arg_idx]
1209 v.add_call_array_add(arr, v.generate_expr(a))
1210 arg_idx = arg_idx + 1
1211 end
1212 args.add(arr)
1213 else
1214 a = raw_args[arg_idx]
1215 args.add(v.generate_expr(a))
1216 arg_idx = arg_idx + 1
1217 end
1218 end
1219 end
1220 end
1221
1222 redef class ASendExpr
1223 redef fun generate_icode(v)
1224 do
1225 var recv = v.generate_expr(n_expr)
1226 var args = new Array[IRegister]
1227 args.add(recv)
1228 var prop = prop
1229 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1230 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1231 var r2: nullable IRegister # The raw result of the call
1232
1233 # Prepare closures
1234 var seq_old = v.seq
1235 var closcns: nullable Array[nullable IClosureDef] = null
1236 if not prop_signature.closures.is_empty then
1237 var rtype = prop_signature.return_type
1238 if rtype != null then
1239 r = v.new_register(rtype)
1240 end
1241 var seq = new ISeq
1242 v.stmt(seq)
1243 v.seq = seq
1244 closcns = new Array[nullable IClosureDef]
1245 var cdarity = 0
1246 if closure_defs != null then cdarity = closure_defs.length
1247 for i in [0..cdarity[ do
1248 closure_defs[i].escapable.break_seq = seq
1249 closure_defs[i].escapable.break_value = r
1250 var cn = closure_defs[i].generate_iclosuredef(v)
1251 closcns.add(cn)
1252 end
1253 for i in [cdarity..prop_signature.closures.length[ do
1254 closcns.add(null)
1255 end
1256 end
1257
1258 r2 = v.add_call(prop, args, closcns)
1259
1260 # Closure work
1261 if not prop_signature.closures.is_empty then
1262 if r != null and r2 != null then v.add_assignment(r, r2)
1263 v.seq = seq_old
1264 else
1265 r = r2
1266 end
1267
1268 if prop.global.is_init then
1269 v.invoke_super_init_calls_after(prop)
1270 end
1271 return r
1272 end
1273 end
1274
1275 redef class ASendReassignExpr
1276 redef fun generate_icode(v)
1277 do
1278 var recv = v.generate_expr(n_expr)
1279 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1280 var args = new Array[IRegister]
1281 args.add(recv)
1282 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1283
1284 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1285 var e3 = v.generate_expr(n_value)
1286 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1287 var args2 = args.to_a
1288 args2.add(e4)
1289 v.stmt(new ICall(prop, args2))
1290 return null
1291 end
1292 end
1293
1294 redef class ANewExpr
1295 redef fun generate_icode(v)
1296 do
1297 var args = new Array[IRegister]
1298 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1299 return v.expr(new INew(stype, prop, args), stype)
1300 end
1301 end
1302
1303 redef class AProxyExpr
1304 redef fun generate_icode(v)
1305 do
1306 return v.generate_expr(n_expr)
1307 end
1308 end
1309
1310 redef class AOnceExpr
1311 redef fun generate_icode(v)
1312 do
1313 var ionce = new IOnce
1314 var reg = v.expr(ionce, stype)
1315 var old_seq = v.seq
1316 v.seq = ionce.body
1317
1318 var e = v.generate_expr(n_expr)
1319 v.add_assignment(reg, e)
1320
1321 v.seq = old_seq
1322 return reg
1323 end
1324 end
1325
1326
1327 redef class AClosureDef
1328 var _iclosure_def: nullable IClosureDef
1329
1330 fun generate_iclosuredef(v: A2IContext): IClosureDef
1331 do
1332 # Prepare signature
1333 var args = new Array[IRegister]
1334 var sig = closure.signature
1335 for i in [0..sig.arity[ do
1336 args.add(v.new_register(sig[i]))
1337 end
1338 var ret: nullable IRegister = null
1339 var rtype = sig.return_type
1340 if rtype != null then
1341 ret = v.new_register(rtype)
1342 end
1343
1344 var iclos = new IClosureDef(args, ret)
1345 iclos.location = location
1346
1347 # Prepare env
1348 var seq_old = v.seq
1349 v.seq = iclos.body
1350 escapable.continue_seq = iclos.body
1351 escapable.continue_value = iclos.result
1352
1353 # Assign parameters
1354 for i in [0..variables.length[ do
1355 var res = v.variable(variables[i])
1356 v.add_assignment(res, iclos.params[i])
1357 end
1358
1359 v.generate_stmt(n_expr)
1360
1361 v.seq = seq_old
1362 _iclosure_def = iclos
1363 return iclos
1364 end
1365 end
1366
1367 redef class AClosureCallExpr
1368 redef fun generate_icode(v)
1369 do
1370 # Geneate arguments
1371 var args = new Array[IRegister]
1372 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1373
1374 # Prepare icall
1375 var closdecl = v.closurevariables[variable]
1376 var icall = new IClosCall(closdecl, args)
1377 var seq_old = v.seq
1378
1379 # Fill break of ical
1380 if n_closure_defs.length == 1 then do
1381 var iseq = new ISeq
1382 icall.break_seq = iseq
1383 v.seq = iseq
1384 v.generate_stmt(n_closure_defs.first.n_expr)
1385 v.seq = seq_old
1386 end
1387
1388 # Prepare in case of default block
1389 var iif: nullable IIf = null # The iif of default block
1390 var closdecl_default = closdecl.default # The default (if any)
1391 if closdecl_default != null then
1392 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1393 v.stmt(iif)
1394 v.seq = iif.then_seq
1395 end
1396
1397 # Add the icall
1398 var r2: nullable IRegister = null # the result of the icall
1399 var rtype = variable.closure.signature.return_type
1400 if rtype == null then
1401 v.stmt(icall)
1402 else
1403 r2 = v.expr(icall, rtype)
1404 end
1405
1406 # Process the case of default block
1407 var r: nullable IRegister = null # the real result
1408 if closdecl_default != null then
1409 assert iif != null
1410 if r2 != null then
1411 assert rtype != null
1412 r = v.new_register(rtype)
1413 v.add_assignment(r, r2)
1414 end
1415 v.seq = iif.else_seq
1416 var r3 = closdecl_default.inline_in_seq(iif.else_seq, args)
1417 if r != null then
1418 assert r3 != null
1419 v.add_assignment(r, r3)
1420 end
1421 v.seq = seq_old
1422 else
1423 r = r2
1424 end
1425 return r
1426 end
1427 end