syntax: new 'assert else' statement
[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*)raw_alloc((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 v.generate_stmt(n_else)
829 var id = n_id
830 if id == null then
831 v.add_abort("Assert failed")
832 else
833 v.add_abort("Assert %s failed", id.to_s)
834 end
835 v.seq = seq_old
836 return null
837 end
838 end
839
840 redef class AVarExpr
841 redef fun generate_icode(v)
842 do
843 return v.variable(variable)
844 end
845 end
846
847 redef class AVarAssignExpr
848 redef fun generate_icode(v)
849 do
850 var e = v.generate_expr(n_value)
851 v.add_assignment(v.variable(variable), e)
852 return null
853 end
854 end
855
856 redef class AVarReassignExpr
857 redef fun generate_icode(v)
858 do
859 var e1 = v.variable(variable)
860 var e2 = v.generate_expr(n_value)
861 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
862 v.add_assignment(e1, e3)
863 return null
864 end
865 end
866
867 redef class ASelfExpr
868 redef fun generate_icode(v)
869 do
870 return v.variable(variable)
871 end
872 end
873
874 redef class AIfexprExpr
875 redef fun generate_icode(v)
876 do
877 # Process condition
878 var iif = new IIf(v.generate_expr(n_expr))
879 v.stmt(iif)
880 var seq_old = v.seq
881
882 # Prepare result
883 var reg = v.new_register(stype)
884
885 # Process 'then'
886 v.seq = iif.then_seq
887 v.add_assignment(reg, v.generate_expr(n_then))
888
889 # Process 'else'
890 v.seq = iif.else_seq
891 v.add_assignment(reg, v.generate_expr(n_else))
892
893 v.seq = seq_old
894 return reg
895 end
896 end
897
898 redef class AEeExpr
899 redef fun generate_icode(v)
900 do
901 var e = v.generate_expr(n_expr)
902 var e2 = v.generate_expr(n_expr2)
903 return v.expr(new IIs(e, e2), stype)
904 end
905 end
906
907 redef class AOrExpr
908 redef fun generate_icode(v)
909 do
910 # Prepare result
911 var reg = v.new_register(stype)
912
913 # Process left operand (in a if/then)
914 var iif = new IIf(v.generate_expr(n_expr))
915 v.stmt(iif)
916 var seq_old = v.seq
917 v.seq = iif.then_seq
918 v.add_assignment(reg, v.lit_true_reg)
919
920 # Process right operand (in the else)
921 v.seq = iif.else_seq
922 v.add_assignment(reg, v.generate_expr(n_expr2))
923
924 v.seq = seq_old
925 return reg
926 end
927 end
928
929 redef class AAndExpr
930 redef fun generate_icode(v)
931 do
932 # Prepare result
933 var reg = v.new_register(stype)
934
935 # Process left operand (in a if/else)
936 var iif = new IIf(v.generate_expr(n_expr))
937 v.stmt(iif)
938 var seq_old = v.seq
939 v.seq = iif.else_seq
940 v.add_assignment(reg, v.lit_false_reg)
941
942 # Process right operand (in the then)
943 v.seq = iif.then_seq
944 v.add_assignment(reg, v.generate_expr(n_expr2))
945
946 v.seq = seq_old
947 return reg
948 end
949 end
950
951 redef class ANotExpr
952 redef fun generate_icode(v)
953 do
954 var e = v.generate_expr(n_expr)
955 return v.expr(new INot(e), stype)
956 end
957 end
958
959 redef class AIsaExpr
960 redef fun generate_icode(v)
961 do
962 var e = v.generate_expr(n_expr)
963 return v.expr(new ITypeCheck(e, n_type.stype), stype)
964 end
965 end
966
967 redef class AAsCastExpr
968 redef fun generate_icode(v)
969 do
970 var e = v.generate_expr(n_expr)
971 v.add_type_cast(e, stype)
972 return e
973 end
974 end
975
976 redef class AAsNotnullExpr
977 redef fun generate_icode(v)
978 do
979 var e = v.generate_expr(n_expr)
980 v.add_type_cast(e, stype)
981 return e
982 end
983 end
984
985 redef class ATrueExpr
986 redef fun generate_icode(v)
987 do
988 return v.lit_true_reg
989 end
990 end
991
992 redef class AFalseExpr
993 redef fun generate_icode(v)
994 do
995 return v.lit_false_reg
996 end
997 end
998
999 redef class AIntExpr
1000 redef fun generate_icode(v)
1001 do
1002 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
1003 end
1004 end
1005
1006 redef class AFloatExpr
1007 redef fun generate_icode(v)
1008 do
1009 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
1010 end
1011 end
1012
1013 redef class ACharExpr
1014 redef fun generate_icode(v)
1015 do
1016 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
1017 end
1018 end
1019
1020 redef class AStringFormExpr
1021 redef fun generate_icode(v)
1022 do
1023 compute_string_infos
1024 var old_seq = v.seq
1025 var ionce = new IOnce
1026 var reg = v.expr(ionce, stype)
1027 v.seq = ionce.body
1028 var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring)
1029 var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int)
1030 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
1031 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
1032 v.add_assignment(reg, e)
1033 v.seq = old_seq
1034 return reg
1035 end
1036
1037 # The raw string value
1038 protected fun string_text: String is abstract
1039
1040 # The string in a C native format
1041 protected var _cstring: nullable String
1042
1043 # The string length in bytes
1044 protected var _cstring_length: nullable Int
1045
1046 # Compute _cstring and _cstring_length using string_text
1047 protected fun compute_string_infos
1048 do
1049 var len = 0
1050 var str = string_text
1051 var res = new Buffer
1052 var i = 0
1053 while i < str.length do
1054 var c = str[i]
1055 if c == '\\' then
1056 i = i + 1
1057 var c2 = str[i]
1058 if c2 != '{' and c2 != '}' then
1059 res.add(c)
1060 end
1061 c = c2
1062 end
1063 len = len + 1
1064 res.add(c)
1065 i = i + 1
1066 end
1067 _cstring = res.to_s
1068 _cstring_length = len
1069 end
1070 end
1071
1072 redef class AStringExpr
1073 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1074 end
1075 redef class AStartStringExpr
1076 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1077 end
1078 redef class AMidStringExpr
1079 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1080 end
1081 redef class AEndStringExpr
1082 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1083 end
1084
1085 redef class ASuperstringExpr
1086 redef fun generate_icode(v)
1087 do
1088 var array = v.add_new_array(atype, n_exprs.length)
1089 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
1090 for ne in n_exprs do
1091 var e = v.generate_expr(ne)
1092 if ne.stype != stype then
1093 e = v.expr(new ICall(prop_to_s, [e]), stype)
1094 end
1095 v.add_call_array_add(array, e)
1096 end
1097 return v.expr(new ICall(prop_to_s, [array]), stype)
1098 end
1099 end
1100
1101 redef class ANullExpr
1102 redef fun generate_icode(v)
1103 do
1104 return v.lit_null_reg
1105 end
1106 end
1107
1108 redef class AArrayExpr
1109 redef fun generate_icode(v)
1110 do
1111 var recv = v.add_new_array(stype, n_exprs.length)
1112 for ne in n_exprs do
1113 var e = v.generate_expr(ne)
1114 v.add_call_array_add(recv, e)
1115 end
1116 return recv
1117 end
1118 end
1119
1120 redef class ACrangeExpr
1121 redef fun generate_icode(v)
1122 do
1123 var e = v.generate_expr(n_expr)
1124 var e2 = v.generate_expr(n_expr2)
1125 var prop = v.visitor.get_method(stype, once "init".to_symbol)
1126 return v.expr(new INew(stype, prop, [e, e2]), stype)
1127 end
1128 end
1129
1130 redef class AOrangeExpr
1131 redef fun generate_icode(v)
1132 do
1133 var e = v.generate_expr(n_expr)
1134 var e2 = v.generate_expr(n_expr2)
1135 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1136 return v.expr(new INew(stype, prop, [e, e2]), stype)
1137 end
1138 end
1139
1140 redef class ASuperExpr
1141 redef fun generate_icode(v)
1142 do
1143 var arity = v.iroutine.params.length - 1
1144 if init_in_superclass != null then
1145 arity = init_in_superclass.signature.arity
1146 end
1147 var args = new Array[IRegister].with_capacity(arity + 1)
1148 args.add(v.iroutine.params[0])
1149 if n_args.length != arity then
1150 for i in [0..arity[ do
1151 args.add(v.iroutine.params[i + 1])
1152 end
1153 else
1154 for na in n_args do
1155 args.add(v.generate_expr(na))
1156 end
1157 end
1158 var p = init_in_superclass
1159 if p != null then
1160 var rtype = p.signature.return_type
1161 if rtype != null then
1162 return v.expr(new ICall(p, args), rtype)
1163 else
1164 v.stmt(new ICall(p, args))
1165 return null
1166 end
1167 else
1168 p = prop
1169 var rtype = p.signature.return_type
1170 if rtype == null then
1171 v.stmt(new ISuper(p, args))
1172 return null
1173 else
1174 return v.expr(new ISuper(p, args), rtype)
1175 end
1176 end
1177 end
1178 end
1179
1180 redef class AAttrExpr
1181 redef fun generate_icode(v)
1182 do
1183 var e = v.generate_expr(n_expr)
1184 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1185 return v.add_attr_read(prop, e)
1186 end
1187 end
1188
1189 redef class AAttrAssignExpr
1190 redef fun generate_icode(v)
1191 do
1192 var e = v.generate_expr(n_expr)
1193 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1194 var e2 = v.generate_expr(n_value)
1195 v.stmt(new IAttrWrite(prop, e, e2))
1196 return null
1197 end
1198 end
1199 redef class AAttrReassignExpr
1200 redef fun generate_icode(v)
1201 do
1202 var e1 = v.generate_expr(n_expr)
1203 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1204 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1205 var e3 = v.generate_expr(n_value)
1206 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1207 v.stmt(new IAttrWrite(prop, e1, e4))
1208 return null
1209 end
1210 end
1211
1212 redef class AIssetAttrExpr
1213 redef fun generate_icode(v)
1214 do
1215 var e = v.generate_expr(n_expr)
1216 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1217 return v.expr(new IAttrIsset(prop, e), stype)
1218 end
1219 end
1220
1221 redef class AAbsAbsSendExpr
1222 # Compile each argument and add them to the array
1223 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1224 do
1225 var par_arity = signature.arity
1226 var par_vararg = signature.vararg_rank
1227 var raw_args = raw_arguments
1228 var raw_arity = raw_args.length
1229 var arg_idx = 0
1230 for par_idx in [0..par_arity[ do
1231 var a: AExpr
1232 var par_type = signature[par_idx]
1233 if par_idx == par_vararg then
1234 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1235 for i in [0..(raw_arity-par_arity)] do
1236 a = raw_args[arg_idx]
1237 v.add_call_array_add(arr, v.generate_expr(a))
1238 arg_idx = arg_idx + 1
1239 end
1240 args.add(arr)
1241 else
1242 a = raw_args[arg_idx]
1243 args.add(v.generate_expr(a))
1244 arg_idx = arg_idx + 1
1245 end
1246 end
1247 end
1248 end
1249
1250 redef class ASendExpr
1251 redef fun generate_icode(v)
1252 do
1253 var recv = v.generate_expr(n_expr)
1254 var args = new Array[IRegister]
1255 args.add(recv)
1256 var prop = prop
1257 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1258 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1259 var r2: nullable IRegister # The raw result of the call
1260
1261 # Prepare closures
1262 var seq_old = v.seq
1263 var closcns: nullable Array[nullable IClosureDef] = null
1264 if not prop_signature.closures.is_empty then
1265 var rtype = prop_signature.return_type
1266 if rtype != null then
1267 r = v.new_register(rtype)
1268 end
1269 var seq = new ISeq
1270 v.stmt(seq)
1271 v.seq = seq
1272 closcns = new Array[nullable IClosureDef]
1273 var cdarity = 0
1274 if closure_defs != null then cdarity = closure_defs.length
1275 var closure_defs = closure_defs
1276 for mmc in prop_signature.closures do
1277 var found = false
1278 var name = mmc.name
1279 if closure_defs != null then
1280 for cd in closure_defs do
1281 if cd.n_id.to_symbol != name then continue
1282 assert found == false
1283 found = true
1284 cd.escapable.break_seq = seq
1285 cd.escapable.break_value = r
1286 var cn = cd.generate_iclosuredef(v)
1287 closcns.add(cn)
1288 end
1289 end
1290 if not found then
1291 closcns.add(null)
1292 end
1293 end
1294 end
1295
1296 r2 = v.add_call(prop, args, closcns)
1297
1298 # Closure work
1299 if not prop_signature.closures.is_empty then
1300 if r != null and r2 != null then v.add_assignment(r, r2)
1301 v.seq = seq_old
1302 else
1303 r = r2
1304 end
1305
1306 if prop.global.is_init then
1307 v.invoke_super_init_calls_after(prop)
1308 end
1309 return r
1310 end
1311 end
1312
1313 redef class ASendReassignExpr
1314 redef fun generate_icode(v)
1315 do
1316 var recv = v.generate_expr(n_expr)
1317 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1318 var args = new Array[IRegister]
1319 args.add(recv)
1320 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1321
1322 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1323 var e3 = v.generate_expr(n_value)
1324 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1325 var args2 = args.to_a
1326 args2.add(e4)
1327 v.stmt(new ICall(prop, args2))
1328 return null
1329 end
1330 end
1331
1332 redef class ANewExpr
1333 redef fun generate_icode(v)
1334 do
1335 var args = new Array[IRegister]
1336 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1337 return v.expr(new INew(stype, prop, args), stype)
1338 end
1339 end
1340
1341 redef class AProxyExpr
1342 redef fun generate_icode(v)
1343 do
1344 return v.generate_expr(n_expr)
1345 end
1346 end
1347
1348 redef class AOnceExpr
1349 redef fun generate_icode(v)
1350 do
1351 var ionce = new IOnce
1352 var reg = v.expr(ionce, stype)
1353 var old_seq = v.seq
1354 v.seq = ionce.body
1355
1356 var e = v.generate_expr(n_expr)
1357 v.add_assignment(reg, e)
1358
1359 v.seq = old_seq
1360 return reg
1361 end
1362 end
1363
1364
1365 redef class AClosureDef
1366 var _iclosure_def: nullable IClosureDef
1367
1368 fun generate_iclosuredef(v: A2IContext): IClosureDef
1369 do
1370 # Prepare signature
1371 var args = new Array[IRegister]
1372 var sig = closure.signature
1373 for i in [0..sig.arity[ do
1374 args.add(v.new_register(sig[i]))
1375 end
1376 var ret: nullable IRegister = null
1377 var rtype = sig.return_type
1378 if rtype != null then
1379 ret = v.new_register(rtype)
1380 end
1381
1382 var iclos = new IClosureDef(args, ret)
1383 iclos.location = location
1384
1385 # Prepare env
1386 var seq_old = v.seq
1387 v.seq = iclos.body
1388 escapable.continue_seq = iclos.body
1389 escapable.continue_value = iclos.result
1390
1391 # Assign parameters
1392 for i in [0..variables.length[ do
1393 var res = v.variable(variables[i])
1394 v.add_assignment(res, iclos.params[i])
1395 end
1396
1397 v.generate_stmt(n_expr)
1398
1399 v.seq = seq_old
1400 _iclosure_def = iclos
1401 return iclos
1402 end
1403 end
1404
1405 redef class AClosureCallExpr
1406 redef fun generate_icode(v)
1407 do
1408 # Geneate arguments
1409 var args = new Array[IRegister]
1410 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1411
1412 # Prepare icall
1413 var closdecl = v.closurevariables[variable]
1414 var icall = new IClosCall(closdecl, args)
1415 var seq_old = v.seq
1416
1417 # Fill break of ical
1418 if n_closure_defs.length == 1 then do
1419 var iseq = new ISeq
1420 icall.break_seq = iseq
1421 v.seq = iseq
1422 v.generate_stmt(n_closure_defs.first.n_expr)
1423 v.seq = seq_old
1424 end
1425
1426 # Prepare in case of default block
1427 var iif: nullable IIf = null # The iif of default block
1428 var closdecl_default = closdecl.default # The default (if any)
1429 if closdecl_default != null then
1430 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1431 v.stmt(iif)
1432 v.seq = iif.then_seq
1433 end
1434
1435 # Add the icall
1436 var r2: nullable IRegister = null # the result of the icall
1437 var rtype = variable.closure.signature.return_type
1438 if rtype == null then
1439 v.stmt(icall)
1440 else
1441 r2 = v.expr(icall, rtype)
1442 end
1443
1444 # Process the case of default block
1445 var r: nullable IRegister = null # the real result
1446 if closdecl_default != null then
1447 assert iif != null
1448 if r2 != null then
1449 assert rtype != null
1450 r = v.new_register(rtype)
1451 v.add_assignment(r, r2)
1452 end
1453 v.seq = iif.else_seq
1454 var r3 = v.inline_routine(closdecl_default, args, null)
1455 if r != null then
1456 assert r3 != null
1457 v.add_assignment(r, r3)
1458 end
1459 v.seq = seq_old
1460 else
1461 r = r2
1462 end
1463 return r
1464 end
1465 end