Make 'self' a standard parameter (ParamVariable)
[nit.git] / src / compiling / compiling_methods.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 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 # Compile method bodies, statments and expressions to C.
18 package compiling_methods
19
20 import compiling_base
21 private import syntax
22
23 redef class CompilerVisitor
24 # Compile a statment node
25 meth compile_stmt(n: PExpr)
26 do
27 n.prepare_compile_stmt(self)
28 var i = cfc._variable_index
29 n.compile_stmt(self)
30 cfc._variable_index = i
31 end
32
33 # Compile is expression node
34 meth compile_expr(n: PExpr): String
35 do
36 var i = cfc._variable_index
37 var s = n.compile_expr(self)
38 cfc._variable_index = i
39 if s[0] == ' ' then
40 return s
41 end
42 var v = cfc.get_var
43 add_assignment(v, s)
44 return v
45 end
46
47 # Ensure that a c expression is a var
48 meth ensure_var(s: String): String
49 do
50 if s.substring(0,3) == "variable" then
51 return s
52 end
53 var v = cfc.get_var
54 add_assignment(v, s)
55 return v
56 end
57
58 # Add a assignment between a variable and an expression
59 meth add_assignment(v: String, s: String)
60 do
61 if v != s then
62 add_instr("{v} = {s};")
63 end
64 end
65
66 readable writable attr _cfc: CFunctionContext
67
68 readable writable attr _nmc: NitMethodContext
69
70 # Generate an fprintf to display an error location
71 meth printf_locate_error(node: PNode): String
72 do
73 var s = "fprintf(stderr, \""
74 if nmc != null then s.append(" in %s")
75 s.append(" (%s:%d)\\n\", ")
76 if nmc != null then s.append("LOCATE_{nmc.method.cname}, ")
77 s.append("LOCATE_{module.name}, {node.line_number});")
78 return s
79 end
80
81 redef init(module: MMSrcModule)
82 do
83 super
84 end
85
86 meth invoke_super_init_calls_after(start_prop: MMMethod)
87 do
88 var n = nmc.method.node
89 assert n isa AConcreteInitPropdef
90
91 if n.super_init_calls.is_empty then return
92 var i = 0
93 var j = 0
94 #var s = ""
95 if start_prop != null then
96 while n.super_init_calls[i] != start_prop do
97 #s.append(" {n.super_init_calls[i]}")
98 i += 1
99 end
100 i += 1
101 #s.append(" {start_prop}")
102
103 while n.explicit_super_init_calls[j] != start_prop do
104 j += 1
105 end
106 j += 1
107 end
108 var stop_prop: MMMethod = null
109 if j < n.explicit_super_init_calls.length then
110 stop_prop = n.explicit_super_init_calls[j]
111 end
112 var l = n.super_init_calls.length
113 #s.append(" [")
114 while i < l do
115 var p = n.super_init_calls[i]
116 if p == stop_prop then break
117 var cargs = new Array[String]
118 if p.signature.arity == 0 then
119 cargs.add(cfc.varname(nmc.method_params[0]))
120 else
121 for va in nmc.method_params do
122 cargs.add(cfc.varname(va))
123 end
124 end
125 #s.append(" {p}")
126 p.compile_call(self, cargs)
127 i += 1
128 end
129 #s.append(" ]")
130 #while i < l do
131 # s.append(" {n.super_init_calls[i]}")
132 # i += 1
133 #end
134 #if stop_prop != null then s.append(" (stop at {stop_prop})")
135 #n.printl("implicit calls in {n.method}: {s}")
136 end
137 end
138
139 # A C function currently written
140 class CFunctionContext
141 readable attr _visitor: CompilerVisitor
142
143 # Next available variable number
144 attr _variable_index: Int = 0
145
146 # Total number of variable
147 attr _variable_index_max: Int = 0
148
149 # Association between nit variable and the corrsponding c variable
150 attr _varnames: Map[Variable, String] = new HashMap[Variable, String]
151
152 meth varname(v: Variable): String
153 do
154 return _varnames[v]
155 end
156
157 # Return the next available variable
158 meth get_var: String
159 do
160 var v = variable(_variable_index)
161 _variable_index = _variable_index + 1
162 if _variable_index > _variable_index_max then
163 _variable_index_max = _variable_index
164 end
165 return v
166 end
167
168 meth register_variable(v: Variable): String
169 do
170 var s = get_var
171 _varnames[v] = "variable[{_variable_index-1}]"
172 return s
173 end
174
175 # Return the ith variable
176 protected meth variable(i: Int): String
177 do
178 return "variable[{i}]"
179 end
180
181 # Mark the variable available
182 meth free_var(v: String)
183 do
184 # FIXME: So ugly..
185 if v == variable(_variable_index-1) then
186 _variable_index = _variable_index - 1
187 end
188 end
189
190 # Generate the local variable declarations
191 # To use at the end of the C function once all variables are known
192 meth generate_var_decls
193 do
194 if _variable_index_max > 0 then
195 visitor.add_decl("val_t variable[{_variable_index_max}];")
196 else
197 visitor.add_decl("val_t *variable = NULL;")
198 end
199 end
200
201 init(v: CompilerVisitor) do _visitor = v
202 end
203
204 # A Nit method currenlty compiled
205 class NitMethodContext
206 # Current method compiled
207 readable attr _method: MMSrcMethod
208
209 # Is a "return" found in the method body
210 readable writable attr _has_return: Bool = false
211
212 # Association between parameters and the corresponding variables
213 readable writable attr _method_params: Array[ParamVariable]
214
215 # Where a nit return must branch
216 readable writable attr _return_label: String
217
218 # Where a nit break must branch
219 readable writable attr _break_label: String
220
221 # Where a nit continue must branch
222 readable writable attr _continue_label: String
223
224 # Variable where a functionnal nit return must store its value
225 readable writable attr _return_value: String
226
227 init(method: MMSrcMethod)
228 do
229 _method = method
230 end
231 end
232
233 ###############################################################################
234
235 redef class MMMethod
236 # Compile a call on self for given arguments
237 # Most calls are compiled with a table access,
238 # primitive calles are inlined
239 # == and != are guarded and possibly inlined
240 meth compile_call(v: CompilerVisitor, cargs: Array[String]): String
241 do
242 var i = self
243 if i isa MMSrcMethod then
244 if i isa MMMethSrcMethod and i.node isa AInternMethPropdef or
245 (i.local_class.name == (once "Array".to_symbol) and name == (once "[]".to_symbol))
246 then
247 var e = i.do_compile_inside(v, cargs)
248 return e
249 end
250 end
251 var ee = once "==".to_symbol
252 var ne = once "!=".to_symbol
253 if name == ne then
254 var eqp = signature.recv.local_class.select_method(ee)
255 var eqcall = eqp.compile_call(v, cargs)
256 return "TAG_Bool(!UNTAG_Bool({eqcall}))"
257 end
258 if global.is_init then
259 cargs = cargs.to_a
260 cargs.add("init_table /*YYY*/")
261 end
262
263 var m = "(({cname}_t)CALL({cargs[0]},{global.color_id}))"
264 var vcall = "{m}({cargs.join(", ")}) /*{local_class}::{name}*/"
265 if name == ee then
266 vcall = "UNTAG_Bool({vcall})"
267 var obj = once "Object".to_symbol
268 if i.local_class.name == obj then
269 vcall = "(({m}=={i.cname})?(IS_EQUAL_NN({cargs[0]},{cargs[1]})):({vcall}))"
270 end
271 vcall = "TAG_Bool(({cargs.first} == {cargs[1]}) || (({cargs.first} != NIT_NULL) && {vcall}))"
272 end
273 if signature.return_type != null then
274 return vcall
275 else
276 v.add_instr(vcall + ";")
277 return null
278 end
279 end
280
281 # Compile a call as constructor with given args
282 meth compile_constructor_call(v: CompilerVisitor, recvtype: MMType, cargs: Array[String]): String
283 do
284 var recv = v.cfc.get_var
285 v.add_instr("{recv} = NEW_{recvtype.local_class}_{global.intro.cname}({cargs.join(", ")}); /*new {recvtype}*/")
286 return recv
287 end
288
289 # Compile a call as call-next-method on self with given args
290 meth compile_super_call(v: CompilerVisitor, cargs: Array[String]): String
291 do
292 var m = "(({cname}_t)CALL({cargs[0]},{color_id_for_super}))"
293 var vcall = "{m}({cargs.join(", ")}) /*super {local_class}::{name}*/"
294 return vcall
295 end
296 end
297
298 redef class MMAttribute
299 # Compile an acces on selffor a given reciever.
300 # Result is a valid C left-value for assigment
301 meth compile_access(v: CompilerVisitor, recv: String): String
302 do
303 return "{global.attr_access}({recv}) /*{local_class}::{name}*/"
304 end
305 end
306
307 redef class MMLocalProperty
308 # Compile the property as a C property
309 meth compile_property_to_c(v: CompilerVisitor) do end
310 end
311
312 redef class MMSrcMethod
313 # Compile and declare the signature to C
314 protected meth decl_csignature(v: CompilerVisitor, args: Array[String]): String
315 do
316 var params = new Array[String]
317 var params_new: Array[String] = null
318 if global.is_init then
319 params_new = new Array[String]
320 end
321 params.add("val_t {args[0]}")
322 for i in [0..signature.arity[ do
323 var p = "val_t {args[i+1]}"
324 params.add(p)
325 if params_new != null then params_new.add(p)
326 end
327 if global.is_init then
328 params.add("int* init_table")
329 end
330 var ret: String
331 if signature.return_type != null then
332 ret = "val_t"
333 else
334 ret = "void"
335 end
336 var p = params.join(", ")
337 var s = "{ret} {cname}({p})"
338 v.add_decl("typedef {ret} (* {cname}_t)({p});")
339 v.add_decl(s + ";")
340 if params_new != null then
341 v.add_decl("val_t NEW_{cname}({params_new.join(", ")});")
342 end
343 return s
344 end
345
346 redef meth compile_property_to_c(v)
347 do
348 v.cfc = new CFunctionContext(v)
349
350 var args = new Array[String]
351 args.add(" self")
352 for i in [0..signature.arity[ do
353 args.add(" param{i}")
354 end
355 var cs = decl_csignature(v, args)
356 v.add_decl("#define LOCATE_{cname} \"{full_name}\"")
357
358 v.add_instr("{cs} \{")
359 v.indent
360 var ctx_old = v.ctx
361 v.ctx = new CContext
362
363 var ln = 0
364 var s = self
365 if s.node != null then ln = s.node.line_number
366 v.add_decl("struct trace_t trace = \{NULL, NULL, {ln}, LOCATE_{cname}};")
367 v.add_instr("trace.prev = tracehead; tracehead = &trace;")
368 v.add_instr("trace.file = LOCATE_{module.name};")
369 var s = do_compile_inside(v, args)
370 v.add_instr("tracehead = trace.prev;")
371 if s == null then
372 v.add_instr("return;")
373 else
374 v.add_instr("return {s};")
375 end
376
377 v.cfc.generate_var_decls
378
379 ctx_old.append(v.ctx)
380 v.ctx = ctx_old
381 v.unindent
382 v.add_instr("}")
383 end
384
385 # Compile the method body inline
386 meth do_compile_inside(v: CompilerVisitor, params: Array[String]): String is abstract
387 end
388
389 redef class MMReadImplementationMethod
390 redef meth do_compile_inside(v, params)
391 do
392 return node.prop.compile_access(v, params[0])
393 end
394 end
395
396 redef class MMWriteImplementationMethod
397 redef meth do_compile_inside(v, params)
398 do
399 v.add_assignment(node.prop.compile_access(v, params[0]), params[1])
400 return null
401 end
402 end
403
404 redef class MMMethSrcMethod
405 redef meth do_compile_inside(v, params)
406 do
407 return node.do_compile_inside(v, self, params)
408 end
409 end
410
411 redef class MMImplicitInit
412 redef meth do_compile_inside(v, params)
413 do
414 var f = params.length - unassigned_attributes.length
415 var recv = params.first
416 for sp in super_inits do
417 assert sp isa MMMethod
418 var args_recv = [recv]
419 if sp == super_init then
420 var args = new Array[String].with_capacity(f)
421 args.add(recv)
422 for i in [1..f[ do
423 args.add(params[i])
424 end
425 sp.compile_call(v, args)
426 else
427 sp.compile_call(v, args_recv)
428 end
429 end
430 for i in [f..params.length[ do
431 var attribute = unassigned_attributes[i-f]
432 v.add_assignment(attribute.compile_access(v, recv), params[i])
433 end
434 return null
435 end
436 end
437
438 redef class MMType
439 # Compile a subtype check to self
440 # Return a NIT Bool
441 meth compile_cast(v: CompilerVisitor, recv: String): String
442 do
443 # Fixme: handle formaltypes
444 var g = local_class.global
445 return "TAG_Bool(({recv}==NIT_NULL) || VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {self}*/"
446 end
447
448 # Compile a cast assertion
449 meth compile_type_check(v: CompilerVisitor, recv: String, n: PNode)
450 do
451 # Fixme: handle formaltypes
452 var g = local_class.global
453 v.add_instr("if (({recv}!=NIT_NULL) && !VAL_ISA({recv}, {g.color_id}, {g.id_id})) \{ fprintf(stderr, \"Cast failled\"); {v.printf_locate_error(n)} nit_exit(1); } /*cast {self}*/;")
454 end
455 end
456
457 ###############################################################################
458
459 redef class AMethPropdef
460 # Compile the method body
461 meth do_compile_inside(v: CompilerVisitor, method: MMSrcMethod, params: Array[String]): String is abstract
462 end
463
464 redef class AConcreteMethPropdef
465 redef meth do_compile_inside(v, method, params)
466 do
467 var old_nmc = v.nmc
468 v.nmc = new NitMethodContext(method)
469
470 var cname = v.cfc.register_variable(self_var)
471 v.add_assignment(cname, params[0])
472 v.nmc.method_params = [self_var]
473
474 var orig_meth: MMLocalProperty = method.global.intro
475 var orig_sig = orig_meth.signature_for(method.signature.recv)
476 if n_signature != null then
477 var sig = n_signature
478 assert sig isa ASignature
479 for ap in sig.n_params do
480 var cname = v.cfc.register_variable(ap.variable)
481 v.nmc.method_params.add(ap.variable)
482 var orig_type = orig_sig[ap.position]
483 if not orig_type < ap.variable.stype then
484 # FIXME: do not test always
485 # FIXME: handle formal types
486 v.add_instr("/* check if p<{ap.variable.stype} with p:{orig_type} */")
487 ap.variable.stype.compile_type_check(v, params[ap.position + 1], ap)
488 end
489 v.add_assignment(cname, params[ap.position + 1])
490 end
491 end
492
493 var itpos: String = null
494 if self isa AConcreteInitPropdef then
495 itpos = "VAL2OBJ({params[0]})->vft[{method.local_class.global.init_table_pos_id}].i"
496 # v.add_instr("printf(\"{method.full_name}: inittable[%d] = %d\\n\", {itpos}, init_table[{itpos}]);")
497 v.add_instr("if (init_table[{itpos}]) return;")
498 end
499
500 v.nmc.return_label = "return_label{v.new_number}"
501 if method.signature.return_type != null then
502 v.nmc.return_value = v.cfc.get_var
503 v.cfc.free_var(v.nmc.return_value)
504 else
505 v.nmc.return_value = null
506 end
507 if self isa AConcreteInitPropdef then
508 v.invoke_super_init_calls_after(null)
509 end
510 if n_block != null then
511 v.compile_stmt(n_block)
512 end
513 if v.nmc.has_return then
514 v.add_instr("{v.nmc.return_label}: while(false);")
515 end
516 if self isa AConcreteInitPropdef then
517 v.add_instr("init_table[{itpos}] = 1;")
518 end
519 var ret = v.nmc.return_value
520
521 v.nmc = old_nmc
522 return ret
523 end
524 end
525
526 redef class ADeferredMethPropdef
527 redef meth do_compile_inside(v, method, params)
528 do
529 v.add_instr("fprintf(stderr, \"Deferred method %s called\");")
530 v.add_instr(v.printf_locate_error(self))
531 v.add_instr("nit_exit(1);")
532 if method.signature.return_type != null then
533 return("NIT_NULL")
534 else
535 return null
536 end
537 end
538 end
539
540 redef class AExternMethPropdef
541 redef meth do_compile_inside(v, method, params)
542 do
543 var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
544 if n_extern != null then
545 ename = n_extern.text
546 ename = ename.substring(1, ename.length-2)
547 end
548 var sig = method.signature
549 if params.length != sig.arity + 1 then
550 printl("par:{params.length} sig:{sig.arity}")
551 end
552 var args = new Array[String]
553 args.add(sig.recv.unboxtype(params[0]))
554 for i in [0..sig.arity[ do
555 args.add(sig[i].unboxtype(params[i+1]))
556 end
557 var s = "{ename}({args.join(", ")})"
558 if sig.return_type != null then
559 return sig.return_type.boxtype(s)
560 else
561 v.add_instr("{s};")
562 return null
563 end
564 end
565 end
566
567 redef class AInternMethPropdef
568 redef meth do_compile_inside(v, method, p)
569 do
570 var c = method.local_class.name
571 var n = method.name
572 var s: String = null
573 if c == once "Int".to_symbol then
574 if n == once "object_id".to_symbol then
575 s = "{p[0]}"
576 else if n == once "unary -".to_symbol then
577 s = "TAG_Int(-UNTAG_Int({p[0]}))"
578 else if n == once "output".to_symbol then
579 v.add_instr("printf(\"%d\\n\", UNTAG_Int({p[0]}));")
580 else if n == once "ascii".to_symbol then
581 s = "TAG_Char(UNTAG_Int({p[0]}))"
582 else if n == once "succ".to_symbol then
583 s = "TAG_Int(UNTAG_Int({p[0]})+1)"
584 else if n == once "prec".to_symbol then
585 s = "TAG_Int(UNTAG_Int({p[0]})-1)"
586 else if n == once "to_f".to_symbol then
587 s = "BOX_Float((float)UNTAG_Int({p[0]}))"
588 else if n == once "+".to_symbol then
589 s = "TAG_Int(UNTAG_Int({p[0]})+UNTAG_Int({p[1]}))"
590 else if n == once "-".to_symbol then
591 s = "TAG_Int(UNTAG_Int({p[0]})-UNTAG_Int({p[1]}))"
592 else if n == once "*".to_symbol then
593 s = "TAG_Int(UNTAG_Int({p[0]})*UNTAG_Int({p[1]}))"
594 else if n == once "/".to_symbol then
595 s = "TAG_Int(UNTAG_Int({p[0]})/UNTAG_Int({p[1]}))"
596 else if n == once "%".to_symbol then
597 s = "TAG_Int(UNTAG_Int({p[0]})%UNTAG_Int({p[1]}))"
598 else if n == once "<".to_symbol then
599 s = "TAG_Bool(UNTAG_Int({p[0]})<UNTAG_Int({p[1]}))"
600 else if n == once ">".to_symbol then
601 s = "TAG_Bool(UNTAG_Int({p[0]})>UNTAG_Int({p[1]}))"
602 else if n == once "<=".to_symbol then
603 s = "TAG_Bool(UNTAG_Int({p[0]})<=UNTAG_Int({p[1]}))"
604 else if n == once ">=".to_symbol then
605 s = "TAG_Bool(UNTAG_Int({p[0]})>=UNTAG_Int({p[1]}))"
606 else if n == once "lshift".to_symbol then
607 s = "TAG_Int(UNTAG_Int({p[0]})<<UNTAG_Int({p[1]}))"
608 else if n == once "rshift".to_symbol then
609 s = "TAG_Int(UNTAG_Int({p[0]})>>UNTAG_Int({p[1]}))"
610 else if n == once "==".to_symbol then
611 s = "TAG_Bool(({p[0]})==({p[1]}))"
612 else if n == once "!=".to_symbol then
613 s = "TAG_Bool(({p[0]})!=({p[1]}))"
614 end
615 else if c == once "Float".to_symbol then
616 if n == once "object_id".to_symbol then
617 s = "TAG_Int((bigint)UNBOX_Float({p[0]}))"
618 else if n == once "unary -".to_symbol then
619 s = "BOX_Float(-UNBOX_Float({p[0]}))"
620 else if n == once "output".to_symbol then
621 v.add_instr("printf(\"%f\\n\", UNBOX_Float({p[0]}));")
622 else if n == once "to_i".to_symbol then
623 s = "TAG_Int((bigint)UNBOX_Float({p[0]}))"
624 else if n == once "+".to_symbol then
625 s = "BOX_Float(UNBOX_Float({p[0]})+UNBOX_Float({p[1]}))"
626 else if n == once "-".to_symbol then
627 s = "BOX_Float(UNBOX_Float({p[0]})-UNBOX_Float({p[1]}))"
628 else if n == once "*".to_symbol then
629 s = "BOX_Float(UNBOX_Float({p[0]})*UNBOX_Float({p[1]}))"
630 else if n == once "/".to_symbol then
631 s = "BOX_Float(UNBOX_Float({p[0]})/UNBOX_Float({p[1]}))"
632 else if n == once "<".to_symbol then
633 s = "TAG_Bool(UNBOX_Float({p[0]})<UNBOX_Float({p[1]}))"
634 else if n == once ">".to_symbol then
635 s = "TAG_Bool(UNBOX_Float({p[0]})>UNBOX_Float({p[1]}))"
636 else if n == once "<=".to_symbol then
637 s = "TAG_Bool(UNBOX_Float({p[0]})<=UNBOX_Float({p[1]}))"
638 else if n == once ">=".to_symbol then
639 s = "TAG_Bool(UNBOX_Float({p[0]})>=UNBOX_Float({p[1]}))"
640 end
641 else if c == once "Char".to_symbol then
642 if n == once "object_id".to_symbol then
643 s = "TAG_Int(UNTAG_Char({p[0]}))"
644 else if n == once "unary -".to_symbol then
645 s = "TAG_Char(-UNTAG_Char({p[0]}))"
646 else if n == once "output".to_symbol then
647 v.add_instr("printf(\"%c\", (unsigned char)UNTAG_Char({p[0]}));")
648 else if n == once "ascii".to_symbol then
649 s = "TAG_Int((unsigned char)UNTAG_Char({p[0]}))"
650 else if n == once "succ".to_symbol then
651 s = "TAG_Char(UNTAG_Char({p[0]})+1)"
652 else if n == once "prec".to_symbol then
653 s = "TAG_Char(UNTAG_Char({p[0]})-1)"
654 else if n == once "to_i".to_symbol then
655 s = "TAG_Int(UNTAG_Char({p[0]})-'0')"
656 else if n == once "+".to_symbol then
657 s = "TAG_Char(UNTAG_Char({p[0]})+UNTAG_Char({p[1]}))"
658 else if n == once "-".to_symbol then
659 s = "TAG_Char(UNTAG_Char({p[0]})-UNTAG_Char({p[1]}))"
660 else if n == once "*".to_symbol then
661 s = "TAG_Char(UNTAG_Char({p[0]})*UNTAG_Char({p[1]}))"
662 else if n == once "/".to_symbol then
663 s = "TAG_Char(UNTAG_Char({p[0]})/UNTAG_Char({p[1]}))"
664 else if n == once "%".to_symbol then
665 s = "TAG_Char(UNTAG_Char({p[0]})%UNTAG_Char({p[1]}))"
666 else if n == once "<".to_symbol then
667 s = "TAG_Bool(UNTAG_Char({p[0]})<UNTAG_Char({p[1]}))"
668 else if n == once ">".to_symbol then
669 s = "TAG_Bool(UNTAG_Char({p[0]})>UNTAG_Char({p[1]}))"
670 else if n == once "<=".to_symbol then
671 s = "TAG_Bool(UNTAG_Char({p[0]})<=UNTAG_Char({p[1]}))"
672 else if n == once ">=".to_symbol then
673 s = "TAG_Bool(UNTAG_Char({p[0]})>=UNTAG_Char({p[1]}))"
674 else if n == once "==".to_symbol then
675 s = "TAG_Bool(({p[0]})==({p[1]}))"
676 else if n == once "!=".to_symbol then
677 s = "TAG_Bool(({p[0]})!=({p[1]}))"
678 end
679 else if c == once "Bool".to_symbol then
680 if n == once "object_id".to_symbol then
681 s = "TAG_Int(UNTAG_Bool({p[0]}))"
682 else if n == once "unary -".to_symbol then
683 s = "TAG_Bool(-UNTAG_Bool({p[0]}))"
684 else if n == once "output".to_symbol then
685 v.add_instr("(void)printf(UNTAG_Bool({p[0]})?\"true\\n\":\"false\\n\");")
686 else if n == once "ascii".to_symbol then
687 s = "TAG_Bool(UNTAG_Bool({p[0]}))"
688 else if n == once "to_i".to_symbol then
689 s = "TAG_Int(UNTAG_Bool({p[0]}))"
690 else if n == once "==".to_symbol then
691 s = "TAG_Bool(({p[0]})==({p[1]}))"
692 else if n == once "!=".to_symbol then
693 s = "TAG_Bool(({p[0]})!=({p[1]}))"
694 end
695 else if c == once "NativeArray".to_symbol then
696 if n == once "object_id".to_symbol then
697 s = "TAG_Int(UNBOX_NativeArray({p[0]}))"
698 else if n == once "[]".to_symbol then
699 s = "UNBOX_NativeArray({p[0]})[UNTAG_Int({p[1]})]"
700 else if n == once "[]=".to_symbol then
701 v.add_instr("UNBOX_NativeArray({p[0]})[UNTAG_Int({p[1]})]={p[2]};")
702 else if n == once "copy_to".to_symbol then
703 v.add_instr("(void)memcpy(UNBOX_NativeArray({p[1]}), UNBOX_NativeArray({p[0]}), UNTAG_Int({p[2]})*sizeof(val_t));")
704 end
705 else if c == once "NativeString".to_symbol then
706 if n == once "object_id".to_symbol then
707 s = "TAG_Int(UNBOX_NativeString({p[0]}))"
708 else if n == once "atoi".to_symbol then
709 s = "TAG_Int(atoi(UNBOX_NativeString({p[0]})))"
710 else if n == once "[]".to_symbol then
711 s = "TAG_Char(UNBOX_NativeString({p[0]})[UNTAG_Int({p[1]})])"
712 else if n == once "[]=".to_symbol then
713 v.add_instr("UNBOX_NativeString({p[0]})[UNTAG_Int({p[1]})]=UNTAG_Char({p[2]});")
714 else if n == once "copy_to".to_symbol then
715 v.add_instr("(void)memcpy(UNBOX_NativeString({p[1]})+UNTAG_Int({p[4]}), UNBOX_NativeString({p[0]})+UNTAG_Int({p[3]}), UNTAG_Int({p[2]}));")
716 end
717 else if n == once "object_id".to_symbol then
718 s = "TAG_Int((bigint){p[0]})"
719 else if n == once "sys".to_symbol then
720 s = "(G_sys)"
721 else if n == once "is_same_type".to_symbol then
722 s = "TAG_Bool((VAL2VFT({p[0]})==VAL2VFT({p[1]})))"
723 else if n == once "exit".to_symbol then
724 v.add_instr("exit(UNTAG_Int({p[1]}));")
725 else if n == once "calloc_array".to_symbol then
726 s = "BOX_NativeArray((val_t*)malloc((UNTAG_Int({p[1]}) * sizeof(val_t))))"
727 else if n == once "calloc_string".to_symbol then
728 s = "BOX_NativeString((char*)malloc((UNTAG_Int({p[1]}) * sizeof(char))))"
729
730 else
731 v.add_instr("fprintf(stderr, \"Intern {n}\\n\"); nit_exit(1);")
732 end
733 if method.signature.return_type != null and s == null then
734 s = "NIT_NULL /*stub*/"
735 end
736 return s
737 end
738 end
739
740 ###############################################################################
741
742 redef class PExpr
743 # Compile the node as an expression
744 # Only the visitor should call it
745 meth compile_expr(v: CompilerVisitor): String is abstract
746
747 # Prepare a call of node as a statement
748 # Only the visitor should call it
749 # It's used for local variable managment
750 meth prepare_compile_stmt(v: CompilerVisitor) do end
751
752 # Compile the node as a statement
753 # Only the visitor should call it
754 meth compile_stmt(v: CompilerVisitor) do printl("Error!")
755 end
756
757 redef class ABlockExpr
758 redef meth compile_stmt(v)
759 do
760 for n in n_expr do
761 v.compile_stmt(n)
762 end
763 end
764 end
765
766 redef class AVardeclExpr
767 redef meth prepare_compile_stmt(v)
768 do
769 v.cfc.register_variable(variable)
770 end
771
772 redef meth compile_stmt(v)
773 do
774 var cname = v.cfc.varname(variable)
775 if n_expr == null then
776 var t = variable.stype
777 v.add_assignment(cname, "{t.default_cvalue} /*decl variable {variable.name}*/")
778 else
779 var e = v.compile_expr(n_expr)
780 v.add_assignment(cname, e)
781 end
782 end
783 end
784
785 redef class AReturnExpr
786 redef meth compile_stmt(v)
787 do
788 v.nmc.has_return = true
789 if n_expr != null then
790 var e = v.compile_expr(n_expr)
791 v.add_assignment(v.nmc.return_value, e)
792 end
793 v.add_instr("goto {v.nmc.return_label};")
794 end
795 end
796
797 redef class ABreakExpr
798 redef meth compile_stmt(v)
799 do
800 v.add_instr("goto {v.nmc.break_label};")
801 end
802 end
803
804 redef class AContinueExpr
805 redef meth compile_stmt(v)
806 do
807 v.add_instr("goto {v.nmc.continue_label};")
808 end
809 end
810
811 redef class AAbortExpr
812 redef meth compile_stmt(v)
813 do
814 v.add_instr("fprintf(stderr, \"Aborted\"); {v.printf_locate_error(self)} nit_exit(1);")
815 end
816 end
817
818 redef class ADoExpr
819 redef meth compile_stmt(v)
820 do
821 if n_block != null then
822 v.compile_stmt(n_block)
823 end
824 end
825 end
826
827 redef class AIfExpr
828 redef meth compile_stmt(v)
829 do
830 var e = v.compile_expr(n_expr)
831 v.add_instr("if (UNTAG_Bool({e})) \{ /*if*/")
832 v.cfc.free_var(e)
833 if n_then != null then
834 v.indent
835 v.compile_stmt(n_then)
836 v.unindent
837 end
838 if n_else != null then
839 v.add_instr("} else \{ /*if*/")
840 v.indent
841 v.compile_stmt(n_else)
842 v.unindent
843 end
844 v.add_instr("}")
845 end
846 end
847
848 redef class AIfexprExpr
849 redef meth compile_expr(v)
850 do
851 var e = v.compile_expr(n_expr)
852 v.add_instr("if (UNTAG_Bool({e})) \{ /*if*/")
853 v.cfc.free_var(e)
854 v.indent
855 var e = v.ensure_var(v.compile_expr(n_then))
856 v.unindent
857 v.add_instr("} else \{ /*if*/")
858 v.cfc.free_var(e)
859 v.indent
860 var e2 = v.ensure_var(v.compile_expr(n_else))
861 v.add_assignment(e, e2)
862 v.unindent
863 v.add_instr("}")
864 return e
865 end
866 end
867
868 redef class AControlableBlock
869 meth compile_inside_block(v: CompilerVisitor) is abstract
870 redef meth compile_stmt(v)
871 do
872 var old_break_label = v.nmc.break_label
873 var old_continue_label = v.nmc.continue_label
874 var id = v.new_number
875 v.nmc.break_label = "break_{id}"
876 v.nmc.continue_label = "continue_{id}"
877
878 compile_inside_block(v)
879
880
881 v.nmc.break_label = old_break_label
882 v.nmc.continue_label = old_continue_label
883 end
884 end
885
886 redef class AWhileExpr
887 redef meth compile_inside_block(v)
888 do
889 v.add_instr("while (true) \{ /*while*/")
890 v.indent
891 var e = v.compile_expr(n_expr)
892 v.add_instr("if (!UNTAG_Bool({e})) break; /* while*/")
893 v.cfc.free_var(e)
894 if n_block != null then
895 v.compile_stmt(n_block)
896 end
897 v.add_instr("{v.nmc.continue_label}: while(0);")
898 v.unindent
899 v.add_instr("}")
900 v.add_instr("{v.nmc.break_label}: while(0);")
901 end
902 end
903
904 redef class AForExpr
905 redef meth compile_inside_block(v)
906 do
907 v.compile_stmt(n_vardecl)
908 end
909 end
910
911 redef class AForVardeclExpr
912 redef meth compile_stmt(v)
913 do
914 var e = v.compile_expr(n_expr)
915 var prop = n_expr.stype.local_class.select_method(once "iterator".to_symbol)
916 if prop == null then
917 printl("No iterator")
918 return
919 end
920 var ittype = prop.signature.return_type
921 v.cfc.free_var(e)
922 var iter = v.cfc.get_var
923 v.add_assignment(iter, prop.compile_call(v, [e]))
924 var prop2 = ittype.local_class.select_method(once "is_ok".to_symbol)
925 if prop2 == null then
926 printl("No is_ok")
927 return
928 end
929 var prop3 = ittype.local_class.select_method(once "item".to_symbol)
930 if prop3 == null then
931 printl("No item")
932 return
933 end
934 var prop4 = ittype.local_class.select_method(once "next".to_symbol)
935 if prop4 == null then
936 printl("No next")
937 return
938 end
939 v.add_instr("while (true) \{ /*for*/")
940 v.indent
941 var ok = v.cfc.get_var
942 v.add_assignment(ok, prop2.compile_call(v, [iter]))
943 v.add_instr("if (!UNTAG_Bool({ok})) break; /*for*/")
944 v.cfc.free_var(ok)
945 var e = prop3.compile_call(v, [iter])
946 e = v.ensure_var(e)
947 var cname = v.cfc.register_variable(variable)
948 v.add_assignment(cname, e)
949 var par = parent
950 assert par isa AForExpr
951 var n_block = par.n_block
952 if n_block != null then
953 v.compile_stmt(n_block)
954 end
955 v.add_instr("{v.nmc.continue_label}: while(0);")
956 e = prop4.compile_call(v, [iter])
957 assert e == null
958 v.unindent
959 v.add_instr("}")
960 v.add_instr("{v.nmc.break_label}: while(0);")
961 end
962 end
963
964 redef class AAssertExpr
965 redef meth compile_stmt(v)
966 do
967 var e = v.compile_expr(n_expr)
968 var s = ""
969 if n_id != null then
970 s = " '{n_id.text}' "
971 end
972 v.add_instr("if (!UNTAG_Bool({e})) \{ fprintf(stderr, \"Assert%s failed\", \"{s}\"); {v.printf_locate_error(self)} nit_exit(1);}")
973 end
974 end
975
976 redef class AVarExpr
977 redef meth compile_expr(v)
978 do
979 return " {v.cfc.varname(variable)} /*{variable.name}*/"
980 end
981 end
982
983 redef class AVarAssignExpr
984 redef meth compile_stmt(v)
985 do
986 var e = v.compile_expr(n_value)
987 v.add_assignment(v.cfc.varname(variable), "{e} /*{variable.name}=*/")
988 end
989 end
990
991 redef class AVarReassignExpr
992 redef meth compile_stmt(v)
993 do
994 var e1 = v.cfc.varname(variable)
995 var e2 = v.compile_expr(n_value)
996 var e3 = assign_method.compile_call(v, [e1, e2])
997 v.add_assignment(v.cfc.varname(variable), "{e3} /*{variable.name}*/")
998 end
999 end
1000
1001 redef class ASelfExpr
1002 redef meth compile_expr(v)
1003 do
1004 return v.cfc.varname(v.nmc.method_params[0])
1005 end
1006 end
1007
1008 redef class AOrExpr
1009 redef meth compile_expr(v)
1010 do
1011 var e = v.ensure_var(v.compile_expr(n_expr))
1012 v.add_instr("if (!UNTAG_Bool({e})) \{ /* or */")
1013 v.cfc.free_var(e)
1014 v.indent
1015 var e2 = v.compile_expr(n_expr2)
1016 v.add_assignment(e, e2)
1017 v.unindent
1018 v.add_instr("}")
1019 return e
1020 end
1021 end
1022
1023 redef class AAndExpr
1024 redef meth compile_expr(v)
1025 do
1026 var e = v.ensure_var(v.compile_expr(n_expr))
1027 v.add_instr("if (UNTAG_Bool({e})) \{ /* and */")
1028 v.cfc.free_var(e)
1029 v.indent
1030 var e2 = v.compile_expr(n_expr2)
1031 v.add_assignment(e, e2)
1032 v.unindent
1033 v.add_instr("}")
1034 return e
1035 end
1036 end
1037
1038 redef class ANotExpr
1039 redef meth compile_expr(v)
1040 do
1041 return " TAG_Bool(!UNTAG_Bool({v.compile_expr(n_expr)}))"
1042 end
1043 end
1044
1045 redef class AEeExpr
1046 redef meth compile_expr(v)
1047 do
1048 var e = v.compile_expr(n_expr)
1049 var e2 = v.compile_expr(n_expr2)
1050 return "TAG_Bool(IS_EQUAL_NN({e},{e2}))"
1051 end
1052 end
1053
1054 redef class AIsaExpr
1055 redef meth compile_expr(v)
1056 do
1057 var e = v.compile_expr(n_expr)
1058 return n_type.stype.compile_cast(v, e)
1059 end
1060 end
1061
1062 redef class AAsCastExpr
1063 redef meth compile_expr(v)
1064 do
1065 var e = v.compile_expr(n_expr)
1066 n_type.stype.compile_type_check(v, e, self)
1067 return e
1068 end
1069 end
1070
1071 redef class ATrueExpr
1072 redef meth compile_expr(v)
1073 do
1074 return " TAG_Bool(true)"
1075 end
1076 end
1077
1078 redef class AFalseExpr
1079 redef meth compile_expr(v)
1080 do
1081 return " TAG_Bool(false)"
1082 end
1083 end
1084
1085 redef class AIntExpr
1086 redef meth compile_expr(v)
1087 do
1088 return " TAG_Int({n_number.text})"
1089 end
1090 end
1091
1092 redef class AFloatExpr
1093 redef meth compile_expr(v)
1094 do
1095 return "BOX_Float({n_float.text})"
1096 end
1097 end
1098
1099 redef class ACharExpr
1100 redef meth compile_expr(v)
1101 do
1102 return " TAG_Char({n_char.text})"
1103 end
1104 end
1105
1106 redef class AStringFormExpr
1107 redef meth compile_expr(v)
1108 do
1109 var prop = stype.local_class.select_method(once "with_native".to_symbol)
1110 compute_string_info
1111 return prop.compile_constructor_call(v, stype , ["BOX_NativeString(\"{_cstring}\")", "TAG_Int({_cstring_length})"])
1112 end
1113
1114 # The raw string value
1115 protected meth string_text: String is abstract
1116
1117 # The string in a C native format
1118 protected attr _cstring: String
1119
1120 # The string length in bytes
1121 protected attr _cstring_length: Int
1122
1123 # Compute _cstring and _cstring_length using string_text
1124 protected meth compute_string_info
1125 do
1126 var len = 0
1127 var str = string_text
1128 var res = new String
1129 var i = 0
1130 while i < str.length do
1131 var c = str[i]
1132 if c == '\\' then
1133 i = i + 1
1134 var c2 = str[i]
1135 if c2 != '{' and c2 != '}' then
1136 res.add(c)
1137 end
1138 c = c2
1139 end
1140 len = len + 1
1141 res.add(c)
1142 i = i + 1
1143 end
1144 _cstring = res
1145 _cstring_length = len
1146 end
1147 end
1148
1149 redef class AStringExpr
1150 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1151 end
1152 redef class AStartStringExpr
1153 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1154 end
1155 redef class AMidStringExpr
1156 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1157 end
1158 redef class AEndStringExpr
1159 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1160 end
1161
1162 redef class ASuperstringExpr
1163 redef meth compile_expr(v)
1164 do
1165 var prop = stype.local_class.select_method(once "init".to_symbol)
1166 var recv = prop.compile_constructor_call(v, stype, new Array[String])
1167
1168 var prop2 = stype.local_class.select_method(once "append".to_symbol)
1169
1170 var prop3 = stype.local_class.select_method(once "to_s".to_symbol)
1171 for ne in n_exprs do
1172 var e = v.ensure_var(v.compile_expr(ne))
1173 if ne.stype != stype then
1174 v.add_assignment(e, prop3.compile_call(v, [e]))
1175 end
1176 prop2.compile_call(v, [recv, e])
1177 end
1178
1179 return recv
1180 end
1181 end
1182
1183 redef class ANullExpr
1184 redef meth compile_expr(v)
1185 do
1186 return " NIT_NULL /*null*/"
1187 end
1188 end
1189
1190 redef class AArrayExpr
1191 redef meth compile_expr(v)
1192 do
1193 var prop = stype.local_class.select_method(once "with_capacity".to_symbol)
1194 var recv = prop.compile_constructor_call(v, stype, ["TAG_Int({n_exprs.length})"])
1195
1196 var prop2 = stype.local_class.select_method(once "add".to_symbol)
1197 for ne in n_exprs do
1198 var e = v.compile_expr(ne)
1199 prop2.compile_call(v, [recv, e])
1200 end
1201 return recv
1202 end
1203 end
1204
1205 redef class ARangeExpr
1206 redef meth compile_expr(v)
1207 do
1208 var prop = stype.local_class.select_method(propname)
1209 var e = v.compile_expr(n_expr)
1210 var e2 = v.compile_expr(n_expr2)
1211 return prop.compile_constructor_call(v, stype, [e, e2])
1212 end
1213 # The constructor that must be used for the range
1214 protected meth propname: Symbol is abstract
1215 end
1216
1217 redef class ACrangeExpr
1218 redef meth propname do return once "init".to_symbol
1219 end
1220 redef class AOrangeExpr
1221 redef meth propname do return once "without_last".to_symbol
1222 end
1223
1224 redef class ASuperExpr
1225 redef meth compile_stmt(v)
1226 do
1227 var e = compile_expr(v)
1228 if e != null then v.add_instr("{e};")
1229 end
1230
1231 redef meth compile_expr(v)
1232 do
1233 var arity = v.nmc.method_params.length - 1
1234 if init_in_superclass != null then
1235 arity = init_in_superclass.signature.arity
1236 end
1237 var args = new Array[String].with_capacity(arity + 1)
1238 args.add(v.cfc.varname(v.nmc.method_params[0]))
1239 if n_args.length != arity then
1240 for i in [0..arity[ do
1241 args.add(v.cfc.varname(v.nmc.method_params[i + 1]))
1242 end
1243 else
1244 for na in n_args do
1245 args.add(v.compile_expr(na))
1246 end
1247 end
1248 #return "{prop.cname}({args.join(", ")}) /*super {prop.local_class}::{prop.name}*/"
1249 if init_in_superclass != null then
1250 return init_in_superclass.compile_call(v, args)
1251 else
1252 if prop.global.is_init then args.add("init_table")
1253 return prop.compile_super_call(v, args)
1254 end
1255 end
1256 end
1257
1258 redef class AAttrExpr
1259 redef meth compile_expr(v)
1260 do
1261 var e = v.compile_expr(n_expr)
1262 return prop.compile_access(v, e)
1263 end
1264 end
1265
1266 redef class AAttrAssignExpr
1267 redef meth compile_stmt(v)
1268 do
1269 var e = v.compile_expr(n_expr)
1270 var e2 = v.compile_expr(n_value)
1271 v.add_assignment(prop.compile_access(v, e), e2)
1272 end
1273 end
1274 redef class AAttrReassignExpr
1275 redef meth compile_stmt(v)
1276 do
1277 var e1 = v.compile_expr(n_expr)
1278 var e2 = prop.compile_access(v, e1)
1279 var e3 = v.compile_expr(n_value)
1280 var e4 = assign_method.compile_call(v, [e2, e3])
1281 v.add_assignment(e2, e4)
1282 end
1283 end
1284
1285 redef class ASendExpr
1286 redef meth compile_expr(v)
1287 do
1288 var recv = v.compile_expr(n_expr)
1289 var cargs = new Array[String]
1290 cargs.add(recv)
1291 for a in arguments do
1292 cargs.add(v.compile_expr(a))
1293 end
1294
1295 var e = prop.compile_call(v, cargs)
1296 if prop.global.is_init then
1297 v.invoke_super_init_calls_after(prop)
1298 end
1299 return e
1300 end
1301
1302 redef meth compile_stmt(v)
1303 do
1304 var e = compile_expr(v)
1305 if e != null then
1306 v.add_instr(e + ";")
1307 end
1308 end
1309 end
1310
1311 redef class ASendReassignExpr
1312 redef meth compile_expr(v)
1313 do
1314 var recv = v.compile_expr(n_expr)
1315 var cargs = new Array[String]
1316 cargs.add(recv)
1317 for a in arguments do
1318 cargs.add(v.compile_expr(a))
1319 end
1320
1321 var e2 = read_prop.compile_call(v, cargs)
1322 var e3 = v.compile_expr(n_value)
1323 var e4 = assign_method.compile_call(v, [e2, e3])
1324 cargs.add(e4)
1325 return prop.compile_call(v, cargs)
1326 end
1327 end
1328
1329 redef class ANewExpr
1330 redef meth compile_expr(v)
1331 do
1332 var cargs = new Array[String]
1333 for a in arguments do
1334 cargs.add(v.compile_expr(a))
1335 end
1336 return prop.compile_constructor_call(v, stype, cargs)
1337 end
1338 end
1339
1340 redef class AProxyExpr
1341 redef meth compile_expr(v)
1342 do
1343 return v.compile_expr(n_expr)
1344 end
1345 end
1346
1347 redef class AOnceExpr
1348 redef meth compile_expr(v)
1349 do
1350 var i = v.new_number
1351 var cvar = v.cfc.get_var
1352 v.add_decl("static val_t once_value_{i}; static int once_bool_{i}; /* Once value for {cvar}*/")
1353 v.add_instr("if (once_bool_{i}) {cvar} = once_value_{i};")
1354 v.add_instr("else \{")
1355 v.indent
1356 v.cfc.free_var(cvar)
1357 var e = v.compile_expr(n_expr)
1358 v.add_assignment(cvar, e)
1359 v.add_instr("once_value_{i} = {cvar};")
1360 v.add_instr("once_bool_{i} = true;")
1361 v.unindent
1362 v.add_instr("}")
1363 return cvar
1364 end
1365 end