syntax: enable a generalized for with iterate
[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 init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod)
86 do
87 super(visitor.mmmodule, 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 super 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 for i in [0..variables.length[ do
629 v.stmt(new IMove(v.variable(variables[i]), iclos.params[i]))
630 end
631 v.generate_stmt(n_block)
632
633 # Call closure
634 v.seq = seq
635 v.add_call(meth, args, [iclos])
636
637 v.seq = old_seq
638 return null
639 end
640 end
641
642 redef class AAssertExpr
643 redef fun generate_icode(v)
644 do
645 var e = v.generate_expr(n_expr)
646 var iif = new IIf(e)
647 v.stmt(iif)
648 var seq_old = v.seq
649 v.seq = iif.else_seq
650 v.generate_stmt(n_else)
651 var id = n_id
652 if id == null then
653 v.add_abort("Assert failed")
654 else
655 v.add_abort("Assert %s failed", id.to_s)
656 end
657 v.seq = seq_old
658 return null
659 end
660 end
661
662 redef class AVarExpr
663 redef fun generate_icode(v)
664 do
665 return v.variable(variable)
666 end
667 end
668
669 redef class AVarAssignExpr
670 redef fun generate_icode(v)
671 do
672 var e = v.generate_expr(n_value)
673 v.add_assignment(v.variable(variable), e)
674 return null
675 end
676 end
677
678 redef class AVarReassignExpr
679 redef fun generate_icode(v)
680 do
681 var e1 = v.variable(variable)
682 var e2 = v.generate_expr(n_value)
683 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
684 v.add_assignment(e1, e3)
685 return null
686 end
687 end
688
689 redef class ASelfExpr
690 redef fun generate_icode(v)
691 do
692 return v.variable(variable)
693 end
694 end
695
696 redef class AIfexprExpr
697 redef fun generate_icode(v)
698 do
699 # Process condition
700 var iif = new IIf(v.generate_expr(n_expr))
701 v.stmt(iif)
702 var seq_old = v.seq
703
704 # Prepare result
705 var reg = v.new_register(stype)
706
707 # Process 'then'
708 v.seq = iif.then_seq
709 v.add_assignment(reg, v.generate_expr(n_then))
710
711 # Process 'else'
712 v.seq = iif.else_seq
713 v.add_assignment(reg, v.generate_expr(n_else))
714
715 v.seq = seq_old
716 return reg
717 end
718 end
719
720 redef class AEeExpr
721 redef fun generate_icode(v)
722 do
723 var e = v.generate_expr(n_expr)
724 var e2 = v.generate_expr(n_expr2)
725 return v.expr(new IIs(e, e2), stype)
726 end
727 end
728
729 redef class AOrExpr
730 redef fun generate_icode(v)
731 do
732 # Prepare result
733 var reg = v.new_register(stype)
734
735 # Process left operand (in a if/then)
736 var iif = new IIf(v.generate_expr(n_expr))
737 v.stmt(iif)
738 var seq_old = v.seq
739 v.seq = iif.then_seq
740 v.add_assignment(reg, v.lit_true_reg)
741
742 # Process right operand (in the else)
743 v.seq = iif.else_seq
744 v.add_assignment(reg, v.generate_expr(n_expr2))
745
746 v.seq = seq_old
747 return reg
748 end
749 end
750
751 redef class AAndExpr
752 redef fun generate_icode(v)
753 do
754 # Prepare result
755 var reg = v.new_register(stype)
756
757 # Process left operand (in a if/else)
758 var iif = new IIf(v.generate_expr(n_expr))
759 v.stmt(iif)
760 var seq_old = v.seq
761 v.seq = iif.else_seq
762 v.add_assignment(reg, v.lit_false_reg)
763
764 # Process right operand (in the then)
765 v.seq = iif.then_seq
766 v.add_assignment(reg, v.generate_expr(n_expr2))
767
768 v.seq = seq_old
769 return reg
770 end
771 end
772
773 redef class ANotExpr
774 redef fun generate_icode(v)
775 do
776 var e = v.generate_expr(n_expr)
777 return v.expr(new INot(e), stype)
778 end
779 end
780
781 redef class AOrElseExpr
782 redef fun generate_icode(v)
783 do
784 # Compute left operand
785 var e = v.generate_expr(n_expr)
786
787 # Prepare result
788 var reg = v.new_register(stype)
789
790 # Compare left and null
791 var n = v.lit_null_reg
792 var c = v.expr(new IIs(e, n), v.mmmodule.type_bool)
793 var iif = new IIf(c)
794 v.stmt(iif)
795 var old_seq = v.seq
796
797 # if equal, result = right opr
798 v.seq = iif.then_seq
799 v.add_assignment(reg, v.generate_expr(n_expr2))
800
801 # else, result = left operand
802 v.seq = iif.else_seq
803 v.add_assignment(reg, e)
804
805 v.seq = old_seq
806
807 return reg
808 end
809 end
810
811 redef class AIsaExpr
812 redef fun generate_icode(v)
813 do
814 var e = v.generate_expr(n_expr)
815 return v.expr(new ITypeCheck(e, n_type.stype), stype)
816 end
817 end
818
819 redef class AAsCastExpr
820 redef fun generate_icode(v)
821 do
822 var e = v.generate_expr(n_expr)
823 v.add_type_cast(e, stype)
824 return e
825 end
826 end
827
828 redef class AAsNotnullExpr
829 redef fun generate_icode(v)
830 do
831 var e = v.generate_expr(n_expr)
832 v.add_type_cast(e, stype)
833 return e
834 end
835 end
836
837 redef class ATrueExpr
838 redef fun generate_icode(v)
839 do
840 return v.lit_true_reg
841 end
842 end
843
844 redef class AFalseExpr
845 redef fun generate_icode(v)
846 do
847 return v.lit_false_reg
848 end
849 end
850
851 redef class AIntExpr
852 redef fun generate_icode(v)
853 do
854 return v.expr(new IIntValue(n_number.text), stype)
855 end
856 end
857
858 redef class AFloatExpr
859 redef fun generate_icode(v)
860 do
861 return v.expr(new IFloatValue(n_float.text), stype)
862 end
863 end
864
865 redef class ACharExpr
866 redef fun generate_icode(v)
867 do
868 return v.expr(new ICharValue(n_char.text), stype)
869 end
870 end
871
872 redef class AStringFormExpr
873 redef fun generate_icode(v)
874 do
875 compute_string_infos
876 var old_seq = v.seq
877 var ionce = new IOnce
878 var reg = v.expr(ionce, stype)
879 v.seq = ionce.body
880 var ns = v.expr(new IStringValue(_cstring.as(not null)), v.visitor.type_nativestring)
881 var ni = v.expr(new IIntValue(_cstring_length.to_s), v.visitor.type_int)
882 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
883 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
884 v.add_assignment(reg, e)
885 v.seq = old_seq
886 return reg
887 end
888
889 # The raw string value
890 protected fun string_text: String is abstract
891
892 # The string in a C native format
893 protected var _cstring: nullable String
894
895 # The string length in bytes
896 protected var _cstring_length: nullable Int
897
898 # Compute _cstring and _cstring_length using string_text
899 protected fun compute_string_infos
900 do
901 var len = 0
902 var str = string_text
903 var res = new Buffer
904 var i = 0
905 while i < str.length do
906 var c = str[i]
907 if c == '\\' then
908 i = i + 1
909 var c2 = str[i]
910 if c2 != '{' and c2 != '}' then
911 res.add(c)
912 end
913 c = c2
914 end
915 len = len + 1
916 res.add(c)
917 i = i + 1
918 end
919 _cstring = res.to_s
920 _cstring_length = len
921 end
922 end
923
924 redef class AStringExpr
925 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
926 end
927 redef class AStartStringExpr
928 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
929 end
930 redef class AMidStringExpr
931 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
932 end
933 redef class AEndStringExpr
934 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
935 end
936
937 redef class ASuperstringExpr
938 redef fun generate_icode(v)
939 do
940 var array = v.add_new_array(atype, n_exprs.length)
941 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
942 for ne in n_exprs do
943 var e = v.generate_expr(ne)
944 if ne.stype != stype then
945 e = v.expr(new ICall(prop_to_s, [e]), stype)
946 end
947 v.add_call_array_add(array, e)
948 end
949 return v.expr(new ICall(prop_to_s, [array]), stype)
950 end
951 end
952
953 redef class ANullExpr
954 redef fun generate_icode(v)
955 do
956 return v.lit_null_reg
957 end
958 end
959
960 redef class AArrayExpr
961 redef fun generate_icode(v)
962 do
963 var recv = v.add_new_array(stype, n_exprs.length)
964 for ne in n_exprs do
965 var e = v.generate_expr(ne)
966 v.add_call_array_add(recv, e)
967 end
968 return recv
969 end
970 end
971
972 redef class ACrangeExpr
973 redef fun generate_icode(v)
974 do
975 var e = v.generate_expr(n_expr)
976 var e2 = v.generate_expr(n_expr2)
977 var prop = v.visitor.get_method(stype, once "init".to_symbol)
978 return v.expr(new INew(stype, prop, [e, e2]), stype)
979 end
980 end
981
982 redef class AOrangeExpr
983 redef fun generate_icode(v)
984 do
985 var e = v.generate_expr(n_expr)
986 var e2 = v.generate_expr(n_expr2)
987 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
988 return v.expr(new INew(stype, prop, [e, e2]), stype)
989 end
990 end
991
992 redef class ASuperExpr
993 redef fun generate_icode(v)
994 do
995 var arity = v.iroutine.params.length - 1
996 if init_in_superclass != null then
997 arity = init_in_superclass.signature.arity
998 end
999 var args = new Array[IRegister].with_capacity(arity + 1)
1000 args.add(v.iroutine.params[0])
1001 if n_args.length != arity then
1002 for i in [0..arity[ do
1003 args.add(v.iroutine.params[i + 1])
1004 end
1005 else
1006 for na in n_args do
1007 args.add(v.generate_expr(na))
1008 end
1009 end
1010 var p = init_in_superclass
1011 if p != null then
1012 var rtype = p.signature.return_type
1013 if rtype != null then
1014 return v.expr(new ICall(p, args), rtype)
1015 else
1016 v.stmt(new ICall(p, args))
1017 return null
1018 end
1019 else
1020 p = prop
1021 var rtype = p.signature.return_type
1022 if rtype == null then
1023 v.stmt(new ISuper(p, args))
1024 return null
1025 else
1026 return v.expr(new ISuper(p, args), rtype)
1027 end
1028 end
1029 end
1030 end
1031
1032 redef class AAttrExpr
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.add_attr_read(prop, e)
1038 end
1039 end
1040
1041 redef class AAttrAssignExpr
1042 redef fun generate_icode(v)
1043 do
1044 var e = v.generate_expr(n_expr)
1045 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1046 var e2 = v.generate_expr(n_value)
1047 v.stmt(new IAttrWrite(prop, e, e2))
1048 return null
1049 end
1050 end
1051 redef class AAttrReassignExpr
1052 redef fun generate_icode(v)
1053 do
1054 var e1 = v.generate_expr(n_expr)
1055 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1056 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1057 var e3 = v.generate_expr(n_value)
1058 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1059 v.stmt(new IAttrWrite(prop, e1, e4))
1060 return null
1061 end
1062 end
1063
1064 redef class AIssetAttrExpr
1065 redef fun generate_icode(v)
1066 do
1067 var e = v.generate_expr(n_expr)
1068 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1069 return v.expr(new IAttrIsset(prop, e), stype)
1070 end
1071 end
1072
1073 redef class AAbsAbsSendExpr
1074 # Compile each argument and add them to the array
1075 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1076 do
1077 var par_arity = signature.arity
1078 var par_vararg = signature.vararg_rank
1079 var raw_args = raw_arguments
1080 var raw_arity = raw_args.length
1081 var arg_idx = 0
1082 for par_idx in [0..par_arity[ do
1083 var a: AExpr
1084 var par_type = signature[par_idx]
1085 if par_idx == par_vararg then
1086 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1087 for i in [0..(raw_arity-par_arity)] do
1088 a = raw_args[arg_idx]
1089 v.add_call_array_add(arr, v.generate_expr(a))
1090 arg_idx = arg_idx + 1
1091 end
1092 args.add(arr)
1093 else
1094 a = raw_args[arg_idx]
1095 args.add(v.generate_expr(a))
1096 arg_idx = arg_idx + 1
1097 end
1098 end
1099 end
1100 end
1101
1102 redef class ASendExpr
1103 redef fun generate_icode(v)
1104 do
1105 var recv = v.generate_expr(n_expr)
1106 var args = new Array[IRegister]
1107 args.add(recv)
1108 var prop = prop
1109 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1110 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1111 var r2: nullable IRegister # The raw result of the call
1112
1113 # Prepare closures
1114 var seq_old = v.seq
1115 var closcns: nullable Array[nullable IClosureDef] = null
1116 if not prop_signature.closures.is_empty then
1117 var rtype = prop_signature.return_type
1118 if rtype != null then
1119 r = v.new_register(rtype)
1120 end
1121 var seq = new ISeq
1122 v.stmt(seq)
1123 v.seq = seq
1124 closcns = new Array[nullable IClosureDef]
1125 var cdarity = 0
1126 if closure_defs != null then cdarity = closure_defs.length
1127 var closure_defs = closure_defs
1128 for mmc in prop_signature.closures do
1129 var found = false
1130 var name = mmc.name
1131 if closure_defs != null then
1132 for cd in closure_defs do
1133 if cd.n_id.to_symbol != name then continue
1134 assert found == false
1135 found = true
1136 cd.escapable.break_seq = seq
1137 cd.escapable.break_value = r
1138 var cn = cd.generate_iclosuredef(v)
1139 closcns.add(cn)
1140 end
1141 end
1142 if not found then
1143 closcns.add(null)
1144 end
1145 end
1146 end
1147
1148 r2 = v.add_call(prop, args, closcns)
1149
1150 # Closure work
1151 if not prop_signature.closures.is_empty then
1152 if r != null and r2 != null then v.add_assignment(r, r2)
1153 v.seq = seq_old
1154 else
1155 r = r2
1156 end
1157
1158 if prop.global.is_init then
1159 v.invoke_super_init_calls_after(prop)
1160 end
1161 return r
1162 end
1163 end
1164
1165 redef class ASendReassignExpr
1166 redef fun generate_icode(v)
1167 do
1168 var recv = v.generate_expr(n_expr)
1169 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1170 var args = new Array[IRegister]
1171 args.add(recv)
1172 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1173
1174 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1175 var e3 = v.generate_expr(n_value)
1176 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1177 var args2 = args.to_a
1178 args2.add(e4)
1179 v.stmt(new ICall(prop, args2))
1180 return null
1181 end
1182 end
1183
1184 redef class ANewExpr
1185 redef fun generate_icode(v)
1186 do
1187 var args = new Array[IRegister]
1188 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1189 return v.expr(new INew(stype, prop, args), stype)
1190 end
1191 end
1192
1193 redef class AProxyExpr
1194 redef fun generate_icode(v)
1195 do
1196 return v.generate_expr(n_expr)
1197 end
1198 end
1199
1200 redef class AOnceExpr
1201 redef fun generate_icode(v)
1202 do
1203 var ionce = new IOnce
1204 var reg = v.expr(ionce, stype)
1205 var old_seq = v.seq
1206 v.seq = ionce.body
1207
1208 var e = v.generate_expr(n_expr)
1209 v.add_assignment(reg, e)
1210
1211 v.seq = old_seq
1212 return reg
1213 end
1214 end
1215
1216
1217 redef class AClosureDef
1218 var _iclosure_def: nullable IClosureDef
1219
1220 fun generate_iclosuredef(v: A2IContext): IClosureDef
1221 do
1222 # Prepare signature
1223 var args = new Array[IRegister]
1224 var sig = closure.signature
1225 for i in [0..sig.arity[ do
1226 args.add(v.new_register(sig[i]))
1227 end
1228 var ret: nullable IRegister = null
1229 var rtype = sig.return_type
1230 if rtype != null then
1231 ret = v.new_register(rtype)
1232 end
1233
1234 var iclos = new IClosureDef(args, ret)
1235 iclos.location = location
1236
1237 # Prepare env
1238 var seq_old = v.seq
1239 v.seq = iclos.body
1240 escapable.continue_seq = iclos.body
1241 escapable.continue_value = iclos.result
1242
1243 # Assign parameters
1244 for i in [0..variables.length[ do
1245 var res = v.variable(variables[i])
1246 v.add_assignment(res, iclos.params[i])
1247 end
1248
1249 v.generate_stmt(n_expr)
1250
1251 # Add a final break in case of break block witout value
1252 if closure.is_break and escapable.break_value == null then
1253 v.add_escape(escapable.break_seq.as(not null))
1254 end
1255
1256 v.seq = seq_old
1257 _iclosure_def = iclos
1258 return iclos
1259 end
1260 end
1261
1262 redef class AClosureCallExpr
1263 redef fun generate_icode(v)
1264 do
1265 # Geneate arguments
1266 var args = new Array[IRegister]
1267 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1268
1269 # Prepare icall
1270 var closdecl = v.closurevariables[variable]
1271 var icall = new IClosCall(closdecl, args)
1272 var seq_old = v.seq
1273
1274 # Fill break of ical
1275 if n_closure_defs.length == 1 then do
1276 var iseq = new ISeq
1277 icall.break_seq = iseq
1278 v.seq = iseq
1279 v.generate_stmt(n_closure_defs.first.n_expr)
1280 v.seq = seq_old
1281 end
1282
1283 # Prepare in case of default block
1284 var iif: nullable IIf = null # The iif of default block
1285 var closdecl_default = closdecl.default # The default (if any)
1286 if closdecl_default != null then
1287 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1288 v.stmt(iif)
1289 v.seq = iif.then_seq
1290 end
1291
1292 # Add the icall
1293 var r2: nullable IRegister = null # the result of the icall
1294 var rtype = variable.closure.signature.return_type
1295 if rtype == null then
1296 v.stmt(icall)
1297 else
1298 r2 = v.expr(icall, rtype)
1299 end
1300
1301 # Process the case of default block
1302 var r: nullable IRegister = null # the real result
1303 if closdecl_default != null then
1304 assert iif != null
1305 if r2 != null then
1306 assert rtype != null
1307 r = v.new_register(rtype)
1308 v.add_assignment(r, r2)
1309 end
1310 v.seq = iif.else_seq
1311 var r3 = v.inline_routine(closdecl_default, args, null)
1312 if r != null then
1313 assert r3 != null
1314 v.add_assignment(r, r3)
1315 end
1316 v.seq = seq_old
1317 else
1318 r = r2
1319 end
1320 return r
1321 end
1322 end