+ compile_arguments_in(v, cargs)
+ return prop.compile_constructor_call(v, stype, cargs)
+ end
+
+ redef fun compile_stmt(v) do abort
+end
+
+redef class PClosureDef
+ # Compile the closure definition as a function in v.out_contexts
+ # Return the cname of the function
+ fun compile_closure(v: CompilerVisitor, closcn: String): String is abstract
+
+ # Compile the closure definition inside the current C function.
+ fun do_compile_inside(v: CompilerVisitor, params: nullable Array[String]): nullable String is abstract
+end
+
+redef class AClosureDef
+ # The cname of the function
+ readable var _cname: nullable String
+
+ redef fun compile_closure(v, closcn)
+ do
+ var ctx_old = v.ctx
+ v.ctx = new CContext
+ v.out_contexts.add(v.ctx)
+
+ var cfc_old = v.cfc.closure
+ v.cfc.closure = v.nmc
+
+ var old_rv = v.nmc.return_value
+ var old_bv = v.nmc.break_value
+ if cfc_old == null then
+ v.nmc.return_value = "closctx->{old_rv}"
+ v.nmc.break_value = "closctx->{old_bv}"
+ end
+
+ var cname = "OC_{v.nmc.method.cname}_{v.out_contexts.length}"
+ _cname = cname
+ var args = new Array[String]
+ for i in [0..closure.signature.arity[ do
+ args.add(" param{i}")
+ end
+
+ var cs = decl_csignature(v, args, closcn)
+
+ v.add_instr("{cs} \{")
+ v.indent
+ var ctx_old2 = v.ctx
+ v.ctx = new CContext
+
+ v.add_decl("struct trace_t trace = \{NULL, NULL, {line_number}, LOCATE_{v.nmc.method.cname}};")
+ v.add_instr("trace.prev = tracehead; tracehead = &trace;")
+
+ v.add_instr("trace.file = LOCATE_{v.module.name};")
+ var s = do_compile_inside(v, args)
+
+ v.add_instr("{v.nmc.return_label}:")
+ v.add_instr("tracehead = trace.prev;")
+ if s == null then
+ v.add_instr("return;")
+ else
+ v.add_instr("return {s};")
+ end
+
+ ctx_old2.append(v.ctx)
+ v.ctx = ctx_old2
+ v.unindent
+ v.add_instr("}")
+ v.ctx = ctx_old
+
+ v.cfc.closure = cfc_old
+ v.nmc.return_value = old_rv
+ v.nmc.break_value = old_bv
+
+ # Build closure
+ var closcnv = "wbclos{v.new_number}"
+ v.add_decl("struct WBT_ {closcnv};")
+ v.add_instr("{closcnv}.fun = (fun_t){cname};")
+ v.add_instr("{closcnv}.has_broke = NULL;")
+ if cfc_old != null then
+ v.add_instr("{closcnv}.variable = closctx->variable;")
+ v.add_instr("{closcnv}.closurevariable = closctx->closurevariable;")
+ else
+ v.add_instr("{closcnv}.variable = variable;")
+ v.add_instr("{closcnv}.closurevariable = closurevariable;")
+ end
+
+ return "(&{closcnv})"
+ end
+
+ protected fun decl_csignature(v: CompilerVisitor, args: Array[String], closcn: String): String
+ do
+ var params = new Array[String]
+ params.add("struct WBT_ *closctx")
+ for i in [0..closure.signature.arity[ do
+ var p = "val_t {args[i]}"
+ params.add(p)
+ end
+ var ret: String
+ if closure.signature.return_type != null then
+ ret = "val_t"
+ else
+ ret = "void"
+ end
+ var p = params.join(", ")
+ var s = "{ret} {cname}({p})"
+ v.add_decl("typedef {ret} (* {cname}_t)({p});")
+ v.add_decl(s + ";")
+ return s
+ end
+
+ redef fun do_compile_inside(v, params)
+ do
+ for i in [0..variables.length[ do
+ var vacname = v.cfc.register_variable(variables[i])
+ v.add_assignment(vacname, params[i])
+ end
+
+ var old_cv = v.nmc.continue_value
+ var old_cl = v.nmc.continue_label
+ var old_bl = v.nmc.break_label
+
+ v.nmc.continue_value = v.cfc.get_var("Continue value and escape marker")
+ v.nmc.continue_label = "continue_label{v.new_number}"
+ v.nmc.break_label = v.nmc.return_label
+
+ v.compile_stmt(n_expr)
+
+ v.add_instr("{v.nmc.continue_label}: while(false);")
+
+ var ret: nullable String = null
+ if closure.signature.return_type != null then ret = v.nmc.continue_value
+
+ v.nmc.continue_value = old_cv
+ v.nmc.continue_label = old_cl
+ v.nmc.break_label = old_bl
+
+ return ret
+ end
+end
+
+redef class PClosureDecl
+ fun do_compile_inside(v: CompilerVisitor, params: Array[String]): nullable String is abstract
+end
+redef class AClosureDecl
+ redef fun do_compile_inside(v, params)
+ do
+ n_signature.compile_parameters(v, variable.closure.signature, params)
+
+ var old_cv = v.nmc.continue_value
+ var old_cl = v.nmc.continue_label
+ var old_bl = v.nmc.break_label
+
+ v.nmc.continue_value = v.cfc.get_var("Continue value and escape marker")
+ v.nmc.continue_label = "continue_label{v.new_number}"
+ v.nmc.break_label = v.nmc.return_label
+
+ v.compile_stmt(n_expr)
+
+ v.add_instr("{v.nmc.continue_label}: while(false);")
+
+ var ret: nullable String = null
+ if variable.closure.signature.return_type != null then ret = v.nmc.continue_value
+
+ v.nmc.continue_value = old_cv
+ v.nmc.continue_label = old_cl
+ v.nmc.break_label = old_bl
+
+ return ret
+ end
+end
+
+redef class AClosureCallExpr
+ fun intern_compile_call(v: CompilerVisitor): nullable String
+ do
+ var cargs = new Array[String]
+ compile_arguments_in(v, cargs)
+ var va: nullable String = null
+ if variable.closure.signature.return_type != null then va = v.cfc.get_var("Closure call result value")
+
+ if variable.closure.is_optional then
+ v.add_instr("if({v.cfc.varname(variable)}==NULL) \{")
+ v.indent
+ var n = variable.decl
+ assert n isa AClosureDecl
+ var s = n.do_compile_inside(v, cargs)
+ if s != null then v.add_assignment(va.as(not null), s)
+ v.unindent
+ v.add_instr("} else \{")
+ v.indent
+ end
+
+ var ivar = v.cfc.varname(variable)
+ var cargs2 = [ivar]
+ cargs2.append(cargs)
+ var s = "(({variable.ctypename})({ivar}->fun))({cargs2.join(", ")}) /* Invoke closure {variable} */"
+ if va != null then
+ v.add_assignment(va, s)
+ else
+ v.add_instr("{s};")
+ end
+ v.add_instr("if ({ivar}->has_broke) \{")
+ v.indent
+ if n_closure_defs.length == 1 then do
+ n_closure_defs.first.do_compile_inside(v, null)
+ end
+ 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;\}")
+ v.add_instr("goto {v.nmc.return_label};")
+ v.unindent
+ v.add_instr("\}")
+
+ if variable.closure.is_optional then
+ v.unindent
+ v.add_instr("\}")
+ end
+ return va
+ end
+
+ redef fun compile_expr(v)
+ do
+ var e = intern_compile_call(v)
+ assert e != null
+ return e
+ end
+
+ redef fun compile_stmt(v)
+ do
+ var e = intern_compile_call(v)
+ if e != null then
+ v.add_instr(e + ";")