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