011dca57695458f97f85bd63b6b4575fb3af178a
[nit.git] / src / compiling / compiling_icode.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 # Generate C code from intermediate code representation
18 package compiling_icode
19
20 import icode
21 private import analysis
22 import compiling_base
23
24 # Compiler context from ICode to C
25 class I2CCompilerVisitor
26 # Associate things
27 var _ids: HashMap[Object, String] = new HashMap[Object, String]
28 # Associate other things
29 var _ids2: HashMap[Object, String] = new HashMap[Object, String]
30
31 # Return the string associated with a register
32 fun register(e: IRegister): String
33 do
34 if e.stype isa MMTypeNone then return "NIT_NULL"
35 var ids = _ids
36 if closure and not e.is_local then ids = _ids2
37 if ids.has_key(e) then
38 return ids[e]
39 else
40 var i = e.slot_index
41 if i == null then
42 # The register is dead
43 var s = "NIT_NULL"
44 ids[e] = s
45 return s
46 else
47 var s: String
48 var strs: HashMap[Int, String]
49 if e.in_tag_slots then
50 strs = once new HashMap[Int, String]
51 if not strs.has_key(i) then strs[i] = "REGB{i}"
52 else if closure and not e.is_local then
53 strs = once new HashMap[Int, String]
54 if not strs.has_key(i) then strs[i] = "closctx->REG[{i}]"
55 else
56 strs = once new HashMap[Int, String]
57 if not strs.has_key(i) then strs[i] = "fra.me.REG[{i}]"
58 end
59 s = strs[i]
60 ids[e] = s
61 return s
62 end
63 end
64 end
65
66 # Return the strings associated with registers
67 fun registers(a: Collection[IRegister]): Array[String]
68 do
69 var r = new Array[String].with_capacity(a.length)
70 for e in a do
71 r.add(register(e))
72 end
73 return r
74 end
75
76 var _last_number: Int = 0
77 # Give a new unique number (unique for the visitor)
78 fun new_number: Int
79 do
80 _last_number += 1
81 return _last_number
82 end
83
84 # Return the string associated with a escape label
85 fun lab(e: ISeq): String
86 do
87 if _ids.has_key(e) then
88 return _ids[e]
89 else
90 var s = "label{new_number}"
91 _ids[e] = s
92 return s
93 end
94 end
95
96 # The rank (number) of each closure
97 readable var _closures: HashMap[IClosureDecl, Int] = new HashMap[IClosureDecl, Int]
98
99 # The functionnal type of each closure
100 readable var _clostypes: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
101
102 # label locally accessibles
103 readable writable var _local_labels: HashSet[ISeq] = new HashSet[ISeq]
104
105 # Not local escaped labels
106 # The integer value is an index identifying the label
107 readable writable var _escaped_labels: HashMap[ISeq, Int] = new HashMap[ISeq, Int]
108
109 # Register a escape to a non local label and return an index identifying the label
110 fun register_escape_label(e: ISeq): Int
111 do
112 if _escaped_labels.has_key(e) then
113 return _escaped_labels[e]
114 else
115 var res = _escaped_labels.length + 1
116 _escaped_labels[e] = res
117 return res
118 end
119 end
120
121 # Add a C label mark (if needed)
122 fun add_label(e: ISeq)
123 do
124 if _ids.has_key(e) then
125 add_instr("{_ids[e]}: while(0);")
126 end
127 end
128
129 # Add a goto to a label (even outside a closure)
130 fun add_goto(seq: ISeq)
131 do
132 if local_labels.has(seq) then
133 add_instr("goto {lab(seq)};")
134 else
135 assert closure
136 var ind = register_escape_label(seq)
137 add_instr("closctx->has_broke = {ind};")
138 add_instr("goto {lab(return_label.as(not null))};")
139 end
140 end
141
142 # Are we in a closure ?
143 readable writable var _closure: Bool = false
144
145 # The current compiler visitor
146 readable var _visitor: CompilerVisitor
147
148 # The current compiled iroutine
149 readable var _iroutine: IRoutine
150
151 # The return label of the current compiling C function
152 readable writable var _return_label: nullable ISeq = null
153
154 fun add_decl(s: String)
155 do
156 visitor.add_decl(s)
157 end
158
159 fun add_instr(s: String)
160 do
161 var l = _next_location
162 if l != null then
163 visitor.add_instr("/* ", l.file, ":", l.line_start.to_s, " */")
164 _next_location = null
165 end
166 visitor.add_instr(s)
167 end
168
169 fun indent
170 do
171 visitor.indent
172 end
173
174 fun unindent
175 do
176 visitor.unindent
177 end
178
179 fun add_assignment(to, from: String)
180 do
181 visitor.add_assignment(to, from)
182 end
183
184 var _last_location: nullable Location = null
185 var _next_location: nullable Location = null
186
187 # Add location information in a comment
188 # Do nothing if the last location added is the same
189 fun add_location(l: nullable Location)
190 do
191 var last = _last_location
192 if last == l or l == null then return
193 _last_location = l
194 if last != null and last.file == l.file and last.line_start == l.line_start then
195 return
196 else
197 _next_location = l
198 end
199 end
200
201 # The C fonction name of the iroutine
202 readable var _basecname: String
203
204 init(v: CompilerVisitor, ir: IRoutine, cname: String)
205 do
206 _visitor = v
207 _iroutine = ir
208 _basecname = cname
209 end
210 end
211
212 redef class IRoutine
213 # Declare and start a C function that match the routine
214 # Return what must be given to compile_inside_to_c or to compile_to_c
215 # After the method, an openinig { and and indent is added.
216 # So, do not forget to add a sub_context, to unintent and to add a closing }
217 fun compile_signature_to_c(v: CompilerVisitor, cname: String, human_name: nullable String, before_params, after_params: nullable String): Array[String]
218 do
219 var cargs = new Array[String]
220 var cparams = new Array[String]
221 if before_params != null then cparams.add(before_params)
222 for i in [0..params.length[ do
223 cargs.add("p{i}")
224 cparams.add("val_t p{i}")
225 end
226 if closure_decls != null then
227 cparams.add("struct stack_frame_t *closctx_param")
228 for i in [0..closure_decls.length[ do
229 var closcn = "CLOS_{cname}_{i}"
230 var cs = closure_decls[i].closure.signature
231 var subparams = new Array[String] # Parameters of the closure
232 subparams.add("struct stack_frame_t *")
233 for j in [0..cs.arity[ do
234 subparams.add("val_t")
235 end
236 var rr = "void"
237 if cs.return_type != null then rr = "val_t"
238 v.add_decl("typedef {rr} (*{closcn})({subparams.join(", ")});")
239 cargs.add("clos_fun{i}")
240 cparams.add("fun_t clos_fun{i}")
241 end
242 end
243 if after_params != null then cparams.add(after_params)
244 var r = "void"
245 if result != null then r = "val_t"
246 var p: String
247 if cparams.is_empty then
248 p = "void"
249 else
250 p = cparams.join(", ")
251 end
252 if human_name != null then v.add_decl("#define LOCATE_", cname, " \"", human_name, "\"")
253 v.add_decl(r, " ", cname, "(", p, ");")
254 v.add_decl("typedef ", r, " (*", cname, "_t)(", p, ");")
255 v.add_instr(r, " ", cname, "(", p, ")\{")
256 v.indent
257 return cargs
258 end
259
260 # Compile the body of the routine, return the result value is any
261 fun compile_inside_to_c(v: I2CCompilerVisitor, args: Array[String]): nullable String
262 do
263 # Create and push the stack frame
264 var ll = 0
265 if location != null then
266 ll = location.line_start
267 end
268 # Encapsulate the frame ('me') in a larger structure ('fra') that has enough space to store the local variables (REG)
269 if std_slots_nb > 1 then
270 v.add_decl("struct \{struct stack_frame_t me; val_t MORE_REG[{std_slots_nb-1}];\} fra;")
271 else
272 v.add_decl("struct \{struct stack_frame_t me;\} fra;")
273 end
274 v.add_instr("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;")
275 v.add_instr("fra.me.file = LOCATE_{v.visitor.module.name};")
276 v.add_instr("fra.me.line = {ll};")
277 v.add_instr("fra.me.meth = LOCATE_{v.basecname};")
278 v.add_instr("fra.me.has_broke = 0;")
279 v.add_instr("fra.me.REG_size = {std_slots_nb};")
280
281 # Declare/initialize local variables
282 for i in [0..std_slots_nb[ do
283 v.add_instr("fra.me.REG[{i}] = NIT_NULL;")
284 end
285 for i in [0..tag_slots_nb[ do
286 v.add_decl("val_t REGB{i};")
287 end
288 var iclosdecls = closure_decls
289 if iclosdecls != null then
290 v.add_decl("fun_t CREG[{iclosdecls.length}];")
291 v.add_instr("fra.me.closure_ctx = closctx_param;")
292 v.add_instr("fra.me.closure_funs = CREG;")
293 end
294 var k = 0
295 for r in params do
296 if r.slot_index != null then v.add_assignment(v.register(r), args[k])
297 k += 1
298 end
299 if iclosdecls != null then
300 for i in [0..iclosdecls.length[ do
301 var iclosdecl = iclosdecls[i]
302 v.add_instr("CREG[{i}] = {args[params.length+i]};")
303 v.closures[iclosdecl] = i
304 var cs = iclosdecl.closure.signature # Closure signature
305 var subparams = new Array[String] # Parameters of the closure
306 subparams.add("struct stack_frame_t *")
307 for j in [0..cs.arity[ do
308 var p = "val_t"
309 subparams.add(p)
310 end
311 var r = "void"
312 if cs.return_type != null then r = "val_t"
313 v.clostypes[iclosdecl] = "{r} (*)({subparams.join(", ")})"
314 end
315 end
316 v.add_decl("val_t tmp;")
317
318 # Prepare return
319 var old_rl = v.return_label
320 v.return_label = body
321
322 # Compile body
323 body.compile_to_c(v)
324
325 v.add_instr("stack_frame_head = fra.me.prev;")
326 v.return_label = old_rl
327 var r = result
328 if r != null then
329 return v.register(r)
330 else
331 return null
332 end
333 end
334
335 # Full compilation of the routine
336 # Including optimization and other stuff.
337 # cv must be in the correct function
338 fun compile_to_c(cv: CompilerVisitor, cname: String, args: Array[String]): nullable String
339 do
340 optimize(cv.module)
341 var v = new I2CCompilerVisitor(cv, self, cname)
342 return compile_inside_to_c(v, args)
343 end
344 end
345
346 redef class ICode
347 # Full compilation of the icode
348 fun compile_to_c(v: I2CCompilerVisitor)
349 do
350 v.add_location(location)
351 store_result(v, inner_compile_to_c(v))
352 end
353
354 # Is a result really needed
355 private fun need_result: Bool
356 do
357 var r = result
358 return r != null and r.slot_index != null
359 end
360
361 # Store s in the result value of self
362 private fun store_result(v: I2CCompilerVisitor, s: nullable String)
363 do
364 var r = result
365 if r != null and r.slot_index != null then
366 assert s != null
367 v.add_assignment(v.register(r), s)
368 else if s != null and not is_pure then
369 # ICode with side effects must be evaluated
370 # even if the result is not wanted
371 v.add_instr(s + ";")
372 end
373 end
374
375 # Compilation of without the result assigment
376 # Return the right value is case of expression
377 # Return the full expression (witout ;) in case of statement
378 private fun inner_compile_to_c(v: I2CCompilerVisitor): nullable String is abstract
379 end
380
381 redef class ISeq
382 redef fun inner_compile_to_c(v)
383 do
384 v.local_labels.add(self)
385 for ic in icodes do
386 ic.compile_to_c(v)
387 end
388 v.add_label(self)
389 return null
390 end
391 end
392
393 redef class IIf
394 redef fun inner_compile_to_c(v)
395 do
396 v.add_instr("if (UNTAG_Bool({v.register(expr)})) \{")
397 if not then_seq.icodes.is_empty then
398 v.indent
399 then_seq.inner_compile_to_c(v)
400 v.unindent
401 end
402 if not else_seq.icodes.is_empty then
403 v.add_instr("} else \{")
404 v.indent
405 else_seq.inner_compile_to_c(v)
406 v.unindent
407 end
408 v.add_instr("}")
409 return null
410 end
411 end
412
413 redef class ILoop
414 redef fun inner_compile_to_c(v)
415 do
416 v.local_labels.add(self)
417 v.add_instr("while(1) \{")
418 v.indent
419 for ic in icodes do
420 ic.compile_to_c(v)
421 end
422 v.unindent
423 v.add_instr("}")
424 v.add_label(self)
425 return null
426 end
427 end
428
429 redef class IEscape
430 redef fun inner_compile_to_c(v)
431 do
432 v.add_goto(seq)
433 return null
434 end
435 end
436
437 redef class IAbsCall
438 redef fun compile_to_c(v)
439 do
440 v.add_location(location)
441 var args = v.registers(exprs)
442
443 # Compile closure definitions
444 var old_el = v.escaped_labels
445 var closdefs = closure_defs
446 var closctx: nullable String = null # The closure context of closdefs
447 if closdefs != null then
448 # Get the closure context
449 if v.closure then
450 closctx = "closctx"
451 else
452 closctx = "(&(fra.me))"
453 end
454
455 # First aditionnal arguments is the closure context
456 args.add(closctx)
457
458 # We are in a new escape boundary
459 v.escaped_labels = new HashMap[ISeq, Int]
460
461 # Compile each closures and add each sub-function as an other additionnal parameter
462 for cd in closdefs do
463 if cd != null then
464 var cn = cd.compile_closure(v)
465 args.add(cn)
466 else
467 args.add("NULL")
468 end
469 end
470 end
471
472 # Compile the real call
473 var s = compile_call_to_c(v, args)
474 var r: nullable String = s
475
476 # Intercept escapes
477 if closctx != null then
478 var els = v.escaped_labels
479 v.escaped_labels = old_el
480 # Is there possible escapes?
481 if not els.is_empty then
482 # Call in a tmp variable to avoid 'break' overwrite
483 if need_result then
484 r = "tmp"
485 v.add_assignment(r, s)
486 else
487 r = null
488 v.add_instr(s + ";")
489 end
490 # What are the expected escape indexes
491 v.add_instr("switch ({closctx}->has_broke) \{")
492 v.indent
493 # No escape occured, continue as usual
494 v.add_instr("case 0: break;")
495 var lls = v.local_labels
496 var iels = els.iterator
497 var forward_escape = false
498 while iels.is_ok do
499 var seq = iels.key
500 if lls.has(seq) then
501 # Local escape occured
502 # Clear the has_broke information and go to the target
503 v.add_instr("case {iels.item}: {closctx}->has_broke = 0; goto {v.lab(seq)};")
504 else
505 # Forward escape occured: register the escape label
506 assert v.closure
507 v.register_escape_label(seq)
508 forward_escape = true
509 end
510 iels.next
511 end
512 # If forward escape occured, just pass to the next one
513 if forward_escape then
514 # Do not need to copy 'has_broke' value since it is shared by the next one.
515 # So just exit the C function.
516 v.add_instr("default: goto {v.lab(v.return_label.as(not null))};")
517 end
518 v.unindent
519 v.add_instr("\}")
520 end
521 end
522
523 store_result(v, r)
524 end
525
526 redef fun inner_compile_to_c(v) do abort
527
528 # The single invocation witout fancy stuffs
529 private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): String is abstract
530 end
531
532 redef class ICall
533 redef fun compile_call_to_c(v, args)
534 do
535 var prop = property
536 if prop.global.is_init then args.add("init_table")
537 if prop.name == (once ("add".to_symbol)) and prop.local_class.name == (once ("Array".to_symbol)) then
538 return "{prop.cname}({args.join(", ")})"
539 else
540 return "{prop.global.meth_call}({args[0]})({args.join(", ")})"
541 end
542 end
543 end
544
545 redef class ISuper
546 redef fun compile_call_to_c(v, args)
547 do
548 var prop = property
549 if prop.global.is_init then args.add("init_table")
550 return "{prop.super_meth_call}({args[0]})({args.join(", ")})"
551 end
552 end
553
554 redef class INew
555 redef fun compile_call_to_c(v, args)
556 do
557 return "NEW_{stype.local_class}_{property.global.intro.cname}({args.join(", ")})"
558 end
559 end
560
561 redef class IAllocateInstance
562 redef fun inner_compile_to_c(v)
563 do
564 return "NEW_{stype.local_class.name}()"
565 end
566 end
567
568 redef class ICheckInstance
569 redef fun inner_compile_to_c(v)
570 do
571 return "CHECKNEW_{stype.local_class.name}({v.register(expr)})"
572 end
573 end
574
575 redef class IInitAttributes
576 redef fun inner_compile_to_c(v)
577 do
578 return "INIT_ATTRIBUTES__{stype.local_class.name}({v.register(expr)})"
579 end
580 end
581
582 redef class IStaticCall
583 redef fun compile_call_to_c(v, args)
584 do
585 var prop = property
586 if prop.global.is_init then args.add("init_table")
587 return "{property.cname}({args.join(", ")})"
588 end
589 end
590
591 redef class INative
592 redef fun inner_compile_to_c(v)
593 do
594 if exprs.is_empty then
595 return code
596 else
597 var res = new Buffer
598 var i = 0
599 var c = code.split_with("@@@")
600 for s in c do
601 res.append(s)
602 if i < exprs.length and i < c.length-1 then
603 res.append(v.register(exprs[i]))
604 end
605 i += 1
606 end
607 return res.to_s
608 end
609 end
610 end
611
612 redef class IAbort
613 redef fun inner_compile_to_c(v)
614 do
615 var s = new Buffer.from("fprintf(stderr")
616 for t in texts do
617 s.append(", \"{t}\"")
618 end
619 s.append(");")
620 v.add_instr(s.to_s)
621
622 var ll = location
623 s = new Buffer.from("fprintf(stderr, \" (%s")
624 if ll != null then
625 s.append(":%d")
626 end
627 s.append(")\\n\", LOCATE_{module_location.name}")
628 if ll != null then
629 s.append(", {ll.line_start}")
630 end
631 s.append(");")
632 v.add_instr(s.to_s)
633
634 v.add_instr("nit_exit(1);")
635 return null
636 end
637 end
638
639 redef class IMove
640 redef fun inner_compile_to_c(v)
641 do
642 return v.register(expr)
643 end
644 end
645
646 redef class IAttrRead
647 redef fun inner_compile_to_c(v)
648 do
649 return "{property.global.attr_access}({v.register(expr)})"
650 end
651 end
652
653 redef class IAttrIsset
654 redef fun inner_compile_to_c(v)
655 do
656 return "TAG_Bool({property.global.attr_access}({v.register(expr)})!=NIT_NULL)"
657 end
658 end
659
660 redef class IAttrWrite
661 redef fun inner_compile_to_c(v)
662 do
663 v.add_instr("{property.global.attr_access}({v.register(expr1)}) = {v.register(expr2)};")
664 return null
665 end
666 end
667
668 redef class ITypeCheck
669 redef fun inner_compile_to_c(v)
670 do
671 # FIXME handle formaltypes
672 var g = stype.local_class.global
673 var recv = v.register(expr)
674 var s = ""
675 if expr.stype.is_nullable then
676 if stype.is_nullable then
677 s = "({recv}==NIT_NULL) || "
678 else if stype.as_nullable == expr.stype then
679 return "TAG_Bool({recv}!=NIT_NULL)"
680 else
681 s = "({recv}!=NIT_NULL) && "
682 end
683 end
684 return "TAG_Bool({s}VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {stype}*/"
685 end
686 end
687
688 redef class IIs
689 redef fun inner_compile_to_c(v)
690 do
691 var t1 = expr1.stype
692 var t2 = expr2.stype
693 if t1 isa MMTypeNone then
694 if t2 isa MMTypeNone then
695 return "TAG_Bool(1)"
696 else if t2.is_nullable then
697 return "TAG_Bool({v.register(expr2)}==NIT_NULL)"
698 else
699 return "TAG_Bool(0)"
700 end
701 else if t1.is_nullable then
702 if t2 isa MMTypeNone then
703 return "TAG_Bool({v.register(expr1)}==NIT_NULL)"
704 else if t2.is_nullable then
705 return "TAG_Bool(IS_EQUAL_NN({v.register(expr1)},{v.register(expr2)}))"
706 else
707 return "TAG_Bool(IS_EQUAL_ON({v.register(expr2)},{v.register(expr1)}))"
708 end
709 else
710 if t2 isa MMTypeNone then
711 return "TAG_Bool(0)"
712 else if t2.is_nullable then
713 return "TAG_Bool(IS_EQUAL_ON({v.register(expr1)},{v.register(expr2)}))"
714 else
715 return "TAG_Bool(IS_EQUAL_OO({v.register(expr1)},{v.register(expr2)}))"
716 end
717 end
718 end
719 end
720
721 redef class INot
722 redef fun inner_compile_to_c(v)
723 do
724 return "TAG_Bool(!UNTAG_Bool({v.register(expr)}))"
725 end
726 end
727
728 redef class IOnce
729 redef fun inner_compile_to_c(v)
730 do
731 var i = v.new_number
732 var res = result.as(not null)
733 if res.stype.is_nullable then
734 v.add_decl("static val_t once_value_{i}; static int once_bool_{i}; /* Once value */")
735 v.add_instr("if (!once_bool_{i}) \{")
736 else
737 # Since the value is not nullable, we use the null value to represent the boolean
738 v.add_decl("static val_t once_value_{i}; /* Once value */")
739 v.add_instr("if (!once_value_{i}) \{")
740 end
741 v.indent
742 body.compile_to_c(v)
743 var e = v.register(result.as(not null))
744 v.add_instr("once_value_{i} = {e};")
745 v.add_instr("register_static_object(&once_value_{i});")
746 if res.stype.is_nullable then v.add_instr("once_bool_{i} = true;")
747 v.unindent
748 v.add_instr("} else {e} = once_value_{i};")
749 return e
750 end
751 end
752
753 redef class IClosCall
754 redef fun compile_to_c(v: I2CCompilerVisitor)
755 do
756 v.add_location(location)
757 var ivar: String
758 var args: Array[String]
759 if v.closure then
760 ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
761 args = ["closctx->closure_ctx"]
762 else
763 ivar = "CREG[{v.closures[closure_decl]}]"
764 args = ["closctx_param"]
765 end
766 args.append(v.registers(exprs))
767
768 var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
769 store_result(v, s)
770
771 # Intercept escape
772 v.add_instr("if ({args.first}->has_broke) \{")
773 v.indent
774 var bs = break_seq
775 if bs != null then
776 bs.compile_to_c(v)
777 end
778 v.add_goto(v.iroutine.body)
779 v.unindent
780 v.add_instr("\}")
781 end
782
783 redef fun inner_compile_to_c(v) do abort
784 end
785
786 redef class IHasClos
787 redef fun inner_compile_to_c(v)
788 do
789 var ivar: String
790 if v.closure then
791 ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
792 else
793 ivar = "CREG[{v.closures[closure_decl]}]"
794 end
795 return "TAG_Bool({ivar} != NULL)"
796 end
797 end
798
799 redef class IClosureDef
800 # Compile the closure as a separate C function in the visitor out_contexts.
801 # Return a fun_t pointer to the function.
802 fun compile_closure(v: I2CCompilerVisitor): String
803 do
804 var cv = v.visitor
805
806 # We are now in a closure
807 var cfc_old = v.closure
808 v.closure = true
809
810 # We are now in a escape boundary
811 var lls_old = v.local_labels
812 v.local_labels = new HashSet[ISeq]
813
814 # We are now in a new C context
815 var ctx_old = cv.ctx
816 cv.ctx = new CContext
817 cv.out_contexts.add(cv.ctx)
818
819 # Generate the C function
820 var cname = "OC_{v.basecname}_{v.new_number}"
821 var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
822 var ctx_old2 = cv.ctx
823 cv.ctx = new CContext
824 var s = compile_inside_to_c(v, args)
825 if s == null then
826 v.add_instr("return;")
827 else
828 v.add_instr("return {s};")
829 end
830 ctx_old2.append(cv.ctx)
831 cv.ctx = ctx_old2
832 v.unindent
833 v.add_instr("}")
834
835 # Restore things
836 cv.ctx = ctx_old
837 v.closure = cfc_old
838 v.local_labels = lls_old
839 return "((fun_t){cname})"
840 end
841 end