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 init(visitor
: AbsSyntaxVisitor, r
: IRoutine, m
: nullable MMMethod)
87 super(visitor
.mmmodule
, r
)
90 _return_value
= r
.result
94 # Insert implicit super init calls
95 fun invoke_super_init_calls_after
(start_prop
: nullable MMMethod)
98 assert p
isa MMSrcMethod
100 assert n
isa AConcreteInitPropdef
102 if n
.super_init_calls
.is_empty
then return
105 if start_prop
!= null then
106 while n
.super_init_calls
[i
] != start_prop
do
111 while n
.explicit_super_init_calls
[j
] != start_prop
do
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
]
120 var l
= n
.super_init_calls
.length
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
)
128 for va
in iroutine
.params
do
132 stmt
(new ICall(sp
, cargs
))
138 var _current_node
: nullable AExpr = null
140 # Generate icode in the current sequence from a statement
141 fun generate_stmt
(n
: nullable AExpr)
143 if n
== null then return
144 var old
= _current_node
146 n
.generate_icode
(self)
150 # Generate icode in the current sequence from an expression
151 fun generate_expr
(n
: AExpr): IRegister
153 var old
= _current_node
155 var reg
= n
.generate_icode
(self).as(not null)
161 redef class EscapableBlock
162 # Where a nit break must branch
163 readable writable var _break_seq
: nullable ISeq
165 # Where a nit continue must branch
166 readable writable var _continue_seq
: nullable ISeq
168 # Register where a functionnal nit break must store its value
169 readable writable var _break_value
: nullable IRegister
171 # Register where a functionnal nit continue must store its value
172 readable writable var _continue_value
: nullable IRegister
175 redef class MMSrcModule
176 # Generate icode for method bodies
177 fun generate_icode
(tc
: ToolContext)
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
)
192 redef class MMSrcAttribute
193 redef readable writable var _iroutine
: nullable IRoutine
195 # Generate the initialization iroutine
196 fun generate_iroutine
(visitor
: A2IVisitor)
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
210 redef class MMSrcMethod
211 redef readable writable var _iroutine
: nullable IRoutine
213 # Generate the body iroutine
214 fun generate_iroutine
(visitor
: A2IVisitor)
216 var iroutine
= signature
.generate_empty_iroutine
218 iroutine
.location
= node
.location
220 var v
= new A2IContext(visitor
, iroutine
, self)
221 visitor
.icode_ctx
= v
222 inner_generate_iroutine
(v
)
223 visitor
.icode_ctx
= null
227 # Generate the body iroutine (specific part)
228 fun inner_generate_iroutine
(v
: A2IContext) is abstract
231 redef class MMReadImplementationMethod
232 redef fun inner_generate_iroutine
(v
)
234 var e
= v
.add_attr_read
(node
.prop
, v
.iroutine
.params
.first
)
235 v
.add_return_value
(e
)
239 redef class MMWriteImplementationMethod
240 redef fun inner_generate_iroutine
(v
)
242 var params
= v
.iroutine
.params
243 v
.stmt
(new IAttrWrite(node
.prop
, params
[0], params
[1]))
247 redef class MMMethSrcMethod
248 redef fun inner_generate_iroutine
(v
)
250 v
.visitor
.enter_visit
(node
)
254 redef class MMImplicitInit
255 redef fun inner_generate_iroutine
(v
)
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
)
269 v
.stmt
(new ICall(sp
, args
))
271 v
.stmt
(new ICall(sp
, args_recv
))
274 for i
in [f
..params
.length
[ do
275 var attribute
= unassigned_attributes
[i-f
]
276 v
.stmt
(new IAttrWrite(attribute
, recv
, params
[i
]))
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)
290 ###############################################################################
293 fun accept_icode_generation
(v
: A2IVisitor) do accept_abs_syntax_visitor
(v
) end
296 redef class AAttrPropdef
297 redef fun accept_icode_generation
(vv
)
300 v
.stmt
(new IMove(v
.variable
(self_var
), v
.iroutine
.params
.first
))
304 v
.stmt
(new IMove(v
.iroutine
.result
.as(not null), v
.generate_expr
(ne
)))
309 redef class AMethPropdef
310 redef fun accept_icode_generation
(vv
)
313 fill_iroutine
(vv
.icode_ctx
, method
)
316 # Compile the method body common preambule (before specific body stuff if any)
317 fun fill_iroutine
(v
: A2IContext, method
: MMSrcMethod) is abstract
320 redef class ASignature
321 fun fill_iroutine_parameters
(v
: A2IContext, orig_sig
: MMSignature, params
: Sequence[IRegister], closdecls
: nullable Sequence[IClosureDecl])
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
)
330 v
.stmt
(new IMove(reg
, params
[ap
.position
]))
332 for i
in [0..n_closure_decls
.length
[ do
333 var wd
= n_closure_decls
[i
]
334 v
.closurevariables
[wd
.variable
] = closdecls
[i
]
339 redef class AClosureDecl
340 redef fun accept_icode_generation
(vv
)
343 var iclos
= variable
.closure
.signature
.generate_empty_iclosuredef
(v
)
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)
352 if n_expr
!= null then
353 v
.generate_stmt
(n_expr
)
354 v
.iroutine
.closure_decls
[position
].default
= iclos
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))
365 redef class AConcreteMethPropdef
366 redef fun fill_iroutine
(v
, method
)
368 var params
= v
.iroutine
.params
.to_a
369 var selfreg
= v
.variable
(self_var
)
370 v
.stmt
(new IMove(selfreg
, params
[0]))
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
)
379 if self isa AConcreteInitPropdef then
380 v
.invoke_super_init_calls_after
(null)
383 if n_block
!= null then
384 v
.generate_stmt
(n_block
)
389 redef class ADeferredMethPropdef
390 redef fun fill_iroutine
(v
, method
)
392 v
.add_abort
("Deferred method called")
396 redef class AExternMethPropdef
397 redef fun fill_iroutine
(v
, method
)
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
))
404 v
.stmt
(new INative(method
, params
))
409 redef class AInternMethPropdef
410 redef fun fill_iroutine
(v
, method
)
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
))
417 v
.stmt
(new INative(method
, params
))
422 ###############################################################################
425 redef fun accept_icode_generation
(v
) do end
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
432 redef class AVardeclExpr
433 redef fun generate_icode
(v
)
435 var reg
= v
.variable
(variable
)
438 v
.add_assignment
(reg
, v
.generate_expr
(ne
))
444 redef class ABlockExpr
445 redef fun generate_icode
(v
)
447 for ne
in n_expr
do v
.generate_stmt
(ne
)
453 redef fun generate_icode
(v
)
458 escapable
.break_seq
= seq
461 v
.generate_stmt
(n_block
)
468 redef class AReturnExpr
469 redef fun generate_icode
(v
)
473 v
.add_assignment
(v
.return_value
.as(not null), v
.generate_expr
(ne
))
475 v
.add_escape
(v
.return_seq
.as(not null))
480 redef class ABreakExpr
481 redef fun generate_icode
(v
)
485 v
.add_assignment
(escapable
.break_value
.as(not null), v
.generate_expr
(ne
))
487 v
.add_escape
(escapable
.break_seq
.as(not null))
492 redef class AContinueExpr
493 redef fun generate_icode
(v
)
497 v
.add_assignment
(escapable
.continue_value
.as(not null), v
.generate_expr
(ne
))
499 v
.add_escape
(escapable
.continue_seq
.as(not null))
504 redef class AAbortExpr
505 redef fun generate_icode
(v
)
507 v
.add_abort
("Aborted")
513 redef fun generate_icode
(v
)
515 var iif
= new IIf(v
.generate_expr
(n_expr
))
519 if n_then
!= null then
521 v
.generate_stmt
(n_then
)
524 if n_else
!= null then
526 v
.generate_stmt
(n_else
)
534 redef class AWhileExpr
535 redef fun generate_icode
(v
)
538 var iloop
= new ILoop
540 escapable
.break_seq
= iloop
544 var iif
= new IIf(v
.generate_expr
(n_expr
))
547 # Process inside (condition is true)
548 if n_block
!= null then
550 escapable
.continue_seq
= iif
.then_seq
551 v
.generate_stmt
(n_block
)
554 # Process escape (condition is false)
563 redef class ALoopExpr
564 redef fun generate_icode
(v
)
567 var iloop
= new ILoop
569 escapable
.break_seq
= iloop
573 if n_block
!= null then
577 escapable
.continue_seq
= seq
578 v
.generate_stmt
(n_block
)
587 redef fun generate_icode
(v
)
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
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
)
604 assert ne
isa AOrangeExpr
605 meth
= v
.visitor
.get_method
(tint
, once
"enumerate_before".to_symbol
)
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
)]
616 var iclos
= meth
.signature
.closures
.first
.signature
.generate_empty_iclosuredef
(v
)
622 escapable
.break_seq
= seq
623 escapable
.break_value
= null
626 escapable
.continue_seq
= iclos
.body
627 escapable
.continue_value
= null
628 for i
in [0..variables
.length
[ do
629 v
.stmt
(new IMove(v
.variable
(variables
[i
]), iclos
.params
[i
]))
631 v
.generate_stmt
(n_block
)
635 v
.add_call
(meth
, args
, [iclos
])
642 redef class AAssertExpr
643 redef fun generate_icode
(v
)
645 var e
= v
.generate_expr
(n_expr
)
650 v
.generate_stmt
(n_else
)
653 v
.add_abort
("Assert failed")
655 v
.add_abort
("Assert %s failed", id
.to_s
)
663 redef fun generate_icode
(v
)
665 return v
.variable
(variable
)
669 redef class AVarAssignExpr
670 redef fun generate_icode
(v
)
672 var e
= v
.generate_expr
(n_value
)
673 v
.add_assignment
(v
.variable
(variable
), e
)
678 redef class AVarReassignExpr
679 redef fun generate_icode
(v
)
681 var e1
= v
.variable
(variable
)
682 var e2
= v
.generate_expr
(n_value
)
683 var e3
= v
.expr
(new ICall(assign_method
, [e1
, e2
]), assign_method
.signature
.return_type
.as(not null))
684 v
.add_assignment
(e1
, e3
)
689 redef class ASelfExpr
690 redef fun generate_icode
(v
)
692 return v
.variable
(variable
)
696 redef class AIfexprExpr
697 redef fun generate_icode
(v
)
700 var iif
= new IIf(v
.generate_expr
(n_expr
))
705 var reg
= v
.new_register
(stype
)
709 v
.add_assignment
(reg
, v
.generate_expr
(n_then
))
713 v
.add_assignment
(reg
, v
.generate_expr
(n_else
))
721 redef fun generate_icode
(v
)
723 var e
= v
.generate_expr
(n_expr
)
724 var e2
= v
.generate_expr
(n_expr2
)
725 return v
.expr
(new IIs(e
, e2
), stype
)
730 redef fun generate_icode
(v
)
733 var reg
= v
.new_register
(stype
)
735 # Process left operand (in a if/then)
736 var iif
= new IIf(v
.generate_expr
(n_expr
))
740 v
.add_assignment
(reg
, v
.lit_true_reg
)
742 # Process right operand (in the else)
744 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
752 redef fun generate_icode
(v
)
755 var reg
= v
.new_register
(stype
)
757 # Process left operand (in a if/else)
758 var iif
= new IIf(v
.generate_expr
(n_expr
))
762 v
.add_assignment
(reg
, v
.lit_false_reg
)
764 # Process right operand (in the then)
766 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
774 redef fun generate_icode
(v
)
776 var e
= v
.generate_expr
(n_expr
)
777 return v
.expr
(new INot(e
), stype
)
781 redef class AOrElseExpr
782 redef fun generate_icode
(v
)
784 # Compute left operand
785 var e
= v
.generate_expr
(n_expr
)
788 var reg
= v
.new_register
(stype
)
790 # Compare left and null
791 var n
= v
.lit_null_reg
792 var c
= v
.expr
(new IIs(e
, n
), v
.mmmodule
.type_bool
)
797 # if equal, result = right opr
799 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
801 # else, result = left operand
803 v
.add_assignment
(reg
, e
)
812 redef fun generate_icode
(v
)
814 var e
= v
.generate_expr
(n_expr
)
815 return v
.expr
(new ITypeCheck(e
, n_type
.stype
), stype
)
819 redef class AAsCastExpr
820 redef fun generate_icode
(v
)
822 var e
= v
.generate_expr
(n_expr
)
823 v
.add_type_cast
(e
, stype
)
828 redef class AAsNotnullExpr
829 redef fun generate_icode
(v
)
831 var e
= v
.generate_expr
(n_expr
)
832 v
.add_type_cast
(e
, stype
)
837 redef class ATrueExpr
838 redef fun generate_icode
(v
)
840 return v
.lit_true_reg
844 redef class AFalseExpr
845 redef fun generate_icode
(v
)
847 return v
.lit_false_reg
852 redef fun generate_icode
(v
)
854 return v
.expr
(new IIntValue(n_number
.text
), stype
)
858 redef class AFloatExpr
859 redef fun generate_icode
(v
)
861 return v
.expr
(new IFloatValue(n_float
.text
), stype
)
865 redef class ACharExpr
866 redef fun generate_icode
(v
)
868 return v
.expr
(new ICharValue(n_char
.text
), stype
)
872 redef class AStringFormExpr
873 redef fun generate_icode
(v
)
877 var ionce
= new IOnce
878 var reg
= v
.expr
(ionce
, stype
)
880 var ns
= v
.expr
(new IStringValue(_cstring
.as(not null)), v
.visitor
.type_nativestring
)
881 var ni
= v
.expr
(new IIntValue(_cstring_length
.to_s
), v
.visitor
.type_int
)
882 var prop
= v
.visitor
.get_method
(stype
, once
"with_native".to_symbol
)
883 var e
= v
.expr
(new INew(stype
, prop
, [ns
, ni
]), stype
)
884 v
.add_assignment
(reg
, e
)
889 # The raw string value
890 protected fun string_text
: String is abstract
892 # The string in a C native format
893 protected var _cstring
: nullable String
895 # The string length in bytes
896 protected var _cstring_length
: nullable Int
898 # Compute _cstring and _cstring_length using string_text
899 protected fun compute_string_infos
902 var str
= string_text
905 while i
< str
.length
do
910 if c2
!= '{' and c2 != '}' then
920 _cstring_length
= len
924 redef class AStringExpr
925 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
927 redef class AStartStringExpr
928 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
930 redef class AMidStringExpr
931 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
933 redef class AEndStringExpr
934 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
937 redef class ASuperstringExpr
938 redef fun generate_icode
(v
)
940 var array
= v
.add_new_array
(atype
, n_exprs
.length
)
941 var prop_to_s
= v
.visitor
.get_method
(v
.visitor
.type_object
, once
"to_s".to_symbol
)
943 var e
= v
.generate_expr
(ne
)
944 if ne
.stype
!= stype
then
945 e
= v
.expr
(new ICall(prop_to_s
, [e
]), stype
)
947 v
.add_call_array_add
(array
, e
)
949 return v
.expr
(new ICall(prop_to_s
, [array
]), stype
)
953 redef class ANullExpr
954 redef fun generate_icode
(v
)
956 return v
.lit_null_reg
960 redef class AArrayExpr
961 redef fun generate_icode
(v
)
963 var recv
= v
.add_new_array
(stype
, n_exprs
.length
)
965 var e
= v
.generate_expr
(ne
)
966 v
.add_call_array_add
(recv
, e
)
972 redef class ACrangeExpr
973 redef fun generate_icode
(v
)
975 var e
= v
.generate_expr
(n_expr
)
976 var e2
= v
.generate_expr
(n_expr2
)
977 var prop
= v
.visitor
.get_method
(stype
, once
"init".to_symbol
)
978 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
982 redef class AOrangeExpr
983 redef fun generate_icode
(v
)
985 var e
= v
.generate_expr
(n_expr
)
986 var e2
= v
.generate_expr
(n_expr2
)
987 var prop
= v
.visitor
.get_method
(stype
, once
"without_last".to_symbol
)
988 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
992 redef class ASuperExpr
993 redef fun generate_icode
(v
)
995 var arity
= v
.iroutine
.params
.length
- 1
996 if init_in_superclass
!= null then
997 arity
= init_in_superclass
.signature
.arity
999 var args
= new Array[IRegister].with_capacity
(arity
+ 1)
1000 args
.add
(v
.iroutine
.params
[0])
1001 if n_args
.length
!= arity
then
1002 for i
in [0..arity
[ do
1003 args
.add
(v
.iroutine
.params
[i
+ 1])
1007 args
.add
(v
.generate_expr
(na
))
1010 var p
= init_in_superclass
1012 var rtype
= p
.signature
.return_type
1013 if rtype
!= null then
1014 return v
.expr
(new ICall(p
, args
), rtype
)
1016 v
.stmt
(new ICall(p
, args
))
1021 var rtype
= p
.signature
.return_type
1022 if rtype
== null then
1023 v
.stmt
(new ISuper(p
, args
))
1026 return v
.expr
(new ISuper(p
, args
), rtype
)
1032 redef class AAttrExpr
1033 redef fun generate_icode
(v
)
1035 var e
= v
.generate_expr
(n_expr
)
1036 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1037 return v
.add_attr_read
(prop
, e
)
1041 redef class AAttrAssignExpr
1042 redef fun generate_icode
(v
)
1044 var e
= v
.generate_expr
(n_expr
)
1045 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1046 var e2
= v
.generate_expr
(n_value
)
1047 v
.stmt
(new IAttrWrite(prop
, e
, e2
))
1051 redef class AAttrReassignExpr
1052 redef fun generate_icode
(v
)
1054 var e1
= v
.generate_expr
(n_expr
)
1055 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e1
)
1056 var e2
= v
.expr
(new IAttrRead(prop
, e1
), attr_type
)
1057 var e3
= v
.generate_expr
(n_value
)
1058 var e4
= v
.expr
(new ICall(assign_method
, [e2
, e3
]), attr_type
)
1059 v
.stmt
(new IAttrWrite(prop
, e1
, e4
))
1064 redef class AIssetAttrExpr
1065 redef fun generate_icode
(v
)
1067 var e
= v
.generate_expr
(n_expr
)
1068 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1069 return v
.expr
(new IAttrIsset(prop
, e
), stype
)
1073 redef class AAbsAbsSendExpr
1074 # Compile each argument and add them to the array
1075 fun generate_icode_for_arguments_in
(v
: A2IContext, args
: Array[IRegister], signature
: MMSignature)
1077 var par_arity
= signature
.arity
1078 var par_vararg
= signature
.vararg_rank
1079 var raw_args
= raw_arguments
1080 var raw_arity
= raw_args
.length
1082 for par_idx
in [0..par_arity
[ do
1084 var par_type
= signature
[par_idx
]
1085 if par_idx
== par_vararg
then
1086 var arr
= v
.add_new_array
(v
.visitor
.type_array
(par_type
), raw_arity-par_arity
)
1087 for i
in [0..(raw_arity-par_arity
)] do
1088 a
= raw_args
[arg_idx
]
1089 v
.add_call_array_add
(arr
, v
.generate_expr
(a
))
1090 arg_idx
= arg_idx
+ 1
1094 a
= raw_args
[arg_idx
]
1095 args
.add
(v
.generate_expr
(a
))
1096 arg_idx
= arg_idx
+ 1
1102 redef class ASendExpr
1103 redef fun generate_icode
(v
)
1105 var recv
= v
.generate_expr
(n_expr
)
1106 var args
= new Array[IRegister]
1109 generate_icode_for_arguments_in
(v
, args
, prop
.signature
.as(not null))
1110 var r
: nullable IRegister = null # The full result of the send (raw call + breaks)
1111 var r2
: nullable IRegister # The raw result of the call
1115 var closcns
: nullable Array[nullable IClosureDef] = null
1116 if not prop_signature
.closures
.is_empty
then
1117 var rtype
= prop_signature
.return_type
1118 if rtype
!= null then
1119 r
= v
.new_register
(rtype
)
1124 closcns
= new Array[nullable IClosureDef]
1126 if closure_defs
!= null then cdarity
= closure_defs
.length
1127 var closure_defs
= closure_defs
1128 for mmc
in prop_signature
.closures
do
1131 if closure_defs
!= null then
1132 for cd
in closure_defs
do
1133 if cd
.n_id
.to_symbol
!= name
then continue
1134 assert found
== false
1136 cd
.escapable
.break_seq
= seq
1137 cd
.escapable
.break_value
= r
1138 var cn
= cd
.generate_iclosuredef
(v
)
1148 r2
= v
.add_call
(prop
, args
, closcns
)
1151 if not prop_signature
.closures
.is_empty
then
1152 if r
!= null and r2
!= null then v
.add_assignment
(r
, r2
)
1158 if prop
.global
.is_init
then
1159 v
.invoke_super_init_calls_after
(prop
)
1165 redef class ASendReassignExpr
1166 redef fun generate_icode
(v
)
1168 var recv
= v
.generate_expr
(n_expr
)
1169 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(recv
)
1170 var args
= new Array[IRegister]
1172 generate_icode_for_arguments_in
(v
, args
, read_prop
.signature
.as(not null))
1174 var e2
= v
.expr
(new ICall(read_prop
, args
), read_prop
.signature
.return_type
.as(not null))
1175 var e3
= v
.generate_expr
(n_value
)
1176 var e4
= v
.expr
(new ICall(assign_method
, [e2
, e3
]), assign_method
.signature
.return_type
.as(not null))
1177 var args2
= args
.to_a
1179 v
.stmt
(new ICall(prop
, args2
))
1184 redef class ANewExpr
1185 redef fun generate_icode
(v
)
1187 var args
= new Array[IRegister]
1188 generate_icode_for_arguments_in
(v
, args
, prop
.signature
.as(not null))
1189 return v
.expr
(new INew(stype
, prop
, args
), stype
)
1193 redef class AProxyExpr
1194 redef fun generate_icode
(v
)
1196 return v
.generate_expr
(n_expr
)
1200 redef class AOnceExpr
1201 redef fun generate_icode
(v
)
1203 var ionce
= new IOnce
1204 var reg
= v
.expr
(ionce
, stype
)
1208 var e
= v
.generate_expr
(n_expr
)
1209 v
.add_assignment
(reg
, e
)
1217 redef class AClosureDef
1218 var _iclosure_def
: nullable IClosureDef
1220 fun generate_iclosuredef
(v
: A2IContext): IClosureDef
1223 var args
= new Array[IRegister]
1224 var sig
= closure
.signature
1225 for i
in [0..sig
.arity
[ do
1226 args
.add
(v
.new_register
(sig
[i
]))
1228 var ret
: nullable IRegister = null
1229 var rtype
= sig
.return_type
1230 if rtype
!= null then
1231 ret
= v
.new_register
(rtype
)
1234 var iclos
= new IClosureDef(args
, ret
)
1235 iclos
.location
= location
1240 escapable
.continue_seq
= iclos
.body
1241 escapable
.continue_value
= iclos
.result
1244 for i
in [0..variables
.length
[ do
1245 var res
= v
.variable
(variables
[i
])
1246 v
.add_assignment
(res
, iclos
.params
[i
])
1249 v
.generate_stmt
(n_expr
)
1251 # Add a final break in case of break block witout value
1252 if closure
.is_break
and escapable
.break_value
== null then
1253 v
.add_escape
(escapable
.break_seq
.as(not null))
1257 _iclosure_def
= iclos
1262 redef class AClosureCallExpr
1263 redef fun generate_icode
(v
)
1266 var args
= new Array[IRegister]
1267 generate_icode_for_arguments_in
(v
, args
, variable
.closure
.signature
)
1270 var closdecl
= v
.closurevariables
[variable
]
1271 var icall
= new IClosCall(closdecl
, args
)
1274 # Fill break of ical
1275 if n_closure_defs
.length
== 1 then do
1277 icall
.break_seq
= iseq
1279 v
.generate_stmt
(n_closure_defs
.first
.n_expr
)
1283 # Prepare in case of default block
1284 var iif
: nullable IIf = null # The iif of default block
1285 var closdecl_default
= closdecl
.default
# The default (if any)
1286 if closdecl_default
!= null then
1287 iif
= new IIf(v
.expr
(new IHasClos(closdecl
), v
.visitor
.type_bool
))
1289 v
.seq
= iif
.then_seq
1293 var r2
: nullable IRegister = null # the result of the icall
1294 var rtype
= variable
.closure
.signature
.return_type
1295 if rtype
== null then
1298 r2
= v
.expr
(icall
, rtype
)
1301 # Process the case of default block
1302 var r
: nullable IRegister = null # the real result
1303 if closdecl_default
!= null then
1306 assert rtype
!= null
1307 r
= v
.new_register
(rtype
)
1308 v
.add_assignment
(r
, r2
)
1310 v
.seq
= iif
.else_seq
1311 var r3
= v
.inline_routine
(closdecl_default
, args
, null)
1314 v
.add_assignment
(r
, r3
)