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
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
.module, 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 special 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 n_signature
.fill_iroutine_parameters
(v
, variable
.closure
.signature
, iclos
.params
, null)
350 if n_expr
!= null then
351 v
.generate_stmt
(n_expr
)
352 v
.iroutine
.closure_decls
[position
].default
= iclos
358 redef class AConcreteMethPropdef
359 redef fun fill_iroutine
(v
, method
)
361 var params
= v
.iroutine
.params
.to_a
362 var selfreg
= v
.variable
(self_var
)
363 v
.stmt
(new IMove(selfreg
, params
[0]))
366 var orig_meth
: MMLocalProperty = method
.global
.intro
367 var orig_sig
= orig_meth
.signature_for
(method
.signature
.recv
)
368 if n_signature
!= null then
369 n_signature
.fill_iroutine_parameters
(v
, orig_sig
, params
, v
.iroutine
.closure_decls
)
372 if self isa AConcreteInitPropdef then
373 v
.invoke_super_init_calls_after
(null)
376 if n_block
!= null then
377 v
.generate_stmt
(n_block
)
382 redef class ADeferredMethPropdef
383 redef fun fill_iroutine
(v
, method
)
385 v
.add_abort
("Deferred method called")
389 redef class AExternMethPropdef
390 redef fun fill_iroutine
(v
, method
)
392 var params
= v
.iroutine
.params
393 var ename
= "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
394 if n_extern
!= null then
395 ename
= n_extern
.text
396 ename
= ename
.substring
(1, ename
.length-2
)
398 var sig
= method
.signature
399 assert params
.length
== sig
.arity
+ 1
400 var args
= new Array[String]
401 args
.add
(sig
.recv
.unboxtype
("@@@"))
402 for i
in [0..sig
.arity
[ do
403 args
.add
(sig
[i
].unboxtype
("@@@"))
405 var s
= "{ename}({args.join(", ")})"
406 var rtype
= sig
.return_type
407 if rtype
!= null then
409 v
.add_return_value
(v
.expr
(new INative(s
, params
), rtype
))
411 v
.stmt
(new INative(s
, params
))
416 redef class AInternMethPropdef
417 redef fun fill_iroutine
(v
, method
)
419 var p
= v
.iroutine
.params
.to_a
420 var c
= method
.local_class
.name
422 var s
: nullable String = null
423 if c
== once
"Int".to_symbol
then
424 if n
== once
"object_id".to_symbol
then
426 else if n
== once
"unary -".to_symbol
then
427 s
= "TAG_Int(-UNTAG_Int(@@@))"
428 else if n
== once
"output".to_symbol
then
429 s
= "printf(\"%ld\\n\
", UNTAG_Int(@@@));"
430 else if n
== once
"ascii".to_symbol
then
431 s
= "TAG_Char(UNTAG_Int(@@@))"
432 else if n
== once
"succ".to_symbol
then
433 s
= "TAG_Int(UNTAG_Int(@@@)+1)"
434 else if n
== once
"prec".to_symbol
then
435 s
= "TAG_Int(UNTAG_Int(@@@)-1)"
436 else if n
== once
"to_f".to_symbol
then
437 s
= "BOX_Float((float)UNTAG_Int(@@@))"
438 else if n
== once
"+".to_symbol
then
439 s
= "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))"
440 else if n
== once
"-".to_symbol
then
441 s
= "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))"
442 else if n
== once
"*".to_symbol
then
443 s
= "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))"
444 else if n
== once
"/".to_symbol
then
445 s
= "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
446 else if n
== once
"%".to_symbol
then
447 s
= "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))"
448 else if n
== once
"<".to_symbol
then
449 s
= "TAG_Bool(UNTAG_Int(@@@)<UNTAG_Int(@@@))"
450 else if n
== once
">".to_symbol
then
451 s
= "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))"
452 else if n
== once
"<=".to_symbol
then
453 s
= "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
454 else if n
== once
">=".to_symbol
then
455 s
= "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
456 else if n
== once
"lshift".to_symbol
then
457 s
= "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
458 else if n
== once
"rshift".to_symbol
then
459 s
= "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
460 else if n
== once
"==".to_symbol
then
461 s
= "TAG_Bool((@@@)==(@@@))"
462 else if n
== once
"!=".to_symbol
then
463 s
= "TAG_Bool((@@@)!=(@@@))"
465 else if c
== once
"Float".to_symbol
then
466 if n
== once
"object_id".to_symbol
then
467 s
= "TAG_Int((bigint)UNBOX_Float(@@@))"
468 else if n
== once
"unary -".to_symbol
then
469 s
= "BOX_Float(-UNBOX_Float(@@@))"
470 else if n
== once
"output".to_symbol
then
471 s
= "printf(\"%f\\n\
", UNBOX_Float(@@@));"
472 else if n
== once
"to_i".to_symbol
then
473 s
= "TAG_Int((bigint)UNBOX_Float(@@@))"
474 else if n
== once
"+".to_symbol
then
475 s
= "BOX_Float(UNBOX_Float(@@@)+UNBOX_Float(@@@))"
476 else if n
== once
"-".to_symbol
then
477 s
= "BOX_Float(UNBOX_Float(@@@)-UNBOX_Float(@@@))"
478 else if n
== once
"*".to_symbol
then
479 s
= "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
480 else if n
== once
"/".to_symbol
then
481 s
= "BOX_Float(UNBOX_Float(@@@)/UNBOX_Float(@@@))"
482 else if n
== once
"<".to_symbol
then
483 s
= "TAG_Bool(UNBOX_Float(@@@)<UNBOX_Float(@@@))"
484 else if n
== once
">".to_symbol
then
485 s
= "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))"
486 else if n
== once
"<=".to_symbol
then
487 s
= "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
488 else if n
== once
">=".to_symbol
then
489 s
= "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
491 else if c
== once
"Char".to_symbol
then
492 if n
== once
"object_id".to_symbol
then
493 s
= "TAG_Int(UNTAG_Char(@@@))"
494 else if n
== once
"unary -".to_symbol
then
495 s
= "TAG_Char(-UNTAG_Char(@@@))"
496 else if n
== once
"output".to_symbol
then
497 s
= "printf(\"%c\
", (unsigned char)UNTAG_Char(@@@));"
498 else if n
== once
"ascii".to_symbol
then
499 s
= "TAG_Int((unsigned char)UNTAG_Char(@@@))"
500 else if n
== once
"succ".to_symbol
then
501 s
= "TAG_Char(UNTAG_Char(@@@)+1)"
502 else if n
== once
"prec".to_symbol
then
503 s
= "TAG_Char(UNTAG_Char(@@@)-1)"
504 else if n
== once
"to_i".to_symbol
then
505 s
= "TAG_Int(UNTAG_Char(@@@)-'0')"
506 else if n
== once
"+".to_symbol
then
507 s
= "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))"
508 else if n
== once
"-".to_symbol
then
509 s
= "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))"
510 else if n
== once
"*".to_symbol
then
511 s
= "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))"
512 else if n
== once
"/".to_symbol
then
513 s
= "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
514 else if n
== once
"%".to_symbol
then
515 s
= "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))"
516 else if n
== once
"<".to_symbol
then
517 s
= "TAG_Bool(UNTAG_Char(@@@)<UNTAG_Char(@@@))"
518 else if n
== once
">".to_symbol
then
519 s
= "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))"
520 else if n
== once
"<=".to_symbol
then
521 s
= "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
522 else if n
== once
">=".to_symbol
then
523 s
= "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
524 else if n
== once
"==".to_symbol
then
525 s
= "TAG_Bool((@@@)==(@@@))"
526 else if n
== once
"!=".to_symbol
then
527 s
= "TAG_Bool((@@@)!=(@@@))"
529 else if c
== once
"Bool".to_symbol
then
530 if n
== once
"object_id".to_symbol
then
531 s
= "TAG_Int(UNTAG_Bool(@@@))"
532 else if n
== once
"unary -".to_symbol
then
533 s
= "TAG_Bool(-UNTAG_Bool(@@@))"
534 else if n
== once
"output".to_symbol
then
535 s
= "(void)printf(UNTAG_Bool(@@@)?\"true\\n\
":\"false\\n\
");"
536 else if n
== once
"ascii".to_symbol
then
537 s
= "TAG_Bool(UNTAG_Bool(@@@))"
538 else if n
== once
"to_i".to_symbol
then
539 s
= "TAG_Int(UNTAG_Bool(@@@))"
540 else if n
== once
"==".to_symbol
then
541 s
= "TAG_Bool((@@@)==(@@@))"
542 else if n
== once
"!=".to_symbol
then
543 s
= "TAG_Bool((@@@)!=(@@@))"
545 else if c
== once
"NativeArray".to_symbol
then
546 if n
== once
"object_id".to_symbol
then
547 s
= "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
548 else if n
== once
"[]".to_symbol
then
549 s
= "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
550 else if n
== once
"[]=".to_symbol
then
551 s
= "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
552 else if n
== once
"copy_to".to_symbol
then
556 s
= "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
558 else if c
== once
"NativeString".to_symbol
then
559 if n
== once
"object_id".to_symbol
then
560 s
= "TAG_Int(UNBOX_NativeString(@@@))"
561 else if n
== once
"atoi".to_symbol
then
562 s
= "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
563 else if n
== once
"[]".to_symbol
then
564 s
= "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
565 else if n
== once
"[]=".to_symbol
then
566 s
= "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
567 else if n
== once
"copy_to".to_symbol
then
573 s
= "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
575 else if n
== once
"object_id".to_symbol
then
576 s
= "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
577 else if n
== once
"sys".to_symbol
then
579 else if n
== once
"is_same_type".to_symbol
then
580 s
= "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
581 else if n
== once
"exit".to_symbol
then
583 s
= "exit(UNTAG_Int(@@@));"
584 else if n
== once
"calloc_array".to_symbol
then
586 s
= "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
587 else if n
== once
"calloc_string".to_symbol
then
589 s
= "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
592 v
.visitor
.error
(self, "Fatal error: unknown intern method {method.full_name}.")
595 var rtype
= method
.signature
.return_type
596 if rtype
!= null then
597 v
.add_return_value
(v
.expr
(new INative(s
, p
), rtype
))
599 v
.stmt
(new INative(s
, p
))
604 ###############################################################################
607 redef fun accept_icode_generation
(v
) do end
609 # Generate icode sequence in the current A2IContext
610 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
611 protected fun generate_icode
(v
: A2IContext): nullable IRegister is abstract
614 redef class AVardeclExpr
615 redef fun generate_icode
(v
)
617 var reg
= v
.variable
(variable
)
620 v
.add_assignment
(reg
, v
.generate_expr
(ne
))
626 redef class ABlockExpr
627 redef fun generate_icode
(v
)
629 for ne
in n_expr
do v
.generate_stmt
(ne
)
635 redef fun generate_icode
(v
)
640 escapable
.break_seq
= seq
643 v
.generate_stmt
(n_block
)
650 redef class AReturnExpr
651 redef fun generate_icode
(v
)
655 v
.add_assignment
(v
.return_value
.as(not null), v
.generate_expr
(ne
))
657 v
.stmt
(new IEscape(v
.return_seq
.as(not null)))
662 redef class ABreakExpr
663 redef fun generate_icode
(v
)
667 v
.add_assignment
(escapable
.break_value
.as(not null), v
.generate_expr
(ne
))
669 v
.stmt
(new IEscape(escapable
.break_seq
.as(not null)))
674 redef class AContinueExpr
675 redef fun generate_icode
(v
)
679 v
.add_assignment
(escapable
.continue_value
.as(not null), v
.generate_expr
(ne
))
681 v
.stmt
(new IEscape(escapable
.continue_seq
.as(not null)))
686 redef class AAbortExpr
687 redef fun generate_icode
(v
)
689 v
.add_abort
("Aborted")
695 redef fun generate_icode
(v
)
697 var iif
= new IIf(v
.generate_expr
(n_expr
))
701 if n_then
!= null then
703 v
.generate_stmt
(n_then
)
706 if n_else
!= null then
708 v
.generate_stmt
(n_else
)
716 redef class AWhileExpr
717 redef fun generate_icode
(v
)
720 var iloop
= new ILoop
722 escapable
.break_seq
= iloop
726 var iif
= new IIf(v
.generate_expr
(n_expr
))
729 # Process inside (condition is true)
730 if n_block
!= null then
732 escapable
.continue_seq
= iif
.then_seq
733 v
.generate_stmt
(n_block
)
736 # Process escape (condition is false)
738 v
.stmt
(new IEscape(iloop
))
745 redef class ALoopExpr
746 redef fun generate_icode
(v
)
749 var iloop
= new ILoop
751 escapable
.break_seq
= iloop
755 if n_block
!= null then
759 escapable
.continue_seq
= seq
760 v
.generate_stmt
(n_block
)
769 redef fun generate_icode
(v
)
771 var expr_type
= n_expr
.stype
774 var meth_iterator
= v
.visitor
.get_method
(expr_type
, once
"iterator".to_symbol
)
776 var iter_type
= meth_iterator
.signature_for
(expr_type
).return_type
.as(not null)
777 var ireg_iter
= v
.expr
(new ICall(meth_iterator
, [v
.generate_expr
(n_expr
)]), iter_type
)
781 var iloop
= new ILoop
783 escapable
.break_seq
= iloop
786 # Condition evaluation
787 var meth_is_ok
= v
.visitor
.get_method
(iter_type
, once
("is_ok".to_symbol
))
788 var ireg_isok
= v
.expr
(new ICall(meth_is_ok
, [ireg_iter
]), v
.visitor
.type_bool
)
789 var iif
= new IIf(ireg_isok
)
791 # Process insite the loop (condition is true)
794 escapable
.continue_seq
= iif
.then_seq
796 # Automatic variable assignment
797 var meth_item
= v
.visitor
.get_method
(iter_type
, once
("item".to_symbol
))
798 var va_stype
= variable
.stype
.as(not null)
799 var ireg_item
= v
.expr
(new ICall(meth_item
, [ireg_iter
]), va_stype
)
800 var ireg_va
= v
.variable
(variable
)
801 v
.add_assignment
(ireg_va
, ireg_item
)
804 v
.generate_stmt
(n_block
)
806 # Exit contition (condition is false)
808 v
.stmt
(new IEscape(iloop
))
811 var meth_next
= v
.visitor
.get_method
(iter_type
, once
("next".to_symbol
))
813 v
.stmt
(new ICall(meth_next
, [ireg_iter
]))
820 redef class AAssertExpr
821 redef fun generate_icode
(v
)
823 var e
= v
.generate_expr
(n_expr
)
830 v
.add_abort
("Assert failed")
832 v
.add_abort
("Assert %s failed", id
.to_s
)
840 redef fun generate_icode
(v
)
842 return v
.variable
(variable
)
846 redef class AVarAssignExpr
847 redef fun generate_icode
(v
)
849 var e
= v
.generate_expr
(n_value
)
850 v
.add_assignment
(v
.variable
(variable
), e
)
855 redef class AVarReassignExpr
856 redef fun generate_icode
(v
)
858 var e1
= v
.variable
(variable
)
859 var e2
= v
.generate_expr
(n_value
)
860 var e3
= v
.expr
(new ICall(assign_method
, [e1
, e2
]), assign_method
.signature
.return_type
.as(not null))
861 v
.add_assignment
(e1
, e3
)
866 redef class ASelfExpr
867 redef fun generate_icode
(v
)
869 return v
.variable
(variable
)
873 redef class AIfexprExpr
874 redef fun generate_icode
(v
)
877 var iif
= new IIf(v
.generate_expr
(n_expr
))
882 var reg
= v
.new_register
(stype
)
886 v
.add_assignment
(reg
, v
.generate_expr
(n_then
))
890 v
.add_assignment
(reg
, v
.generate_expr
(n_else
))
898 redef fun generate_icode
(v
)
900 var e
= v
.generate_expr
(n_expr
)
901 var e2
= v
.generate_expr
(n_expr2
)
902 return v
.expr
(new IIs(e
, e2
), stype
)
907 redef fun generate_icode
(v
)
910 var reg
= v
.new_register
(stype
)
912 # Process left operand (in a if/then)
913 var iif
= new IIf(v
.generate_expr
(n_expr
))
917 v
.add_assignment
(reg
, v
.lit_true_reg
)
919 # Process right operand (in the else)
921 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
929 redef fun generate_icode
(v
)
932 var reg
= v
.new_register
(stype
)
934 # Process left operand (in a if/else)
935 var iif
= new IIf(v
.generate_expr
(n_expr
))
939 v
.add_assignment
(reg
, v
.lit_false_reg
)
941 # Process right operand (in the then)
943 v
.add_assignment
(reg
, v
.generate_expr
(n_expr2
))
951 redef fun generate_icode
(v
)
953 var e
= v
.generate_expr
(n_expr
)
954 return v
.expr
(new INot(e
), stype
)
959 redef fun generate_icode
(v
)
961 var e
= v
.generate_expr
(n_expr
)
962 return v
.expr
(new ITypeCheck(e
, n_type
.stype
), stype
)
966 redef class AAsCastExpr
967 redef fun generate_icode
(v
)
969 var e
= v
.generate_expr
(n_expr
)
970 v
.add_type_cast
(e
, stype
)
975 redef class AAsNotnullExpr
976 redef fun generate_icode
(v
)
978 var e
= v
.generate_expr
(n_expr
)
979 v
.add_type_cast
(e
, stype
)
984 redef class ATrueExpr
985 redef fun generate_icode
(v
)
987 return v
.lit_true_reg
991 redef class AFalseExpr
992 redef fun generate_icode
(v
)
994 return v
.lit_false_reg
999 redef fun generate_icode
(v
)
1001 return v
.expr
(new INative("TAG_Int({n_number.text})", null), stype
)
1005 redef class AFloatExpr
1006 redef fun generate_icode
(v
)
1008 return v
.expr
(new INative("BOX_Float({n_float.text})", null), stype
)
1012 redef class ACharExpr
1013 redef fun generate_icode
(v
)
1015 return v
.expr
(new INative("TAG_Char({n_char.text})", null), stype
)
1019 redef class AStringFormExpr
1020 redef fun generate_icode
(v
)
1022 compute_string_infos
1024 var ionce
= new IOnce
1025 var reg
= v
.expr
(ionce
, stype
)
1027 var ns
= v
.expr
(new INative("BOX_NativeString(\"{_cstring}\
")", null), v
.visitor
.type_nativestring
)
1028 var ni
= v
.expr
(new INative("TAG_Int({_cstring_length})", null), v
.visitor
.type_int
)
1029 var prop
= v
.visitor
.get_method
(stype
, once
"with_native".to_symbol
)
1030 var e
= v
.expr
(new INew(stype
, prop
, [ns
, ni
]), stype
)
1031 v
.add_assignment
(reg
, e
)
1036 # The raw string value
1037 protected fun string_text
: String is abstract
1039 # The string in a C native format
1040 protected var _cstring
: nullable String
1042 # The string length in bytes
1043 protected var _cstring_length
: nullable Int
1045 # Compute _cstring and _cstring_length using string_text
1046 protected fun compute_string_infos
1049 var str
= string_text
1050 var res
= new Buffer
1052 while i
< str
.length
do
1057 if c2
!= '{' and c2 != '}' then
1067 _cstring_length
= len
1071 redef class AStringExpr
1072 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1074 redef class AStartStringExpr
1075 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1077 redef class AMidStringExpr
1078 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1080 redef class AEndStringExpr
1081 redef fun string_text
do return n_string
.text
.substring
(1, n_string
.text
.length
- 2)
1084 redef class ASuperstringExpr
1085 redef fun generate_icode
(v
)
1087 var array
= v
.add_new_array
(atype
, n_exprs
.length
)
1088 var prop_to_s
= v
.visitor
.get_method
(v
.visitor
.type_object
, once
"to_s".to_symbol
)
1089 for ne
in n_exprs
do
1090 var e
= v
.generate_expr
(ne
)
1091 if ne
.stype
!= stype
then
1092 e
= v
.expr
(new ICall(prop_to_s
, [e
]), stype
)
1094 v
.add_call_array_add
(array
, e
)
1096 return v
.expr
(new ICall(prop_to_s
, [array
]), stype
)
1100 redef class ANullExpr
1101 redef fun generate_icode
(v
)
1103 return v
.lit_null_reg
1107 redef class AArrayExpr
1108 redef fun generate_icode
(v
)
1110 var recv
= v
.add_new_array
(stype
, n_exprs
.length
)
1111 for ne
in n_exprs
do
1112 var e
= v
.generate_expr
(ne
)
1113 v
.add_call_array_add
(recv
, e
)
1119 redef class ACrangeExpr
1120 redef fun generate_icode
(v
)
1122 var e
= v
.generate_expr
(n_expr
)
1123 var e2
= v
.generate_expr
(n_expr2
)
1124 var prop
= v
.visitor
.get_method
(stype
, once
"init".to_symbol
)
1125 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
1129 redef class AOrangeExpr
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
"without_last".to_symbol
)
1135 return v
.expr
(new INew(stype
, prop
, [e
, e2
]), stype
)
1139 redef class ASuperExpr
1140 redef fun generate_icode
(v
)
1142 var arity
= v
.iroutine
.params
.length
- 1
1143 if init_in_superclass
!= null then
1144 arity
= init_in_superclass
.signature
.arity
1146 var args
= new Array[IRegister].with_capacity
(arity
+ 1)
1147 args
.add
(v
.iroutine
.params
[0])
1148 if n_args
.length
!= arity
then
1149 for i
in [0..arity
[ do
1150 args
.add
(v
.iroutine
.params
[i
+ 1])
1154 args
.add
(v
.generate_expr
(na
))
1157 var p
= init_in_superclass
1159 var rtype
= p
.signature
.return_type
1160 if rtype
!= null then
1161 return v
.expr
(new ICall(p
, args
), rtype
)
1163 v
.stmt
(new ICall(p
, args
))
1168 var rtype
= p
.signature
.return_type
1169 if rtype
== null then
1170 v
.stmt
(new ISuper(p
, args
))
1173 return v
.expr
(new ISuper(p
, args
), rtype
)
1179 redef class AAttrExpr
1180 redef fun generate_icode
(v
)
1182 var e
= v
.generate_expr
(n_expr
)
1183 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1184 return v
.add_attr_read
(prop
, e
)
1188 redef class AAttrAssignExpr
1189 redef fun generate_icode
(v
)
1191 var e
= v
.generate_expr
(n_expr
)
1192 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1193 var e2
= v
.generate_expr
(n_value
)
1194 v
.stmt
(new IAttrWrite(prop
, e
, e2
))
1198 redef class AAttrReassignExpr
1199 redef fun generate_icode
(v
)
1201 var e1
= v
.generate_expr
(n_expr
)
1202 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e1
)
1203 var e2
= v
.expr
(new IAttrRead(prop
, e1
), attr_type
)
1204 var e3
= v
.generate_expr
(n_value
)
1205 var e4
= v
.expr
(new ICall(assign_method
, [e2
, e3
]), attr_type
)
1206 v
.stmt
(new IAttrWrite(prop
, e1
, e4
))
1211 redef class AIssetAttrExpr
1212 redef fun generate_icode
(v
)
1214 var e
= v
.generate_expr
(n_expr
)
1215 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(e
)
1216 return v
.expr
(new IAttrIsset(prop
, e
), stype
)
1220 redef class AAbsAbsSendExpr
1221 # Compile each argument and add them to the array
1222 fun generate_icode_for_arguments_in
(v
: A2IContext, args
: Array[IRegister], signature
: MMSignature)
1224 var par_arity
= signature
.arity
1225 var par_vararg
= signature
.vararg_rank
1226 var raw_args
= raw_arguments
1227 var raw_arity
= raw_args
.length
1229 for par_idx
in [0..par_arity
[ do
1231 var par_type
= signature
[par_idx
]
1232 if par_idx
== par_vararg
then
1233 var arr
= v
.add_new_array
(v
.visitor
.type_array
(par_type
), raw_arity-par_arity
)
1234 for i
in [0..(raw_arity-par_arity
)] do
1235 a
= raw_args
[arg_idx
]
1236 v
.add_call_array_add
(arr
, v
.generate_expr
(a
))
1237 arg_idx
= arg_idx
+ 1
1241 a
= raw_args
[arg_idx
]
1242 args
.add
(v
.generate_expr
(a
))
1243 arg_idx
= arg_idx
+ 1
1249 redef class ASendExpr
1250 redef fun generate_icode
(v
)
1252 var recv
= v
.generate_expr
(n_expr
)
1253 var args
= new Array[IRegister]
1256 generate_icode_for_arguments_in
(v
, args
, prop
.signature
.as(not null))
1257 var r
: nullable IRegister = null # The full result of the send (raw call + breaks)
1258 var r2
: nullable IRegister # The raw result of the call
1262 var closcns
: nullable Array[nullable IClosureDef] = null
1263 if not prop_signature
.closures
.is_empty
then
1264 var rtype
= prop_signature
.return_type
1265 if rtype
!= null then
1266 r
= v
.new_register
(rtype
)
1271 closcns
= new Array[nullable IClosureDef]
1273 if closure_defs
!= null then cdarity
= closure_defs
.length
1274 var closure_defs
= closure_defs
1275 for mmc
in prop_signature
.closures
do
1278 if closure_defs
!= null then
1279 for cd
in closure_defs
do
1280 if cd
.n_id
.to_symbol
!= name
then continue
1281 assert found
== false
1283 cd
.escapable
.break_seq
= seq
1284 cd
.escapable
.break_value
= r
1285 var cn
= cd
.generate_iclosuredef
(v
)
1295 r2
= v
.add_call
(prop
, args
, closcns
)
1298 if not prop_signature
.closures
.is_empty
then
1299 if r
!= null and r2
!= null then v
.add_assignment
(r
, r2
)
1305 if prop
.global
.is_init
then
1306 v
.invoke_super_init_calls_after
(prop
)
1312 redef class ASendReassignExpr
1313 redef fun generate_icode
(v
)
1315 var recv
= v
.generate_expr
(n_expr
)
1316 if n_expr
.stype
.is_nullable
then v
.add_null_reciever_check
(recv
)
1317 var args
= new Array[IRegister]
1319 generate_icode_for_arguments_in
(v
, args
, read_prop
.signature
.as(not null))
1321 var e2
= v
.expr
(new ICall(read_prop
, args
), read_prop
.signature
.return_type
.as(not null))
1322 var e3
= v
.generate_expr
(n_value
)
1323 var e4
= v
.expr
(new ICall(assign_method
, [e2
, e3
]), assign_method
.signature
.return_type
.as(not null))
1324 var args2
= args
.to_a
1326 v
.stmt
(new ICall(prop
, args2
))
1331 redef class ANewExpr
1332 redef fun generate_icode
(v
)
1334 var args
= new Array[IRegister]
1335 generate_icode_for_arguments_in
(v
, args
, prop
.signature
.as(not null))
1336 return v
.expr
(new INew(stype
, prop
, args
), stype
)
1340 redef class AProxyExpr
1341 redef fun generate_icode
(v
)
1343 return v
.generate_expr
(n_expr
)
1347 redef class AOnceExpr
1348 redef fun generate_icode
(v
)
1350 var ionce
= new IOnce
1351 var reg
= v
.expr
(ionce
, stype
)
1355 var e
= v
.generate_expr
(n_expr
)
1356 v
.add_assignment
(reg
, e
)
1364 redef class AClosureDef
1365 var _iclosure_def
: nullable IClosureDef
1367 fun generate_iclosuredef
(v
: A2IContext): IClosureDef
1370 var args
= new Array[IRegister]
1371 var sig
= closure
.signature
1372 for i
in [0..sig
.arity
[ do
1373 args
.add
(v
.new_register
(sig
[i
]))
1375 var ret
: nullable IRegister = null
1376 var rtype
= sig
.return_type
1377 if rtype
!= null then
1378 ret
= v
.new_register
(rtype
)
1381 var iclos
= new IClosureDef(args
, ret
)
1382 iclos
.location
= location
1387 escapable
.continue_seq
= iclos
.body
1388 escapable
.continue_value
= iclos
.result
1391 for i
in [0..variables
.length
[ do
1392 var res
= v
.variable
(variables
[i
])
1393 v
.add_assignment
(res
, iclos
.params
[i
])
1396 v
.generate_stmt
(n_expr
)
1399 _iclosure_def
= iclos
1404 redef class AClosureCallExpr
1405 redef fun generate_icode
(v
)
1408 var args
= new Array[IRegister]
1409 generate_icode_for_arguments_in
(v
, args
, variable
.closure
.signature
)
1412 var closdecl
= v
.closurevariables
[variable
]
1413 var icall
= new IClosCall(closdecl
, args
)
1416 # Fill break of ical
1417 if n_closure_defs
.length
== 1 then do
1419 icall
.break_seq
= iseq
1421 v
.generate_stmt
(n_closure_defs
.first
.n_expr
)
1425 # Prepare in case of default block
1426 var iif
: nullable IIf = null # The iif of default block
1427 var closdecl_default
= closdecl
.default
# The default (if any)
1428 if closdecl_default
!= null then
1429 iif
= new IIf(v
.expr
(new IHasClos(closdecl
), v
.visitor
.type_bool
))
1431 v
.seq
= iif
.then_seq
1435 var r2
: nullable IRegister = null # the result of the icall
1436 var rtype
= variable
.closure
.signature
.return_type
1437 if rtype
== null then
1440 r2
= v
.expr
(icall
, rtype
)
1443 # Process the case of default block
1444 var r
: nullable IRegister = null # the real result
1445 if closdecl_default
!= null then
1448 assert rtype
!= null
1449 r
= v
.new_register
(rtype
)
1450 v
.add_assignment
(r
, r2
)
1452 v
.seq
= iif
.else_seq
1453 var r3
= v
.inline_routine
(closdecl_default
, args
, null)
1456 v
.add_assignment
(r
, r3
)