compile: give NativeArray its own C structure
[nit.git] / src / syntax / icode_generation.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2009 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Things needed by typing.nit to generate intermediate code from AST
18 package icode_generation
19
20 import icode
21 import syntax_base
22 private import typing
23 private import primitive_info
24
25 # An AST2ICode context stores the currently built icode informations
26 class A2IContext
27 special ICodeBuilder
28 redef fun stmt(s: ICode)
29 do
30 if _current_node != null then
31 current_location = _current_node.location
32 else if visitor.current_node != null then
33 current_location = visitor.current_node.location
34 end
35 super
36 end
37
38 # Prepare a new array of length item
39 fun add_new_array(stype: MMType, length: Int): IRegister
40 do
41 var prop = visitor.get_method(stype, once "with_capacity".to_symbol)
42 var ni = expr(new INative("TAG_Int({length})", null), visitor.type_int)
43 return expr(new INew(stype, prop, [ni]), stype)
44 end
45
46 # Add an array add
47 fun add_call_array_add(recv, item: IRegister)
48 do
49 var stype = recv.stype
50 var prop = visitor.get_method(stype, once "add".to_symbol)
51 stmt(new ICall(prop, [recv, item]))
52 end
53
54 # Get the iregister associated with a variable
55 # Or assign one if none exists
56 fun variable(v: Variable): IRegister
57 do
58 if _variables.has_key(v) then
59 return _variables[v]
60 else
61 var reg = new_register(v.stype.as(not null))
62 _variables[v] = reg
63 return reg
64 end
65 end
66
67 # Current registered variable
68 var _variables: HashMap[Variable, IRegister] = new HashMap[Variable, IRegister]
69
70 # Current registered closurevariables
71 readable var _closurevariables: HashMap[ClosureVariable, IClosureDecl] = new HashMap[ClosureVariable, IClosureDecl]
72
73 # The current syntax visitor
74 readable var _visitor: AbsSyntaxVisitor
75
76 # Where a nit return must branch
77 readable writable var _return_seq: nullable ISeq
78
79 # Register where a functionnal nit return must store its value
80 readable writable var _return_value: nullable IRegister
81
82 # The method associated to the iroutine (if any)
83 readable var _method: nullable MMMethod
84
85 init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod)
86 do
87 super(visitor.module, r)
88 _visitor = visitor
89 _return_seq = r.body
90 _return_value = r.result
91 _method = m
92 end
93
94 # Insert implicit super init calls
95 fun invoke_super_init_calls_after(start_prop: nullable MMMethod)
96 do
97 var p = method
98 assert p isa MMSrcMethod
99 var n = p.node
100 assert n isa AConcreteInitPropdef
101
102 if n.super_init_calls.is_empty then return
103 var i = 0
104 var j = 0
105 if start_prop != null then
106 while n.super_init_calls[i] != start_prop do
107 i += 1
108 end
109 i += 1
110
111 while n.explicit_super_init_calls[j] != start_prop do
112 j += 1
113 end
114 j += 1
115 end
116 var stop_prop: nullable MMMethod = null
117 if j < n.explicit_super_init_calls.length then
118 stop_prop = n.explicit_super_init_calls[j]
119 end
120 var l = n.super_init_calls.length
121 while i < l do
122 var sp = n.super_init_calls[i]
123 if sp == stop_prop then break
124 var cargs = new Array[IRegister]
125 if sp.signature.arity == 0 then
126 cargs.add(iroutine.params.first)
127 else
128 for va in iroutine.params do
129 cargs.add(va)
130 end
131 end
132 stmt(new ICall(sp, cargs))
133 i += 1
134 end
135 end
136
137 # The current AExpr
138 var _current_node: nullable AExpr = null
139
140 # Generate icode in the current sequence from a statement
141 fun generate_stmt(n: nullable AExpr)
142 do
143 if n == null then return
144 var old = _current_node
145 _current_node = n
146 n.generate_icode(self)
147 _current_node = old
148 end
149
150 # Generate icode in the current sequence from an expression
151 fun generate_expr(n: AExpr): IRegister
152 do
153 var old = _current_node
154 _current_node = n
155 var reg = n.generate_icode(self).as(not null)
156 _current_node = old
157 return reg
158 end
159 end
160
161 redef class EscapableBlock
162 # Where a nit break must branch
163 readable writable var _break_seq: nullable ISeq
164
165 # Where a nit continue must branch
166 readable writable var _continue_seq: nullable ISeq
167
168 # Register where a functionnal nit break must store its value
169 readable writable var _break_value: nullable IRegister
170
171 # Register where a functionnal nit continue must store its value
172 readable writable var _continue_value: nullable IRegister
173 end
174
175 redef class MMSrcModule
176 # Generate icode for method bodies
177 fun generate_icode(tc: ToolContext)
178 do
179 var v = new A2IVisitor(tc, self)
180 for c in src_local_classes do
181 for p in c.src_local_properties do
182 if p isa MMSrcMethod then
183 p.generate_iroutine(v)
184 else if p isa MMSrcAttribute then
185 p.generate_iroutine(v)
186 end
187 end
188 end
189 end
190 end
191
192 redef class MMSrcAttribute
193 redef readable writable var _iroutine: nullable IRoutine
194
195 # Generate the initialization iroutine
196 fun generate_iroutine(visitor: A2IVisitor)
197 do
198 if node.n_expr != null then
199 var iroutine = signature.generate_empty_iroutine
200 iroutine.location = node.location
201 var v = new A2IContext(visitor, iroutine, null)
202 visitor.icode_ctx = v
203 visitor.enter_visit(node)
204 visitor.icode_ctx = null
205 _iroutine = iroutine
206 end
207 end
208 end
209
210 redef class MMSrcMethod
211 redef readable writable var _iroutine: nullable IRoutine
212
213 # Generate the body iroutine
214 fun generate_iroutine(visitor: A2IVisitor)
215 do
216 var iroutine = signature.generate_empty_iroutine
217 if node != null then
218 iroutine.location = node.location
219 end
220 var v = new A2IContext(visitor, iroutine, self)
221 visitor.icode_ctx = v
222 inner_generate_iroutine(v)
223 visitor.icode_ctx = null
224 _iroutine = iroutine
225 end
226
227 # Generate the body iroutine (specific part)
228 fun inner_generate_iroutine(v: A2IContext) is abstract
229 end
230
231 redef class MMReadImplementationMethod
232 redef fun inner_generate_iroutine(v)
233 do
234 var e = v.add_attr_read(node.prop, v.iroutine.params.first)
235 v.add_return_value(e)
236 end
237 end
238
239 redef class MMWriteImplementationMethod
240 redef fun inner_generate_iroutine(v)
241 do
242 var params = v.iroutine.params
243 v.stmt(new IAttrWrite(node.prop, params[0], params[1]))
244 end
245 end
246
247 redef class MMMethSrcMethod
248 redef fun inner_generate_iroutine(v)
249 do
250 v.visitor.enter_visit(node)
251 end
252 end
253
254 redef class MMImplicitInit
255 redef fun inner_generate_iroutine(v)
256 do
257 var params = v.iroutine.params
258 var f = params.length - unassigned_attributes.length
259 var recv = params.first
260 for sp in super_inits do
261 assert sp isa MMMethod
262 var args_recv = [recv]
263 if sp == super_init then
264 var args = new Array[IRegister].with_capacity(f)
265 args.add(recv)
266 for i in [1..f[ do
267 args.add(params[i])
268 end
269 v.stmt(new ICall(sp, args))
270 else
271 v.stmt(new ICall(sp, args_recv))
272 end
273 end
274 for i in [f..params.length[ do
275 var attribute = unassigned_attributes[i-f]
276 v.stmt(new IAttrWrite(attribute, recv, params[i]))
277 end
278 end
279 end
280
281 class A2IVisitor
282 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)
286 init(tc, m) do super
287 end
288
289
290 ###############################################################################
291
292 redef class ANode
293 fun accept_icode_generation(v: A2IVisitor) do accept_abs_syntax_visitor(v) end
294 end
295
296 redef class AAttrPropdef
297 redef fun accept_icode_generation(vv)
298 do
299 var v = vv.icode_ctx
300 v.stmt(new IMove(v.variable(self_var), v.iroutine.params.first))
301 super
302 var ne = n_expr
303 if ne != null then
304 v.stmt(new IMove(v.iroutine.result.as(not null), v.generate_expr(ne)))
305 end
306 end
307 end
308
309 redef class AMethPropdef
310 redef fun accept_icode_generation(vv)
311 do
312 super
313 fill_iroutine(vv.icode_ctx, method)
314 end
315
316 # Compile the method body common preambule (before specific body stuff if any)
317 fun fill_iroutine(v: A2IContext, method: MMSrcMethod) is abstract
318 end
319
320 redef class ASignature
321 fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: Sequence[IRegister], closdecls: nullable Sequence[IClosureDecl])
322 do
323 for ap in n_params do
324 var reg = v.variable(ap.variable)
325 var orig_type = orig_sig[ap.position]
326 var apst = ap.variable.stype.as(not null)
327 if not orig_type < apst then
328 v.add_type_cast(params[ap.position], apst)
329 end
330 v.stmt(new IMove(reg, params[ap.position]))
331 end
332 for i in [0..n_closure_decls.length[ do
333 var wd = n_closure_decls[i]
334 v.closurevariables[wd.variable] = closdecls[i]
335 end
336 end
337 end
338
339 redef class AClosureDecl
340 redef fun accept_icode_generation(vv)
341 do
342 var v = vv.icode_ctx
343 var iclos = variable.closure.signature.generate_empty_iclosuredef(v)
344 var old_seq = v.seq
345 v.seq = iclos.body
346 escapable.continue_seq = iclos.body
347 escapable.continue_value = iclos.result
348 n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null)
349
350 if n_expr != null then
351 v.generate_stmt(n_expr)
352 v.iroutine.closure_decls[position].default = iclos
353 end
354 v.seq = old_seq
355 end
356 end
357
358 redef class AConcreteMethPropdef
359 redef fun fill_iroutine(v, method)
360 do
361 var params = v.iroutine.params.to_a
362 var selfreg = v.variable(self_var)
363 v.stmt(new IMove(selfreg, params[0]))
364 params.shift
365
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)
370 end
371
372 if self isa AConcreteInitPropdef then
373 v.invoke_super_init_calls_after(null)
374 end
375
376 if n_block != null then
377 v.generate_stmt(n_block)
378 end
379 end
380 end
381
382 redef class ADeferredMethPropdef
383 redef fun fill_iroutine(v, method)
384 do
385 v.add_abort("Deferred method called")
386 end
387 end
388
389 redef class AExternMethPropdef
390 redef fun fill_iroutine(v, method)
391 do
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)
397 end
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("@@@"))
404 end
405 var s = "{ename}({args.join(", ")})"
406 var rtype = sig.return_type
407 if rtype != null then
408 s = rtype.boxtype(s)
409 v.add_return_value(v.expr(new INative(s, params), rtype))
410 else
411 v.stmt(new INative(s, params))
412 end
413 end
414 end
415
416 redef class AInternMethPropdef
417 redef fun fill_iroutine(v, method)
418 do
419 var p = v.iroutine.params.to_a
420 var c = method.local_class.name
421 var n = method.name
422 var s: nullable String = null
423 if c == once "Int".to_symbol then
424 if n == once "object_id".to_symbol then
425 s = "@@@"
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((@@@)!=(@@@))"
464 end
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(@@@))"
490 end
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((@@@)!=(@@@))"
528 end
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((@@@)!=(@@@))"
544 end
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
553 var t = p[0]
554 p[0] = p[1]
555 p[1] = t
556 s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
557 end
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
568 var t = p[0]
569 p[0] = p[1]
570 p[1] = p[4]
571 p[4] = p[2]
572 p[2] = t
573 s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
574 end
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
578 s = "(G_sys)"
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
582 p[0] = p[1]
583 s = "exit(UNTAG_Int(@@@));"
584 else if n == once "calloc_array".to_symbol then
585 p[0] = p[1]
586 s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
587 else if n == once "calloc_string".to_symbol then
588 p[0] = p[1]
589 s = "BOX_NativeString((char*)malloc((UNTAG_Int(@@@) * sizeof(char))))"
590 end
591 if s == null then
592 v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
593 s = "NIT_NULL"
594 end
595 var rtype = method.signature.return_type
596 if rtype != null then
597 v.add_return_value(v.expr(new INative(s, p), rtype))
598 else
599 v.stmt(new INative(s, p))
600 end
601 end
602 end
603
604 ###############################################################################
605
606 redef class AExpr
607 redef fun accept_icode_generation(v) do end
608
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
612 end
613
614 redef class AVardeclExpr
615 redef fun generate_icode(v)
616 do
617 var reg = v.variable(variable)
618 var ne = n_expr
619 if ne != null then
620 v.add_assignment(reg, v.generate_expr(ne))
621 end
622 return null
623 end
624 end
625
626 redef class ABlockExpr
627 redef fun generate_icode(v)
628 do
629 for ne in n_expr do v.generate_stmt(ne)
630 return null
631 end
632 end
633
634 redef class ADoExpr
635 redef fun generate_icode(v)
636 do
637 var seq_old = v.seq
638 var seq = new ISeq
639 v.stmt(seq)
640 escapable.break_seq = seq
641 v.seq = seq
642
643 v.generate_stmt(n_block)
644
645 v.seq = seq_old
646 return null
647 end
648 end
649
650 redef class AReturnExpr
651 redef fun generate_icode(v)
652 do
653 var ne = n_expr
654 if ne != null then
655 v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
656 end
657 v.stmt(new IEscape(v.return_seq.as(not null)))
658 return null
659 end
660 end
661
662 redef class ABreakExpr
663 redef fun generate_icode(v)
664 do
665 var ne = n_expr
666 if ne != null then
667 v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
668 end
669 v.stmt(new IEscape(escapable.break_seq.as(not null)))
670 return null
671 end
672 end
673
674 redef class AContinueExpr
675 redef fun generate_icode(v)
676 do
677 var ne = n_expr
678 if ne != null then
679 v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
680 end
681 v.stmt(new IEscape(escapable.continue_seq.as(not null)))
682 return null
683 end
684 end
685
686 redef class AAbortExpr
687 redef fun generate_icode(v)
688 do
689 v.add_abort("Aborted")
690 return null
691 end
692 end
693
694 redef class AIfExpr
695 redef fun generate_icode(v)
696 do
697 var iif = new IIf(v.generate_expr(n_expr))
698 v.stmt(iif)
699 var seq_old = v.seq
700
701 if n_then != null then
702 v.seq = iif.then_seq
703 v.generate_stmt(n_then)
704 end
705
706 if n_else != null then
707 v.seq = iif.else_seq
708 v.generate_stmt(n_else)
709 end
710
711 v.seq = seq_old
712 return null
713 end
714 end
715
716 redef class AWhileExpr
717 redef fun generate_icode(v)
718 do
719 var seq_old = v.seq
720 var iloop = new ILoop
721 v.stmt(iloop)
722 escapable.break_seq = iloop
723 v.seq = iloop
724
725 # Process condition
726 var iif = new IIf(v.generate_expr(n_expr))
727 v.stmt(iif)
728
729 # Process inside (condition is true)
730 if n_block != null then
731 v.seq = iif.then_seq
732 escapable.continue_seq = iif.then_seq
733 v.generate_stmt(n_block)
734 end
735
736 # Process escape (condition is false)
737 v.seq = iif.else_seq
738 v.stmt(new IEscape(iloop))
739
740 v.seq = seq_old
741 return null
742 end
743 end
744
745 redef class ALoopExpr
746 redef fun generate_icode(v)
747 do
748 var seq_old = v.seq
749 var iloop = new ILoop
750 v.stmt(iloop)
751 escapable.break_seq = iloop
752 v.seq = iloop
753
754 # Process inside
755 if n_block != null then
756 var seq = new ISeq
757 v.stmt(seq)
758 v.seq = seq
759 escapable.continue_seq = seq
760 v.generate_stmt(n_block)
761 end
762
763 v.seq = seq_old
764 return null
765 end
766 end
767
768 redef class AForExpr
769 redef fun generate_icode(v)
770 do
771 var expr_type = n_expr.stype
772
773 # Get iterator
774 var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol)
775
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)
778
779 # Enter loop
780 var seq_old = v.seq
781 var iloop = new ILoop
782 v.stmt(iloop)
783 escapable.break_seq = iloop
784 v.seq = iloop
785
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)
790
791 # Process insite the loop (condition is true)
792 v.stmt(iif)
793 v.seq = iif.then_seq
794 escapable.continue_seq = iif.then_seq
795
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)
802
803 # Body evaluation
804 v.generate_stmt(n_block)
805
806 # Exit contition (condition is false)
807 v.seq = iif.else_seq
808 v.stmt(new IEscape(iloop))
809
810 # Next step
811 var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol))
812 v.seq = iloop
813 v.stmt(new ICall(meth_next, [ireg_iter]))
814
815 v.seq = seq_old
816 return null
817 end
818 end
819
820 redef class AAssertExpr
821 redef fun generate_icode(v)
822 do
823 var e = v.generate_expr(n_expr)
824 var iif = new IIf(e)
825 v.stmt(iif)
826 var seq_old = v.seq
827 v.seq = iif.else_seq
828 var id = n_id
829 if id == null then
830 v.add_abort("Assert failed")
831 else
832 v.add_abort("Assert %s failed", id.to_s)
833 end
834 v.seq = seq_old
835 return null
836 end
837 end
838
839 redef class AVarExpr
840 redef fun generate_icode(v)
841 do
842 return v.variable(variable)
843 end
844 end
845
846 redef class AVarAssignExpr
847 redef fun generate_icode(v)
848 do
849 var e = v.generate_expr(n_value)
850 v.add_assignment(v.variable(variable), e)
851 return null
852 end
853 end
854
855 redef class AVarReassignExpr
856 redef fun generate_icode(v)
857 do
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)
862 return null
863 end
864 end
865
866 redef class ASelfExpr
867 redef fun generate_icode(v)
868 do
869 return v.variable(variable)
870 end
871 end
872
873 redef class AIfexprExpr
874 redef fun generate_icode(v)
875 do
876 # Process condition
877 var iif = new IIf(v.generate_expr(n_expr))
878 v.stmt(iif)
879 var seq_old = v.seq
880
881 # Prepare result
882 var reg = v.new_register(stype)
883
884 # Process 'then'
885 v.seq = iif.then_seq
886 v.add_assignment(reg, v.generate_expr(n_then))
887
888 # Process 'else'
889 v.seq = iif.else_seq
890 v.add_assignment(reg, v.generate_expr(n_else))
891
892 v.seq = seq_old
893 return reg
894 end
895 end
896
897 redef class AEeExpr
898 redef fun generate_icode(v)
899 do
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)
903 end
904 end
905
906 redef class AOrExpr
907 redef fun generate_icode(v)
908 do
909 # Prepare result
910 var reg = v.new_register(stype)
911
912 # Process left operand (in a if/then)
913 var iif = new IIf(v.generate_expr(n_expr))
914 v.stmt(iif)
915 var seq_old = v.seq
916 v.seq = iif.then_seq
917 v.add_assignment(reg, v.lit_true_reg)
918
919 # Process right operand (in the else)
920 v.seq = iif.else_seq
921 v.add_assignment(reg, v.generate_expr(n_expr2))
922
923 v.seq = seq_old
924 return reg
925 end
926 end
927
928 redef class AAndExpr
929 redef fun generate_icode(v)
930 do
931 # Prepare result
932 var reg = v.new_register(stype)
933
934 # Process left operand (in a if/else)
935 var iif = new IIf(v.generate_expr(n_expr))
936 v.stmt(iif)
937 var seq_old = v.seq
938 v.seq = iif.else_seq
939 v.add_assignment(reg, v.lit_false_reg)
940
941 # Process right operand (in the then)
942 v.seq = iif.then_seq
943 v.add_assignment(reg, v.generate_expr(n_expr2))
944
945 v.seq = seq_old
946 return reg
947 end
948 end
949
950 redef class ANotExpr
951 redef fun generate_icode(v)
952 do
953 var e = v.generate_expr(n_expr)
954 return v.expr(new INot(e), stype)
955 end
956 end
957
958 redef class AIsaExpr
959 redef fun generate_icode(v)
960 do
961 var e = v.generate_expr(n_expr)
962 return v.expr(new ITypeCheck(e, n_type.stype), stype)
963 end
964 end
965
966 redef class AAsCastExpr
967 redef fun generate_icode(v)
968 do
969 var e = v.generate_expr(n_expr)
970 v.add_type_cast(e, stype)
971 return e
972 end
973 end
974
975 redef class AAsNotnullExpr
976 redef fun generate_icode(v)
977 do
978 var e = v.generate_expr(n_expr)
979 v.add_type_cast(e, stype)
980 return e
981 end
982 end
983
984 redef class ATrueExpr
985 redef fun generate_icode(v)
986 do
987 return v.lit_true_reg
988 end
989 end
990
991 redef class AFalseExpr
992 redef fun generate_icode(v)
993 do
994 return v.lit_false_reg
995 end
996 end
997
998 redef class AIntExpr
999 redef fun generate_icode(v)
1000 do
1001 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
1002 end
1003 end
1004
1005 redef class AFloatExpr
1006 redef fun generate_icode(v)
1007 do
1008 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
1009 end
1010 end
1011
1012 redef class ACharExpr
1013 redef fun generate_icode(v)
1014 do
1015 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
1016 end
1017 end
1018
1019 redef class AStringFormExpr
1020 redef fun generate_icode(v)
1021 do
1022 compute_string_infos
1023 var old_seq = v.seq
1024 var ionce = new IOnce
1025 var reg = v.expr(ionce, stype)
1026 v.seq = ionce.body
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)
1032 v.seq = old_seq
1033 return reg
1034 end
1035
1036 # The raw string value
1037 protected fun string_text: String is abstract
1038
1039 # The string in a C native format
1040 protected var _cstring: nullable String
1041
1042 # The string length in bytes
1043 protected var _cstring_length: nullable Int
1044
1045 # Compute _cstring and _cstring_length using string_text
1046 protected fun compute_string_infos
1047 do
1048 var len = 0
1049 var str = string_text
1050 var res = new Buffer
1051 var i = 0
1052 while i < str.length do
1053 var c = str[i]
1054 if c == '\\' then
1055 i = i + 1
1056 var c2 = str[i]
1057 if c2 != '{' and c2 != '}' then
1058 res.add(c)
1059 end
1060 c = c2
1061 end
1062 len = len + 1
1063 res.add(c)
1064 i = i + 1
1065 end
1066 _cstring = res.to_s
1067 _cstring_length = len
1068 end
1069 end
1070
1071 redef class AStringExpr
1072 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1073 end
1074 redef class AStartStringExpr
1075 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1076 end
1077 redef class AMidStringExpr
1078 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1079 end
1080 redef class AEndStringExpr
1081 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1082 end
1083
1084 redef class ASuperstringExpr
1085 redef fun generate_icode(v)
1086 do
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)
1093 end
1094 v.add_call_array_add(array, e)
1095 end
1096 return v.expr(new ICall(prop_to_s, [array]), stype)
1097 end
1098 end
1099
1100 redef class ANullExpr
1101 redef fun generate_icode(v)
1102 do
1103 return v.lit_null_reg
1104 end
1105 end
1106
1107 redef class AArrayExpr
1108 redef fun generate_icode(v)
1109 do
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)
1114 end
1115 return recv
1116 end
1117 end
1118
1119 redef class ACrangeExpr
1120 redef fun generate_icode(v)
1121 do
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)
1126 end
1127 end
1128
1129 redef class AOrangeExpr
1130 redef fun generate_icode(v)
1131 do
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)
1136 end
1137 end
1138
1139 redef class ASuperExpr
1140 redef fun generate_icode(v)
1141 do
1142 var arity = v.iroutine.params.length - 1
1143 if init_in_superclass != null then
1144 arity = init_in_superclass.signature.arity
1145 end
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])
1151 end
1152 else
1153 for na in n_args do
1154 args.add(v.generate_expr(na))
1155 end
1156 end
1157 var p = init_in_superclass
1158 if p != null then
1159 var rtype = p.signature.return_type
1160 if rtype != null then
1161 return v.expr(new ICall(p, args), rtype)
1162 else
1163 v.stmt(new ICall(p, args))
1164 return null
1165 end
1166 else
1167 p = prop
1168 var rtype = p.signature.return_type
1169 if rtype == null then
1170 v.stmt(new ISuper(p, args))
1171 return null
1172 else
1173 return v.expr(new ISuper(p, args), rtype)
1174 end
1175 end
1176 end
1177 end
1178
1179 redef class AAttrExpr
1180 redef fun generate_icode(v)
1181 do
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)
1185 end
1186 end
1187
1188 redef class AAttrAssignExpr
1189 redef fun generate_icode(v)
1190 do
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))
1195 return null
1196 end
1197 end
1198 redef class AAttrReassignExpr
1199 redef fun generate_icode(v)
1200 do
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))
1207 return null
1208 end
1209 end
1210
1211 redef class AIssetAttrExpr
1212 redef fun generate_icode(v)
1213 do
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)
1217 end
1218 end
1219
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)
1223 do
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
1228 var arg_idx = 0
1229 for par_idx in [0..par_arity[ do
1230 var a: AExpr
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
1238 end
1239 args.add(arr)
1240 else
1241 a = raw_args[arg_idx]
1242 args.add(v.generate_expr(a))
1243 arg_idx = arg_idx + 1
1244 end
1245 end
1246 end
1247 end
1248
1249 redef class ASendExpr
1250 redef fun generate_icode(v)
1251 do
1252 var recv = v.generate_expr(n_expr)
1253 var args = new Array[IRegister]
1254 args.add(recv)
1255 var prop = prop
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
1259
1260 # Prepare closures
1261 var seq_old = v.seq
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)
1267 end
1268 var seq = new ISeq
1269 v.stmt(seq)
1270 v.seq = seq
1271 closcns = new Array[nullable IClosureDef]
1272 var cdarity = 0
1273 if closure_defs != null then cdarity = closure_defs.length
1274 var closure_defs = closure_defs
1275 for mmc in prop_signature.closures do
1276 var found = false
1277 var name = mmc.name
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
1282 found = true
1283 cd.escapable.break_seq = seq
1284 cd.escapable.break_value = r
1285 var cn = cd.generate_iclosuredef(v)
1286 closcns.add(cn)
1287 end
1288 end
1289 if not found then
1290 closcns.add(null)
1291 end
1292 end
1293 end
1294
1295 r2 = v.add_call(prop, args, closcns)
1296
1297 # Closure work
1298 if not prop_signature.closures.is_empty then
1299 if r != null and r2 != null then v.add_assignment(r, r2)
1300 v.seq = seq_old
1301 else
1302 r = r2
1303 end
1304
1305 if prop.global.is_init then
1306 v.invoke_super_init_calls_after(prop)
1307 end
1308 return r
1309 end
1310 end
1311
1312 redef class ASendReassignExpr
1313 redef fun generate_icode(v)
1314 do
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]
1318 args.add(recv)
1319 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1320
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
1325 args2.add(e4)
1326 v.stmt(new ICall(prop, args2))
1327 return null
1328 end
1329 end
1330
1331 redef class ANewExpr
1332 redef fun generate_icode(v)
1333 do
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)
1337 end
1338 end
1339
1340 redef class AProxyExpr
1341 redef fun generate_icode(v)
1342 do
1343 return v.generate_expr(n_expr)
1344 end
1345 end
1346
1347 redef class AOnceExpr
1348 redef fun generate_icode(v)
1349 do
1350 var ionce = new IOnce
1351 var reg = v.expr(ionce, stype)
1352 var old_seq = v.seq
1353 v.seq = ionce.body
1354
1355 var e = v.generate_expr(n_expr)
1356 v.add_assignment(reg, e)
1357
1358 v.seq = old_seq
1359 return reg
1360 end
1361 end
1362
1363
1364 redef class AClosureDef
1365 var _iclosure_def: nullable IClosureDef
1366
1367 fun generate_iclosuredef(v: A2IContext): IClosureDef
1368 do
1369 # Prepare signature
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]))
1374 end
1375 var ret: nullable IRegister = null
1376 var rtype = sig.return_type
1377 if rtype != null then
1378 ret = v.new_register(rtype)
1379 end
1380
1381 var iclos = new IClosureDef(args, ret)
1382 iclos.location = location
1383
1384 # Prepare env
1385 var seq_old = v.seq
1386 v.seq = iclos.body
1387 escapable.continue_seq = iclos.body
1388 escapable.continue_value = iclos.result
1389
1390 # Assign parameters
1391 for i in [0..variables.length[ do
1392 var res = v.variable(variables[i])
1393 v.add_assignment(res, iclos.params[i])
1394 end
1395
1396 v.generate_stmt(n_expr)
1397
1398 v.seq = seq_old
1399 _iclosure_def = iclos
1400 return iclos
1401 end
1402 end
1403
1404 redef class AClosureCallExpr
1405 redef fun generate_icode(v)
1406 do
1407 # Geneate arguments
1408 var args = new Array[IRegister]
1409 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1410
1411 # Prepare icall
1412 var closdecl = v.closurevariables[variable]
1413 var icall = new IClosCall(closdecl, args)
1414 var seq_old = v.seq
1415
1416 # Fill break of ical
1417 if n_closure_defs.length == 1 then do
1418 var iseq = new ISeq
1419 icall.break_seq = iseq
1420 v.seq = iseq
1421 v.generate_stmt(n_closure_defs.first.n_expr)
1422 v.seq = seq_old
1423 end
1424
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))
1430 v.stmt(iif)
1431 v.seq = iif.then_seq
1432 end
1433
1434 # Add the icall
1435 var r2: nullable IRegister = null # the result of the icall
1436 var rtype = variable.closure.signature.return_type
1437 if rtype == null then
1438 v.stmt(icall)
1439 else
1440 r2 = v.expr(icall, rtype)
1441 end
1442
1443 # Process the case of default block
1444 var r: nullable IRegister = null # the real result
1445 if closdecl_default != null then
1446 assert iif != null
1447 if r2 != null then
1448 assert rtype != null
1449 r = v.new_register(rtype)
1450 v.add_assignment(r, r2)
1451 end
1452 v.seq = iif.else_seq
1453 var r3 = v.inline_routine(closdecl_default, args, null)
1454 if r != null then
1455 assert r3 != null
1456 v.add_assignment(r, r3)
1457 end
1458 v.seq = seq_old
1459 else
1460 r = r2
1461 end
1462 return r
1463 end
1464 end