1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2009 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Things needed by typing.nit to generate intermediate code from AST
18 package icode_generation
23 private import primitive_info
25 # An AST2ICode context stores the currently built icode informations
28 redef fun stmt
(s
: ICode)
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
38 # Prepare a new array of length item
39 fun add_new_array
(stype
: MMType, length
: Int): IRegister
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
)
47 fun add_call_array_add
(recv
, item
: IRegister)
49 var stype
= recv
.stype
50 var prop
= visitor
.get_method
(stype
, once
"add".to_symbol
)
51 stmt
(new ICall(prop
, [recv
, item
]))
54 # Get the iregister associated with a variable
55 # Or assign one if none exists
56 fun variable
(v
: Variable): IRegister
58 if _variables
.has_key
(v
) then
61 var reg
= new_register
(v
.stype
.as(not null))
67 # Current registered variable
68 var _variables
: HashMap[Variable, IRegister] = new HashMap[Variable, IRegister]
70 # Current registered closurevariables
71 readable var _closurevariables
: HashMap[ClosureVariable, IClosureDecl] = new HashMap[ClosureVariable, IClosureDecl]
73 # The current syntax visitor
74 readable var _visitor
: AbsSyntaxVisitor
76 # Where a nit return must branch
77 readable writable var _return_seq
: nullable ISeq
79 # Register where a functionnal nit return must store its value
80 readable writable var _return_value
: nullable IRegister
82 # The method associated to the iroutine (if any)
83 readable var _method
: nullable MMMethod
85 # The register of self (if any)
86 var selfreg
: nullable IRegister writable
88 init(visitor
: AbsSyntaxVisitor, r
: IRoutine, m
: nullable MMMethod)
90 super(visitor
.mmmodule
, r
)
93 _return_value
= r
.result
97 # Insert implicit super init calls
98 fun invoke_super_init_calls_after
(start_prop
: nullable MMMethod)
101 assert p
isa MMSrcMethod
103 assert n
isa AConcreteInitPropdef
105 if n
.super_init_calls
.is_empty
then return
108 if start_prop
!= null then
109 while n
.super_init_calls
[i
] != start_prop
do
114 while n
.explicit_super_init_calls
[j
] != start_prop
do
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
]
123 var l
= n
.super_init_calls
.length
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
)
131 for va
in iroutine
.params
do
135 stmt
(new ICall(sp
, cargs
))
141 var _current_node
: nullable AExpr = null
143 # Generate icode in the current sequence from a statement
144 fun generate_stmt
(n
: nullable AExpr)
146 if n
== null then return
147 var old
= _current_node
149 n
.generate_icode
(self)
153 # Generate icode in the current sequence from an expression
154 fun generate_expr
(n
: AExpr): IRegister
156 var old
= _current_node
158 var reg
= n
.generate_icode
(self).as(not null)
164 redef class EscapableBlock
165 # Where a nit break must branch
166 readable writable var _break_seq
: nullable ISeq
168 # Where a nit continue must branch
169 readable writable var _continue_seq
: nullable ISeq
171 # Register where a functionnal nit break must store its value
172 readable writable var _break_value
: nullable IRegister
174 # Register where a functionnal nit continue must store its value
175 readable writable var _continue_value
: nullable IRegister
178 redef class MMSrcModule
179 # Generate icode for method bodies
180 fun generate_icode
(tc
: ToolContext)
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
)
195 redef class MMSrcAttribute
196 redef readable writable var _iroutine
: nullable IRoutine
198 # Generate the initialization iroutine
199 fun generate_iroutine
(visitor
: A2IVisitor)
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
213 redef class MMSrcMethod
214 redef readable writable var _iroutine
: nullable IRoutine
216 # Generate the body iroutine
217 fun generate_iroutine
(visitor
: A2IVisitor)
219 var iroutine
= signature
.generate_empty_iroutine
221 iroutine
.location
= node
.location
223 var v
= new A2IContext(visitor
, iroutine
, self)
224 visitor
.icode_ctx
= v
225 inner_generate_iroutine
(v
)
226 visitor
.icode_ctx
= null
230 # Generate the body iroutine (specific part)
231 fun inner_generate_iroutine
(v
: A2IContext) is abstract
234 redef class MMReadImplementationMethod
235 redef fun inner_generate_iroutine
(v
)
237 var e
= v
.add_attr_read
(node
.prop
, v
.iroutine
.params
.first
)
238 v
.add_return_value
(e
)
242 redef class MMWriteImplementationMethod
243 redef fun inner_generate_iroutine
(v
)
245 var params
= v
.iroutine
.params
246 v
.stmt
(new IAttrWrite(node
.prop
, params
[0], params
[1]))
250 redef class MMMethSrcMethod
251 redef fun inner_generate_iroutine
(v
)
253 v
.visitor
.enter_visit
(node
)
257 redef class MMImplicitInit
258 redef fun inner_generate_iroutine
(v
)
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
)
272 v
.stmt
(new ICall(sp
, args
))
274 v
.stmt
(new ICall(sp
, args_recv
))
277 for i
in [f
..params
.length
[ do
278 var attribute
= unassigned_attributes
[i-f
]
279 v
.stmt
(new IAttrWrite(attribute
, recv
, params
[i
]))
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)
293 ###############################################################################
296 fun accept_icode_generation
(v
: A2IVisitor) do accept_abs_syntax_visitor
(v
) end
299 redef class AAttrPropdef
300 redef fun accept_icode_generation
(vv
)
303 v
.stmt
(new IMove(v
.variable
(self_var
), v
.iroutine
.params
.first
))
307 v
.stmt
(new IMove(v
.iroutine
.result
.as(not null), v
.generate_expr
(ne
)))
312 redef class AMethPropdef
313 redef fun accept_icode_generation
(vv
)
316 fill_iroutine
(vv
.icode_ctx
, method
)
319 # Compile the method body common preambule (before specific body stuff if any)
320 fun fill_iroutine
(v
: A2IContext, method
: MMSrcMethod) is abstract
323 redef class ASignature
324 fun fill_iroutine_parameters
(v
: A2IContext, orig_sig
: MMSignature, params
: Sequence[IRegister], closdecls
: nullable Sequence[IClosureDecl])
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
)
333 v
.stmt
(new IMove(reg
, params
[ap
.position
]))
335 for i
in [0..n_closure_decls
.length
[ do
336 var wd
= n_closure_decls
[i
]
337 v
.closurevariables
[wd
.variable
] = closdecls
[i
]
342 redef class AClosureDecl
343 redef fun accept_icode_generation
(vv
)
346 var iclos
= variable
.closure
.signature
.generate_empty_iclosuredef
(v
)
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)
355 if n_expr
!= null then
356 v
.generate_stmt
(n_expr
)
357 v
.iroutine
.closure_decls
[position
].default
= iclos
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))
368 redef class AConcreteMethPropdef
369 redef fun fill_iroutine
(v
, method
)
371 var params
= v
.iroutine
.params
.to_a
372 var selfreg
= v
.variable
(self_var
)
373 v
.stmt
(new IMove(selfreg
, params
[0]))
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
)
383 if self isa AConcreteInitPropdef then
384 v
.invoke_super_init_calls_after
(null)
387 if n_block
!= null then
388 v
.generate_stmt
(n_block
)
394 redef class AExternPropdef
395 redef fun fill_iroutine
(v
, method
)
397 # add all explicit extern calls for this extern method
398 for explicit_import
in method
.as(MMMethSrcMethod).explicit_imports
400 var prop
= explicit_import
.method
403 ic
= new INew(prop
.signature
.recv
, prop
, new List[IRegister])
405 ic
= new ICall(prop
, new List[IRegister])
407 ic
.is_explicit_from_extern
= true
413 redef class AExternInitPropdef
414 redef fun fill_iroutine
(v
, method
)
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
))
426 redef class ADeferredMethPropdef
427 redef fun fill_iroutine
(v
, method
)
429 v
.add_abort
("Deferred method called")
433 redef class AExternMethPropdef
434 redef fun fill_iroutine
(v
, method
)
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
))
441 v
.stmt
(new INative(method
, params
))
448 redef class AInternMethPropdef
449 redef fun fill_iroutine
(v
, method
)
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
))
456 v
.stmt
(new INative(method
, params
))
461 ###############################################################################
464 redef fun accept_icode_generation
(v
) do end
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
471 redef class AVardeclExpr
472 redef fun generate_icode
(v
)
474 var reg
= v
.variable
(variable
)
477 v
.add_assignment
(reg
, v
.generate_expr
(ne
))
483 redef class ABlockExpr
484 redef fun generate_icode
(v
)
486 for ne
in n_expr
do v
.generate_stmt
(ne
)
492 redef fun generate_icode
(v
)
497 escapable
.break_seq
= seq
500 v
.generate_stmt
(n_block
)
507 redef class AReturnExpr
508 redef fun generate_icode
(v
)
512 v
.add_assignment
(v
.return_value
.as(not null), v
.generate_expr
(ne
))
514 v
.add_escape
(v
.return_seq
.as(not null))
519 redef class ABreakExpr
520 redef fun generate_icode
(v
)
524 v
.add_assignment
(escapable
.break_value
.as(not null), v
.generate_expr
(ne
))
526 v
.add_escape
(escapable
.break_seq
.as(not null))
531 redef class AContinueExpr
532 redef fun generate_icode
(v
)
536 v
.add_assignment
(escapable
.continue_value
.as(not null), v
.generate_expr
(ne
))
538 v
.add_escape
(escapable
.continue_seq
.as(not null))
543 redef class AAbortExpr
544 redef fun generate_icode
(v
)
546 v
.add_abort
("Aborted")
552 redef fun generate_icode
(v
)
554 var iif
= new IIf(v
.generate_expr
(n_expr
))
558 if n_then
!= null then
560 v
.generate_stmt
(n_then
)
563 if n_else
!= null then
565 v
.generate_stmt
(n_else
)
573 redef class AWhileExpr
574 redef fun generate_icode
(v
)
577 var iloop
= new ILoop
579 escapable
.break_seq
= iloop
583 var iif
= new IIf(v
.generate_expr
(n_expr
))
586 # Process inside (condition is true)
587 if n_block
!= null then
589 escapable
.continue_seq
= iif
.then_seq
590 v
.generate_stmt
(n_block
)
593 # Process escape (condition is false)
602 redef class ALoopExpr
603 redef fun generate_icode
(v
)
606 var iloop
= new ILoop
608 escapable
.break_seq
= iloop
612 if n_block
!= null then
616 escapable
.continue_seq
= seq
617 v
.generate_stmt
(n_block
)
626 redef fun generate_icode
(v
)
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
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
)
643 assert ne
isa AOrangeExpr
644 meth
= v
.visitor
.get_method
(tint
, once
"enumerate_before".to_symbol
)
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
)]
655 var iclos
= meth
.signature
.closures
.first
.signature
.generate_empty_iclosuredef
(v
)
661 escapable
.break_seq
= seq
662 escapable
.break_value
= null
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
]))
670 v
.generate_stmt
(n_block
)
674 v
.add_call
(meth
, args
, [iclos
])
681 redef class AAssertExpr
682 redef fun generate_icode
(v
)
684 var e
= v
.generate_expr
(n_expr
)
689 v
.generate_stmt
(n_else
)
692 v
.add_abort
("Assert failed")
694 v
.add_abort
("Assert '%s' failed", id
.text
.to_s
)
702 redef fun generate_icode
(v
)
704 return v
.variable
(variable
)
708 redef class AVarAssignExpr
709 redef fun generate_icode
(v
)
711 var e
= v
.generate_expr
(n_value
)
712 v
.add_assignment
(v
.variable
(variable
), e
)
717 redef class AVarReassignExpr
718 redef fun generate_icode
(v
)
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
)
728 redef class ASelfExpr
729 redef fun generate_icode
(v
)
731 return v
.variable
(variable
)
735 redef class AIfexprExpr
736 redef fun generate_icode
(v
)
739 var iif
= new IIf(v
.generate_expr
(n_expr
))
744 var reg
= v
.new_register
(stype
)
748 v
.add_assignment
(reg
, v
.generate_expr
(n_then
))
752 v
.add_assignment
(reg
, v
.generate_expr
(n_else
))
760 redef fun generate_icode
(v
)
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
)
769 redef fun generate_icode
(v
)
772 var reg
= v
.new_register
(stype
)
774 # Process left operand (in a if/then)
775 var iif
= new IIf(v
.generate_expr
(n_expr
))
779 v
.add_assignment
(reg
, v
.lit_true_reg
)
781 # Process right operand (in the else)
783 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
791 redef fun generate_icode
(v
)
794 var reg
= v
.new_register
(stype
)
796 # Process left operand (in a if/else)
797 var iif
= new IIf(v
.generate_expr
(n_expr
))
801 v
.add_assignment
(reg
, v
.lit_false_reg
)
803 # Process right operand (in the then)
805 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
813 redef fun generate_icode
(v
)
815 var e
= v
.generate_expr
(n_expr
)
816 return v
.expr
(new INot(e
), stype
)
820 redef class AOrElseExpr
821 redef fun generate_icode
(v
)
823 # Compute left operand
824 var e
= v
.generate_expr
(n_expr
)
827 var reg
= v
.new_register
(stype
)
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
)
836 # if equal, result = right opr
838 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
840 # else, result = left operand
842 v
.add_assignment
(reg
, e
)
851 redef fun generate_icode
(v
)
853 var e
= v
.generate_expr
(n_expr
)
854 return v
.expr
(new ITypeCheck(v
.selfreg
.as(not null), e
, n_type
.stype
), stype
)
858 redef class AAsCastExpr
859 redef fun generate_icode
(v
)
861 var e
= v
.generate_expr
(n_expr
)
862 v
.add_type_cast
(e
, stype
)
867 redef class AAsNotnullExpr
868 redef fun generate_icode
(v
)
870 var e
= v
.generate_expr
(n_expr
)
871 v
.add_type_cast
(e
, stype
)
876 redef class ATrueExpr
877 redef fun generate_icode
(v
)
879 return v
.lit_true_reg
883 redef class AFalseExpr
884 redef fun generate_icode
(v
)
886 return v
.lit_false_reg
891 redef fun generate_icode
(v
)
893 return v
.expr
(new IIntValue(n_number
.text
), stype
)
897 redef class AFloatExpr
898 redef fun generate_icode
(v
)
900 return v
.expr
(new IFloatValue(n_float
.text
), stype
)
904 redef class ACharExpr
905 redef fun generate_icode
(v
)
907 return v
.expr
(new ICharValue(n_char
.text
), stype
)
911 redef class AStringFormExpr
912 redef fun generate_icode
(v
)
916 var ionce
= new IOnce
917 var reg
= v
.expr
(ionce
, stype
)
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
)
928 # The raw string value
929 protected fun string_text
: String is abstract
931 # The string in a C native format
932 protected var _cstring
: nullable String
934 # The string length in bytes
935 protected var _cstring_length
: nullable Int
937 # Compute _cstring and _cstring_length using string_text
938 protected fun compute_string_infos
941 var str
= string_text
944 while i
< str
.length
do
949 if c2
!= '{' and c2 != '}' then
959 _cstring_length
= len
963 redef class AStringExpr
964 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
966 redef class AStartStringExpr
967 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
969 redef class AMidStringExpr
970 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
972 redef class AEndStringExpr
973 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
976 redef class ASuperstringExpr
977 redef fun generate_icode
(v
)
979 var array
= v
.add_new_array
(atype
, n_exprs
.length
)
980 var prop_to_s
= v
.visitor
.get_method
(v
.visitor
.type_object
, once
"to_s".to_symbol
)
982 var e
= v
.generate_expr
(ne
)
983 if ne
.stype
!= stype
then
984 e
= v
.expr
(new ICall(prop_to_s
, [e
]), stype
)
986 v
.add_call_array_add
(array
, e
)
988 return v
.expr
(new ICall(prop_to_s
, [array
]), stype
)
992 redef class ANullExpr
993 redef fun generate_icode
(v
)
995 return v
.lit_null_reg
999 redef class AArrayExpr
1000 redef fun generate_icode
(v
)
1002 var nes
= n_exprs
.n_exprs
1003 var recv
= v
.add_new_array
(stype
, nes
.length
)
1005 var e
= v
.generate_expr
(ne
)
1006 v
.add_call_array_add
(recv
, e
)
1012 redef class ACrangeExpr
1013 redef fun generate_icode
(v
)
1015 var e
= v
.generate_expr
(n_expr
)
1016 var e2
= v
.generate_expr
(n_expr2
)
1017 var prop
= v
.visitor
.get_method
(stype
, once
"init".to_symbol
)
1018 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
1022 redef class AOrangeExpr
1023 redef fun generate_icode
(v
)
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
"without_last".to_symbol
)
1028 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
1032 redef class ASuperExpr
1033 redef fun generate_icode
(v
)
1035 var arity
= v
.iroutine
.params
.length
- 1
1036 if init_in_superclass
!= null then
1037 arity
= init_in_superclass
.signature
.arity
1039 var args
= new Array[IRegister].with_capacity
(arity
+ 1)
1040 args
.add
(v
.iroutine
.params
[0])
1041 var nas
= n_args
.n_exprs
1042 if nas
.length
!= arity
then
1043 for i
in [0..arity
[ do
1044 args
.add
(v
.iroutine
.params
[i
+ 1])
1048 args
.add
(v
.generate_expr
(na
))
1051 var p
= init_in_superclass
1053 var rtype
= p
.signature
.return_type
1054 if rtype
!= null then
1055 return v
.expr
(new ICall(p
, args
), rtype
)
1057 v
.stmt
(new ICall(p
, args
))
1062 var rtype
= p
.signature
.return_type
1063 if rtype
== null then
1064 v
.stmt
(new ISuper(p
, args
))
1067 return v
.expr
(new ISuper(p
, args
), rtype
)
1073 redef class AAttrExpr
1074 redef fun generate_icode
(v
)
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
)
1082 redef class AAttrAssignExpr
1083 redef fun generate_icode
(v
)
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
))
1092 redef class AAttrReassignExpr
1093 redef fun generate_icode
(v
)
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
))
1105 redef class AIssetAttrExpr
1106 redef fun generate_icode
(v
)
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
)
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)
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
1123 for par_idx
in [0..par_arity
[ do
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
1135 a
= raw_args
[arg_idx
]
1136 args
.add
(v
.generate_expr
(a
))
1137 arg_idx
= arg_idx
+ 1
1143 redef class ASendExpr
1144 redef fun generate_icode
(v
)
1146 var recv
= v
.generate_expr
(n_expr
)
1147 var args
= new Array[IRegister]
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
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
)
1165 closcns
= new Array[nullable IClosureDef]
1167 if closure_defs
!= null then cdarity
= closure_defs
.length
1168 var closure_defs
= closure_defs
1169 for mmc
in prop_signature
.closures
do
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
1177 cd
.escapable
.break_seq
= seq
1178 cd
.escapable
.break_value
= r
1179 var cn
= cd
.generate_iclosuredef
(v
)
1189 r2
= v
.add_call
(prop
, args
, closcns
)
1192 if not prop_signature
.closures
.is_empty
then
1193 if r
!= null and r2
!= null then v
.add_assignment
(r
, r2
)
1199 if prop
.global
.is_init
then
1200 v
.invoke_super_init_calls_after
(prop
)
1206 redef class ASendReassignExpr
1207 redef fun generate_icode
(v
)
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]
1213 generate_icode_for_arguments_in
(v
, args
, read_prop
.signature
.as(not null))
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
1220 v
.stmt
(new ICall(prop
, args2
))
1225 redef class ANewExpr
1226 redef fun generate_icode
(v
)
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
)
1234 redef class AProxyExpr
1235 redef fun generate_icode
(v
)
1237 return v
.generate_expr
(n_expr
)
1241 redef class AOnceExpr
1242 redef fun generate_icode
(v
)
1244 var ionce
= new IOnce
1245 var reg
= v
.expr
(ionce
, stype
)
1249 var e
= v
.generate_expr
(n_expr
)
1250 v
.add_assignment
(reg
, e
)
1258 redef class AClosureDef
1259 var _iclosure_def
: nullable IClosureDef
1261 fun generate_iclosuredef
(v
: A2IContext): IClosureDef
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
]))
1269 var ret
: nullable IRegister = null
1270 var rtype
= sig
.return_type
1271 if rtype
!= null then
1272 ret
= v
.new_register
(rtype
)
1275 var iclos
= new IClosureDef(args
, ret
)
1276 iclos
.location
= location
1281 escapable
.continue_seq
= iclos
.body
1282 escapable
.continue_value
= iclos
.result
1285 for i
in [0..variables
.length
[ do
1286 var res
= v
.variable
(variables
[i
])
1287 v
.add_assignment
(res
, iclos
.params
[i
])
1290 v
.generate_stmt
(n_expr
)
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))
1298 _iclosure_def
= iclos
1303 redef class AClosureCallExpr
1304 redef fun generate_icode
(v
)
1307 var args
= new Array[IRegister]
1308 generate_icode_for_arguments_in
(v
, args
, variable
.closure
.signature
)
1311 var closdecl
= v
.closurevariables
[variable
]
1312 var icall
= new IClosCall(closdecl
, args
)
1315 # Fill break of ical
1316 if n_closure_defs
.length
== 1 then do
1318 icall
.break_seq
= iseq
1320 v
.generate_stmt
(n_closure_defs
.first
.n_expr
)
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
))
1330 v
.seq
= iif
.then_seq
1334 var r2
: nullable IRegister = null # the result of the icall
1335 var rtype
= variable
.closure
.signature
.return_type
1336 if rtype
== null then
1339 r2
= v
.expr
(icall
, rtype
)
1342 # Process the case of default block
1343 var r
: nullable IRegister = null # the real result
1344 if closdecl_default
!= null then
1347 assert rtype
!= null
1348 r
= v
.new_register
(rtype
)
1349 v
.add_assignment
(r
, r2
)
1351 v
.seq
= iif
.else_seq
1352 var r3
= v
.inline_routine
(closdecl_default
, args
, null)
1355 v
.add_assignment
(r
, r3
)
1365 redef class ADebugTypeExpr
1366 redef fun generate_icode
(v
)