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