syntax: fix code using superstrings with nullables
[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 escapable.break_seq = v.return_seq
349 escapable.break_value = v.return_value
350 n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null)
351
352 if n_expr != null then
353 v.generate_stmt(n_expr)
354 v.iroutine.closure_decls[position].default = iclos
355
356 # Add a final break in case of break block witout value
357 if variable.closure.is_break and v.return_value == null then
358 v.add_escape(v.return_seq.as(not null))
359 end
360 end
361 v.seq = old_seq
362 end
363 end
364
365 redef class AConcreteMethPropdef
366 redef fun fill_iroutine(v, method)
367 do
368 var params = v.iroutine.params.to_a
369 var selfreg = v.variable(self_var)
370 v.stmt(new IMove(selfreg, params[0]))
371 params.shift
372
373 var orig_meth: MMLocalProperty = method.global.intro
374 var orig_sig = orig_meth.signature_for(method.signature.recv)
375 if n_signature != null then
376 n_signature.fill_iroutine_parameters(v, orig_sig, params, v.iroutine.closure_decls)
377 end
378
379 if self isa AConcreteInitPropdef then
380 v.invoke_super_init_calls_after(null)
381 end
382
383 if n_block != null then
384 v.generate_stmt(n_block)
385 end
386 end
387 end
388
389 redef class ADeferredMethPropdef
390 redef fun fill_iroutine(v, method)
391 do
392 v.add_abort("Deferred method called")
393 end
394 end
395
396 redef class AExternMethPropdef
397 redef fun fill_iroutine(v, method)
398 do
399 var params = v.iroutine.params
400 var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
401 if n_extern != null then
402 ename = n_extern.text
403 ename = ename.substring(1, ename.length-2)
404 end
405 var sig = method.signature
406 assert params.length == sig.arity + 1
407 var args = new Array[String]
408 args.add(sig.recv.unboxtype("@@@"))
409 for i in [0..sig.arity[ do
410 args.add(sig[i].unboxtype("@@@"))
411 end
412 var s = "{ename}({args.join(", ")})"
413 var rtype = sig.return_type
414 if rtype != null then
415 s = rtype.boxtype(s)
416 v.add_return_value(v.expr(new INative(s, params), rtype))
417 else
418 v.stmt(new INative(s, params))
419 end
420 end
421 end
422
423 redef class AInternMethPropdef
424 redef fun fill_iroutine(v, method)
425 do
426 var p = v.iroutine.params.to_a
427 var c = method.local_class.name
428 var n = method.name
429 var s: nullable String = null
430 if c == once "Int".to_symbol then
431 if n == once "object_id".to_symbol then
432 s = "@@@"
433 else if n == once "unary -".to_symbol then
434 s = "TAG_Int(-UNTAG_Int(@@@))"
435 else if n == once "output".to_symbol then
436 s = "printf(\"%ld\\n\", UNTAG_Int(@@@));"
437 else if n == once "ascii".to_symbol then
438 s = "TAG_Char(UNTAG_Int(@@@))"
439 else if n == once "succ".to_symbol then
440 s = "TAG_Int(UNTAG_Int(@@@)+1)"
441 else if n == once "prec".to_symbol then
442 s = "TAG_Int(UNTAG_Int(@@@)-1)"
443 else if n == once "to_f".to_symbol then
444 s = "BOX_Float((float)UNTAG_Int(@@@))"
445 else if n == once "+".to_symbol then
446 s = "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))"
447 else if n == once "-".to_symbol then
448 s = "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))"
449 else if n == once "*".to_symbol then
450 s = "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))"
451 else if n == once "/".to_symbol then
452 s = "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
453 else if n == once "%".to_symbol then
454 s = "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))"
455 else if n == once "<".to_symbol then
456 s = "TAG_Bool(UNTAG_Int(@@@)<UNTAG_Int(@@@))"
457 else if n == once ">".to_symbol then
458 s = "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))"
459 else if n == once "<=".to_symbol then
460 s = "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
461 else if n == once ">=".to_symbol then
462 s = "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
463 else if n == once "lshift".to_symbol then
464 s = "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
465 else if n == once "rshift".to_symbol then
466 s = "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
467 else if n == once "==".to_symbol then
468 s = "TAG_Bool((@@@)==(@@@))"
469 else if n == once "!=".to_symbol then
470 s = "TAG_Bool((@@@)!=(@@@))"
471 end
472 else if c == once "Float".to_symbol then
473 if n == once "object_id".to_symbol then
474 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
475 else if n == once "unary -".to_symbol then
476 s = "BOX_Float(-UNBOX_Float(@@@))"
477 else if n == once "output".to_symbol then
478 s = "printf(\"%f\\n\", UNBOX_Float(@@@));"
479 else if n == once "to_i".to_symbol then
480 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
481 else if n == once "+".to_symbol then
482 s = "BOX_Float(UNBOX_Float(@@@)+UNBOX_Float(@@@))"
483 else if n == once "-".to_symbol then
484 s = "BOX_Float(UNBOX_Float(@@@)-UNBOX_Float(@@@))"
485 else if n == once "*".to_symbol then
486 s = "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
487 else if n == once "/".to_symbol then
488 s = "BOX_Float(UNBOX_Float(@@@)/UNBOX_Float(@@@))"
489 else if n == once "<".to_symbol then
490 s = "TAG_Bool(UNBOX_Float(@@@)<UNBOX_Float(@@@))"
491 else if n == once ">".to_symbol then
492 s = "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))"
493 else if n == once "<=".to_symbol then
494 s = "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
495 else if n == once ">=".to_symbol then
496 s = "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
497 end
498 else if c == once "Char".to_symbol then
499 if n == once "object_id".to_symbol then
500 s = "TAG_Int(UNTAG_Char(@@@))"
501 else if n == once "unary -".to_symbol then
502 s = "TAG_Char(-UNTAG_Char(@@@))"
503 else if n == once "output".to_symbol then
504 s = "printf(\"%c\", (unsigned char)UNTAG_Char(@@@));"
505 else if n == once "ascii".to_symbol then
506 s = "TAG_Int((unsigned char)UNTAG_Char(@@@))"
507 else if n == once "succ".to_symbol then
508 s = "TAG_Char(UNTAG_Char(@@@)+1)"
509 else if n == once "prec".to_symbol then
510 s = "TAG_Char(UNTAG_Char(@@@)-1)"
511 else if n == once "to_i".to_symbol then
512 s = "TAG_Int(UNTAG_Char(@@@)-'0')"
513 else if n == once "+".to_symbol then
514 s = "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))"
515 else if n == once "-".to_symbol then
516 s = "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))"
517 else if n == once "*".to_symbol then
518 s = "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))"
519 else if n == once "/".to_symbol then
520 s = "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
521 else if n == once "%".to_symbol then
522 s = "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))"
523 else if n == once "<".to_symbol then
524 s = "TAG_Bool(UNTAG_Char(@@@)<UNTAG_Char(@@@))"
525 else if n == once ">".to_symbol then
526 s = "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))"
527 else if n == once "<=".to_symbol then
528 s = "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
529 else if n == once ">=".to_symbol then
530 s = "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
531 else if n == once "==".to_symbol then
532 s = "TAG_Bool((@@@)==(@@@))"
533 else if n == once "!=".to_symbol then
534 s = "TAG_Bool((@@@)!=(@@@))"
535 end
536 else if c == once "Bool".to_symbol then
537 if n == once "object_id".to_symbol then
538 s = "TAG_Int(UNTAG_Bool(@@@))"
539 else if n == once "unary -".to_symbol then
540 s = "TAG_Bool(-UNTAG_Bool(@@@))"
541 else if n == once "output".to_symbol then
542 s = "(void)printf(UNTAG_Bool(@@@)?\"true\\n\":\"false\\n\");"
543 else if n == once "ascii".to_symbol then
544 s = "TAG_Bool(UNTAG_Bool(@@@))"
545 else if n == once "to_i".to_symbol then
546 s = "TAG_Int(UNTAG_Bool(@@@))"
547 else if n == once "==".to_symbol then
548 s = "TAG_Bool((@@@)==(@@@))"
549 else if n == once "!=".to_symbol then
550 s = "TAG_Bool((@@@)!=(@@@))"
551 end
552 else if c == once "NativeArray".to_symbol then
553 if n == once "object_id".to_symbol then
554 s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
555 else if n == once "[]".to_symbol then
556 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
557 else if n == once "[]=".to_symbol then
558 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
559 else if n == once "copy_to".to_symbol then
560 var t = p[0]
561 p[0] = p[1]
562 p[1] = t
563 s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
564 end
565 else if c == once "NativeString".to_symbol then
566 if n == once "object_id".to_symbol then
567 s = "TAG_Int(UNBOX_NativeString(@@@))"
568 else if n == once "atoi".to_symbol then
569 s = "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
570 else if n == once "[]".to_symbol then
571 s = "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
572 else if n == once "[]=".to_symbol then
573 s = "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
574 else if n == once "copy_to".to_symbol then
575 var t = p[0]
576 p[0] = p[1]
577 p[1] = p[4]
578 p[4] = p[2]
579 p[2] = t
580 s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
581 end
582 else if n == once "object_id".to_symbol then
583 s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
584 else if n == once "sys".to_symbol then
585 s = "(G_sys)"
586 else if n == once "is_same_type".to_symbol then
587 s = "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
588 else if n == once "exit".to_symbol then
589 p[0] = p[1]
590 s = "exit(UNTAG_Int(@@@));"
591 else if n == once "calloc_array".to_symbol then
592 p[0] = p[1]
593 s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
594 else if n == once "calloc_string".to_symbol then
595 p[0] = p[1]
596 s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
597 end
598 if s == null then
599 v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
600 s = "NIT_NULL"
601 end
602 var rtype = method.signature.return_type
603 if rtype != null then
604 v.add_return_value(v.expr(new INative(s, p), rtype))
605 else
606 v.stmt(new INative(s, p))
607 end
608 end
609 end
610
611 ###############################################################################
612
613 redef class AExpr
614 redef fun accept_icode_generation(v) do end
615
616 # Generate icode sequence in the current A2IContext
617 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
618 protected fun generate_icode(v: A2IContext): nullable IRegister is abstract
619 end
620
621 redef class AVardeclExpr
622 redef fun generate_icode(v)
623 do
624 var reg = v.variable(variable)
625 var ne = n_expr
626 if ne != null then
627 v.add_assignment(reg, v.generate_expr(ne))
628 end
629 return null
630 end
631 end
632
633 redef class ABlockExpr
634 redef fun generate_icode(v)
635 do
636 for ne in n_expr do v.generate_stmt(ne)
637 return null
638 end
639 end
640
641 redef class ADoExpr
642 redef fun generate_icode(v)
643 do
644 var seq_old = v.seq
645 var seq = new ISeq
646 v.stmt(seq)
647 escapable.break_seq = seq
648 v.seq = seq
649
650 v.generate_stmt(n_block)
651
652 v.seq = seq_old
653 return null
654 end
655 end
656
657 redef class AReturnExpr
658 redef fun generate_icode(v)
659 do
660 var ne = n_expr
661 if ne != null then
662 v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
663 end
664 v.add_escape(v.return_seq.as(not null))
665 return null
666 end
667 end
668
669 redef class ABreakExpr
670 redef fun generate_icode(v)
671 do
672 var ne = n_expr
673 if ne != null then
674 v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
675 end
676 v.add_escape(escapable.break_seq.as(not null))
677 return null
678 end
679 end
680
681 redef class AContinueExpr
682 redef fun generate_icode(v)
683 do
684 var ne = n_expr
685 if ne != null then
686 v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
687 end
688 v.add_escape(escapable.continue_seq.as(not null))
689 return null
690 end
691 end
692
693 redef class AAbortExpr
694 redef fun generate_icode(v)
695 do
696 v.add_abort("Aborted")
697 return null
698 end
699 end
700
701 redef class AIfExpr
702 redef fun generate_icode(v)
703 do
704 var iif = new IIf(v.generate_expr(n_expr))
705 v.stmt(iif)
706 var seq_old = v.seq
707
708 if n_then != null then
709 v.seq = iif.then_seq
710 v.generate_stmt(n_then)
711 end
712
713 if n_else != null then
714 v.seq = iif.else_seq
715 v.generate_stmt(n_else)
716 end
717
718 v.seq = seq_old
719 return null
720 end
721 end
722
723 redef class AWhileExpr
724 redef fun generate_icode(v)
725 do
726 var seq_old = v.seq
727 var iloop = new ILoop
728 v.stmt(iloop)
729 escapable.break_seq = iloop
730 v.seq = iloop
731
732 # Process condition
733 var iif = new IIf(v.generate_expr(n_expr))
734 v.stmt(iif)
735
736 # Process inside (condition is true)
737 if n_block != null then
738 v.seq = iif.then_seq
739 escapable.continue_seq = iif.then_seq
740 v.generate_stmt(n_block)
741 end
742
743 # Process escape (condition is false)
744 v.seq = iif.else_seq
745 v.add_escape(iloop)
746
747 v.seq = seq_old
748 return null
749 end
750 end
751
752 redef class ALoopExpr
753 redef fun generate_icode(v)
754 do
755 var seq_old = v.seq
756 var iloop = new ILoop
757 v.stmt(iloop)
758 escapable.break_seq = iloop
759 v.seq = iloop
760
761 # Process inside
762 if n_block != null then
763 var seq = new ISeq
764 v.stmt(seq)
765 v.seq = seq
766 escapable.continue_seq = seq
767 v.generate_stmt(n_block)
768 end
769
770 v.seq = seq_old
771 return null
772 end
773 end
774
775 redef class AForExpr
776 redef fun generate_icode(v)
777 do
778 var ne = n_expr
779 var expr_type = ne.stype
780 var tint = v.visitor.type_int
781 var meth # The method that call the closure
782 var args # The arguments of meth
783
784 if ne isa ARangeExpr and expr_type == v.visitor.type_range(tint) then
785 # Shortcut. No Range[Int] object allocated.
786 # 'for x in [y..z] do' become 'y.enumerate_to(z) !each(x) do'
787 # 'for x in [y..z[ do' become 'y.enumerate_before(z) !each(x) do'
788 # And both methods may be inlined
789 args = [v.generate_expr(ne.n_expr), v.generate_expr(ne.n_expr2)]
790 if ne isa ACrangeExpr then
791 meth = v.visitor.get_method(tint, once "enumerate_to".to_symbol)
792 else
793 assert ne isa AOrangeExpr
794 meth = v.visitor.get_method(tint, once "enumerate_before".to_symbol)
795 end
796 else
797 # Standard way.
798 # 'for x in e do' become 'e.iterate !each(x) do'
799 # Some iterate methods may be inlined (eg. the Array one)
800 meth = v.visitor.get_method(expr_type, once "iterate".to_symbol)
801 args = [v.generate_expr(n_expr)]
802 end
803
804 # Build closure
805 var iclos = meth.signature.closures.first.signature.generate_empty_iclosuredef(v)
806 var old_seq = v.seq
807
808 var seq = new ISeq
809 v.stmt(seq)
810 v.seq = seq
811 escapable.break_seq = seq
812 escapable.break_value = null
813
814 v.seq = iclos.body
815 escapable.continue_seq = iclos.body
816 escapable.continue_value = null
817 v.stmt(new IMove(v.variable(variable), iclos.params.first))
818 v.generate_stmt(n_block)
819
820 # Call closure
821 v.seq = seq
822 v.add_call(meth, args, [iclos])
823
824 v.seq = old_seq
825 return null
826 end
827 end
828
829 redef class AAssertExpr
830 redef fun generate_icode(v)
831 do
832 var e = v.generate_expr(n_expr)
833 var iif = new IIf(e)
834 v.stmt(iif)
835 var seq_old = v.seq
836 v.seq = iif.else_seq
837 v.generate_stmt(n_else)
838 var id = n_id
839 if id == null then
840 v.add_abort("Assert failed")
841 else
842 v.add_abort("Assert %s failed", id.to_s)
843 end
844 v.seq = seq_old
845 return null
846 end
847 end
848
849 redef class AVarExpr
850 redef fun generate_icode(v)
851 do
852 return v.variable(variable)
853 end
854 end
855
856 redef class AVarAssignExpr
857 redef fun generate_icode(v)
858 do
859 var e = v.generate_expr(n_value)
860 v.add_assignment(v.variable(variable), e)
861 return null
862 end
863 end
864
865 redef class AVarReassignExpr
866 redef fun generate_icode(v)
867 do
868 var e1 = v.variable(variable)
869 var e2 = v.generate_expr(n_value)
870 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
871 v.add_assignment(e1, e3)
872 return null
873 end
874 end
875
876 redef class ASelfExpr
877 redef fun generate_icode(v)
878 do
879 return v.variable(variable)
880 end
881 end
882
883 redef class AIfexprExpr
884 redef fun generate_icode(v)
885 do
886 # Process condition
887 var iif = new IIf(v.generate_expr(n_expr))
888 v.stmt(iif)
889 var seq_old = v.seq
890
891 # Prepare result
892 var reg = v.new_register(stype)
893
894 # Process 'then'
895 v.seq = iif.then_seq
896 v.add_assignment(reg, v.generate_expr(n_then))
897
898 # Process 'else'
899 v.seq = iif.else_seq
900 v.add_assignment(reg, v.generate_expr(n_else))
901
902 v.seq = seq_old
903 return reg
904 end
905 end
906
907 redef class AEeExpr
908 redef fun generate_icode(v)
909 do
910 var e = v.generate_expr(n_expr)
911 var e2 = v.generate_expr(n_expr2)
912 return v.expr(new IIs(e, e2), stype)
913 end
914 end
915
916 redef class AOrExpr
917 redef fun generate_icode(v)
918 do
919 # Prepare result
920 var reg = v.new_register(stype)
921
922 # Process left operand (in a if/then)
923 var iif = new IIf(v.generate_expr(n_expr))
924 v.stmt(iif)
925 var seq_old = v.seq
926 v.seq = iif.then_seq
927 v.add_assignment(reg, v.lit_true_reg)
928
929 # Process right operand (in the else)
930 v.seq = iif.else_seq
931 v.add_assignment(reg, v.generate_expr(n_expr2))
932
933 v.seq = seq_old
934 return reg
935 end
936 end
937
938 redef class AAndExpr
939 redef fun generate_icode(v)
940 do
941 # Prepare result
942 var reg = v.new_register(stype)
943
944 # Process left operand (in a if/else)
945 var iif = new IIf(v.generate_expr(n_expr))
946 v.stmt(iif)
947 var seq_old = v.seq
948 v.seq = iif.else_seq
949 v.add_assignment(reg, v.lit_false_reg)
950
951 # Process right operand (in the then)
952 v.seq = iif.then_seq
953 v.add_assignment(reg, v.generate_expr(n_expr2))
954
955 v.seq = seq_old
956 return reg
957 end
958 end
959
960 redef class ANotExpr
961 redef fun generate_icode(v)
962 do
963 var e = v.generate_expr(n_expr)
964 return v.expr(new INot(e), stype)
965 end
966 end
967
968 redef class AIsaExpr
969 redef fun generate_icode(v)
970 do
971 var e = v.generate_expr(n_expr)
972 return v.expr(new ITypeCheck(e, n_type.stype), stype)
973 end
974 end
975
976 redef class AAsCastExpr
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 AAsNotnullExpr
986 redef fun generate_icode(v)
987 do
988 var e = v.generate_expr(n_expr)
989 v.add_type_cast(e, stype)
990 return e
991 end
992 end
993
994 redef class ATrueExpr
995 redef fun generate_icode(v)
996 do
997 return v.lit_true_reg
998 end
999 end
1000
1001 redef class AFalseExpr
1002 redef fun generate_icode(v)
1003 do
1004 return v.lit_false_reg
1005 end
1006 end
1007
1008 redef class AIntExpr
1009 redef fun generate_icode(v)
1010 do
1011 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
1012 end
1013 end
1014
1015 redef class AFloatExpr
1016 redef fun generate_icode(v)
1017 do
1018 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
1019 end
1020 end
1021
1022 redef class ACharExpr
1023 redef fun generate_icode(v)
1024 do
1025 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
1026 end
1027 end
1028
1029 redef class AStringFormExpr
1030 redef fun generate_icode(v)
1031 do
1032 compute_string_infos
1033 var old_seq = v.seq
1034 var ionce = new IOnce
1035 var reg = v.expr(ionce, stype)
1036 v.seq = ionce.body
1037 var ns = v.expr(new INative("BOX_NativeString(\"{_cstring.as(not null)}\")", null), v.visitor.type_nativestring)
1038 var ni = v.expr(new INative("TAG_Int({_cstring_length.as(not null)})", null), v.visitor.type_int)
1039 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
1040 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
1041 v.add_assignment(reg, e)
1042 v.seq = old_seq
1043 return reg
1044 end
1045
1046 # The raw string value
1047 protected fun string_text: String is abstract
1048
1049 # The string in a C native format
1050 protected var _cstring: nullable String
1051
1052 # The string length in bytes
1053 protected var _cstring_length: nullable Int
1054
1055 # Compute _cstring and _cstring_length using string_text
1056 protected fun compute_string_infos
1057 do
1058 var len = 0
1059 var str = string_text
1060 var res = new Buffer
1061 var i = 0
1062 while i < str.length do
1063 var c = str[i]
1064 if c == '\\' then
1065 i = i + 1
1066 var c2 = str[i]
1067 if c2 != '{' and c2 != '}' then
1068 res.add(c)
1069 end
1070 c = c2
1071 end
1072 len = len + 1
1073 res.add(c)
1074 i = i + 1
1075 end
1076 _cstring = res.to_s
1077 _cstring_length = len
1078 end
1079 end
1080
1081 redef class AStringExpr
1082 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1083 end
1084 redef class AStartStringExpr
1085 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1086 end
1087 redef class AMidStringExpr
1088 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1089 end
1090 redef class AEndStringExpr
1091 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1092 end
1093
1094 redef class ASuperstringExpr
1095 redef fun generate_icode(v)
1096 do
1097 var array = v.add_new_array(atype, n_exprs.length)
1098 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
1099 for ne in n_exprs do
1100 var e = v.generate_expr(ne)
1101 if ne.stype != stype then
1102 e = v.expr(new ICall(prop_to_s, [e]), stype)
1103 end
1104 v.add_call_array_add(array, e)
1105 end
1106 return v.expr(new ICall(prop_to_s, [array]), stype)
1107 end
1108 end
1109
1110 redef class ANullExpr
1111 redef fun generate_icode(v)
1112 do
1113 return v.lit_null_reg
1114 end
1115 end
1116
1117 redef class AArrayExpr
1118 redef fun generate_icode(v)
1119 do
1120 var recv = v.add_new_array(stype, n_exprs.length)
1121 for ne in n_exprs do
1122 var e = v.generate_expr(ne)
1123 v.add_call_array_add(recv, e)
1124 end
1125 return recv
1126 end
1127 end
1128
1129 redef class ACrangeExpr
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 "init".to_symbol)
1135 return v.expr(new INew(stype, prop, [e, e2]), stype)
1136 end
1137 end
1138
1139 redef class AOrangeExpr
1140 redef fun generate_icode(v)
1141 do
1142 var e = v.generate_expr(n_expr)
1143 var e2 = v.generate_expr(n_expr2)
1144 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1145 return v.expr(new INew(stype, prop, [e, e2]), stype)
1146 end
1147 end
1148
1149 redef class ASuperExpr
1150 redef fun generate_icode(v)
1151 do
1152 var arity = v.iroutine.params.length - 1
1153 if init_in_superclass != null then
1154 arity = init_in_superclass.signature.arity
1155 end
1156 var args = new Array[IRegister].with_capacity(arity + 1)
1157 args.add(v.iroutine.params[0])
1158 if n_args.length != arity then
1159 for i in [0..arity[ do
1160 args.add(v.iroutine.params[i + 1])
1161 end
1162 else
1163 for na in n_args do
1164 args.add(v.generate_expr(na))
1165 end
1166 end
1167 var p = init_in_superclass
1168 if p != null then
1169 var rtype = p.signature.return_type
1170 if rtype != null then
1171 return v.expr(new ICall(p, args), rtype)
1172 else
1173 v.stmt(new ICall(p, args))
1174 return null
1175 end
1176 else
1177 p = prop
1178 var rtype = p.signature.return_type
1179 if rtype == null then
1180 v.stmt(new ISuper(p, args))
1181 return null
1182 else
1183 return v.expr(new ISuper(p, args), rtype)
1184 end
1185 end
1186 end
1187 end
1188
1189 redef class AAttrExpr
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 return v.add_attr_read(prop, e)
1195 end
1196 end
1197
1198 redef class AAttrAssignExpr
1199 redef fun generate_icode(v)
1200 do
1201 var e = v.generate_expr(n_expr)
1202 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1203 var e2 = v.generate_expr(n_value)
1204 v.stmt(new IAttrWrite(prop, e, e2))
1205 return null
1206 end
1207 end
1208 redef class AAttrReassignExpr
1209 redef fun generate_icode(v)
1210 do
1211 var e1 = v.generate_expr(n_expr)
1212 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1213 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1214 var e3 = v.generate_expr(n_value)
1215 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1216 v.stmt(new IAttrWrite(prop, e1, e4))
1217 return null
1218 end
1219 end
1220
1221 redef class AIssetAttrExpr
1222 redef fun generate_icode(v)
1223 do
1224 var e = v.generate_expr(n_expr)
1225 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1226 return v.expr(new IAttrIsset(prop, e), stype)
1227 end
1228 end
1229
1230 redef class AAbsAbsSendExpr
1231 # Compile each argument and add them to the array
1232 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1233 do
1234 var par_arity = signature.arity
1235 var par_vararg = signature.vararg_rank
1236 var raw_args = raw_arguments
1237 var raw_arity = raw_args.length
1238 var arg_idx = 0
1239 for par_idx in [0..par_arity[ do
1240 var a: AExpr
1241 var par_type = signature[par_idx]
1242 if par_idx == par_vararg then
1243 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1244 for i in [0..(raw_arity-par_arity)] do
1245 a = raw_args[arg_idx]
1246 v.add_call_array_add(arr, v.generate_expr(a))
1247 arg_idx = arg_idx + 1
1248 end
1249 args.add(arr)
1250 else
1251 a = raw_args[arg_idx]
1252 args.add(v.generate_expr(a))
1253 arg_idx = arg_idx + 1
1254 end
1255 end
1256 end
1257 end
1258
1259 redef class ASendExpr
1260 redef fun generate_icode(v)
1261 do
1262 var recv = v.generate_expr(n_expr)
1263 var args = new Array[IRegister]
1264 args.add(recv)
1265 var prop = prop
1266 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1267 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1268 var r2: nullable IRegister # The raw result of the call
1269
1270 # Prepare closures
1271 var seq_old = v.seq
1272 var closcns: nullable Array[nullable IClosureDef] = null
1273 if not prop_signature.closures.is_empty then
1274 var rtype = prop_signature.return_type
1275 if rtype != null then
1276 r = v.new_register(rtype)
1277 end
1278 var seq = new ISeq
1279 v.stmt(seq)
1280 v.seq = seq
1281 closcns = new Array[nullable IClosureDef]
1282 var cdarity = 0
1283 if closure_defs != null then cdarity = closure_defs.length
1284 var closure_defs = closure_defs
1285 for mmc in prop_signature.closures do
1286 var found = false
1287 var name = mmc.name
1288 if closure_defs != null then
1289 for cd in closure_defs do
1290 if cd.n_id.to_symbol != name then continue
1291 assert found == false
1292 found = true
1293 cd.escapable.break_seq = seq
1294 cd.escapable.break_value = r
1295 var cn = cd.generate_iclosuredef(v)
1296 closcns.add(cn)
1297 end
1298 end
1299 if not found then
1300 closcns.add(null)
1301 end
1302 end
1303 end
1304
1305 r2 = v.add_call(prop, args, closcns)
1306
1307 # Closure work
1308 if not prop_signature.closures.is_empty then
1309 if r != null and r2 != null then v.add_assignment(r, r2)
1310 v.seq = seq_old
1311 else
1312 r = r2
1313 end
1314
1315 if prop.global.is_init then
1316 v.invoke_super_init_calls_after(prop)
1317 end
1318 return r
1319 end
1320 end
1321
1322 redef class ASendReassignExpr
1323 redef fun generate_icode(v)
1324 do
1325 var recv = v.generate_expr(n_expr)
1326 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1327 var args = new Array[IRegister]
1328 args.add(recv)
1329 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1330
1331 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1332 var e3 = v.generate_expr(n_value)
1333 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1334 var args2 = args.to_a
1335 args2.add(e4)
1336 v.stmt(new ICall(prop, args2))
1337 return null
1338 end
1339 end
1340
1341 redef class ANewExpr
1342 redef fun generate_icode(v)
1343 do
1344 var args = new Array[IRegister]
1345 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1346 return v.expr(new INew(stype, prop, args), stype)
1347 end
1348 end
1349
1350 redef class AProxyExpr
1351 redef fun generate_icode(v)
1352 do
1353 return v.generate_expr(n_expr)
1354 end
1355 end
1356
1357 redef class AOnceExpr
1358 redef fun generate_icode(v)
1359 do
1360 var ionce = new IOnce
1361 var reg = v.expr(ionce, stype)
1362 var old_seq = v.seq
1363 v.seq = ionce.body
1364
1365 var e = v.generate_expr(n_expr)
1366 v.add_assignment(reg, e)
1367
1368 v.seq = old_seq
1369 return reg
1370 end
1371 end
1372
1373
1374 redef class AClosureDef
1375 var _iclosure_def: nullable IClosureDef
1376
1377 fun generate_iclosuredef(v: A2IContext): IClosureDef
1378 do
1379 # Prepare signature
1380 var args = new Array[IRegister]
1381 var sig = closure.signature
1382 for i in [0..sig.arity[ do
1383 args.add(v.new_register(sig[i]))
1384 end
1385 var ret: nullable IRegister = null
1386 var rtype = sig.return_type
1387 if rtype != null then
1388 ret = v.new_register(rtype)
1389 end
1390
1391 var iclos = new IClosureDef(args, ret)
1392 iclos.location = location
1393
1394 # Prepare env
1395 var seq_old = v.seq
1396 v.seq = iclos.body
1397 escapable.continue_seq = iclos.body
1398 escapable.continue_value = iclos.result
1399
1400 # Assign parameters
1401 for i in [0..variables.length[ do
1402 var res = v.variable(variables[i])
1403 v.add_assignment(res, iclos.params[i])
1404 end
1405
1406 v.generate_stmt(n_expr)
1407
1408 # Add a final break in case of break block witout value
1409 if closure.is_break and escapable.break_value == null then
1410 v.add_escape(escapable.break_seq.as(not null))
1411 end
1412
1413 v.seq = seq_old
1414 _iclosure_def = iclos
1415 return iclos
1416 end
1417 end
1418
1419 redef class AClosureCallExpr
1420 redef fun generate_icode(v)
1421 do
1422 # Geneate arguments
1423 var args = new Array[IRegister]
1424 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1425
1426 # Prepare icall
1427 var closdecl = v.closurevariables[variable]
1428 var icall = new IClosCall(closdecl, args)
1429 var seq_old = v.seq
1430
1431 # Fill break of ical
1432 if n_closure_defs.length == 1 then do
1433 var iseq = new ISeq
1434 icall.break_seq = iseq
1435 v.seq = iseq
1436 v.generate_stmt(n_closure_defs.first.n_expr)
1437 v.seq = seq_old
1438 end
1439
1440 # Prepare in case of default block
1441 var iif: nullable IIf = null # The iif of default block
1442 var closdecl_default = closdecl.default # The default (if any)
1443 if closdecl_default != null then
1444 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1445 v.stmt(iif)
1446 v.seq = iif.then_seq
1447 end
1448
1449 # Add the icall
1450 var r2: nullable IRegister = null # the result of the icall
1451 var rtype = variable.closure.signature.return_type
1452 if rtype == null then
1453 v.stmt(icall)
1454 else
1455 r2 = v.expr(icall, rtype)
1456 end
1457
1458 # Process the case of default block
1459 var r: nullable IRegister = null # the real result
1460 if closdecl_default != null then
1461 assert iif != null
1462 if r2 != null then
1463 assert rtype != null
1464 r = v.new_register(rtype)
1465 v.add_assignment(r, r2)
1466 end
1467 v.seq = iif.else_seq
1468 var r3 = v.inline_routine(closdecl_default, args, null)
1469 if r != null then
1470 assert r3 != null
1471 v.add_assignment(r, r3)
1472 end
1473 v.seq = seq_old
1474 else
1475 r = r2
1476 end
1477 return r
1478 end
1479 end