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