08466d959e1971f1705fd50c868a5e863d1f8abe
[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 t = v.stype
62 if t == null then t = visitor.type_object.as_nullable
63 var reg = new_register(t)
64 _variables[v] = reg
65 return reg
66 end
67 end
68
69 # Current registered variable
70 var _variables: HashMap[Variable, IRegister] = new HashMap[Variable, IRegister]
71
72 # Current registered closurevariables
73 readable var _closurevariables: HashMap[ClosureVariable, IClosureDecl] = new HashMap[ClosureVariable, IClosureDecl]
74
75 # The current syntax visitor
76 readable var _visitor: AbsSyntaxVisitor
77
78 # Where a nit return must branch
79 readable writable var _return_seq: nullable ISeq
80
81 # Register where a functionnal nit return must store its value
82 readable writable var _return_value: nullable IRegister
83
84 # The method associated to the iroutine (if any)
85 readable var _method: nullable MMMethod
86
87 init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod)
88 do
89 super(visitor.module, r)
90 _visitor = visitor
91 _return_seq = r.body
92 _return_value = r.result
93 _method = m
94 end
95
96 # Insert implicit super init calls
97 fun invoke_super_init_calls_after(start_prop: nullable MMMethod)
98 do
99 var p = method
100 assert p isa MMSrcMethod
101 var n = p.node
102 assert n isa AConcreteInitPropdef
103
104 if n.super_init_calls.is_empty then return
105 var i = 0
106 var j = 0
107 if start_prop != null then
108 while n.super_init_calls[i] != start_prop do
109 i += 1
110 end
111 i += 1
112
113 while n.explicit_super_init_calls[j] != start_prop do
114 j += 1
115 end
116 j += 1
117 end
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]
121 end
122 var l = n.super_init_calls.length
123 while i < l do
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)
129 else
130 for va in iroutine.params do
131 cargs.add(va)
132 end
133 end
134 stmt(new ICall(sp, cargs))
135 i += 1
136 end
137 end
138
139 # The current AExpr
140 var _current_node: nullable AExpr = null
141
142 # Generate icode in the current sequence from a statement
143 fun generate_stmt(n: nullable AExpr)
144 do
145 if n == null then return
146 var old = _current_node
147 _current_node = n
148 n.generate_icode(self)
149 _current_node = old
150 end
151
152 # Generate icode in the current sequence from an expression
153 fun generate_expr(n: AExpr): IRegister
154 do
155 var old = _current_node
156 _current_node = n
157 var reg = n.generate_icode(self).as(not null)
158 _current_node = old
159 return reg
160 end
161 end
162
163 redef class EscapableBlock
164 # Where a nit break must branch
165 readable writable var _break_seq: nullable ISeq
166
167 # Where a nit continue must branch
168 readable writable var _continue_seq: nullable ISeq
169
170 # Register where a functionnal nit break must store its value
171 readable writable var _break_value: nullable IRegister
172
173 # Register where a functionnal nit continue must store its value
174 readable writable var _continue_value: nullable IRegister
175 end
176
177 redef class MMSrcModule
178 # Generate icode for method bodies
179 fun generate_icode(tc: ToolContext)
180 do
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)
188 end
189 end
190 end
191 end
192 end
193
194 redef class MMSrcAttribute
195 redef readable writable var _iroutine: nullable IRoutine
196
197 # Generate the initialization iroutine
198 fun generate_iroutine(visitor: A2IVisitor)
199 do
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
207 _iroutine = iroutine
208 end
209 end
210 end
211
212 redef class MMSrcMethod
213 redef readable writable var _iroutine: nullable IRoutine
214
215 # Generate the body iroutine
216 fun generate_iroutine(visitor: A2IVisitor)
217 do
218 var iroutine = signature.generate_empty_iroutine
219 if node != null then
220 iroutine.location = node.location
221 end
222 var v = new A2IContext(visitor, iroutine, self)
223 visitor.icode_ctx = v
224 inner_generate_iroutine(v)
225 visitor.icode_ctx = null
226 _iroutine = iroutine
227 end
228
229 # Generate the body iroutine (specific part)
230 fun inner_generate_iroutine(v: A2IContext) is abstract
231 end
232
233 redef class MMReadImplementationMethod
234 redef fun inner_generate_iroutine(v)
235 do
236 var e = v.add_attr_read(node.prop, v.iroutine.params.first)
237 v.add_return_value(e)
238 end
239 end
240
241 redef class MMWriteImplementationMethod
242 redef fun inner_generate_iroutine(v)
243 do
244 var params = v.iroutine.params
245 v.stmt(new IAttrWrite(node.prop, params[0], params[1]))
246 end
247 end
248
249 redef class MMMethSrcMethod
250 redef fun inner_generate_iroutine(v)
251 do
252 v.visitor.enter_visit(node)
253 end
254 end
255
256 redef class MMImplicitInit
257 redef fun inner_generate_iroutine(v)
258 do
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)
267 args.add(recv)
268 for i in [1..f[ do
269 args.add(params[i])
270 end
271 v.stmt(new ICall(sp, args))
272 else
273 v.stmt(new ICall(sp, args_recv))
274 end
275 end
276 for i in [f..params.length[ do
277 var attribute = unassigned_attributes[i-f]
278 v.stmt(new IAttrWrite(attribute, recv, params[i]))
279 end
280 end
281 end
282
283 class A2IVisitor
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)
288 init(tc, m) do super
289 end
290
291
292 ###############################################################################
293
294 redef class ANode
295 fun accept_icode_generation(v: A2IVisitor) do accept_abs_syntax_visitor(v) end
296 end
297
298 redef class AAttrPropdef
299 redef fun accept_icode_generation(vv)
300 do
301 var v = vv.icode_ctx
302 v.stmt(new IMove(v.variable(self_var), v.iroutine.params.first))
303 super
304 var ne = n_expr
305 if ne != null then
306 v.stmt(new IMove(v.iroutine.result.as(not null), v.generate_expr(ne)))
307 end
308 end
309 end
310
311 redef class AMethPropdef
312 redef fun accept_icode_generation(vv)
313 do
314 super
315 fill_iroutine(vv.icode_ctx, method)
316 end
317
318 # Compile the method body common preambule (before specific body stuff if any)
319 fun fill_iroutine(v: A2IContext, method: MMSrcMethod) is abstract
320 end
321
322 redef class ASignature
323 fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: Sequence[IRegister], closdecls: nullable Sequence[IClosureDecl])
324 do
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)
331 end
332 v.stmt(new IMove(reg, params[ap.position]))
333 end
334 for i in [0..n_closure_decls.length[ do
335 var wd = n_closure_decls[i]
336 v.closurevariables[wd.variable] = closdecls[i]
337 end
338 end
339 end
340
341 redef class AClosureDecl
342 redef fun accept_icode_generation(vv)
343 do
344 var v = vv.icode_ctx
345 var iclos = variable.closure.signature.generate_empty_iclosuredef(v)
346 var old_seq = v.seq
347 v.seq = iclos.body
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)
353
354 if n_expr != null then
355 v.generate_stmt(n_expr)
356 v.iroutine.closure_decls[position].default = iclos
357 end
358 v.seq = old_seq
359 end
360 end
361
362 redef class AConcreteMethPropdef
363 redef fun fill_iroutine(v, method)
364 do
365 var params = v.iroutine.params.to_a
366 var selfreg = v.variable(self_var)
367 v.stmt(new IMove(selfreg, params[0]))
368 params.shift
369
370 var orig_meth: MMLocalProperty = method.global.intro
371 var orig_sig = orig_meth.signature_for(method.signature.recv)
372 if n_signature != null then
373 n_signature.fill_iroutine_parameters(v, orig_sig, params, v.iroutine.closure_decls)
374 end
375
376 if self isa AConcreteInitPropdef then
377 v.invoke_super_init_calls_after(null)
378 end
379
380 if n_block != null then
381 v.generate_stmt(n_block)
382 end
383 end
384 end
385
386 redef class ADeferredMethPropdef
387 redef fun fill_iroutine(v, method)
388 do
389 v.add_abort("Deferred method called")
390 end
391 end
392
393 redef class AExternMethPropdef
394 redef fun fill_iroutine(v, method)
395 do
396 var params = v.iroutine.params
397 var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
398 if n_extern != null then
399 ename = n_extern.text
400 ename = ename.substring(1, ename.length-2)
401 end
402 var sig = method.signature
403 assert params.length == sig.arity + 1
404 var args = new Array[String]
405 args.add(sig.recv.unboxtype("@@@"))
406 for i in [0..sig.arity[ do
407 args.add(sig[i].unboxtype("@@@"))
408 end
409 var s = "{ename}({args.join(", ")})"
410 var rtype = sig.return_type
411 if rtype != null then
412 s = rtype.boxtype(s)
413 v.add_return_value(v.expr(new INative(s, params), rtype))
414 else
415 v.stmt(new INative(s, params))
416 end
417 end
418 end
419
420 redef class AInternMethPropdef
421 redef fun fill_iroutine(v, method)
422 do
423 var p = v.iroutine.params.to_a
424 var c = method.local_class.name
425 var n = method.name
426 var s: nullable String = null
427 if c == once "Int".to_symbol then
428 if n == once "object_id".to_symbol then
429 s = "@@@"
430 else if n == once "unary -".to_symbol then
431 s = "TAG_Int(-UNTAG_Int(@@@))"
432 else if n == once "output".to_symbol then
433 s = "printf(\"%ld\\n\", UNTAG_Int(@@@));"
434 else if n == once "ascii".to_symbol then
435 s = "TAG_Char(UNTAG_Int(@@@))"
436 else if n == once "succ".to_symbol then
437 s = "TAG_Int(UNTAG_Int(@@@)+1)"
438 else if n == once "prec".to_symbol then
439 s = "TAG_Int(UNTAG_Int(@@@)-1)"
440 else if n == once "to_f".to_symbol then
441 s = "BOX_Float((float)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_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
450 else if n == once "%".to_symbol then
451 s = "TAG_Int(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 "<=".to_symbol then
457 s = "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
458 else if n == once ">=".to_symbol then
459 s = "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
460 else if n == once "lshift".to_symbol then
461 s = "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
462 else if n == once "rshift".to_symbol then
463 s = "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
464 else if n == once "==".to_symbol then
465 s = "TAG_Bool((@@@)==(@@@))"
466 else if n == once "!=".to_symbol then
467 s = "TAG_Bool((@@@)!=(@@@))"
468 end
469 else if c == once "Float".to_symbol then
470 if n == once "object_id".to_symbol then
471 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
472 else if n == once "unary -".to_symbol then
473 s = "BOX_Float(-UNBOX_Float(@@@))"
474 else if n == once "output".to_symbol then
475 s = "printf(\"%f\\n\", UNBOX_Float(@@@));"
476 else if n == once "to_i".to_symbol then
477 s = "TAG_Int((bigint)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 = "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
484 else if n == once "/".to_symbol then
485 s = "BOX_Float(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 else if n == once "<=".to_symbol then
491 s = "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
492 else if n == once ">=".to_symbol then
493 s = "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
494 end
495 else if c == once "Char".to_symbol then
496 if n == once "object_id".to_symbol then
497 s = "TAG_Int(UNTAG_Char(@@@))"
498 else if n == once "unary -".to_symbol then
499 s = "TAG_Char(-UNTAG_Char(@@@))"
500 else if n == once "output".to_symbol then
501 s = "printf(\"%c\", (unsigned char)UNTAG_Char(@@@));"
502 else if n == once "ascii".to_symbol then
503 s = "TAG_Int((unsigned char)UNTAG_Char(@@@))"
504 else if n == once "succ".to_symbol then
505 s = "TAG_Char(UNTAG_Char(@@@)+1)"
506 else if n == once "prec".to_symbol then
507 s = "TAG_Char(UNTAG_Char(@@@)-1)"
508 else if n == once "to_i".to_symbol then
509 s = "TAG_Int(UNTAG_Char(@@@)-'0')"
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_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
518 else if n == once "%".to_symbol then
519 s = "TAG_Char(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(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
526 else if n == once ">=".to_symbol then
527 s = "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
528 else if n == once "==".to_symbol then
529 s = "TAG_Bool((@@@)==(@@@))"
530 else if n == once "!=".to_symbol then
531 s = "TAG_Bool((@@@)!=(@@@))"
532 end
533 else if c == once "Bool".to_symbol then
534 if n == once "object_id".to_symbol then
535 s = "TAG_Int(UNTAG_Bool(@@@))"
536 else if n == once "unary -".to_symbol then
537 s = "TAG_Bool(-UNTAG_Bool(@@@))"
538 else if n == once "output".to_symbol then
539 s = "(void)printf(UNTAG_Bool(@@@)?\"true\\n\":\"false\\n\");"
540 else if n == once "ascii".to_symbol then
541 s = "TAG_Bool(UNTAG_Bool(@@@))"
542 else if n == once "to_i".to_symbol then
543 s = "TAG_Int(UNTAG_Bool(@@@))"
544 else if n == once "==".to_symbol then
545 s = "TAG_Bool((@@@)==(@@@))"
546 else if n == once "!=".to_symbol then
547 s = "TAG_Bool((@@@)!=(@@@))"
548 end
549 else if c == once "NativeArray".to_symbol then
550 if n == once "object_id".to_symbol then
551 s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
552 else if n == once "[]".to_symbol then
553 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
554 else if n == once "[]=".to_symbol then
555 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
556 else if n == once "copy_to".to_symbol then
557 var t = p[0]
558 p[0] = p[1]
559 p[1] = t
560 s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
561 end
562 else if c == once "NativeString".to_symbol then
563 if n == once "object_id".to_symbol then
564 s = "TAG_Int(UNBOX_NativeString(@@@))"
565 else if n == once "atoi".to_symbol then
566 s = "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
567 else if n == once "[]".to_symbol then
568 s = "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
569 else if n == once "[]=".to_symbol then
570 s = "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
571 else if n == once "copy_to".to_symbol then
572 var t = p[0]
573 p[0] = p[1]
574 p[1] = p[4]
575 p[4] = p[2]
576 p[2] = t
577 s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
578 end
579 else if n == once "object_id".to_symbol then
580 s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
581 else if n == once "sys".to_symbol then
582 s = "(G_sys)"
583 else if n == once "is_same_type".to_symbol then
584 s = "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
585 else if n == once "exit".to_symbol then
586 p[0] = p[1]
587 s = "exit(UNTAG_Int(@@@));"
588 else if n == once "calloc_array".to_symbol then
589 p[0] = p[1]
590 s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
591 else if n == once "calloc_string".to_symbol then
592 p[0] = p[1]
593 s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
594 end
595 if s == null then
596 v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
597 s = "NIT_NULL"
598 end
599 var rtype = method.signature.return_type
600 if rtype != null then
601 v.add_return_value(v.expr(new INative(s, p), rtype))
602 else
603 v.stmt(new INative(s, p))
604 end
605 end
606 end
607
608 ###############################################################################
609
610 redef class AExpr
611 redef fun accept_icode_generation(v) do end
612
613 # Generate icode sequence in the current A2IContext
614 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
615 protected fun generate_icode(v: A2IContext): nullable IRegister is abstract
616 end
617
618 redef class AVardeclExpr
619 redef fun generate_icode(v)
620 do
621 var reg = v.variable(variable)
622 var ne = n_expr
623 if ne != null then
624 v.add_assignment(reg, v.generate_expr(ne))
625 end
626 return null
627 end
628 end
629
630 redef class ABlockExpr
631 redef fun generate_icode(v)
632 do
633 for ne in n_expr do v.generate_stmt(ne)
634 return null
635 end
636 end
637
638 redef class ADoExpr
639 redef fun generate_icode(v)
640 do
641 var seq_old = v.seq
642 var seq = new ISeq
643 v.stmt(seq)
644 escapable.break_seq = seq
645 v.seq = seq
646
647 v.generate_stmt(n_block)
648
649 v.seq = seq_old
650 return null
651 end
652 end
653
654 redef class AReturnExpr
655 redef fun generate_icode(v)
656 do
657 var ne = n_expr
658 if ne != null then
659 v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
660 end
661 v.stmt(new IEscape(v.return_seq.as(not null)))
662 return null
663 end
664 end
665
666 redef class ABreakExpr
667 redef fun generate_icode(v)
668 do
669 var ne = n_expr
670 if ne != null then
671 v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
672 end
673 v.stmt(new IEscape(escapable.break_seq.as(not null)))
674 return null
675 end
676 end
677
678 redef class AContinueExpr
679 redef fun generate_icode(v)
680 do
681 var ne = n_expr
682 if ne != null then
683 v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
684 end
685 v.stmt(new IEscape(escapable.continue_seq.as(not null)))
686 return null
687 end
688 end
689
690 redef class AAbortExpr
691 redef fun generate_icode(v)
692 do
693 v.add_abort("Aborted")
694 return null
695 end
696 end
697
698 redef class AIfExpr
699 redef fun generate_icode(v)
700 do
701 var iif = new IIf(v.generate_expr(n_expr))
702 v.stmt(iif)
703 var seq_old = v.seq
704
705 if n_then != null then
706 v.seq = iif.then_seq
707 v.generate_stmt(n_then)
708 end
709
710 if n_else != null then
711 v.seq = iif.else_seq
712 v.generate_stmt(n_else)
713 end
714
715 v.seq = seq_old
716 return null
717 end
718 end
719
720 redef class AWhileExpr
721 redef fun generate_icode(v)
722 do
723 var seq_old = v.seq
724 var iloop = new ILoop
725 v.stmt(iloop)
726 escapable.break_seq = iloop
727 v.seq = iloop
728
729 # Process condition
730 var iif = new IIf(v.generate_expr(n_expr))
731 v.stmt(iif)
732
733 # Process inside (condition is true)
734 if n_block != null then
735 v.seq = iif.then_seq
736 escapable.continue_seq = iif.then_seq
737 v.generate_stmt(n_block)
738 end
739
740 # Process escape (condition is false)
741 v.seq = iif.else_seq
742 v.stmt(new IEscape(iloop))
743
744 v.seq = seq_old
745 return null
746 end
747 end
748
749 redef class ALoopExpr
750 redef fun generate_icode(v)
751 do
752 var seq_old = v.seq
753 var iloop = new ILoop
754 v.stmt(iloop)
755 escapable.break_seq = iloop
756 v.seq = iloop
757
758 # Process inside
759 if n_block != null then
760 var seq = new ISeq
761 v.stmt(seq)
762 v.seq = seq
763 escapable.continue_seq = seq
764 v.generate_stmt(n_block)
765 end
766
767 v.seq = seq_old
768 return null
769 end
770 end
771
772 redef class AForExpr
773 redef fun generate_icode(v)
774 do
775 var expr_type = n_expr.stype
776
777 # Get iterator
778 var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol)
779
780 var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null)
781 var ireg_iter = v.expr(new ICall(meth_iterator, [v.generate_expr(n_expr)]), iter_type)
782
783 # Enter loop
784 var seq_old = v.seq
785 var iloop = new ILoop
786 v.stmt(iloop)
787 escapable.break_seq = iloop
788 v.seq = iloop
789
790 # Condition evaluation
791 var meth_is_ok = v.visitor.get_method(iter_type, once ("is_ok".to_symbol))
792 var ireg_isok = v.expr(new ICall(meth_is_ok, [ireg_iter]), v.visitor.type_bool)
793 var iif = new IIf(ireg_isok)
794
795 # Process insite the loop (condition is true)
796 v.stmt(iif)
797 v.seq = iif.then_seq
798 escapable.continue_seq = iif.then_seq
799
800 # Automatic variable assignment
801 var meth_item = v.visitor.get_method(iter_type, once ("item".to_symbol))
802 var va_stype = variable.stype.as(not null)
803 var ireg_item = v.expr(new ICall(meth_item, [ireg_iter]), va_stype)
804 var ireg_va = v.variable(variable)
805 v.add_assignment(ireg_va, ireg_item)
806
807 # Body evaluation
808 v.generate_stmt(n_block)
809
810 # Exit contition (condition is false)
811 v.seq = iif.else_seq
812 v.stmt(new IEscape(iloop))
813
814 # Next step
815 var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol))
816 v.seq = iloop
817 v.stmt(new ICall(meth_next, [ireg_iter]))
818
819 v.seq = seq_old
820 return null
821 end
822 end
823
824 redef class AAssertExpr
825 redef fun generate_icode(v)
826 do
827 var e = v.generate_expr(n_expr)
828 var iif = new IIf(e)
829 v.stmt(iif)
830 var seq_old = v.seq
831 v.seq = iif.else_seq
832 v.generate_stmt(n_else)
833 var id = n_id
834 if id == null then
835 v.add_abort("Assert failed")
836 else
837 v.add_abort("Assert %s failed", id.to_s)
838 end
839 v.seq = seq_old
840 return null
841 end
842 end
843
844 redef class AVarExpr
845 redef fun generate_icode(v)
846 do
847 return v.variable(variable)
848 end
849 end
850
851 redef class AVarAssignExpr
852 redef fun generate_icode(v)
853 do
854 var e = v.generate_expr(n_value)
855 v.add_assignment(v.variable(variable), e)
856 return null
857 end
858 end
859
860 redef class AVarReassignExpr
861 redef fun generate_icode(v)
862 do
863 var e1 = v.variable(variable)
864 var e2 = v.generate_expr(n_value)
865 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
866 v.add_assignment(e1, e3)
867 return null
868 end
869 end
870
871 redef class ASelfExpr
872 redef fun generate_icode(v)
873 do
874 return v.variable(variable)
875 end
876 end
877
878 redef class AIfexprExpr
879 redef fun generate_icode(v)
880 do
881 # Process condition
882 var iif = new IIf(v.generate_expr(n_expr))
883 v.stmt(iif)
884 var seq_old = v.seq
885
886 # Prepare result
887 var reg = v.new_register(stype)
888
889 # Process 'then'
890 v.seq = iif.then_seq
891 v.add_assignment(reg, v.generate_expr(n_then))
892
893 # Process 'else'
894 v.seq = iif.else_seq
895 v.add_assignment(reg, v.generate_expr(n_else))
896
897 v.seq = seq_old
898 return reg
899 end
900 end
901
902 redef class AEeExpr
903 redef fun generate_icode(v)
904 do
905 var e = v.generate_expr(n_expr)
906 var e2 = v.generate_expr(n_expr2)
907 return v.expr(new IIs(e, e2), stype)
908 end
909 end
910
911 redef class AOrExpr
912 redef fun generate_icode(v)
913 do
914 # Prepare result
915 var reg = v.new_register(stype)
916
917 # Process left operand (in a if/then)
918 var iif = new IIf(v.generate_expr(n_expr))
919 v.stmt(iif)
920 var seq_old = v.seq
921 v.seq = iif.then_seq
922 v.add_assignment(reg, v.lit_true_reg)
923
924 # Process right operand (in the else)
925 v.seq = iif.else_seq
926 v.add_assignment(reg, v.generate_expr(n_expr2))
927
928 v.seq = seq_old
929 return reg
930 end
931 end
932
933 redef class AAndExpr
934 redef fun generate_icode(v)
935 do
936 # Prepare result
937 var reg = v.new_register(stype)
938
939 # Process left operand (in a if/else)
940 var iif = new IIf(v.generate_expr(n_expr))
941 v.stmt(iif)
942 var seq_old = v.seq
943 v.seq = iif.else_seq
944 v.add_assignment(reg, v.lit_false_reg)
945
946 # Process right operand (in the then)
947 v.seq = iif.then_seq
948 v.add_assignment(reg, v.generate_expr(n_expr2))
949
950 v.seq = seq_old
951 return reg
952 end
953 end
954
955 redef class ANotExpr
956 redef fun generate_icode(v)
957 do
958 var e = v.generate_expr(n_expr)
959 return v.expr(new INot(e), stype)
960 end
961 end
962
963 redef class AIsaExpr
964 redef fun generate_icode(v)
965 do
966 var e = v.generate_expr(n_expr)
967 return v.expr(new ITypeCheck(e, n_type.stype), stype)
968 end
969 end
970
971 redef class AAsCastExpr
972 redef fun generate_icode(v)
973 do
974 var e = v.generate_expr(n_expr)
975 v.add_type_cast(e, stype)
976 return e
977 end
978 end
979
980 redef class AAsNotnullExpr
981 redef fun generate_icode(v)
982 do
983 var e = v.generate_expr(n_expr)
984 v.add_type_cast(e, stype)
985 return e
986 end
987 end
988
989 redef class ATrueExpr
990 redef fun generate_icode(v)
991 do
992 return v.lit_true_reg
993 end
994 end
995
996 redef class AFalseExpr
997 redef fun generate_icode(v)
998 do
999 return v.lit_false_reg
1000 end
1001 end
1002
1003 redef class AIntExpr
1004 redef fun generate_icode(v)
1005 do
1006 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
1007 end
1008 end
1009
1010 redef class AFloatExpr
1011 redef fun generate_icode(v)
1012 do
1013 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
1014 end
1015 end
1016
1017 redef class ACharExpr
1018 redef fun generate_icode(v)
1019 do
1020 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
1021 end
1022 end
1023
1024 redef class AStringFormExpr
1025 redef fun generate_icode(v)
1026 do
1027 compute_string_infos
1028 var old_seq = v.seq
1029 var ionce = new IOnce
1030 var reg = v.expr(ionce, stype)
1031 v.seq = ionce.body
1032 var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring)
1033 var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int)
1034 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
1035 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
1036 v.add_assignment(reg, e)
1037 v.seq = old_seq
1038 return reg
1039 end
1040
1041 # The raw string value
1042 protected fun string_text: String is abstract
1043
1044 # The string in a C native format
1045 protected var _cstring: nullable String
1046
1047 # The string length in bytes
1048 protected var _cstring_length: nullable Int
1049
1050 # Compute _cstring and _cstring_length using string_text
1051 protected fun compute_string_infos
1052 do
1053 var len = 0
1054 var str = string_text
1055 var res = new Buffer
1056 var i = 0
1057 while i < str.length do
1058 var c = str[i]
1059 if c == '\\' then
1060 i = i + 1
1061 var c2 = str[i]
1062 if c2 != '{' and c2 != '}' then
1063 res.add(c)
1064 end
1065 c = c2
1066 end
1067 len = len + 1
1068 res.add(c)
1069 i = i + 1
1070 end
1071 _cstring = res.to_s
1072 _cstring_length = len
1073 end
1074 end
1075
1076 redef class AStringExpr
1077 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1078 end
1079 redef class AStartStringExpr
1080 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1081 end
1082 redef class AMidStringExpr
1083 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1084 end
1085 redef class AEndStringExpr
1086 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1087 end
1088
1089 redef class ASuperstringExpr
1090 redef fun generate_icode(v)
1091 do
1092 var array = v.add_new_array(atype, n_exprs.length)
1093 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
1094 for ne in n_exprs do
1095 var e = v.generate_expr(ne)
1096 if ne.stype != stype then
1097 e = v.expr(new ICall(prop_to_s, [e]), stype)
1098 end
1099 v.add_call_array_add(array, e)
1100 end
1101 return v.expr(new ICall(prop_to_s, [array]), stype)
1102 end
1103 end
1104
1105 redef class ANullExpr
1106 redef fun generate_icode(v)
1107 do
1108 return v.lit_null_reg
1109 end
1110 end
1111
1112 redef class AArrayExpr
1113 redef fun generate_icode(v)
1114 do
1115 var recv = v.add_new_array(stype, n_exprs.length)
1116 for ne in n_exprs do
1117 var e = v.generate_expr(ne)
1118 v.add_call_array_add(recv, e)
1119 end
1120 return recv
1121 end
1122 end
1123
1124 redef class ACrangeExpr
1125 redef fun generate_icode(v)
1126 do
1127 var e = v.generate_expr(n_expr)
1128 var e2 = v.generate_expr(n_expr2)
1129 var prop = v.visitor.get_method(stype, once "init".to_symbol)
1130 return v.expr(new INew(stype, prop, [e, e2]), stype)
1131 end
1132 end
1133
1134 redef class AOrangeExpr
1135 redef fun generate_icode(v)
1136 do
1137 var e = v.generate_expr(n_expr)
1138 var e2 = v.generate_expr(n_expr2)
1139 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1140 return v.expr(new INew(stype, prop, [e, e2]), stype)
1141 end
1142 end
1143
1144 redef class ASuperExpr
1145 redef fun generate_icode(v)
1146 do
1147 var arity = v.iroutine.params.length - 1
1148 if init_in_superclass != null then
1149 arity = init_in_superclass.signature.arity
1150 end
1151 var args = new Array[IRegister].with_capacity(arity + 1)
1152 args.add(v.iroutine.params[0])
1153 if n_args.length != arity then
1154 for i in [0..arity[ do
1155 args.add(v.iroutine.params[i + 1])
1156 end
1157 else
1158 for na in n_args do
1159 args.add(v.generate_expr(na))
1160 end
1161 end
1162 var p = init_in_superclass
1163 if p != null then
1164 var rtype = p.signature.return_type
1165 if rtype != null then
1166 return v.expr(new ICall(p, args), rtype)
1167 else
1168 v.stmt(new ICall(p, args))
1169 return null
1170 end
1171 else
1172 p = prop
1173 var rtype = p.signature.return_type
1174 if rtype == null then
1175 v.stmt(new ISuper(p, args))
1176 return null
1177 else
1178 return v.expr(new ISuper(p, args), rtype)
1179 end
1180 end
1181 end
1182 end
1183
1184 redef class AAttrExpr
1185 redef fun generate_icode(v)
1186 do
1187 var e = v.generate_expr(n_expr)
1188 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1189 return v.add_attr_read(prop, e)
1190 end
1191 end
1192
1193 redef class AAttrAssignExpr
1194 redef fun generate_icode(v)
1195 do
1196 var e = v.generate_expr(n_expr)
1197 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1198 var e2 = v.generate_expr(n_value)
1199 v.stmt(new IAttrWrite(prop, e, e2))
1200 return null
1201 end
1202 end
1203 redef class AAttrReassignExpr
1204 redef fun generate_icode(v)
1205 do
1206 var e1 = v.generate_expr(n_expr)
1207 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1208 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1209 var e3 = v.generate_expr(n_value)
1210 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1211 v.stmt(new IAttrWrite(prop, e1, e4))
1212 return null
1213 end
1214 end
1215
1216 redef class AIssetAttrExpr
1217 redef fun generate_icode(v)
1218 do
1219 var e = v.generate_expr(n_expr)
1220 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1221 return v.expr(new IAttrIsset(prop, e), stype)
1222 end
1223 end
1224
1225 redef class AAbsAbsSendExpr
1226 # Compile each argument and add them to the array
1227 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1228 do
1229 var par_arity = signature.arity
1230 var par_vararg = signature.vararg_rank
1231 var raw_args = raw_arguments
1232 var raw_arity = raw_args.length
1233 var arg_idx = 0
1234 for par_idx in [0..par_arity[ do
1235 var a: AExpr
1236 var par_type = signature[par_idx]
1237 if par_idx == par_vararg then
1238 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1239 for i in [0..(raw_arity-par_arity)] do
1240 a = raw_args[arg_idx]
1241 v.add_call_array_add(arr, v.generate_expr(a))
1242 arg_idx = arg_idx + 1
1243 end
1244 args.add(arr)
1245 else
1246 a = raw_args[arg_idx]
1247 args.add(v.generate_expr(a))
1248 arg_idx = arg_idx + 1
1249 end
1250 end
1251 end
1252 end
1253
1254 redef class ASendExpr
1255 redef fun generate_icode(v)
1256 do
1257 var recv = v.generate_expr(n_expr)
1258 var args = new Array[IRegister]
1259 args.add(recv)
1260 var prop = prop
1261 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1262 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1263 var r2: nullable IRegister # The raw result of the call
1264
1265 # Prepare closures
1266 var seq_old = v.seq
1267 var closcns: nullable Array[nullable IClosureDef] = null
1268 if not prop_signature.closures.is_empty then
1269 var rtype = prop_signature.return_type
1270 if rtype != null then
1271 r = v.new_register(rtype)
1272 end
1273 var seq = new ISeq
1274 v.stmt(seq)
1275 v.seq = seq
1276 closcns = new Array[nullable IClosureDef]
1277 var cdarity = 0
1278 if closure_defs != null then cdarity = closure_defs.length
1279 var closure_defs = closure_defs
1280 for mmc in prop_signature.closures do
1281 var found = false
1282 var name = mmc.name
1283 if closure_defs != null then
1284 for cd in closure_defs do
1285 if cd.n_id.to_symbol != name then continue
1286 assert found == false
1287 found = true
1288 cd.escapable.break_seq = seq
1289 cd.escapable.break_value = r
1290 var cn = cd.generate_iclosuredef(v)
1291 closcns.add(cn)
1292 end
1293 end
1294 if not found then
1295 closcns.add(null)
1296 end
1297 end
1298 end
1299
1300 r2 = v.add_call(prop, args, closcns)
1301
1302 # Closure work
1303 if not prop_signature.closures.is_empty then
1304 if r != null and r2 != null then v.add_assignment(r, r2)
1305 v.seq = seq_old
1306 else
1307 r = r2
1308 end
1309
1310 if prop.global.is_init then
1311 v.invoke_super_init_calls_after(prop)
1312 end
1313 return r
1314 end
1315 end
1316
1317 redef class ASendReassignExpr
1318 redef fun generate_icode(v)
1319 do
1320 var recv = v.generate_expr(n_expr)
1321 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1322 var args = new Array[IRegister]
1323 args.add(recv)
1324 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1325
1326 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1327 var e3 = v.generate_expr(n_value)
1328 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1329 var args2 = args.to_a
1330 args2.add(e4)
1331 v.stmt(new ICall(prop, args2))
1332 return null
1333 end
1334 end
1335
1336 redef class ANewExpr
1337 redef fun generate_icode(v)
1338 do
1339 var args = new Array[IRegister]
1340 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1341 return v.expr(new INew(stype, prop, args), stype)
1342 end
1343 end
1344
1345 redef class AProxyExpr
1346 redef fun generate_icode(v)
1347 do
1348 return v.generate_expr(n_expr)
1349 end
1350 end
1351
1352 redef class AOnceExpr
1353 redef fun generate_icode(v)
1354 do
1355 var ionce = new IOnce
1356 var reg = v.expr(ionce, stype)
1357 var old_seq = v.seq
1358 v.seq = ionce.body
1359
1360 var e = v.generate_expr(n_expr)
1361 v.add_assignment(reg, e)
1362
1363 v.seq = old_seq
1364 return reg
1365 end
1366 end
1367
1368
1369 redef class AClosureDef
1370 var _iclosure_def: nullable IClosureDef
1371
1372 fun generate_iclosuredef(v: A2IContext): IClosureDef
1373 do
1374 # Prepare signature
1375 var args = new Array[IRegister]
1376 var sig = closure.signature
1377 for i in [0..sig.arity[ do
1378 args.add(v.new_register(sig[i]))
1379 end
1380 var ret: nullable IRegister = null
1381 var rtype = sig.return_type
1382 if rtype != null then
1383 ret = v.new_register(rtype)
1384 end
1385
1386 var iclos = new IClosureDef(args, ret)
1387 iclos.location = location
1388
1389 # Prepare env
1390 var seq_old = v.seq
1391 v.seq = iclos.body
1392 escapable.continue_seq = iclos.body
1393 escapable.continue_value = iclos.result
1394
1395 # Assign parameters
1396 for i in [0..variables.length[ do
1397 var res = v.variable(variables[i])
1398 v.add_assignment(res, iclos.params[i])
1399 end
1400
1401 v.generate_stmt(n_expr)
1402
1403 v.seq = seq_old
1404 _iclosure_def = iclos
1405 return iclos
1406 end
1407 end
1408
1409 redef class AClosureCallExpr
1410 redef fun generate_icode(v)
1411 do
1412 # Geneate arguments
1413 var args = new Array[IRegister]
1414 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1415
1416 # Prepare icall
1417 var closdecl = v.closurevariables[variable]
1418 var icall = new IClosCall(closdecl, args)
1419 var seq_old = v.seq
1420
1421 # Fill break of ical
1422 if n_closure_defs.length == 1 then do
1423 var iseq = new ISeq
1424 icall.break_seq = iseq
1425 v.seq = iseq
1426 v.generate_stmt(n_closure_defs.first.n_expr)
1427 v.seq = seq_old
1428 end
1429
1430 # Prepare in case of default block
1431 var iif: nullable IIf = null # The iif of default block
1432 var closdecl_default = closdecl.default # The default (if any)
1433 if closdecl_default != null then
1434 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1435 v.stmt(iif)
1436 v.seq = iif.then_seq
1437 end
1438
1439 # Add the icall
1440 var r2: nullable IRegister = null # the result of the icall
1441 var rtype = variable.closure.signature.return_type
1442 if rtype == null then
1443 v.stmt(icall)
1444 else
1445 r2 = v.expr(icall, rtype)
1446 end
1447
1448 # Process the case of default block
1449 var r: nullable IRegister = null # the real result
1450 if closdecl_default != null then
1451 assert iif != null
1452 if r2 != null then
1453 assert rtype != null
1454 r = v.new_register(rtype)
1455 v.add_assignment(r, r2)
1456 end
1457 v.seq = iif.else_seq
1458 var r3 = v.inline_routine(closdecl_default, args, null)
1459 if r != null then
1460 assert r3 != null
1461 v.add_assignment(r, r3)
1462 end
1463 v.seq = seq_old
1464 else
1465 r = r2
1466 end
1467 return r
1468 end
1469 end