19bf1b0bf548120f1362accf7f972fef63a97133
[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.values do
184 for p in c.src_local_properties.values 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 AExternPropdef
395 redef fun fill_iroutine(v, method)
396 do
397 # add all explicit extern calls for this extern method
398 for explicit_import in method.as(MMMethSrcMethod).explicit_imports
399 do
400 var prop = explicit_import.method
401 var ic : IAbsCall
402 if prop.is_init then
403 ic = new INew(prop.signature.recv, prop, new List[IRegister])
404 else
405 ic = new ICall(prop, new List[IRegister])
406 end
407 ic.is_explicit_from_extern = true
408 v.stmt(ic)
409 end
410 end
411 end
412
413 redef class AExternInitPropdef
414 redef fun fill_iroutine(v, method)
415 do
416 var params = v.iroutine.params
417 var sig = method.signature
418 assert params.length == sig.arity + 1
419 var rtype = sig.recv # sig.return_type
420 if rtype != null then
421 v.add_assignment(new IRegister(rtype), v.expr(new INative(method, params), rtype))
422 end
423
424 super
425 end
426 end
427
428 redef class ADeferredMethPropdef
429 redef fun fill_iroutine(v, method)
430 do
431 v.add_abort("Deferred method called")
432 end
433 end
434
435 redef class AExternMethPropdef
436 redef fun fill_iroutine(v, method)
437 do
438 var params = v.iroutine.params
439 var rtype = method.signature.return_type
440 if rtype != null then
441 v.add_return_value(v.expr(new INative(method, params), rtype))
442 else
443 v.stmt(new INative(method, params))
444 end
445
446 super
447 end
448 end
449
450 redef class AInternMethPropdef
451 redef fun fill_iroutine(v, method)
452 do
453 var params = v.iroutine.params
454 var rtype = method.signature.return_type
455 if rtype != null then
456 v.add_return_value(v.expr(new INative(method, params), rtype))
457 else
458 v.stmt(new INative(method, params))
459 end
460 end
461 end
462
463 ###############################################################################
464
465 redef class AExpr
466 redef fun accept_icode_generation(v) do end
467
468 # Generate icode sequence in the current A2IContext
469 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
470 protected fun generate_icode(v: A2IContext): nullable IRegister is abstract
471 end
472
473 redef class AVardeclExpr
474 redef fun generate_icode(v)
475 do
476 var reg = v.variable(variable)
477 var ne = n_expr
478 if ne != null then
479 v.add_assignment(reg, v.generate_expr(ne))
480 end
481 return null
482 end
483 end
484
485 redef class ABlockExpr
486 redef fun generate_icode(v)
487 do
488 for ne in n_expr do v.generate_stmt(ne)
489 return null
490 end
491 end
492
493 redef class ADoExpr
494 redef fun generate_icode(v)
495 do
496 var seq_old = v.seq
497 var seq = new ISeq
498 v.stmt(seq)
499 escapable.break_seq = seq
500 v.seq = seq
501
502 v.generate_stmt(n_block)
503
504 v.seq = seq_old
505 return null
506 end
507 end
508
509 redef class AReturnExpr
510 redef fun generate_icode(v)
511 do
512 var ne = n_expr
513 if ne != null then
514 v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
515 end
516 v.add_escape(v.return_seq.as(not null))
517 return null
518 end
519 end
520
521 redef class ABreakExpr
522 redef fun generate_icode(v)
523 do
524 var ne = n_expr
525 if ne != null then
526 v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
527 end
528 v.add_escape(escapable.break_seq.as(not null))
529 return null
530 end
531 end
532
533 redef class AContinueExpr
534 redef fun generate_icode(v)
535 do
536 var ne = n_expr
537 if ne != null then
538 v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
539 end
540 v.add_escape(escapable.continue_seq.as(not null))
541 return null
542 end
543 end
544
545 redef class AAbortExpr
546 redef fun generate_icode(v)
547 do
548 v.add_abort("Aborted")
549 return null
550 end
551 end
552
553 redef class AIfExpr
554 redef fun generate_icode(v)
555 do
556 var iif = new IIf(v.generate_expr(n_expr))
557 v.stmt(iif)
558 var seq_old = v.seq
559
560 if n_then != null then
561 v.seq = iif.then_seq
562 v.generate_stmt(n_then)
563 end
564
565 if n_else != null then
566 v.seq = iif.else_seq
567 v.generate_stmt(n_else)
568 end
569
570 v.seq = seq_old
571 return null
572 end
573 end
574
575 redef class AWhileExpr
576 redef fun generate_icode(v)
577 do
578 var seq_old = v.seq
579 var iloop = new ILoop
580 v.stmt(iloop)
581 escapable.break_seq = iloop
582 v.seq = iloop
583
584 # Process condition
585 var iif = new IIf(v.generate_expr(n_expr))
586 v.stmt(iif)
587
588 # Process inside (condition is true)
589 if n_block != null then
590 v.seq = iif.then_seq
591 escapable.continue_seq = iif.then_seq
592 v.generate_stmt(n_block)
593 end
594
595 # Process escape (condition is false)
596 v.seq = iif.else_seq
597 v.add_escape(iloop)
598
599 v.seq = seq_old
600 return null
601 end
602 end
603
604 redef class ALoopExpr
605 redef fun generate_icode(v)
606 do
607 var seq_old = v.seq
608 var iloop = new ILoop
609 v.stmt(iloop)
610 escapable.break_seq = iloop
611 v.seq = iloop
612
613 # Process inside
614 if n_block != null then
615 var seq = new ISeq
616 v.stmt(seq)
617 v.seq = seq
618 escapable.continue_seq = seq
619 v.generate_stmt(n_block)
620 end
621
622 v.seq = seq_old
623 return null
624 end
625 end
626
627 redef class AForExpr
628 redef fun generate_icode(v)
629 do
630 var ne = n_expr
631 var expr_type = ne.stype
632 var tint = v.visitor.type_int
633 var meth # The method that call the closure
634 var args # The arguments of meth
635
636 if ne isa ARangeExpr and expr_type == v.visitor.type_range(tint) then
637 # Shortcut. No Range[Int] object allocated.
638 # 'for x in [y..z] do' become 'y.enumerate_to(z) !each(x) do'
639 # 'for x in [y..z[ do' become 'y.enumerate_before(z) !each(x) do'
640 # And both methods may be inlined
641 args = [v.generate_expr(ne.n_expr), v.generate_expr(ne.n_expr2)]
642 if ne isa ACrangeExpr then
643 meth = v.visitor.get_method(tint, once "enumerate_to".to_symbol)
644 else
645 assert ne isa AOrangeExpr
646 meth = v.visitor.get_method(tint, once "enumerate_before".to_symbol)
647 end
648 else
649 # Standard way.
650 # 'for x in e do' become 'e.iterate !each(x) do'
651 # Some iterate methods may be inlined (eg. the Array one)
652 meth = v.visitor.get_method(expr_type, once "iterate".to_symbol)
653 args = [v.generate_expr(n_expr)]
654 end
655
656 # Build closure
657 var iclos = meth.signature.closures.first.signature.generate_empty_iclosuredef(v)
658 var old_seq = v.seq
659
660 var seq = new ISeq
661 v.stmt(seq)
662 v.seq = seq
663 escapable.break_seq = seq
664 escapable.break_value = null
665
666 v.seq = iclos.body
667 escapable.continue_seq = iclos.body
668 escapable.continue_value = null
669 for i in [0..variables.length[ do
670 v.stmt(new IMove(v.variable(variables[i]), iclos.params[i]))
671 end
672 v.generate_stmt(n_block)
673
674 # Call closure
675 v.seq = seq
676 v.add_call(meth, args, [iclos])
677
678 v.seq = old_seq
679 return null
680 end
681 end
682
683 redef class AAssertExpr
684 redef fun generate_icode(v)
685 do
686 var e = v.generate_expr(n_expr)
687 var iif = new IIf(e)
688 v.stmt(iif)
689 var seq_old = v.seq
690 v.seq = iif.else_seq
691 v.generate_stmt(n_else)
692 var id = n_id
693 if id == null then
694 v.add_abort("Assert failed")
695 else
696 v.add_abort("Assert '%s' failed", id.text.to_s)
697 end
698 v.seq = seq_old
699 return null
700 end
701 end
702
703 redef class AVarExpr
704 redef fun generate_icode(v)
705 do
706 return v.variable(variable)
707 end
708 end
709
710 redef class AVarAssignExpr
711 redef fun generate_icode(v)
712 do
713 var e = v.generate_expr(n_value)
714 v.add_assignment(v.variable(variable), e)
715 return null
716 end
717 end
718
719 redef class AVarReassignExpr
720 redef fun generate_icode(v)
721 do
722 var e1 = v.variable(variable)
723 var e2 = v.generate_expr(n_value)
724 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
725 v.add_assignment(e1, e3)
726 return null
727 end
728 end
729
730 redef class ASelfExpr
731 redef fun generate_icode(v)
732 do
733 return v.variable(variable)
734 end
735 end
736
737 redef class AIfexprExpr
738 redef fun generate_icode(v)
739 do
740 # Process condition
741 var iif = new IIf(v.generate_expr(n_expr))
742 v.stmt(iif)
743 var seq_old = v.seq
744
745 # Prepare result
746 var reg = v.new_register(stype)
747
748 # Process 'then'
749 v.seq = iif.then_seq
750 v.add_assignment(reg, v.generate_expr(n_then))
751
752 # Process 'else'
753 v.seq = iif.else_seq
754 v.add_assignment(reg, v.generate_expr(n_else))
755
756 v.seq = seq_old
757 return reg
758 end
759 end
760
761 redef class AEeExpr
762 redef fun generate_icode(v)
763 do
764 var e = v.generate_expr(n_expr)
765 var e2 = v.generate_expr(n_expr2)
766 return v.expr(new IIs(e, e2), stype)
767 end
768 end
769
770 redef class AOrExpr
771 redef fun generate_icode(v)
772 do
773 # Prepare result
774 var reg = v.new_register(stype)
775
776 # Process left operand (in a if/then)
777 var iif = new IIf(v.generate_expr(n_expr))
778 v.stmt(iif)
779 var seq_old = v.seq
780 v.seq = iif.then_seq
781 v.add_assignment(reg, v.lit_true_reg)
782
783 # Process right operand (in the else)
784 v.seq = iif.else_seq
785 v.add_assignment(reg, v.generate_expr(n_expr2))
786
787 v.seq = seq_old
788 return reg
789 end
790 end
791
792 redef class AAndExpr
793 redef fun generate_icode(v)
794 do
795 # Prepare result
796 var reg = v.new_register(stype)
797
798 # Process left operand (in a if/else)
799 var iif = new IIf(v.generate_expr(n_expr))
800 v.stmt(iif)
801 var seq_old = v.seq
802 v.seq = iif.else_seq
803 v.add_assignment(reg, v.lit_false_reg)
804
805 # Process right operand (in the then)
806 v.seq = iif.then_seq
807 v.add_assignment(reg, v.generate_expr(n_expr2))
808
809 v.seq = seq_old
810 return reg
811 end
812 end
813
814 redef class ANotExpr
815 redef fun generate_icode(v)
816 do
817 var e = v.generate_expr(n_expr)
818 return v.expr(new INot(e), stype)
819 end
820 end
821
822 redef class AOrElseExpr
823 redef fun generate_icode(v)
824 do
825 # Compute left operand
826 var e = v.generate_expr(n_expr)
827
828 # Prepare result
829 var reg = v.new_register(stype)
830
831 # Compare left and null
832 var n = v.lit_null_reg
833 var c = v.expr(new IIs(e, n), v.mmmodule.type_bool)
834 var iif = new IIf(c)
835 v.stmt(iif)
836 var old_seq = v.seq
837
838 # if equal, result = right opr
839 v.seq = iif.then_seq
840 v.add_assignment(reg, v.generate_expr(n_expr2))
841
842 # else, result = left operand
843 v.seq = iif.else_seq
844 v.add_assignment(reg, e)
845
846 v.seq = old_seq
847
848 return reg
849 end
850 end
851
852 redef class AIsaExpr
853 redef fun generate_icode(v)
854 do
855 var e = v.generate_expr(n_expr)
856 return v.expr(new ITypeCheck(v.selfreg.as(not null), e, n_type.stype), stype)
857 end
858 end
859
860 redef class AAsCastExpr
861 redef fun generate_icode(v)
862 do
863 var e = v.generate_expr(n_expr)
864 v.add_type_cast(e, stype)
865 return e
866 end
867 end
868
869 redef class AAsNotnullExpr
870 redef fun generate_icode(v)
871 do
872 var e = v.generate_expr(n_expr)
873 v.add_type_cast(e, stype)
874 return e
875 end
876 end
877
878 redef class ATrueExpr
879 redef fun generate_icode(v)
880 do
881 return v.lit_true_reg
882 end
883 end
884
885 redef class AFalseExpr
886 redef fun generate_icode(v)
887 do
888 return v.lit_false_reg
889 end
890 end
891
892 redef class AIntExpr
893 redef fun generate_icode(v)
894 do
895 return v.expr(new IIntValue(n_number.text), stype)
896 end
897 end
898
899 redef class AFloatExpr
900 redef fun generate_icode(v)
901 do
902 return v.expr(new IFloatValue(n_float.text), stype)
903 end
904 end
905
906 redef class ACharExpr
907 redef fun generate_icode(v)
908 do
909 return v.expr(new ICharValue(n_char.text), stype)
910 end
911 end
912
913 redef class AStringFormExpr
914 redef fun generate_icode(v)
915 do
916 compute_string_infos
917 var old_seq = v.seq
918 var ionce = new IOnce
919 var reg = v.expr(ionce, stype)
920 v.seq = ionce.body
921 var ns = v.expr(new IStringValue(_cstring.as(not null)), v.visitor.type_nativestring)
922 var ni = v.expr(new IIntValue(_cstring_length.to_s), v.visitor.type_int)
923 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
924 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
925 v.add_assignment(reg, e)
926 v.seq = old_seq
927 return reg
928 end
929
930 # The raw string value
931 protected fun string_text: String is abstract
932
933 # The string in a C native format
934 protected var _cstring: nullable String
935
936 # The string length in bytes
937 protected var _cstring_length: nullable Int
938
939 # Compute _cstring and _cstring_length using string_text
940 protected fun compute_string_infos
941 do
942 var len = 0
943 var str = string_text
944 var res = new Buffer
945 var i = 0
946 while i < str.length do
947 var c = str[i]
948 if c == '\\' then
949 i = i + 1
950 var c2 = str[i]
951 if c2 != '{' and c2 != '}' then
952 res.add(c)
953 end
954 c = c2
955 end
956 len = len + 1
957 res.add(c)
958 i = i + 1
959 end
960 _cstring = res.to_s
961 _cstring_length = len
962 end
963 end
964
965 redef class AStringExpr
966 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
967 end
968 redef class AStartStringExpr
969 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
970 end
971 redef class AMidStringExpr
972 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
973 end
974 redef class AEndStringExpr
975 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
976 end
977
978 redef class ASuperstringExpr
979 redef fun generate_icode(v)
980 do
981 var array = v.add_new_array(atype, n_exprs.length)
982 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
983 for ne in n_exprs do
984 var e = v.generate_expr(ne)
985 if ne.stype != stype then
986 e = v.expr(new ICall(prop_to_s, [e]), stype)
987 end
988 v.add_call_array_add(array, e)
989 end
990 return v.expr(new ICall(prop_to_s, [array]), stype)
991 end
992 end
993
994 redef class ANullExpr
995 redef fun generate_icode(v)
996 do
997 return v.lit_null_reg
998 end
999 end
1000
1001 redef class AArrayExpr
1002 redef fun generate_icode(v)
1003 do
1004 var recv = v.add_new_array(stype, n_exprs.length)
1005 for ne in n_exprs do
1006 var e = v.generate_expr(ne)
1007 v.add_call_array_add(recv, e)
1008 end
1009 return recv
1010 end
1011 end
1012
1013 redef class ACrangeExpr
1014 redef fun generate_icode(v)
1015 do
1016 var e = v.generate_expr(n_expr)
1017 var e2 = v.generate_expr(n_expr2)
1018 var prop = v.visitor.get_method(stype, once "init".to_symbol)
1019 return v.expr(new INew(stype, prop, [e, e2]), stype)
1020 end
1021 end
1022
1023 redef class AOrangeExpr
1024 redef fun generate_icode(v)
1025 do
1026 var e = v.generate_expr(n_expr)
1027 var e2 = v.generate_expr(n_expr2)
1028 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1029 return v.expr(new INew(stype, prop, [e, e2]), stype)
1030 end
1031 end
1032
1033 redef class ASuperExpr
1034 redef fun generate_icode(v)
1035 do
1036 var arity = v.iroutine.params.length - 1
1037 if init_in_superclass != null then
1038 arity = init_in_superclass.signature.arity
1039 end
1040 var args = new Array[IRegister].with_capacity(arity + 1)
1041 args.add(v.iroutine.params[0])
1042 if n_args.length != arity then
1043 for i in [0..arity[ do
1044 args.add(v.iroutine.params[i + 1])
1045 end
1046 else
1047 for na in n_args do
1048 args.add(v.generate_expr(na))
1049 end
1050 end
1051 var p = init_in_superclass
1052 if p != null then
1053 var rtype = p.signature.return_type
1054 if rtype != null then
1055 return v.expr(new ICall(p, args), rtype)
1056 else
1057 v.stmt(new ICall(p, args))
1058 return null
1059 end
1060 else
1061 p = prop
1062 var rtype = p.signature.return_type
1063 if rtype == null then
1064 v.stmt(new ISuper(p, args))
1065 return null
1066 else
1067 return v.expr(new ISuper(p, args), rtype)
1068 end
1069 end
1070 end
1071 end
1072
1073 redef class AAttrExpr
1074 redef fun generate_icode(v)
1075 do
1076 var e = v.generate_expr(n_expr)
1077 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1078 return v.add_attr_read(prop, e)
1079 end
1080 end
1081
1082 redef class AAttrAssignExpr
1083 redef fun generate_icode(v)
1084 do
1085 var e = v.generate_expr(n_expr)
1086 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1087 var e2 = v.generate_expr(n_value)
1088 v.stmt(new IAttrWrite(prop, e, e2))
1089 return null
1090 end
1091 end
1092 redef class AAttrReassignExpr
1093 redef fun generate_icode(v)
1094 do
1095 var e1 = v.generate_expr(n_expr)
1096 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1097 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1098 var e3 = v.generate_expr(n_value)
1099 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1100 v.stmt(new IAttrWrite(prop, e1, e4))
1101 return null
1102 end
1103 end
1104
1105 redef class AIssetAttrExpr
1106 redef fun generate_icode(v)
1107 do
1108 var e = v.generate_expr(n_expr)
1109 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1110 return v.expr(new IAttrIsset(prop, e), stype)
1111 end
1112 end
1113
1114 redef class AAbsAbsSendExpr
1115 # Compile each argument and add them to the array
1116 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1117 do
1118 var par_arity = signature.arity
1119 var par_vararg = signature.vararg_rank
1120 var raw_args = raw_arguments
1121 var raw_arity = raw_args.length
1122 var arg_idx = 0
1123 for par_idx in [0..par_arity[ do
1124 var a: AExpr
1125 var par_type = signature[par_idx]
1126 if par_idx == par_vararg then
1127 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1128 for i in [0..(raw_arity-par_arity)] do
1129 a = raw_args[arg_idx]
1130 v.add_call_array_add(arr, v.generate_expr(a))
1131 arg_idx = arg_idx + 1
1132 end
1133 args.add(arr)
1134 else
1135 a = raw_args[arg_idx]
1136 args.add(v.generate_expr(a))
1137 arg_idx = arg_idx + 1
1138 end
1139 end
1140 end
1141 end
1142
1143 redef class ASendExpr
1144 redef fun generate_icode(v)
1145 do
1146 var recv = v.generate_expr(n_expr)
1147 var args = new Array[IRegister]
1148 args.add(recv)
1149 var prop = prop
1150 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1151 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1152 var r2: nullable IRegister # The raw result of the call
1153
1154 # Prepare closures
1155 var seq_old = v.seq
1156 var closcns: nullable Array[nullable IClosureDef] = null
1157 if not prop_signature.closures.is_empty then
1158 var rtype = prop_signature.return_type
1159 if rtype != null then
1160 r = v.new_register(rtype)
1161 end
1162 var seq = new ISeq
1163 v.stmt(seq)
1164 v.seq = seq
1165 closcns = new Array[nullable IClosureDef]
1166 var cdarity = 0
1167 if closure_defs != null then cdarity = closure_defs.length
1168 var closure_defs = closure_defs
1169 for mmc in prop_signature.closures do
1170 var found = false
1171 var name = mmc.name
1172 if closure_defs != null then
1173 for cd in closure_defs do
1174 if cd.n_id.to_symbol != name then continue
1175 assert found == false
1176 found = true
1177 cd.escapable.break_seq = seq
1178 cd.escapable.break_value = r
1179 var cn = cd.generate_iclosuredef(v)
1180 closcns.add(cn)
1181 end
1182 end
1183 if not found then
1184 closcns.add(null)
1185 end
1186 end
1187 end
1188
1189 r2 = v.add_call(prop, args, closcns)
1190
1191 # Closure work
1192 if not prop_signature.closures.is_empty then
1193 if r != null and r2 != null then v.add_assignment(r, r2)
1194 v.seq = seq_old
1195 else
1196 r = r2
1197 end
1198
1199 if prop.global.is_init then
1200 v.invoke_super_init_calls_after(prop)
1201 end
1202 return r
1203 end
1204 end
1205
1206 redef class ASendReassignExpr
1207 redef fun generate_icode(v)
1208 do
1209 var recv = v.generate_expr(n_expr)
1210 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1211 var args = new Array[IRegister]
1212 args.add(recv)
1213 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1214
1215 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1216 var e3 = v.generate_expr(n_value)
1217 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1218 var args2 = args.to_a
1219 args2.add(e4)
1220 v.stmt(new ICall(prop, args2))
1221 return null
1222 end
1223 end
1224
1225 redef class ANewExpr
1226 redef fun generate_icode(v)
1227 do
1228 var args = new Array[IRegister]
1229 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1230 return v.expr(new INew(stype, prop, args), stype)
1231 end
1232 end
1233
1234 redef class AProxyExpr
1235 redef fun generate_icode(v)
1236 do
1237 return v.generate_expr(n_expr)
1238 end
1239 end
1240
1241 redef class AOnceExpr
1242 redef fun generate_icode(v)
1243 do
1244 var ionce = new IOnce
1245 var reg = v.expr(ionce, stype)
1246 var old_seq = v.seq
1247 v.seq = ionce.body
1248
1249 var e = v.generate_expr(n_expr)
1250 v.add_assignment(reg, e)
1251
1252 v.seq = old_seq
1253 return reg
1254 end
1255 end
1256
1257
1258 redef class AClosureDef
1259 var _iclosure_def: nullable IClosureDef
1260
1261 fun generate_iclosuredef(v: A2IContext): IClosureDef
1262 do
1263 # Prepare signature
1264 var args = new Array[IRegister]
1265 var sig = closure.signature
1266 for i in [0..sig.arity[ do
1267 args.add(v.new_register(sig[i]))
1268 end
1269 var ret: nullable IRegister = null
1270 var rtype = sig.return_type
1271 if rtype != null then
1272 ret = v.new_register(rtype)
1273 end
1274
1275 var iclos = new IClosureDef(args, ret)
1276 iclos.location = location
1277
1278 # Prepare env
1279 var seq_old = v.seq
1280 v.seq = iclos.body
1281 escapable.continue_seq = iclos.body
1282 escapable.continue_value = iclos.result
1283
1284 # Assign parameters
1285 for i in [0..variables.length[ do
1286 var res = v.variable(variables[i])
1287 v.add_assignment(res, iclos.params[i])
1288 end
1289
1290 v.generate_stmt(n_expr)
1291
1292 # Add a final break in case of break block witout value
1293 if closure.is_break and escapable.break_value == null then
1294 v.add_escape(escapable.break_seq.as(not null))
1295 end
1296
1297 v.seq = seq_old
1298 _iclosure_def = iclos
1299 return iclos
1300 end
1301 end
1302
1303 redef class AClosureCallExpr
1304 redef fun generate_icode(v)
1305 do
1306 # Geneate arguments
1307 var args = new Array[IRegister]
1308 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1309
1310 # Prepare icall
1311 var closdecl = v.closurevariables[variable]
1312 var icall = new IClosCall(closdecl, args)
1313 var seq_old = v.seq
1314
1315 # Fill break of ical
1316 if n_closure_defs.length == 1 then do
1317 var iseq = new ISeq
1318 icall.break_seq = iseq
1319 v.seq = iseq
1320 v.generate_stmt(n_closure_defs.first.n_expr)
1321 v.seq = seq_old
1322 end
1323
1324 # Prepare in case of default block
1325 var iif: nullable IIf = null # The iif of default block
1326 var closdecl_default = closdecl.default # The default (if any)
1327 if closdecl_default != null then
1328 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1329 v.stmt(iif)
1330 v.seq = iif.then_seq
1331 end
1332
1333 # Add the icall
1334 var r2: nullable IRegister = null # the result of the icall
1335 var rtype = variable.closure.signature.return_type
1336 if rtype == null then
1337 v.stmt(icall)
1338 else
1339 r2 = v.expr(icall, rtype)
1340 end
1341
1342 # Process the case of default block
1343 var r: nullable IRegister = null # the real result
1344 if closdecl_default != null then
1345 assert iif != null
1346 if r2 != null then
1347 assert rtype != null
1348 r = v.new_register(rtype)
1349 v.add_assignment(r, r2)
1350 end
1351 v.seq = iif.else_seq
1352 var r3 = v.inline_routine(closdecl_default, args, null)
1353 if r != null then
1354 assert r3 != null
1355 v.add_assignment(r, r3)
1356 end
1357 v.seq = seq_old
1358 else
1359 r = r2
1360 end
1361 return r
1362 end
1363 end