compile: ccomments for get_var and ensure_var
[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 add_instr("/* Compile stmt {n.locate} */")
28 n.prepare_compile_stmt(self)
29 var i = cfc._variable_index
30 n.compile_stmt(self)
31 cfc._variable_index = i
32 end
33
34 # Compile is expression node
35 meth compile_expr(n: PExpr): String
36 do
37 add_instr("/* Compile expr {n.locate} */")
38 var i = cfc._variable_index
39 var s = n.compile_expr(self)
40 cfc._variable_index = i
41 if s[0] == ' ' then
42 return s
43 end
44 var v = cfc.get_var("Result for expr {n.locate}")
45 add_assignment(v, s)
46 return v
47 end
48
49 # Ensure that a c expression is a var
50 meth ensure_var(s: String, comment: String): String
51 do
52 if s.substring(0,3) == "variable" then
53 return s
54 end
55 var v = cfc.get_var(null)
56 add_assignment(v, "{s} /* Ensure var: {comment}*/")
57 return v
58 end
59
60 # Add a assignment between a variable and an expression
61 meth add_assignment(v: String, s: String)
62 do
63 if v != s then
64 add_instr("{v} = {s};")
65 end
66 end
67
68 readable writable attr _cfc: CFunctionContext
69
70 readable writable attr _nmc: NitMethodContext
71
72 # C outputs written outside the current C function.
73 readable writable attr _out_contexts: Array[CContext] = new Array[CContext]
74
75 # Generate an fprintf to display an error location
76 meth printf_locate_error(node: PNode): String
77 do
78 var s = new Buffer.from("fprintf(stderr, \"")
79 if nmc != null then s.append(" in %s")
80 s.append(" (%s:%d)\\n\", ")
81 if nmc != null then s.append("LOCATE_{nmc.method.cname}, ")
82 s.append("LOCATE_{module.name}, {node.line_number});")
83 return s.to_s
84 end
85
86 redef init(module: MMSrcModule)
87 do
88 super
89 end
90
91 meth invoke_super_init_calls_after(start_prop: MMMethod)
92 do
93 var n = nmc.method.node
94 assert n isa AConcreteInitPropdef
95
96 if n.super_init_calls.is_empty then return
97 var i = 0
98 var j = 0
99 #var s = ""
100 if start_prop != null then
101 while n.super_init_calls[i] != start_prop do
102 #s.append(" {n.super_init_calls[i]}")
103 i += 1
104 end
105 i += 1
106 #s.append(" {start_prop}")
107
108 while n.explicit_super_init_calls[j] != start_prop do
109 j += 1
110 end
111 j += 1
112 end
113 var stop_prop: MMMethod = null
114 if j < n.explicit_super_init_calls.length then
115 stop_prop = n.explicit_super_init_calls[j]
116 end
117 var l = n.super_init_calls.length
118 #s.append(" [")
119 while i < l do
120 var p = n.super_init_calls[i]
121 if p == stop_prop then break
122 var cargs = new Array[String]
123 if p.signature.arity == 0 then
124 cargs.add(cfc.varname(nmc.method_params[0]))
125 else
126 for va in nmc.method_params do
127 cargs.add(cfc.varname(va))
128 end
129 end
130 #s.append(" {p}")
131 p.compile_call(self, cargs)
132 i += 1
133 end
134 #s.append(" ]")
135 #while i < l do
136 # s.append(" {n.super_init_calls[i]}")
137 # i += 1
138 #end
139 #if stop_prop != null then s.append(" (stop at {stop_prop})")
140 #n.printl("implicit calls in {n.method}: {s}")
141 end
142 end
143
144 # A C function currently written
145 class CFunctionContext
146 readable attr _visitor: CompilerVisitor
147
148 # Next available variable number
149 attr _variable_index: Int = 0
150
151 # Total number of variable
152 attr _variable_index_max: Int = 0
153
154 # Association between nit variable and the corrsponding c variable
155 attr _varnames: Map[Variable, String] = new HashMap[Variable, String]
156
157 # Are we currenlty in a closure definition?
158 readable writable attr _closure: NitMethodContext = null
159
160 meth varname(v: Variable): String
161 do
162 if _closure != null then
163 return "closctx->{_varnames[v]}"
164 else
165 return _varnames[v]
166 end
167 end
168
169 # Return the next available variable
170 meth get_var(comment: String): String
171 do
172 var v = variable(_variable_index)
173 _variable_index = _variable_index + 1
174 if _variable_index > _variable_index_max then
175 #visitor.add_decl("val_t {v};")
176 _variable_index_max = _variable_index
177 end
178 if comment != null then
179 visitor.add_instr("/* Register {v}: {comment} */")
180 end
181 return v
182 end
183
184 meth register_variable(v: Variable): String
185 do
186 var s = get_var("Local variable")
187 _varnames[v] = "variable[{_variable_index-1}]"
188 return s
189 end
190
191 # Next available closure variable number
192 attr _closurevariable_index: Int = 0
193
194 meth register_closurevariable(v: ClosureVariable): String
195 do
196 var s = "closurevariable[{_closurevariable_index}]"
197 _closurevariable_index += 1
198 _varnames[v] = s
199 if _closure != null then
200 return "(closctx->{s})"
201 else
202 return s
203 end
204 end
205
206 # Return the ith variable
207 protected meth variable(i: Int): String
208 do
209 if _closure != null then
210 return "(closctx->variable[{i}])"
211 else
212 return "variable[{i}]"
213 end
214 end
215
216 # Mark the variable available
217 meth free_var(v: String)
218 do
219 # FIXME: So ugly..
220 if v == variable(_variable_index-1) then
221 _variable_index = _variable_index - 1
222 end
223 end
224
225 # Generate the local variable declarations
226 # To use at the end of the C function once all variables are known
227 meth generate_var_decls
228 do
229 if _variable_index_max > 0 then
230 visitor.add_decl("val_t variable[{_variable_index_max}];")
231 else
232 visitor.add_decl("val_t *variable = NULL;")
233 end
234 if _closurevariable_index > 0 then
235 visitor.add_decl("struct WBT_ *closurevariable[{_closurevariable_index}];")
236 else
237 visitor.add_decl("struct WBT_ **closurevariable = NULL;")
238 end
239 end
240
241 init(v: CompilerVisitor) do _visitor = v
242 end
243
244 # A Nit method currenlty compiled
245 class NitMethodContext
246 # Current method compiled
247 readable attr _method: MMSrcMethod
248
249 # Association between parameters and the corresponding variables
250 readable writable attr _method_params: Array[ParamVariable]
251
252 # Where a nit return must branch
253 readable writable attr _return_label: String
254
255 # Where a nit break must branch
256 readable writable attr _break_label: String
257
258 # Where a nit continue must branch
259 readable writable attr _continue_label: String
260
261 # Variable where a functionnal nit return must store its value
262 readable writable attr _return_value: String
263
264 # Variable where a functionnal nit break must store its value
265 readable writable attr _break_value: String
266
267 # Variable where a functionnal nit continue must store its value
268 readable writable attr _continue_value: String
269
270 init(method: MMSrcMethod)
271 do
272 _method = method
273 end
274 end
275
276 ###############################################################################
277
278 redef class ClosureVariable
279 readable writable attr _ctypename: String
280 end
281
282 redef class MMMethod
283 # Compile a call on self for given arguments
284 # Most calls are compiled with a table access,
285 # primitive calles are inlined
286 # == and != are guarded and possibly inlined
287 meth compile_call(v: CompilerVisitor, cargs: Array[String]): String
288 do
289 var i = self
290 if i isa MMSrcMethod then
291 if i isa MMMethSrcMethod and i.node isa AInternMethPropdef or
292 (i.local_class.name == (once "Array".to_symbol) and name == (once "[]".to_symbol))
293 then
294 var e = i.do_compile_inside(v, cargs)
295 return e
296 end
297 end
298 var ee = once "==".to_symbol
299 var ne = once "!=".to_symbol
300 if name == ne then
301 var eqp = signature.recv.local_class.select_method(ee)
302 var eqcall = eqp.compile_call(v, cargs)
303 return "TAG_Bool(!UNTAG_Bool({eqcall}))"
304 end
305 if global.is_init then
306 cargs = cargs.to_a
307 cargs.add("init_table /*YYY*/")
308 end
309
310 var m = "{global.meth_call}({cargs[0]})"
311 var vcall = "{m}({cargs.join(", ")}) /*{local_class}::{name}*/"
312 if name == ee then
313 vcall = "UNTAG_Bool({vcall})"
314 var obj = once "Object".to_symbol
315 if i.local_class.name == obj then
316 vcall = "(({m}=={i.cname})?(IS_EQUAL_NN({cargs[0]},{cargs[1]})):({vcall}))"
317 end
318 vcall = "TAG_Bool(({cargs.first} == {cargs[1]}) || (({cargs.first} != NIT_NULL) && {vcall}))"
319 end
320 if signature.return_type != null then
321 return vcall
322 else
323 v.add_instr(vcall + ";")
324 return null
325 end
326 end
327
328 # Compile a call on self for given arguments and given closures
329 meth compile_call_and_closures(v: CompilerVisitor, cargs: Array[String], clos_defs: Array[PClosureDef]): String
330 do
331 var ve: String = null
332 var arity = 0
333 if clos_defs != null then arity = clos_defs.length
334
335 # Prepare result value.
336 # In case of procedure, the return value is still used to intercept breaks
337 var old_bv = v.nmc.break_value
338 ve = v.cfc.get_var("Closure return value and escape marker")
339 v.nmc.break_value = ve
340
341 # Compile closure to c function
342 var realcargs = new Array[String] # Args to pass to the C function call
343 var closcns = new Array[String] # Closure C structure names
344 realcargs.add_all(cargs)
345 for i in [0..arity[ do
346 var cn = clos_defs[i].compile_closure(v, closure_cname(i))
347 closcns.add(cn)
348 realcargs.add(cn)
349 end
350 for i in [arity..signature.closures.length[ do
351 realcargs.add("NULL")
352 end
353
354 v.nmc.break_value = old_bv
355
356 # Call
357 var e = compile_call(v, realcargs)
358 if e != null then
359 v.add_assignment(ve, e)
360 e = ve
361 end
362
363 # Intercept returns and breaks
364 for i in [0..arity[ do
365 # A break or a return is intercepted
366 v.add_instr("if ({closcns[i]}->has_broke != NULL) \{")
367 v.indent
368 # A passtrought break or a return is intercepted: go the the next closure
369 v.add_instr("if ({closcns[i]}->has_broke != &({ve})) \{")
370 v.indent
371 if v.cfc.closure == v.nmc then v.add_instr("closctx->has_broke = {closcns[i]}->has_broke; closctx->broke_value = {closcns[i]}->broke_value;")
372 v.add_instr("goto {v.nmc.return_label};")
373 v.unindent
374 # A direct break is interpected
375 if e != null then
376 # overwrite the returned value in a function
377 v.add_instr("\} else {ve} = {closcns[i]}->broke_value;")
378 else
379 # Do nothing in a procedure
380 v.add_instr("\}")
381 end
382 v.unindent
383 v.add_instr("\}")
384 end
385 return e
386 end
387
388 # Compile a call as constructor with given args
389 meth compile_constructor_call(v: CompilerVisitor, recvtype: MMType, cargs: Array[String]): String
390 do
391 return "NEW_{recvtype.local_class}_{global.intro.cname}({cargs.join(", ")}) /*new {recvtype}*/"
392 end
393
394 # Compile a call as call-next-method on self with given args
395 meth compile_super_call(v: CompilerVisitor, cargs: Array[String]): String
396 do
397 var m = "{super_meth_call}({cargs[0]})"
398 var vcall = "{m}({cargs.join(", ")}) /*super {local_class}::{name}*/"
399 return vcall
400 end
401
402 # Cname of the i-th closure C struct type
403 protected meth closure_cname(i: Int): String
404 do
405 return "FWBT_{cname}_{i}"
406 end
407 end
408
409 redef class MMAttribute
410 # Compile an acces on selffor a given reciever.
411 # Result is a valid C left-value for assigment
412 meth compile_access(v: CompilerVisitor, recv: String): String
413 do
414 return "{global.attr_access}({recv}) /*{local_class}::{name}*/"
415 end
416 end
417
418 redef class MMLocalProperty
419 # Compile the property as a C property
420 meth compile_property_to_c(v: CompilerVisitor) do end
421 end
422
423 redef class MMSrcMethod
424
425 # Compile and declare the signature to C
426 protected meth decl_csignature(v: CompilerVisitor, args: Array[String]): String
427 do
428 var params = new Array[String]
429 params.add("val_t {args[0]}")
430 for i in [0..signature.arity[ do
431 var p = "val_t {args[i+1]}"
432 params.add(p)
433 end
434
435 var first_closure_index = signature.arity + 1 # Wich parameter is the first closure
436 for i in [0..signature.closures.length[ do
437 var closcn = closure_cname(i)
438 var cs = signature.closures[i].signature # Closure signature
439 var subparams = new Array[String] # Parameters of the closure
440 subparams.add("struct WBT_ *")
441 for j in [0..cs.arity[ do
442 var p = "val_t"
443 subparams.add(p)
444 end
445 var r = "void"
446 if cs.return_type != null then r = "val_t"
447 params.add("struct WBT_ *{args[first_closure_index+i]}")
448 v.add_decl("typedef {r} (*{closcn})({subparams.join(", ")});")
449 end
450
451 if global.is_init then
452 params.add("int* init_table")
453 end
454
455 var ret: String
456 if signature.return_type != null then
457 ret = "val_t"
458 else
459 ret = "void"
460 end
461
462 var p = params.join(", ")
463 var s = "{ret} {cname}({p})"
464 v.add_decl("typedef {ret} (* {cname}_t)({p});")
465 v.add_decl(s + ";")
466 return s
467 end
468
469 redef meth compile_property_to_c(v)
470 do
471 v.cfc = new CFunctionContext(v)
472
473 var args = new Array[String]
474 args.add(" self")
475 for i in [0..signature.arity[ do
476 args.add(" param{i}")
477 end
478 for i in [0..signature.closures.length[ do
479 args.add(" wd{i}")
480 end
481 var cs = decl_csignature(v, args)
482 v.add_decl("#define LOCATE_{cname} \"{full_name}\"")
483
484 v.add_instr("{cs} \{")
485 v.indent
486 var ctx_old = v.ctx
487 v.ctx = new CContext
488
489 v.out_contexts.clear
490
491 var ln = 0
492 var s = self
493 if s.node != null then ln = s.node.line_number
494 v.add_decl("struct trace_t trace = \{NULL, NULL, {ln}, LOCATE_{cname}};")
495 v.add_instr("trace.prev = tracehead; tracehead = &trace;")
496 v.add_instr("trace.file = LOCATE_{module.name};")
497 var s = do_compile_inside(v, args)
498 v.add_instr("tracehead = trace.prev;")
499 if s == null then
500 v.add_instr("return;")
501 else
502 v.add_instr("return {s};")
503 end
504
505 v.cfc.generate_var_decls
506
507 ctx_old.append(v.ctx)
508 v.ctx = ctx_old
509 v.unindent
510 v.add_instr("}")
511
512 for ctx in v.out_contexts do v.ctx.merge(ctx)
513 end
514
515 # Compile the method body inline
516 meth do_compile_inside(v: CompilerVisitor, params: Array[String]): String is abstract
517 end
518
519 redef class MMReadImplementationMethod
520 redef meth do_compile_inside(v, params)
521 do
522 return node.prop.compile_access(v, params[0])
523 end
524 end
525
526 redef class MMWriteImplementationMethod
527 redef meth do_compile_inside(v, params)
528 do
529 v.add_assignment(node.prop.compile_access(v, params[0]), params[1])
530 return null
531 end
532 end
533
534 redef class MMMethSrcMethod
535 redef meth do_compile_inside(v, params)
536 do
537 return node.do_compile_inside(v, self, params)
538 end
539 end
540
541 redef class MMImplicitInit
542 redef meth do_compile_inside(v, params)
543 do
544 var f = params.length - unassigned_attributes.length
545 var recv = params.first
546 for sp in super_inits do
547 assert sp isa MMMethod
548 var args_recv = [recv]
549 if sp == super_init then
550 var args = new Array[String].with_capacity(f)
551 args.add(recv)
552 for i in [1..f[ do
553 args.add(params[i])
554 end
555 sp.compile_call(v, args)
556 else
557 sp.compile_call(v, args_recv)
558 end
559 end
560 for i in [f..params.length[ do
561 var attribute = unassigned_attributes[i-f]
562 v.add_assignment(attribute.compile_access(v, recv), params[i])
563 end
564 return null
565 end
566 end
567
568 redef class MMType
569 # Compile a subtype check to self
570 # Return a NIT Bool
571 meth compile_cast(v: CompilerVisitor, recv: String): String
572 do
573 # Fixme: handle formaltypes
574 var g = local_class.global
575 return "TAG_Bool(({recv}==NIT_NULL) || VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {self}*/"
576 end
577
578 # Compile a cast assertion
579 meth compile_type_check(v: CompilerVisitor, recv: String, n: PNode)
580 do
581 # Fixme: handle formaltypes
582 var g = local_class.global
583 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}*/;")
584 end
585 end
586
587 ###############################################################################
588
589 redef class AMethPropdef
590 # Compile the method body
591 meth do_compile_inside(v: CompilerVisitor, method: MMSrcMethod, params: Array[String]): String is abstract
592 end
593
594 redef class PSignature
595 meth compile_parameters(v: CompilerVisitor, orig_sig: MMSignature, params: Array[String]) is abstract
596 end
597
598 redef class ASignature
599 redef meth compile_parameters(v: CompilerVisitor, orig_sig: MMSignature, params: Array[String])
600 do
601 for ap in n_params do
602 var cname = v.cfc.register_variable(ap.variable)
603 v.nmc.method_params.add(ap.variable)
604 var orig_type = orig_sig[ap.position]
605 if not orig_type < ap.variable.stype then
606 # FIXME: do not test always
607 # FIXME: handle formal types
608 v.add_instr("/* check if p<{ap.variable.stype} with p:{orig_type} */")
609 ap.variable.stype.compile_type_check(v, params[ap.position], ap)
610 end
611 v.add_assignment(cname, params[ap.position])
612 end
613 for i in [0..n_closure_decls.length[ do
614 var wd = n_closure_decls[i]
615 var cname = v.cfc.register_closurevariable(wd.variable)
616 wd.variable.ctypename = v.nmc.method.closure_cname(i)
617 v.add_assignment(cname, "{params[orig_sig.arity + i]}")
618 end
619 end
620 end
621
622 redef class AConcreteMethPropdef
623 redef meth do_compile_inside(v, method, params)
624 do
625 var old_nmc = v.nmc
626 v.nmc = new NitMethodContext(method)
627
628 var selfcname = v.cfc.register_variable(self_var)
629 v.add_assignment(selfcname, params[0])
630 params.shift
631 v.nmc.method_params = [self_var]
632
633 if n_signature != null then
634 var orig_meth: MMLocalProperty = method.global.intro
635 var orig_sig = orig_meth.signature_for(method.signature.recv)
636 n_signature.compile_parameters(v, orig_sig, params)
637 end
638
639 var itpos: String = null
640 if self isa AConcreteInitPropdef then
641 itpos = "VAL2OBJ({selfcname})->vft[{method.local_class.global.init_table_pos_id}].i"
642 # v.add_instr("printf(\"{method.full_name}: inittable[%d] = %d\\n\", {itpos}, init_table[{itpos}]);")
643 v.add_instr("if (init_table[{itpos}]) return;")
644 end
645
646 v.nmc.return_label = "return_label{v.new_number}"
647 v.nmc.return_value = v.cfc.get_var("Method return value and escape marker")
648 if self isa AConcreteInitPropdef then
649 v.invoke_super_init_calls_after(null)
650 end
651 if n_block != null then
652 v.compile_stmt(n_block)
653 end
654 v.add_instr("{v.nmc.return_label}: while(false);")
655 if self isa AConcreteInitPropdef then
656 v.add_instr("init_table[{itpos}] = 1;")
657 end
658
659 var ret: String = null
660 if method.signature.return_type != null then
661 ret = v.nmc.return_value
662 end
663
664 v.nmc = old_nmc
665 return ret
666 end
667 end
668
669 redef class ADeferredMethPropdef
670 redef meth do_compile_inside(v, method, params)
671 do
672 v.add_instr("fprintf(stderr, \"Deferred method called\");")
673 v.add_instr(v.printf_locate_error(self))
674 v.add_instr("nit_exit(1);")
675 if method.signature.return_type != null then
676 return("NIT_NULL")
677 else
678 return null
679 end
680 end
681 end
682
683 redef class AExternMethPropdef
684 redef meth do_compile_inside(v, method, params)
685 do
686 var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
687 if n_extern != null then
688 ename = n_extern.text
689 ename = ename.substring(1, ename.length-2)
690 end
691 var sig = method.signature
692 if params.length != sig.arity + 1 then
693 printl("par:{params.length} sig:{sig.arity}")
694 end
695 var args = new Array[String]
696 args.add(sig.recv.unboxtype(params[0]))
697 for i in [0..sig.arity[ do
698 args.add(sig[i].unboxtype(params[i+1]))
699 end
700 var s = "{ename}({args.join(", ")})"
701 if sig.return_type != null then
702 return sig.return_type.boxtype(s)
703 else
704 v.add_instr("{s};")
705 return null
706 end
707 end
708 end
709
710 redef class AInternMethPropdef
711 redef meth do_compile_inside(v, method, p)
712 do
713 var c = method.local_class.name
714 var n = method.name
715 var s: String = null
716 if c == once "Int".to_symbol then
717 if n == once "object_id".to_symbol then
718 s = "{p[0]}"
719 else if n == once "unary -".to_symbol then
720 s = "TAG_Int(-UNTAG_Int({p[0]}))"
721 else if n == once "output".to_symbol then
722 v.add_instr("printf(\"%ld\\n\", UNTAG_Int({p[0]}));")
723 else if n == once "ascii".to_symbol then
724 s = "TAG_Char(UNTAG_Int({p[0]}))"
725 else if n == once "succ".to_symbol then
726 s = "TAG_Int(UNTAG_Int({p[0]})+1)"
727 else if n == once "prec".to_symbol then
728 s = "TAG_Int(UNTAG_Int({p[0]})-1)"
729 else if n == once "to_f".to_symbol then
730 s = "BOX_Float((float)UNTAG_Int({p[0]}))"
731 else if n == once "+".to_symbol then
732 s = "TAG_Int(UNTAG_Int({p[0]})+UNTAG_Int({p[1]}))"
733 else if n == once "-".to_symbol then
734 s = "TAG_Int(UNTAG_Int({p[0]})-UNTAG_Int({p[1]}))"
735 else if n == once "*".to_symbol then
736 s = "TAG_Int(UNTAG_Int({p[0]})*UNTAG_Int({p[1]}))"
737 else if n == once "/".to_symbol then
738 s = "TAG_Int(UNTAG_Int({p[0]})/UNTAG_Int({p[1]}))"
739 else if n == once "%".to_symbol then
740 s = "TAG_Int(UNTAG_Int({p[0]})%UNTAG_Int({p[1]}))"
741 else if n == once "<".to_symbol then
742 s = "TAG_Bool(UNTAG_Int({p[0]})<UNTAG_Int({p[1]}))"
743 else if n == once ">".to_symbol then
744 s = "TAG_Bool(UNTAG_Int({p[0]})>UNTAG_Int({p[1]}))"
745 else if n == once "<=".to_symbol then
746 s = "TAG_Bool(UNTAG_Int({p[0]})<=UNTAG_Int({p[1]}))"
747 else if n == once ">=".to_symbol then
748 s = "TAG_Bool(UNTAG_Int({p[0]})>=UNTAG_Int({p[1]}))"
749 else if n == once "lshift".to_symbol then
750 s = "TAG_Int(UNTAG_Int({p[0]})<<UNTAG_Int({p[1]}))"
751 else if n == once "rshift".to_symbol then
752 s = "TAG_Int(UNTAG_Int({p[0]})>>UNTAG_Int({p[1]}))"
753 else if n == once "==".to_symbol then
754 s = "TAG_Bool(({p[0]})==({p[1]}))"
755 else if n == once "!=".to_symbol then
756 s = "TAG_Bool(({p[0]})!=({p[1]}))"
757 end
758 else if c == once "Float".to_symbol then
759 if n == once "object_id".to_symbol then
760 s = "TAG_Int((bigint)UNBOX_Float({p[0]}))"
761 else if n == once "unary -".to_symbol then
762 s = "BOX_Float(-UNBOX_Float({p[0]}))"
763 else if n == once "output".to_symbol then
764 v.add_instr("printf(\"%f\\n\", UNBOX_Float({p[0]}));")
765 else if n == once "to_i".to_symbol then
766 s = "TAG_Int((bigint)UNBOX_Float({p[0]}))"
767 else if n == once "+".to_symbol then
768 s = "BOX_Float(UNBOX_Float({p[0]})+UNBOX_Float({p[1]}))"
769 else if n == once "-".to_symbol then
770 s = "BOX_Float(UNBOX_Float({p[0]})-UNBOX_Float({p[1]}))"
771 else if n == once "*".to_symbol then
772 s = "BOX_Float(UNBOX_Float({p[0]})*UNBOX_Float({p[1]}))"
773 else if n == once "/".to_symbol then
774 s = "BOX_Float(UNBOX_Float({p[0]})/UNBOX_Float({p[1]}))"
775 else if n == once "<".to_symbol then
776 s = "TAG_Bool(UNBOX_Float({p[0]})<UNBOX_Float({p[1]}))"
777 else if n == once ">".to_symbol then
778 s = "TAG_Bool(UNBOX_Float({p[0]})>UNBOX_Float({p[1]}))"
779 else if n == once "<=".to_symbol then
780 s = "TAG_Bool(UNBOX_Float({p[0]})<=UNBOX_Float({p[1]}))"
781 else if n == once ">=".to_symbol then
782 s = "TAG_Bool(UNBOX_Float({p[0]})>=UNBOX_Float({p[1]}))"
783 end
784 else if c == once "Char".to_symbol then
785 if n == once "object_id".to_symbol then
786 s = "TAG_Int(UNTAG_Char({p[0]}))"
787 else if n == once "unary -".to_symbol then
788 s = "TAG_Char(-UNTAG_Char({p[0]}))"
789 else if n == once "output".to_symbol then
790 v.add_instr("printf(\"%c\", (unsigned char)UNTAG_Char({p[0]}));")
791 else if n == once "ascii".to_symbol then
792 s = "TAG_Int((unsigned char)UNTAG_Char({p[0]}))"
793 else if n == once "succ".to_symbol then
794 s = "TAG_Char(UNTAG_Char({p[0]})+1)"
795 else if n == once "prec".to_symbol then
796 s = "TAG_Char(UNTAG_Char({p[0]})-1)"
797 else if n == once "to_i".to_symbol then
798 s = "TAG_Int(UNTAG_Char({p[0]})-'0')"
799 else if n == once "+".to_symbol then
800 s = "TAG_Char(UNTAG_Char({p[0]})+UNTAG_Char({p[1]}))"
801 else if n == once "-".to_symbol then
802 s = "TAG_Char(UNTAG_Char({p[0]})-UNTAG_Char({p[1]}))"
803 else if n == once "*".to_symbol then
804 s = "TAG_Char(UNTAG_Char({p[0]})*UNTAG_Char({p[1]}))"
805 else if n == once "/".to_symbol then
806 s = "TAG_Char(UNTAG_Char({p[0]})/UNTAG_Char({p[1]}))"
807 else if n == once "%".to_symbol then
808 s = "TAG_Char(UNTAG_Char({p[0]})%UNTAG_Char({p[1]}))"
809 else if n == once "<".to_symbol then
810 s = "TAG_Bool(UNTAG_Char({p[0]})<UNTAG_Char({p[1]}))"
811 else if n == once ">".to_symbol then
812 s = "TAG_Bool(UNTAG_Char({p[0]})>UNTAG_Char({p[1]}))"
813 else if n == once "<=".to_symbol then
814 s = "TAG_Bool(UNTAG_Char({p[0]})<=UNTAG_Char({p[1]}))"
815 else if n == once ">=".to_symbol then
816 s = "TAG_Bool(UNTAG_Char({p[0]})>=UNTAG_Char({p[1]}))"
817 else if n == once "==".to_symbol then
818 s = "TAG_Bool(({p[0]})==({p[1]}))"
819 else if n == once "!=".to_symbol then
820 s = "TAG_Bool(({p[0]})!=({p[1]}))"
821 end
822 else if c == once "Bool".to_symbol then
823 if n == once "object_id".to_symbol then
824 s = "TAG_Int(UNTAG_Bool({p[0]}))"
825 else if n == once "unary -".to_symbol then
826 s = "TAG_Bool(-UNTAG_Bool({p[0]}))"
827 else if n == once "output".to_symbol then
828 v.add_instr("(void)printf(UNTAG_Bool({p[0]})?\"true\\n\":\"false\\n\");")
829 else if n == once "ascii".to_symbol then
830 s = "TAG_Bool(UNTAG_Bool({p[0]}))"
831 else if n == once "to_i".to_symbol then
832 s = "TAG_Int(UNTAG_Bool({p[0]}))"
833 else if n == once "==".to_symbol then
834 s = "TAG_Bool(({p[0]})==({p[1]}))"
835 else if n == once "!=".to_symbol then
836 s = "TAG_Bool(({p[0]})!=({p[1]}))"
837 end
838 else if c == once "NativeArray".to_symbol then
839 if n == once "object_id".to_symbol then
840 s = "TAG_Int(UNBOX_NativeArray({p[0]}))"
841 else if n == once "[]".to_symbol then
842 s = "UNBOX_NativeArray({p[0]})[UNTAG_Int({p[1]})]"
843 else if n == once "[]=".to_symbol then
844 v.add_instr("UNBOX_NativeArray({p[0]})[UNTAG_Int({p[1]})]={p[2]};")
845 else if n == once "copy_to".to_symbol then
846 v.add_instr("(void)memcpy(UNBOX_NativeArray({p[1]}), UNBOX_NativeArray({p[0]}), UNTAG_Int({p[2]})*sizeof(val_t));")
847 end
848 else if c == once "NativeString".to_symbol then
849 if n == once "object_id".to_symbol then
850 s = "TAG_Int(UNBOX_NativeString({p[0]}))"
851 else if n == once "atoi".to_symbol then
852 s = "TAG_Int(atoi(UNBOX_NativeString({p[0]})))"
853 else if n == once "[]".to_symbol then
854 s = "TAG_Char(UNBOX_NativeString({p[0]})[UNTAG_Int({p[1]})])"
855 else if n == once "[]=".to_symbol then
856 v.add_instr("UNBOX_NativeString({p[0]})[UNTAG_Int({p[1]})]=UNTAG_Char({p[2]});")
857 else if n == once "copy_to".to_symbol then
858 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]}));")
859 end
860 else if n == once "object_id".to_symbol then
861 s = "TAG_Int((bigint){p[0]})"
862 else if n == once "sys".to_symbol then
863 s = "(G_sys)"
864 else if n == once "is_same_type".to_symbol then
865 s = "TAG_Bool((VAL2VFT({p[0]})==VAL2VFT({p[1]})))"
866 else if n == once "exit".to_symbol then
867 v.add_instr("exit(UNTAG_Int({p[1]}));")
868 else if n == once "calloc_array".to_symbol then
869 s = "BOX_NativeArray((val_t*)malloc((UNTAG_Int({p[1]}) * sizeof(val_t))))"
870 else if n == once "calloc_string".to_symbol then
871 s = "BOX_NativeString((char*)malloc((UNTAG_Int({p[1]}) * sizeof(char))))"
872
873 else
874 v.add_instr("fprintf(stderr, \"Intern {n}\\n\"); nit_exit(1);")
875 end
876 if method.signature.return_type != null and s == null then
877 s = "NIT_NULL /*stub*/"
878 end
879 return s
880 end
881 end
882
883 ###############################################################################
884
885 redef class PExpr
886 # Compile the node as an expression
887 # Only the visitor should call it
888 meth compile_expr(v: CompilerVisitor): String is abstract
889
890 # Prepare a call of node as a statement
891 # Only the visitor should call it
892 # It's used for local variable managment
893 meth prepare_compile_stmt(v: CompilerVisitor) do end
894
895 # Compile the node as a statement
896 # Only the visitor should call it
897 meth compile_stmt(v: CompilerVisitor) do printl("Error!")
898 end
899
900 redef class ABlockExpr
901 redef meth compile_stmt(v)
902 do
903 for n in n_expr do
904 v.compile_stmt(n)
905 end
906 end
907 end
908
909 redef class AVardeclExpr
910 redef meth prepare_compile_stmt(v)
911 do
912 v.cfc.register_variable(variable)
913 end
914
915 redef meth compile_stmt(v)
916 do
917 var cname = v.cfc.varname(variable)
918 if n_expr == null then
919 v.add_instr("/*{cname} is variable {variable.name}*/")
920 else
921 var e = v.compile_expr(n_expr)
922 v.add_assignment(cname, e)
923 end
924 end
925 end
926
927 redef class AReturnExpr
928 redef meth compile_stmt(v)
929 do
930 if n_expr != null then
931 var e = v.compile_expr(n_expr)
932 v.add_assignment(v.nmc.return_value, e)
933 end
934 if v.cfc.closure == v.nmc then v.add_instr("closctx->has_broke = &({v.nmc.return_value});")
935 v.add_instr("goto {v.nmc.return_label};")
936 end
937 end
938
939 redef class ABreakExpr
940 redef meth compile_stmt(v)
941 do
942 if n_expr != null then
943 var e = v.compile_expr(n_expr)
944 v.add_assignment(v.nmc.break_value, e)
945 end
946 if v.cfc.closure == v.nmc then v.add_instr("closctx->has_broke = &({v.nmc.break_value}); closctx->broke_value = *closctx->has_broke;")
947 v.add_instr("goto {v.nmc.break_label};")
948 end
949 end
950
951 redef class AContinueExpr
952 redef meth compile_stmt(v)
953 do
954 if n_expr != null then
955 var e = v.compile_expr(n_expr)
956 v.add_assignment(v.nmc.continue_value, e)
957 end
958 v.add_instr("goto {v.nmc.continue_label};")
959 end
960 end
961
962 redef class AAbortExpr
963 redef meth compile_stmt(v)
964 do
965 v.add_instr("fprintf(stderr, \"Aborted\"); {v.printf_locate_error(self)} nit_exit(1);")
966 end
967 end
968
969 redef class ADoExpr
970 redef meth compile_stmt(v)
971 do
972 if n_block != null then
973 v.compile_stmt(n_block)
974 end
975 end
976 end
977
978 redef class AIfExpr
979 redef meth compile_stmt(v)
980 do
981 var e = v.compile_expr(n_expr)
982 v.add_instr("if (UNTAG_Bool({e})) \{ /*if*/")
983 v.cfc.free_var(e)
984 if n_then != null then
985 v.indent
986 v.compile_stmt(n_then)
987 v.unindent
988 end
989 if n_else != null then
990 v.add_instr("} else \{ /*if*/")
991 v.indent
992 v.compile_stmt(n_else)
993 v.unindent
994 end
995 v.add_instr("}")
996 end
997 end
998
999 redef class AIfexprExpr
1000 redef meth compile_expr(v)
1001 do
1002 var e = v.compile_expr(n_expr)
1003 v.add_instr("if (UNTAG_Bool({e})) \{ /*if*/")
1004 v.cfc.free_var(e)
1005 v.indent
1006 var e = v.ensure_var(v.compile_expr(n_then), "Then value")
1007 v.unindent
1008 v.add_instr("} else \{ /*if*/")
1009 v.cfc.free_var(e)
1010 v.indent
1011 var e2 = v.ensure_var(v.compile_expr(n_else), "Else value")
1012 v.add_assignment(e, e2)
1013 v.unindent
1014 v.add_instr("}")
1015 return e
1016 end
1017 end
1018
1019 redef class AControlableBlock
1020 meth compile_inside_block(v: CompilerVisitor) is abstract
1021 redef meth compile_stmt(v)
1022 do
1023 var old_break_label = v.nmc.break_label
1024 var old_continue_label = v.nmc.continue_label
1025 var id = v.new_number
1026 v.nmc.break_label = "break_{id}"
1027 v.nmc.continue_label = "continue_{id}"
1028
1029 compile_inside_block(v)
1030
1031
1032 v.nmc.break_label = old_break_label
1033 v.nmc.continue_label = old_continue_label
1034 end
1035 end
1036
1037 redef class AWhileExpr
1038 redef meth compile_inside_block(v)
1039 do
1040 v.add_instr("while (true) \{ /*while*/")
1041 v.indent
1042 var e = v.compile_expr(n_expr)
1043 v.add_instr("if (!UNTAG_Bool({e})) break; /* while*/")
1044 v.cfc.free_var(e)
1045 if n_block != null then
1046 v.compile_stmt(n_block)
1047 end
1048 v.add_instr("{v.nmc.continue_label}: while(0);")
1049 v.unindent
1050 v.add_instr("}")
1051 v.add_instr("{v.nmc.break_label}: while(0);")
1052 end
1053 end
1054
1055 redef class AForExpr
1056 redef meth compile_inside_block(v)
1057 do
1058 var e = v.compile_expr(n_expr)
1059 var ittype = meth_iterator.signature.return_type
1060 v.cfc.free_var(e)
1061 var iter = v.cfc.get_var("For iterator")
1062 v.add_assignment(iter, meth_iterator.compile_call(v, [e]))
1063 v.add_instr("while (true) \{ /*for*/")
1064 v.indent
1065 var ok = v.cfc.get_var("For 'is_ok' result")
1066 v.add_assignment(ok, meth_is_ok.compile_call(v, [iter]))
1067 v.add_instr("if (!UNTAG_Bool({ok})) break; /*for*/")
1068 v.cfc.free_var(ok)
1069 var e = meth_item.compile_call(v, [iter])
1070 e = v.ensure_var(e, "For item")
1071 var cname = v.cfc.register_variable(variable)
1072 v.add_assignment(cname, e)
1073 var n_block = n_block
1074 if n_block != null then
1075 v.compile_stmt(n_block)
1076 end
1077 v.add_instr("{v.nmc.continue_label}: while(0);")
1078 e = meth_next.compile_call(v, [iter])
1079 assert e == null
1080 v.unindent
1081 v.add_instr("}")
1082 v.add_instr("{v.nmc.break_label}: while(0);")
1083 end
1084 end
1085
1086 redef class AAssertExpr
1087 redef meth compile_stmt(v)
1088 do
1089 var e = v.compile_expr(n_expr)
1090 var s = ""
1091 if n_id != null then
1092 s = " '{n_id.text}' "
1093 end
1094 v.add_instr("if (!UNTAG_Bool({e})) \{ fprintf(stderr, \"Assert%s failed\", \"{s}\"); {v.printf_locate_error(self)} nit_exit(1);}")
1095 end
1096 end
1097
1098 redef class AVarExpr
1099 redef meth compile_expr(v)
1100 do
1101 return " {v.cfc.varname(variable)} /*{variable.name}*/"
1102 end
1103 end
1104
1105 redef class AVarAssignExpr
1106 redef meth compile_stmt(v)
1107 do
1108 var e = v.compile_expr(n_value)
1109 v.add_assignment(v.cfc.varname(variable), "{e} /*{variable.name}=*/")
1110 end
1111 end
1112
1113 redef class AVarReassignExpr
1114 redef meth compile_stmt(v)
1115 do
1116 var e1 = v.cfc.varname(variable)
1117 var e2 = v.compile_expr(n_value)
1118 var e3 = assign_method.compile_call(v, [e1, e2])
1119 v.add_assignment(v.cfc.varname(variable), "{e3} /*{variable.name}*/")
1120 end
1121 end
1122
1123 redef class ASelfExpr
1124 redef meth compile_expr(v)
1125 do
1126 return v.cfc.varname(v.nmc.method_params[0])
1127 end
1128 end
1129
1130 redef class AOrExpr
1131 redef meth compile_expr(v)
1132 do
1133 var e = v.ensure_var(v.compile_expr(n_expr), "Left 'or' operand")
1134 v.add_instr("if (!UNTAG_Bool({e})) \{ /* or */")
1135 v.cfc.free_var(e)
1136 v.indent
1137 var e2 = v.compile_expr(n_expr2)
1138 v.add_assignment(e, e2)
1139 v.unindent
1140 v.add_instr("}")
1141 return e
1142 end
1143 end
1144
1145 redef class AAndExpr
1146 redef meth compile_expr(v)
1147 do
1148 var e = v.ensure_var(v.compile_expr(n_expr), "Left 'and' operand")
1149 v.add_instr("if (UNTAG_Bool({e})) \{ /* and */")
1150 v.cfc.free_var(e)
1151 v.indent
1152 var e2 = v.compile_expr(n_expr2)
1153 v.add_assignment(e, e2)
1154 v.unindent
1155 v.add_instr("}")
1156 return e
1157 end
1158 end
1159
1160 redef class ANotExpr
1161 redef meth compile_expr(v)
1162 do
1163 return " TAG_Bool(!UNTAG_Bool({v.compile_expr(n_expr)}))"
1164 end
1165 end
1166
1167 redef class AEeExpr
1168 redef meth compile_expr(v)
1169 do
1170 var e = v.compile_expr(n_expr)
1171 var e2 = v.compile_expr(n_expr2)
1172 return "TAG_Bool(IS_EQUAL_NN({e},{e2}))"
1173 end
1174 end
1175
1176 redef class AIsaExpr
1177 redef meth compile_expr(v)
1178 do
1179 var e = v.compile_expr(n_expr)
1180 return n_type.stype.compile_cast(v, e)
1181 end
1182 end
1183
1184 redef class AAsCastExpr
1185 redef meth compile_expr(v)
1186 do
1187 var e = v.compile_expr(n_expr)
1188 n_type.stype.compile_type_check(v, e, self)
1189 return e
1190 end
1191 end
1192
1193 redef class ATrueExpr
1194 redef meth compile_expr(v)
1195 do
1196 return " TAG_Bool(true)"
1197 end
1198 end
1199
1200 redef class AFalseExpr
1201 redef meth compile_expr(v)
1202 do
1203 return " TAG_Bool(false)"
1204 end
1205 end
1206
1207 redef class AIntExpr
1208 redef meth compile_expr(v)
1209 do
1210 return " TAG_Int({n_number.text})"
1211 end
1212 end
1213
1214 redef class AFloatExpr
1215 redef meth compile_expr(v)
1216 do
1217 return "BOX_Float({n_float.text})"
1218 end
1219 end
1220
1221 redef class ACharExpr
1222 redef meth compile_expr(v)
1223 do
1224 return " TAG_Char({n_char.text})"
1225 end
1226 end
1227
1228 redef class AStringFormExpr
1229 redef meth compile_expr(v)
1230 do
1231 compute_string_info
1232 var i = v.new_number
1233 var cvar = v.cfc.get_var("Once String constant")
1234 v.add_decl("static val_t once_value_{i} = NIT_NULL; /* Once value for string {cvar}*/")
1235 v.add_instr("if (once_value_{i} != NIT_NULL) {cvar} = once_value_{i};")
1236 v.add_instr("else \{")
1237 v.indent
1238 v.cfc.free_var(cvar)
1239 var e = meth_with_native.compile_constructor_call(v, stype , ["BOX_NativeString(\"{_cstring}\")", "TAG_Int({_cstring_length})"])
1240 v.add_assignment(cvar, e)
1241 v.add_instr("once_value_{i} = {cvar};")
1242 v.unindent
1243 v.add_instr("}")
1244 return cvar
1245 end
1246
1247 # The raw string value
1248 protected meth string_text: String is abstract
1249
1250 # The string in a C native format
1251 protected attr _cstring: String
1252
1253 # The string length in bytes
1254 protected attr _cstring_length: Int
1255
1256 # Compute _cstring and _cstring_length using string_text
1257 protected meth compute_string_info
1258 do
1259 var len = 0
1260 var str = string_text
1261 var res = new Buffer
1262 var i = 0
1263 while i < str.length do
1264 var c = str[i]
1265 if c == '\\' then
1266 i = i + 1
1267 var c2 = str[i]
1268 if c2 != '{' and c2 != '}' then
1269 res.add(c)
1270 end
1271 c = c2
1272 end
1273 len = len + 1
1274 res.add(c)
1275 i = i + 1
1276 end
1277 _cstring = res.to_s
1278 _cstring_length = len
1279 end
1280 end
1281
1282 redef class AStringExpr
1283 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1284 end
1285 redef class AStartStringExpr
1286 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1287 end
1288 redef class AMidStringExpr
1289 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1290 end
1291 redef class AEndStringExpr
1292 redef meth string_text do return n_string.text.substring(1, n_string.text.length - 2)
1293 end
1294
1295 redef class ASuperstringExpr
1296 redef meth compile_expr(v)
1297 do
1298 var array = meth_with_capacity.compile_constructor_call(v, atype, ["TAG_Int({n_exprs.length})"])
1299 array = v.ensure_var(array, "Array (for super-string)")
1300
1301 for ne in n_exprs do
1302 var e = v.ensure_var(v.compile_expr(ne), "super-string element")
1303 if ne.stype != stype then
1304 v.add_assignment(e, meth_to_s.compile_call(v, [e]))
1305 end
1306 meth_add.compile_call(v, [array, e])
1307 end
1308
1309 return meth_to_s.compile_call(v, [array])
1310 end
1311 end
1312
1313 redef class ANullExpr
1314 redef meth compile_expr(v)
1315 do
1316 return " NIT_NULL /*null*/"
1317 end
1318 end
1319
1320 redef class AArrayExpr
1321 redef meth compile_expr(v)
1322 do
1323 var recv = meth_with_capacity.compile_constructor_call(v, stype, ["TAG_Int({n_exprs.length})"])
1324 recv = v.ensure_var(recv, "Literal array")
1325
1326 for ne in n_exprs do
1327 var e = v.compile_expr(ne)
1328 meth_add.compile_call(v, [recv, e])
1329 end
1330 return recv
1331 end
1332 end
1333
1334 redef class ARangeExpr
1335 redef meth compile_expr(v)
1336 do
1337 var e = v.compile_expr(n_expr)
1338 var e2 = v.compile_expr(n_expr2)
1339 return meth_init.compile_constructor_call(v, stype, [e, e2])
1340 end
1341 end
1342
1343 redef class ASuperExpr
1344 redef meth compile_stmt(v)
1345 do
1346 var e = compile_expr(v)
1347 if e != null then v.add_instr("{e};")
1348 end
1349
1350 redef meth compile_expr(v)
1351 do
1352 var arity = v.nmc.method_params.length - 1
1353 if init_in_superclass != null then
1354 arity = init_in_superclass.signature.arity
1355 end
1356 var args = new Array[String].with_capacity(arity + 1)
1357 args.add(v.cfc.varname(v.nmc.method_params[0]))
1358 if n_args.length != arity then
1359 for i in [0..arity[ do
1360 args.add(v.cfc.varname(v.nmc.method_params[i + 1]))
1361 end
1362 else
1363 for na in n_args do
1364 args.add(v.compile_expr(na))
1365 end
1366 end
1367 #return "{prop.cname}({args.join(", ")}) /*super {prop.local_class}::{prop.name}*/"
1368 if init_in_superclass != null then
1369 return init_in_superclass.compile_call(v, args)
1370 else
1371 if prop.global.is_init then args.add("init_table")
1372 return prop.compile_super_call(v, args)
1373 end
1374 end
1375 end
1376
1377 redef class AAttrExpr
1378 redef meth compile_expr(v)
1379 do
1380 var e = v.compile_expr(n_expr)
1381 return prop.compile_access(v, e)
1382 end
1383 end
1384
1385 redef class AAttrAssignExpr
1386 redef meth compile_stmt(v)
1387 do
1388 var e = v.compile_expr(n_expr)
1389 var e2 = v.compile_expr(n_value)
1390 v.add_assignment(prop.compile_access(v, e), e2)
1391 end
1392 end
1393 redef class AAttrReassignExpr
1394 redef meth compile_stmt(v)
1395 do
1396 var e1 = v.compile_expr(n_expr)
1397 var e2 = prop.compile_access(v, e1)
1398 var e3 = v.compile_expr(n_value)
1399 var e4 = assign_method.compile_call(v, [e2, e3])
1400 v.add_assignment(e2, e4)
1401 end
1402 end
1403
1404 redef class ASendExpr
1405 redef meth compile_expr(v)
1406 do
1407 var recv = v.compile_expr(n_expr)
1408 var cargs = new Array[String]
1409 cargs.add(recv)
1410 for a in arguments do
1411 cargs.add(v.compile_expr(a))
1412 end
1413
1414 var e: String
1415 if prop_signature.closures.is_empty then
1416 e = prop.compile_call(v, cargs)
1417 else
1418 e = prop.compile_call_and_closures(v, cargs, closure_defs)
1419 end
1420
1421 if prop.global.is_init then
1422 v.invoke_super_init_calls_after(prop)
1423 end
1424 return e
1425 end
1426
1427 redef meth compile_stmt(v)
1428 do
1429 var e = compile_expr(v)
1430 if e != null then
1431 v.add_instr(e + ";")
1432 end
1433 end
1434 end
1435
1436 redef class ASendReassignExpr
1437 redef meth compile_expr(v)
1438 do
1439 var recv = v.compile_expr(n_expr)
1440 var cargs = new Array[String]
1441 cargs.add(recv)
1442 for a in arguments do
1443 cargs.add(v.compile_expr(a))
1444 end
1445
1446 var e2 = read_prop.compile_call(v, cargs)
1447 var e3 = v.compile_expr(n_value)
1448 var e4 = assign_method.compile_call(v, [e2, e3])
1449 cargs.add(e4)
1450 return prop.compile_call(v, cargs)
1451 end
1452 end
1453
1454 redef class ANewExpr
1455 redef meth compile_expr(v)
1456 do
1457 var cargs = new Array[String]
1458 for a in arguments do
1459 cargs.add(v.compile_expr(a))
1460 end
1461 return prop.compile_constructor_call(v, stype, cargs)
1462 end
1463 end
1464
1465 redef class PClosureDef
1466 # Compile the closure definition as a function in v.out_contexts
1467 # Return the cname of the function
1468 meth compile_closure(v: CompilerVisitor, closcn: String): String is abstract
1469
1470 # Compile the closure definition inside the current C function.
1471 meth do_compile_inside(v: CompilerVisitor, params: Array[String]): String is abstract
1472 end
1473
1474 redef class AClosureDef
1475 # The cname of the function
1476 readable attr _cname: String
1477
1478 redef meth compile_closure(v, closcn)
1479 do
1480 var ctx_old = v.ctx
1481 v.ctx = new CContext
1482 v.out_contexts.add(v.ctx)
1483
1484 var cfc_old = v.cfc.closure
1485 v.cfc.closure = v.nmc
1486
1487 var old_rv = v.nmc.return_value
1488 var old_bv = v.nmc.break_value
1489 if cfc_old == null then
1490 v.nmc.return_value = "closctx->{old_rv}"
1491 v.nmc.break_value = "closctx->{old_bv}"
1492 end
1493
1494 var cname = "OC_{v.nmc.method.cname}_{v.out_contexts.length}"
1495 _cname = cname
1496 var args = new Array[String]
1497 for i in [0..closure.signature.arity[ do
1498 args.add(" param{i}")
1499 end
1500
1501 var cs = decl_csignature(v, args, closcn)
1502
1503 v.add_instr("{cs} \{")
1504 v.indent
1505 var ctx_old2 = v.ctx
1506 v.ctx = new CContext
1507
1508 v.add_decl("struct trace_t trace = \{NULL, NULL, {line_number}, LOCATE_{v.nmc.method.cname}};")
1509 v.add_instr("trace.prev = tracehead; tracehead = &trace;")
1510
1511 v.add_instr("trace.file = LOCATE_{v.module.name};")
1512 var s = do_compile_inside(v, args)
1513
1514 v.add_instr("{v.nmc.return_label}:")
1515 v.add_instr("tracehead = trace.prev;")
1516 if s == null then
1517 v.add_instr("return;")
1518 else
1519 v.add_instr("return {s};")
1520 end
1521
1522 ctx_old2.append(v.ctx)
1523 v.ctx = ctx_old2
1524 v.unindent
1525 v.add_instr("}")
1526 v.ctx = ctx_old
1527
1528 v.cfc.closure = cfc_old
1529 v.nmc.return_value = old_rv
1530 v.nmc.break_value = old_bv
1531
1532 # Build closure
1533 var closcnv = "wbclos{v.new_number}"
1534 v.add_decl("struct WBT_ {closcnv};")
1535 v.add_instr("{closcnv}.fun = (fun_t){cname};")
1536 v.add_instr("{closcnv}.has_broke = NULL;")
1537 if cfc_old != null then
1538 v.add_instr("{closcnv}.variable = closctx->variable;")
1539 v.add_instr("{closcnv}.closurevariable = closctx->closurevariable;")
1540 else
1541 v.add_instr("{closcnv}.variable = variable;")
1542 v.add_instr("{closcnv}.closurevariable = closurevariable;")
1543 end
1544
1545 return "(&{closcnv})"
1546 end
1547
1548 protected meth decl_csignature(v: CompilerVisitor, args: Array[String], closcn: String): String
1549 do
1550 var params = new Array[String]
1551 params.add("struct WBT_ *closctx")
1552 for i in [0..closure.signature.arity[ do
1553 var p = "val_t {args[i]}"
1554 params.add(p)
1555 end
1556 var ret: String
1557 if closure.signature.return_type != null then
1558 ret = "val_t"
1559 else
1560 ret = "void"
1561 end
1562 var p = params.join(", ")
1563 var s = "{ret} {cname}({p})"
1564 v.add_decl("typedef {ret} (* {cname}_t)({p});")
1565 v.add_decl(s + ";")
1566 return s
1567 end
1568
1569 redef meth do_compile_inside(v, params)
1570 do
1571 for i in [0..variables.length[ do
1572 var vacname = v.cfc.register_variable(variables[i])
1573 v.add_assignment(vacname, params[i])
1574 end
1575
1576 var old_cv = v.nmc.continue_value
1577 var old_cl = v.nmc.continue_label
1578 var old_bl = v.nmc.break_label
1579
1580 v.nmc.continue_value = v.cfc.get_var("Continue value and escape marker")
1581 v.nmc.continue_label = "continue_label{v.new_number}"
1582 v.nmc.break_label = v.nmc.return_label
1583
1584 if n_expr != null then v.compile_stmt(n_expr)
1585
1586 v.add_instr("{v.nmc.continue_label}: while(false);")
1587
1588 var ret: String = null
1589 if closure.signature.return_type != null then ret = v.nmc.continue_value
1590
1591 v.nmc.continue_value = old_cv
1592 v.nmc.continue_label = old_cl
1593 v.nmc.break_label = old_bl
1594
1595 return ret
1596 end
1597 end
1598
1599 redef class PClosureDecl
1600 meth do_compile_inside(v: CompilerVisitor, params: Array[String]): String is abstract
1601 end
1602 redef class AClosureDecl
1603 redef meth do_compile_inside(v, params)
1604 do
1605 if n_signature != null then n_signature.compile_parameters(v, variable.closure.signature, params)
1606
1607 var old_cv = v.nmc.continue_value
1608 var old_cl = v.nmc.continue_label
1609 var old_bl = v.nmc.break_label
1610
1611 v.nmc.continue_value = v.cfc.get_var("Continue value and escape marker")
1612 v.nmc.continue_label = "continue_label{v.new_number}"
1613 v.nmc.break_label = v.nmc.return_label
1614
1615 if n_expr != null then v.compile_stmt(n_expr)
1616
1617 v.add_instr("{v.nmc.continue_label}: while(false);")
1618
1619 var ret: String = null
1620 if variable.closure.signature.return_type != null then ret = v.nmc.continue_value
1621
1622 v.nmc.continue_value = old_cv
1623 v.nmc.continue_label = old_cl
1624 v.nmc.break_label = old_bl
1625
1626 return ret
1627 end
1628 end
1629
1630 redef class AClosureCallExpr
1631 redef meth compile_expr(v)
1632 do
1633 var cargs = new Array[String]
1634 for a in arguments do cargs.add(v.compile_expr(a))
1635 var va: String = null
1636 if variable.closure.signature.return_type != null then va = v.cfc.get_var("Closure call result value")
1637
1638 if variable.closure.is_optional then
1639 v.add_instr("if({v.cfc.varname(variable)}==NULL) \{")
1640 v.indent
1641 var n = variable.decl
1642 assert n isa AClosureDecl
1643 var s = n.do_compile_inside(v, cargs)
1644 if s != null then v.add_assignment(va, s)
1645 v.unindent
1646 v.add_instr("} else \{")
1647 v.indent
1648 end
1649
1650 var ivar = v.cfc.varname(variable)
1651 var cargs2 = [ivar]
1652 cargs2.append(cargs)
1653 var s = "(({variable.ctypename})({ivar}->fun))({cargs2.join(", ")}) /* Invoke closure {variable} */"
1654 if va != null then
1655 v.add_assignment(va, s)
1656 else
1657 v.add_instr("{s};")
1658 end
1659 v.add_instr("if ({ivar}->has_broke) \{")
1660 v.indent
1661 if n_closure_defs != null and n_closure_defs.length == 1 then do
1662 n_closure_defs.first.do_compile_inside(v, null)
1663 end
1664 if v.cfc.closure == v.nmc then v.add_instr("if ({ivar}->has_broke) \{ closctx->has_broke = {ivar}->has_broke; closctx->broke_value = {ivar}->broke_value;\}")
1665 v.add_instr("goto {v.nmc.return_label};")
1666 v.unindent
1667 v.add_instr("\}")
1668
1669 if variable.closure.is_optional then
1670 v.unindent
1671 v.add_instr("\}")
1672 end
1673 return va
1674 end
1675 end
1676
1677 redef class AProxyExpr
1678 redef meth compile_expr(v)
1679 do
1680 return v.compile_expr(n_expr)
1681 end
1682 end
1683
1684 redef class AOnceExpr
1685 redef meth compile_expr(v)
1686 do
1687 var i = v.new_number
1688 var cvar = v.cfc.get_var("Once expression result")
1689 v.add_decl("static val_t once_value_{i}; static int once_bool_{i}; /* Once value for {cvar}*/")
1690 v.add_instr("if (once_bool_{i}) {cvar} = once_value_{i};")
1691 v.add_instr("else \{")
1692 v.indent
1693 v.cfc.free_var(cvar)
1694 var e = v.compile_expr(n_expr)
1695 v.add_assignment(cvar, e)
1696 v.add_instr("once_value_{i} = {cvar};")
1697 v.add_instr("once_bool_{i} = true;")
1698 v.unindent
1699 v.add_instr("}")
1700 return cvar
1701 end
1702 end