cargs.add(v.compile_expr(a))
end
- var cd = closure_defs
var e: String
- if cd == null then
+ if prop_signature.closures.is_empty then
e = prop.compile_call(v, cargs)
else
+ var cd = closure_defs
+ var arity = 0
+ if cd != null then arity = cd.length
var closcns = new Array[String]
var ve: String = null
v.nmc.break_value = ve
# Compile closure to c function
- for i in [0..cd.length[ do
+ for i in [0..arity[ do
var cn = cd[i].compile_closure(v, prop.closure_cname(i))
closcns.add(cn)
cargs.add(cn)
end
+ for i in [arity..prop_signature.closures.length[ do
+ cargs.add("NULL")
+ end
v.nmc.break_value = old_bv
end
# Intercept returns and breaks
- for i in [0..cd.length[ do
+ for i in [0..arity[ do
# A break or a return is intercepted
v.add_instr("if ({closcns[i]}->has_broke != NULL) \{")
v.indent
redef class AClosureCallExpr
redef meth compile_expr(v)
do
+ 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
+ v.compile_stmt(n.n_expr)
+ v.unindent
+ v.add_instr("} else \{")
+ v.indent
+ end
+
var cargs = new Array[String]
var ivar = "(({variable.ctypename})({v.cfc.varname(variable)}))"
cargs.add(ivar)
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
end
# aka is defined with the break keyword thus does not return
readable attr _is_break: Bool
+ # Is the closure optional?
+ # ie is there a default definition
+ readable attr _is_optional: Bool
+
# Adapt the signature to a different receiver
meth adaptation_to(r: MMType): MMClosure
do
- return new MMClosure(_signature.adaptation_to(r), _is_break)
+ return new MMClosure(_signature.adaptation_to(r), _is_break, _is_optional)
end
- init(s: MMSignature, is_break: Bool)
+ init(s: MMSignature, is_break: Bool, is_optional: Bool)
do
_signature = s
_is_break = is_break
+ _is_optional = is_optional
end
meth not_for_self: MMClosure
do
var sig = _signature.not_for_self
if sig != _signature then
- return new MMClosure(sig, _is_break)
+ return new MMClosure(sig, _is_break, _is_optional)
else
return self
end
# Add the finalizer to the closure signature
var finalize_sig = new MMSignature(new Array[MMType], null, null)
- var finalizer_clos = new MMClosure(finalize_sig, false)
+ var finalizer_clos = new MMClosure(finalize_sig, false, true)
sig.closures.add(finalizer_clos)
- var clos = new MMClosure(sig, n_kwbreak != null)
+ var clos = new MMClosure(sig, n_kwbreak != null, n_expr != null)
v.signature_builder = old_signature_builder
old_signature_builder.closure_decls.add(self)
_variable = new ClosureVariable(n_id.to_symbol, self, clos)
do
var t = psig.return_type
var cs = psig.closures # Declared closures
+ var min_arity = 0
+ for c in cs do
+ if not c.is_optional then min_arity += 1
+ end
if cd != null then
if cs.length == 0 then
v.error(self, "Error: {name} does not require blocs.")
- else if cs.length != cd.length then
+ else if cd.length > cs.length or cd.length < min_arity then
v.error(self, "Error: {name} requires {cs.length} blocs, {cd.length} found.")
else
var old_bbst = v.closure_break_stype
var old_bl = v.break_list
v.closure_break_stype = t
v.break_list = new Array[ABreakExpr]
- for i in [0..cs.length[ do
+ for i in [0..cd.length[ do
cd[i].accept_typing2(v, cs[i])
end
for n in v.break_list do
v.closure_break_stype = old_bbst
v.break_list = old_bl
end
- else if cs.length != 0 then
+ else if min_arity != 0 then
v.error(self, "Error: {name} requires {cs.length} blocs.")
end
return t