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