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 INative("TAG_Int({length})", null), 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
62 if t
== null then t
= visitor
.type_object
.as_nullable
63 var reg
= new_register
(t
)
69 # Current registered variable
70 var _variables
: HashMap[Variable, IRegister] = new HashMap[Variable, IRegister]
72 # Current registered closurevariables
73 readable var _closurevariables
: HashMap[ClosureVariable, IClosureDecl] = new HashMap[ClosureVariable, IClosureDecl]
75 # The current syntax visitor
76 readable var _visitor
: AbsSyntaxVisitor
78 # Where a nit return must branch
79 readable writable var _return_seq
: nullable ISeq
81 # Register where a functionnal nit return must store its value
82 readable writable var _return_value
: nullable IRegister
84 # The method associated to the iroutine (if any)
85 readable var _method
: nullable MMMethod
87 init(visitor
: AbsSyntaxVisitor, r
: IRoutine, m
: nullable MMMethod)
89 super(visitor
.module, r
)
92 _return_value
= r
.result
96 # Insert implicit super init calls
97 fun invoke_super_init_calls_after
(start_prop
: nullable MMMethod)
100 assert p
isa MMSrcMethod
102 assert n
isa AConcreteInitPropdef
104 if n
.super_init_calls
.is_empty
then return
107 if start_prop
!= null then
108 while n
.super_init_calls
[i
] != start_prop
do
113 while n
.explicit_super_init_calls
[j
] != start_prop
do
118 var stop_prop
: nullable MMMethod = null
119 if j
< n
.explicit_super_init_calls
.length
then
120 stop_prop
= n
.explicit_super_init_calls
[j
]
122 var l
= n
.super_init_calls
.length
124 var sp
= n
.super_init_calls
[i
]
125 if sp
== stop_prop
then break
126 var cargs
= new Array[IRegister]
127 if sp
.signature
.arity
== 0 then
128 cargs
.add
(iroutine
.params
.first
)
130 for va
in iroutine
.params
do
134 stmt
(new ICall(sp
, cargs
))
140 var _current_node
: nullable AExpr = null
142 # Generate icode in the current sequence from a statement
143 fun generate_stmt
(n
: nullable AExpr)
145 if n
== null then return
146 var old
= _current_node
148 n
.generate_icode
(self)
152 # Generate icode in the current sequence from an expression
153 fun generate_expr
(n
: AExpr): IRegister
155 var old
= _current_node
157 var reg
= n
.generate_icode
(self).as(not null)
163 redef class EscapableBlock
164 # Where a nit break must branch
165 readable writable var _break_seq
: nullable ISeq
167 # Where a nit continue must branch
168 readable writable var _continue_seq
: nullable ISeq
170 # Register where a functionnal nit break must store its value
171 readable writable var _break_value
: nullable IRegister
173 # Register where a functionnal nit continue must store its value
174 readable writable var _continue_value
: nullable IRegister
177 redef class MMSrcModule
178 # Generate icode for method bodies
179 fun generate_icode
(tc
: ToolContext)
181 var v
= new A2IVisitor(tc
, self)
182 for c
in src_local_classes
do
183 for p
in c
.src_local_properties
do
184 if p
isa MMSrcMethod then
185 p
.generate_iroutine
(v
)
186 else if p
isa MMSrcAttribute then
187 p
.generate_iroutine
(v
)
194 redef class MMSrcAttribute
195 redef readable writable var _iroutine
: nullable IRoutine
197 # Generate the initialization iroutine
198 fun generate_iroutine
(visitor
: A2IVisitor)
200 if node
.n_expr
!= null then
201 var iroutine
= signature
.generate_empty_iroutine
202 iroutine
.location
= node
.location
203 var v
= new A2IContext(visitor
, iroutine
, null)
204 visitor
.icode_ctx
= v
205 visitor
.enter_visit
(node
)
206 visitor
.icode_ctx
= null
212 redef class MMSrcMethod
213 redef readable writable var _iroutine
: nullable IRoutine
215 # Generate the body iroutine
216 fun generate_iroutine
(visitor
: A2IVisitor)
218 var iroutine
= signature
.generate_empty_iroutine
220 iroutine
.location
= node
.location
222 var v
= new A2IContext(visitor
, iroutine
, self)
223 visitor
.icode_ctx
= v
224 inner_generate_iroutine
(v
)
225 visitor
.icode_ctx
= null
229 # Generate the body iroutine (specific part)
230 fun inner_generate_iroutine
(v
: A2IContext) is abstract
233 redef class MMReadImplementationMethod
234 redef fun inner_generate_iroutine
(v
)
236 var e
= v
.add_attr_read
(node
.prop
, v
.iroutine
.params
.first
)
237 v
.add_return_value
(e
)
241 redef class MMWriteImplementationMethod
242 redef fun inner_generate_iroutine
(v
)
244 var params
= v
.iroutine
.params
245 v
.stmt
(new IAttrWrite(node
.prop
, params
[0], params
[1]))
249 redef class MMMethSrcMethod
250 redef fun inner_generate_iroutine
(v
)
252 v
.visitor
.enter_visit
(node
)
256 redef class MMImplicitInit
257 redef fun inner_generate_iroutine
(v
)
259 var params
= v
.iroutine
.params
260 var f
= params
.length
- unassigned_attributes
.length
261 var recv
= params
.first
262 for sp
in super_inits
do
263 assert sp
isa MMMethod
264 var args_recv
= [recv
]
265 if sp
== super_init
then
266 var args
= new Array[IRegister].with_capacity
(f
)
271 v
.stmt
(new ICall(sp
, args
))
273 v
.stmt
(new ICall(sp
, args_recv
))
276 for i
in [f
..params
.length
[ do
277 var attribute
= unassigned_attributes
[i-f
]
278 v
.stmt
(new IAttrWrite(attribute
, recv
, params
[i
]))
284 special AbsSyntaxVisitor
285 writable var _icode_ctx
: nullable A2IContext
286 fun icode_ctx
: A2IContext do return _icode_ctx
.as(not null)
287 redef fun visit
(n
) do n
.accept_icode_generation
(self)
292 ###############################################################################
295 fun accept_icode_generation
(v
: A2IVisitor) do accept_abs_syntax_visitor
(v
) end
298 redef class AAttrPropdef
299 redef fun accept_icode_generation
(vv
)
302 v
.stmt
(new IMove(v
.variable
(self_var
), v
.iroutine
.params
.first
))
306 v
.stmt
(new IMove(v
.iroutine
.result
.as(not null), v
.generate_expr
(ne
)))
311 redef class AMethPropdef
312 redef fun accept_icode_generation
(vv
)
315 fill_iroutine
(vv
.icode_ctx
, method
)
318 # Compile the method body common preambule (before specific body stuff if any)
319 fun fill_iroutine
(v
: A2IContext, method
: MMSrcMethod) is abstract
322 redef class ASignature
323 fun fill_iroutine_parameters
(v
: A2IContext, orig_sig
: MMSignature, params
: Sequence[IRegister], closdecls
: nullable Sequence[IClosureDecl])
325 for ap
in n_params
do
326 var reg
= v
.variable
(ap
.variable
)
327 var orig_type
= orig_sig
[ap
.position
]
328 var apst
= ap
.variable
.stype
.as(not null)
329 if not orig_type
< apst
then
330 v
.add_type_cast
(params
[ap
.position
], apst
)
332 v
.stmt
(new IMove(reg
, params
[ap
.position
]))
334 for i
in [0..n_closure_decls
.length
[ do
335 var wd
= n_closure_decls
[i
]
336 v
.closurevariables
[wd
.variable
] = closdecls
[i
]
341 redef class AClosureDecl
342 redef fun accept_icode_generation
(vv
)
345 var iclos
= variable
.closure
.signature
.generate_empty_iclosuredef
(v
)
348 escapable
.continue_seq
= iclos
.body
349 escapable
.continue_value
= iclos
.result
350 escapable
.break_seq
= v
.return_seq
351 escapable
.break_value
= v
.return_value
352 n_signature
.fill_iroutine_parameters
(v
, variable
.closure
.signature
, iclos
.params
, null)
354 if n_expr
!= null then
355 v
.generate_stmt
(n_expr
)
356 v
.iroutine
.closure_decls
[position
].default
= iclos
358 # Add a final break in case of break block witout value
359 if variable
.closure
.is_break
and v
.return_value
== null then
360 v
.stmt
(new IEscape(v
.return_seq
.as(not null)))
367 redef class AConcreteMethPropdef
368 redef fun fill_iroutine
(v
, method
)
370 var params
= v
.iroutine
.params
.to_a
371 var selfreg
= v
.variable
(self_var
)
372 v
.stmt
(new IMove(selfreg
, params
[0]))
375 var orig_meth
: MMLocalProperty = method
.global
.intro
376 var orig_sig
= orig_meth
.signature_for
(method
.signature
.recv
)
377 if n_signature
!= null then
378 n_signature
.fill_iroutine_parameters
(v
, orig_sig
, params
, v
.iroutine
.closure_decls
)
381 if self isa AConcreteInitPropdef then
382 v
.invoke_super_init_calls_after
(null)
385 if n_block
!= null then
386 v
.generate_stmt
(n_block
)
391 redef class ADeferredMethPropdef
392 redef fun fill_iroutine
(v
, method
)
394 v
.add_abort
("Deferred method called")
398 redef class AExternMethPropdef
399 redef fun fill_iroutine
(v
, method
)
401 var params
= v
.iroutine
.params
402 var ename
= "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
403 if n_extern
!= null then
404 ename
= n_extern
.text
405 ename
= ename
.substring
(1, ename
.length-2
)
407 var sig
= method
.signature
408 assert params
.length
== sig
.arity
+ 1
409 var args
= new Array[String]
410 args
.add
(sig
.recv
.unboxtype
("@@@"))
411 for i
in [0..sig
.arity
[ do
412 args
.add
(sig
[i
].unboxtype
("@@@"))
414 var s
= "{ename}({args.join(", ")})"
415 var rtype
= sig
.return_type
416 if rtype
!= null then
418 v
.add_return_value
(v
.expr
(new INative(s
, params
), rtype
))
420 v
.stmt
(new INative(s
, params
))
425 redef class AInternMethPropdef
426 redef fun fill_iroutine
(v
, method
)
428 var p
= v
.iroutine
.params
.to_a
429 var c
= method
.local_class
.name
431 var s
: nullable String = null
432 if c
== once
"Int".to_symbol
then
433 if n
== once
"object_id".to_symbol
then
435 else if n
== once
"unary -".to_symbol
then
436 s
= "TAG_Int(-UNTAG_Int(@@@))"
437 else if n
== once
"output".to_symbol
then
438 s
= "printf(\"%ld\\n\
", UNTAG_Int(@@@));"
439 else if n
== once
"ascii".to_symbol
then
440 s
= "TAG_Char(UNTAG_Int(@@@))"
441 else if n
== once
"succ".to_symbol
then
442 s
= "TAG_Int(UNTAG_Int(@@@)+1)"
443 else if n
== once
"prec".to_symbol
then
444 s
= "TAG_Int(UNTAG_Int(@@@)-1)"
445 else if n
== once
"to_f".to_symbol
then
446 s
= "BOX_Float((float)UNTAG_Int(@@@))"
447 else if n
== once
"+".to_symbol
then
448 s
= "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))"
449 else if n
== once
"-".to_symbol
then
450 s
= "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))"
451 else if n
== once
"*".to_symbol
then
452 s
= "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))"
453 else if n
== once
"/".to_symbol
then
454 s
= "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
455 else if n
== once
"%".to_symbol
then
456 s
= "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))"
457 else if n
== once
"<".to_symbol
then
458 s
= "TAG_Bool(UNTAG_Int(@@@)<UNTAG_Int(@@@))"
459 else if n
== once
">".to_symbol
then
460 s
= "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))"
461 else if n
== once
"<=".to_symbol
then
462 s
= "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
463 else if n
== once
">=".to_symbol
then
464 s
= "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
465 else if n
== once
"lshift".to_symbol
then
466 s
= "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
467 else if n
== once
"rshift".to_symbol
then
468 s
= "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
469 else if n
== once
"==".to_symbol
then
470 s
= "TAG_Bool((@@@)==(@@@))"
471 else if n
== once
"!=".to_symbol
then
472 s
= "TAG_Bool((@@@)!=(@@@))"
474 else if c
== once
"Float".to_symbol
then
475 if n
== once
"object_id".to_symbol
then
476 s
= "TAG_Int((bigint)UNBOX_Float(@@@))"
477 else if n
== once
"unary -".to_symbol
then
478 s
= "BOX_Float(-UNBOX_Float(@@@))"
479 else if n
== once
"output".to_symbol
then
480 s
= "printf(\"%f\\n\
", UNBOX_Float(@@@));"
481 else if n
== once
"to_i".to_symbol
then
482 s
= "TAG_Int((bigint)UNBOX_Float(@@@))"
483 else if n
== once
"+".to_symbol
then
484 s
= "BOX_Float(UNBOX_Float(@@@)+UNBOX_Float(@@@))"
485 else if n
== once
"-".to_symbol
then
486 s
= "BOX_Float(UNBOX_Float(@@@)-UNBOX_Float(@@@))"
487 else if n
== once
"*".to_symbol
then
488 s
= "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
489 else if n
== once
"/".to_symbol
then
490 s
= "BOX_Float(UNBOX_Float(@@@)/UNBOX_Float(@@@))"
491 else if n
== once
"<".to_symbol
then
492 s
= "TAG_Bool(UNBOX_Float(@@@)<UNBOX_Float(@@@))"
493 else if n
== once
">".to_symbol
then
494 s
= "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))"
495 else if n
== once
"<=".to_symbol
then
496 s
= "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
497 else if n
== once
">=".to_symbol
then
498 s
= "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
500 else if c
== once
"Char".to_symbol
then
501 if n
== once
"object_id".to_symbol
then
502 s
= "TAG_Int(UNTAG_Char(@@@))"
503 else if n
== once
"unary -".to_symbol
then
504 s
= "TAG_Char(-UNTAG_Char(@@@))"
505 else if n
== once
"output".to_symbol
then
506 s
= "printf(\"%c\
", (unsigned char)UNTAG_Char(@@@));"
507 else if n
== once
"ascii".to_symbol
then
508 s
= "TAG_Int((unsigned char)UNTAG_Char(@@@))"
509 else if n
== once
"succ".to_symbol
then
510 s
= "TAG_Char(UNTAG_Char(@@@)+1)"
511 else if n
== once
"prec".to_symbol
then
512 s
= "TAG_Char(UNTAG_Char(@@@)-1)"
513 else if n
== once
"to_i".to_symbol
then
514 s
= "TAG_Int(UNTAG_Char(@@@)-'0')"
515 else if n
== once
"+".to_symbol
then
516 s
= "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))"
517 else if n
== once
"-".to_symbol
then
518 s
= "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))"
519 else if n
== once
"*".to_symbol
then
520 s
= "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))"
521 else if n
== once
"/".to_symbol
then
522 s
= "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
523 else if n
== once
"%".to_symbol
then
524 s
= "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))"
525 else if n
== once
"<".to_symbol
then
526 s
= "TAG_Bool(UNTAG_Char(@@@)<UNTAG_Char(@@@))"
527 else if n
== once
">".to_symbol
then
528 s
= "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))"
529 else if n
== once
"<=".to_symbol
then
530 s
= "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
531 else if n
== once
">=".to_symbol
then
532 s
= "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
533 else if n
== once
"==".to_symbol
then
534 s
= "TAG_Bool((@@@)==(@@@))"
535 else if n
== once
"!=".to_symbol
then
536 s
= "TAG_Bool((@@@)!=(@@@))"
538 else if c
== once
"Bool".to_symbol
then
539 if n
== once
"object_id".to_symbol
then
540 s
= "TAG_Int(UNTAG_Bool(@@@))"
541 else if n
== once
"unary -".to_symbol
then
542 s
= "TAG_Bool(-UNTAG_Bool(@@@))"
543 else if n
== once
"output".to_symbol
then
544 s
= "(void)printf(UNTAG_Bool(@@@)?\"true\\n\
":\"false\\n\
");"
545 else if n
== once
"ascii".to_symbol
then
546 s
= "TAG_Bool(UNTAG_Bool(@@@))"
547 else if n
== once
"to_i".to_symbol
then
548 s
= "TAG_Int(UNTAG_Bool(@@@))"
549 else if n
== once
"==".to_symbol
then
550 s
= "TAG_Bool((@@@)==(@@@))"
551 else if n
== once
"!=".to_symbol
then
552 s
= "TAG_Bool((@@@)!=(@@@))"
554 else if c
== once
"NativeArray".to_symbol
then
555 if n
== once
"object_id".to_symbol
then
556 s
= "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
557 else if n
== once
"[]".to_symbol
then
558 s
= "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
559 else if n
== once
"[]=".to_symbol
then
560 s
= "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
561 else if n
== once
"copy_to".to_symbol
then
565 s
= "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
567 else if c
== once
"NativeString".to_symbol
then
568 if n
== once
"object_id".to_symbol
then
569 s
= "TAG_Int(UNBOX_NativeString(@@@))"
570 else if n
== once
"atoi".to_symbol
then
571 s
= "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
572 else if n
== once
"[]".to_symbol
then
573 s
= "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
574 else if n
== once
"[]=".to_symbol
then
575 s
= "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
576 else if n
== once
"copy_to".to_symbol
then
582 s
= "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
584 else if n
== once
"object_id".to_symbol
then
585 s
= "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
586 else if n
== once
"sys".to_symbol
then
588 else if n
== once
"is_same_type".to_symbol
then
589 s
= "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
590 else if n
== once
"exit".to_symbol
then
592 s
= "exit(UNTAG_Int(@@@));"
593 else if n
== once
"calloc_array".to_symbol
then
595 s
= "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
596 else if n
== once
"calloc_string".to_symbol
then
598 s
= "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
601 v
.visitor
.error
(self, "Fatal error: unknown intern method {method.full_name}.")
604 var rtype
= method
.signature
.return_type
605 if rtype
!= null then
606 v
.add_return_value
(v
.expr
(new INative(s
, p
), rtype
))
608 v
.stmt
(new INative(s
, p
))
613 ###############################################################################
616 redef fun accept_icode_generation
(v
) do end
618 # Generate icode sequence in the current A2IContext
619 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
620 protected fun generate_icode
(v
: A2IContext): nullable IRegister is abstract
623 redef class AVardeclExpr
624 redef fun generate_icode
(v
)
626 var reg
= v
.variable
(variable
)
629 v
.add_assignment
(reg
, v
.generate_expr
(ne
))
635 redef class ABlockExpr
636 redef fun generate_icode
(v
)
638 for ne
in n_expr
do v
.generate_stmt
(ne
)
644 redef fun generate_icode
(v
)
649 escapable
.break_seq
= seq
652 v
.generate_stmt
(n_block
)
659 redef class AReturnExpr
660 redef fun generate_icode
(v
)
664 v
.add_assignment
(v
.return_value
.as(not null), v
.generate_expr
(ne
))
666 v
.stmt
(new IEscape(v
.return_seq
.as(not null)))
671 redef class ABreakExpr
672 redef fun generate_icode
(v
)
676 v
.add_assignment
(escapable
.break_value
.as(not null), v
.generate_expr
(ne
))
678 v
.stmt
(new IEscape(escapable
.break_seq
.as(not null)))
683 redef class AContinueExpr
684 redef fun generate_icode
(v
)
688 v
.add_assignment
(escapable
.continue_value
.as(not null), v
.generate_expr
(ne
))
690 v
.stmt
(new IEscape(escapable
.continue_seq
.as(not null)))
695 redef class AAbortExpr
696 redef fun generate_icode
(v
)
698 v
.add_abort
("Aborted")
704 redef fun generate_icode
(v
)
706 var iif
= new IIf(v
.generate_expr
(n_expr
))
710 if n_then
!= null then
712 v
.generate_stmt
(n_then
)
715 if n_else
!= null then
717 v
.generate_stmt
(n_else
)
725 redef class AWhileExpr
726 redef fun generate_icode
(v
)
729 var iloop
= new ILoop
731 escapable
.break_seq
= iloop
735 var iif
= new IIf(v
.generate_expr
(n_expr
))
738 # Process inside (condition is true)
739 if n_block
!= null then
741 escapable
.continue_seq
= iif
.then_seq
742 v
.generate_stmt
(n_block
)
745 # Process escape (condition is false)
747 v
.stmt
(new IEscape(iloop
))
754 redef class ALoopExpr
755 redef fun generate_icode
(v
)
758 var iloop
= new ILoop
760 escapable
.break_seq
= iloop
764 if n_block
!= null then
768 escapable
.continue_seq
= seq
769 v
.generate_stmt
(n_block
)
778 redef fun generate_icode
(v
)
780 var expr_type
= n_expr
.stype
783 var meth_iterator
= v
.visitor
.get_method
(expr_type
, once
"iterator".to_symbol
)
785 var iter_type
= meth_iterator
.signature_for
(expr_type
).return_type
.as(not null)
786 var ireg_iter
= v
.expr
(new ICall(meth_iterator
, [v
.generate_expr
(n_expr
)]), iter_type
)
790 var iloop
= new ILoop
792 escapable
.break_seq
= iloop
795 # Condition evaluation
796 var meth_is_ok
= v
.visitor
.get_method
(iter_type
, once
("is_ok".to_symbol
))
797 var ireg_isok
= v
.expr
(new ICall(meth_is_ok
, [ireg_iter
]), v
.visitor
.type_bool
)
798 var iif
= new IIf(ireg_isok
)
800 # Process insite the loop (condition is true)
803 escapable
.continue_seq
= iif
.then_seq
805 # Automatic variable assignment
806 var meth_item
= v
.visitor
.get_method
(iter_type
, once
("item".to_symbol
))
807 var va_stype
= variable
.stype
.as(not null)
808 var ireg_item
= v
.expr
(new ICall(meth_item
, [ireg_iter
]), va_stype
)
809 var ireg_va
= v
.variable
(variable
)
810 v
.add_assignment
(ireg_va
, ireg_item
)
813 v
.generate_stmt
(n_block
)
815 # Exit contition (condition is false)
817 v
.stmt
(new IEscape(iloop
))
820 var meth_next
= v
.visitor
.get_method
(iter_type
, once
("next".to_symbol
))
822 v
.stmt
(new ICall(meth_next
, [ireg_iter
]))
829 redef class AAssertExpr
830 redef fun generate_icode
(v
)
832 var e
= v
.generate_expr
(n_expr
)
837 v
.generate_stmt
(n_else
)
840 v
.add_abort
("Assert failed")
842 v
.add_abort
("Assert %s failed", id
.to_s
)
850 redef fun generate_icode
(v
)
852 return v
.variable
(variable
)
856 redef class AVarAssignExpr
857 redef fun generate_icode
(v
)
859 var e
= v
.generate_expr
(n_value
)
860 v
.add_assignment
(v
.variable
(variable
), e
)
865 redef class AVarReassignExpr
866 redef fun generate_icode
(v
)
868 var e1
= v
.variable
(variable
)
869 var e2
= v
.generate_expr
(n_value
)
870 var e3
= v
.expr
(new ICall(assign_method
, [e1
, e2
]), assign_method
.signature
.return_type
.as(not null))
871 v
.add_assignment
(e1
, e3
)
876 redef class ASelfExpr
877 redef fun generate_icode
(v
)
879 return v
.variable
(variable
)
883 redef class AIfexprExpr
884 redef fun generate_icode
(v
)
887 var iif
= new IIf(v
.generate_expr
(n_expr
))
892 var reg
= v
.new_register
(stype
)
896 v
.add_assignment
(reg
, v
.generate_expr
(n_then
))
900 v
.add_assignment
(reg
, v
.generate_expr
(n_else
))
908 redef fun generate_icode
(v
)
910 var e
= v
.generate_expr
(n_expr
)
911 var e2
= v
.generate_expr
(n_expr2
)
912 return v
.expr
(new IIs(e
, e2
), stype
)
917 redef fun generate_icode
(v
)
920 var reg
= v
.new_register
(stype
)
922 # Process left operand (in a if/then)
923 var iif
= new IIf(v
.generate_expr
(n_expr
))
927 v
.add_assignment
(reg
, v
.lit_true_reg
)
929 # Process right operand (in the else)
931 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
939 redef fun generate_icode
(v
)
942 var reg
= v
.new_register
(stype
)
944 # Process left operand (in a if/else)
945 var iif
= new IIf(v
.generate_expr
(n_expr
))
949 v
.add_assignment
(reg
, v
.lit_false_reg
)
951 # Process right operand (in the then)
953 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
961 redef fun generate_icode
(v
)
963 var e
= v
.generate_expr
(n_expr
)
964 return v
.expr
(new INot(e
), stype
)
969 redef fun generate_icode
(v
)
971 var e
= v
.generate_expr
(n_expr
)
972 return v
.expr
(new ITypeCheck(e
, n_type
.stype
), stype
)
976 redef class AAsCastExpr
977 redef fun generate_icode
(v
)
979 var e
= v
.generate_expr
(n_expr
)
980 v
.add_type_cast
(e
, stype
)
985 redef class AAsNotnullExpr
986 redef fun generate_icode
(v
)
988 var e
= v
.generate_expr
(n_expr
)
989 v
.add_type_cast
(e
, stype
)
994 redef class ATrueExpr
995 redef fun generate_icode
(v
)
997 return v
.lit_true_reg
1001 redef class AFalseExpr
1002 redef fun generate_icode
(v
)
1004 return v
.lit_false_reg
1008 redef class AIntExpr
1009 redef fun generate_icode
(v
)
1011 return v
.expr
(new INative("TAG_Int({n_number.text})", null), stype
)
1015 redef class AFloatExpr
1016 redef fun generate_icode
(v
)
1018 return v
.expr
(new INative("BOX_Float({n_float.text})", null), stype
)
1022 redef class ACharExpr
1023 redef fun generate_icode
(v
)
1025 return v
.expr
(new INative("TAG_Char({n_char.text})", null), stype
)
1029 redef class AStringFormExpr
1030 redef fun generate_icode
(v
)
1032 compute_string_infos
1034 var ionce
= new IOnce
1035 var reg
= v
.expr
(ionce
, stype
)
1037 var ns
= v
.expr
(new INative("BOX_NativeString(\"{_cstring}\
")", null), v
.visitor
.type_nativestring
)
1038 var ni
= v
.expr
(new INative("TAG_Int({_cstring_length})", null), v
.visitor
.type_int
)
1039 var prop
= v
.visitor
.get_method
(stype
, once
"with_native".to_symbol
)
1040 var e
= v
.expr
(new INew(stype
, prop
, [ns
, ni
]), stype
)
1041 v
.add_assignment
(reg
, e
)
1046 # The raw string value
1047 protected fun string_text
: String is abstract
1049 # The string in a C native format
1050 protected var _cstring
: nullable String
1052 # The string length in bytes
1053 protected var _cstring_length
: nullable Int
1055 # Compute _cstring and _cstring_length using string_text
1056 protected fun compute_string_infos
1059 var str
= string_text
1060 var res
= new Buffer
1062 while i
< str
.length
do
1067 if c2
!= '{' and c2 != '}' then
1077 _cstring_length
= len
1081 redef class AStringExpr
1082 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1084 redef class AStartStringExpr
1085 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1087 redef class AMidStringExpr
1088 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1090 redef class AEndStringExpr
1091 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1094 redef class ASuperstringExpr
1095 redef fun generate_icode
(v
)
1097 var array
= v
.add_new_array
(atype
, n_exprs
.length
)
1098 var prop_to_s
= v
.visitor
.get_method
(v
.visitor
.type_object
, once
"to_s".to_symbol
)
1099 for ne
in n_exprs
do
1100 var e
= v
.generate_expr
(ne
)
1101 if ne
.stype
!= stype
then
1102 e
= v
.expr
(new ICall(prop_to_s
, [e
]), stype
)
1104 v
.add_call_array_add
(array
, e
)
1106 return v
.expr
(new ICall(prop_to_s
, [array
]), stype
)
1110 redef class ANullExpr
1111 redef fun generate_icode
(v
)
1113 return v
.lit_null_reg
1117 redef class AArrayExpr
1118 redef fun generate_icode
(v
)
1120 var recv
= v
.add_new_array
(stype
, n_exprs
.length
)
1121 for ne
in n_exprs
do
1122 var e
= v
.generate_expr
(ne
)
1123 v
.add_call_array_add
(recv
, e
)
1129 redef class ACrangeExpr
1130 redef fun generate_icode
(v
)
1132 var e
= v
.generate_expr
(n_expr
)
1133 var e2
= v
.generate_expr
(n_expr2
)
1134 var prop
= v
.visitor
.get_method
(stype
, once
"init".to_symbol
)
1135 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
1139 redef class AOrangeExpr
1140 redef fun generate_icode
(v
)
1142 var e
= v
.generate_expr
(n_expr
)
1143 var e2
= v
.generate_expr
(n_expr2
)
1144 var prop
= v
.visitor
.get_method
(stype
, once
"without_last".to_symbol
)
1145 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
1149 redef class ASuperExpr
1150 redef fun generate_icode
(v
)
1152 var arity
= v
.iroutine
.params
.length
- 1
1153 if init_in_superclass
!= null then
1154 arity
= init_in_superclass
.signature
.arity
1156 var args
= new Array[IRegister].with_capacity
(arity
+ 1)
1157 args
.add
(v
.iroutine
.params
[0])
1158 if n_args
.length
!= arity
then
1159 for i
in [0..arity
[ do
1160 args
.add
(v
.iroutine
.params
[i
+ 1])
1164 args
.add
(v
.generate_expr
(na
))
1167 var p
= init_in_superclass
1169 var rtype
= p
.signature
.return_type
1170 if rtype
!= null then
1171 return v
.expr
(new ICall(p
, args
), rtype
)
1173 v
.stmt
(new ICall(p
, args
))
1178 var rtype
= p
.signature
.return_type
1179 if rtype
== null then
1180 v
.stmt
(new ISuper(p
, args
))
1183 return v
.expr
(new ISuper(p
, args
), rtype
)
1189 redef class AAttrExpr
1190 redef fun generate_icode
(v
)
1192 var e
= v
.generate_expr
(n_expr
)
1193 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1194 return v
.add_attr_read
(prop
, e
)
1198 redef class AAttrAssignExpr
1199 redef fun generate_icode
(v
)
1201 var e
= v
.generate_expr
(n_expr
)
1202 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1203 var e2
= v
.generate_expr
(n_value
)
1204 v
.stmt
(new IAttrWrite(prop
, e
, e2
))
1208 redef class AAttrReassignExpr
1209 redef fun generate_icode
(v
)
1211 var e1
= v
.generate_expr
(n_expr
)
1212 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e1
)
1213 var e2
= v
.expr
(new IAttrRead(prop
, e1
), attr_type
)
1214 var e3
= v
.generate_expr
(n_value
)
1215 var e4
= v
.expr
(new ICall(assign_method
, [e2
, e3
]), attr_type
)
1216 v
.stmt
(new IAttrWrite(prop
, e1
, e4
))
1221 redef class AIssetAttrExpr
1222 redef fun generate_icode
(v
)
1224 var e
= v
.generate_expr
(n_expr
)
1225 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1226 return v
.expr
(new IAttrIsset(prop
, e
), stype
)
1230 redef class AAbsAbsSendExpr
1231 # Compile each argument and add them to the array
1232 fun generate_icode_for_arguments_in
(v
: A2IContext, args
: Array[IRegister], signature
: MMSignature)
1234 var par_arity
= signature
.arity
1235 var par_vararg
= signature
.vararg_rank
1236 var raw_args
= raw_arguments
1237 var raw_arity
= raw_args
.length
1239 for par_idx
in [0..par_arity
[ do
1241 var par_type
= signature
[par_idx
]
1242 if par_idx
== par_vararg
then
1243 var arr
= v
.add_new_array
(v
.visitor
.type_array
(par_type
), raw_arity-par_arity
)
1244 for i
in [0..(raw_arity-par_arity
)] do
1245 a
= raw_args
[arg_idx
]
1246 v
.add_call_array_add
(arr
, v
.generate_expr
(a
))
1247 arg_idx
= arg_idx
+ 1
1251 a
= raw_args
[arg_idx
]
1252 args
.add
(v
.generate_expr
(a
))
1253 arg_idx
= arg_idx
+ 1
1259 redef class ASendExpr
1260 redef fun generate_icode
(v
)
1262 var recv
= v
.generate_expr
(n_expr
)
1263 var args
= new Array[IRegister]
1266 generate_icode_for_arguments_in
(v
, args
, prop
.signature
.as(not null))
1267 var r
: nullable IRegister = null # The full result of the send (raw call + breaks)
1268 var r2
: nullable IRegister # The raw result of the call
1272 var closcns
: nullable Array[nullable IClosureDef] = null
1273 if not prop_signature
.closures
.is_empty
then
1274 var rtype
= prop_signature
.return_type
1275 if rtype
!= null then
1276 r
= v
.new_register
(rtype
)
1281 closcns
= new Array[nullable IClosureDef]
1283 if closure_defs
!= null then cdarity
= closure_defs
.length
1284 var closure_defs
= closure_defs
1285 for mmc
in prop_signature
.closures
do
1288 if closure_defs
!= null then
1289 for cd
in closure_defs
do
1290 if cd
.n_id
.to_symbol
!= name
then continue
1291 assert found
== false
1293 cd
.escapable
.break_seq
= seq
1294 cd
.escapable
.break_value
= r
1295 var cn
= cd
.generate_iclosuredef
(v
)
1305 r2
= v
.add_call
(prop
, args
, closcns
)
1308 if not prop_signature
.closures
.is_empty
then
1309 if r
!= null and r2
!= null then v
.add_assignment
(r
, r2
)
1315 if prop
.global
.is_init
then
1316 v
.invoke_super_init_calls_after
(prop
)
1322 redef class ASendReassignExpr
1323 redef fun generate_icode
(v
)
1325 var recv
= v
.generate_expr
(n_expr
)
1326 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(recv
)
1327 var args
= new Array[IRegister]
1329 generate_icode_for_arguments_in
(v
, args
, read_prop
.signature
.as(not null))
1331 var e2
= v
.expr
(new ICall(read_prop
, args
), read_prop
.signature
.return_type
.as(not null))
1332 var e3
= v
.generate_expr
(n_value
)
1333 var e4
= v
.expr
(new ICall(assign_method
, [e2
, e3
]), assign_method
.signature
.return_type
.as(not null))
1334 var args2
= args
.to_a
1336 v
.stmt
(new ICall(prop
, args2
))
1341 redef class ANewExpr
1342 redef fun generate_icode
(v
)
1344 var args
= new Array[IRegister]
1345 generate_icode_for_arguments_in
(v
, args
, prop
.signature
.as(not null))
1346 return v
.expr
(new INew(stype
, prop
, args
), stype
)
1350 redef class AProxyExpr
1351 redef fun generate_icode
(v
)
1353 return v
.generate_expr
(n_expr
)
1357 redef class AOnceExpr
1358 redef fun generate_icode
(v
)
1360 var ionce
= new IOnce
1361 var reg
= v
.expr
(ionce
, stype
)
1365 var e
= v
.generate_expr
(n_expr
)
1366 v
.add_assignment
(reg
, e
)
1374 redef class AClosureDef
1375 var _iclosure_def
: nullable IClosureDef
1377 fun generate_iclosuredef
(v
: A2IContext): IClosureDef
1380 var args
= new Array[IRegister]
1381 var sig
= closure
.signature
1382 for i
in [0..sig
.arity
[ do
1383 args
.add
(v
.new_register
(sig
[i
]))
1385 var ret
: nullable IRegister = null
1386 var rtype
= sig
.return_type
1387 if rtype
!= null then
1388 ret
= v
.new_register
(rtype
)
1391 var iclos
= new IClosureDef(args
, ret
)
1392 iclos
.location
= location
1397 escapable
.continue_seq
= iclos
.body
1398 escapable
.continue_value
= iclos
.result
1401 for i
in [0..variables
.length
[ do
1402 var res
= v
.variable
(variables
[i
])
1403 v
.add_assignment
(res
, iclos
.params
[i
])
1406 v
.generate_stmt
(n_expr
)
1408 # Add a final break in case of break block witout value
1409 if closure
.is_break
and escapable
.break_value
== null then
1410 v
.stmt
(new IEscape(escapable
.break_seq
.as(not null)))
1414 _iclosure_def
= iclos
1419 redef class AClosureCallExpr
1420 redef fun generate_icode
(v
)
1423 var args
= new Array[IRegister]
1424 generate_icode_for_arguments_in
(v
, args
, variable
.closure
.signature
)
1427 var closdecl
= v
.closurevariables
[variable
]
1428 var icall
= new IClosCall(closdecl
, args
)
1431 # Fill break of ical
1432 if n_closure_defs
.length
== 1 then do
1434 icall
.break_seq
= iseq
1436 v
.generate_stmt
(n_closure_defs
.first
.n_expr
)
1440 # Prepare in case of default block
1441 var iif
: nullable IIf = null # The iif of default block
1442 var closdecl_default
= closdecl
.default
# The default (if any)
1443 if closdecl_default
!= null then
1444 iif
= new IIf(v
.expr
(new IHasClos(closdecl
), v
.visitor
.type_bool
))
1446 v
.seq
= iif
.then_seq
1450 var r2
: nullable IRegister = null # the result of the icall
1451 var rtype
= variable
.closure
.signature
.return_type
1452 if rtype
== null then
1455 r2
= v
.expr
(icall
, rtype
)
1458 # Process the case of default block
1459 var r
: nullable IRegister = null # the real result
1460 if closdecl_default
!= null then
1463 assert rtype
!= null
1464 r
= v
.new_register
(rtype
)
1465 v
.add_assignment
(r
, r2
)
1467 v
.seq
= iif
.else_seq
1468 var r3
= v
.inline_routine
(closdecl_default
, args
, null)
1471 v
.add_assignment
(r
, r3
)