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