Basic typing and compilation for default closures.
authorJean Privat <jean@pryen.org>
Fri, 30 Jan 2009 09:15:00 +0000 (04:15 -0500)
committerJean Privat <jean@pryen.org>
Fri, 30 Jan 2009 09:15:00 +0000 (04:15 -0500)
src/compiling/compiling_methods.nit
src/metamodel/static_type.nit
src/syntax/mmbuilder.nit
src/syntax/typing.nit

index 9de0463..7e27df8 100644 (file)
@@ -1372,11 +1372,13 @@ redef class ASendExpr
                        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
 
@@ -1387,11 +1389,14 @@ redef class ASendExpr
                        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
 
@@ -1403,7 +1408,7 @@ redef class ASendExpr
                        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
@@ -1606,6 +1611,17 @@ end
 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)
@@ -1629,6 +1645,11 @@ redef class AClosureCallExpr
                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
index a5301ae..627fe9e 100644 (file)
@@ -232,23 +232,28 @@ class MMClosure
        # 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
index 5f7e0a0..038ab90 100644 (file)
@@ -1185,10 +1185,10 @@ redef class AClosureDecl
 
                # 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)
index 362f802..5f49fba 100644 (file)
@@ -939,17 +939,21 @@ special PExpr
        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
@@ -965,7 +969,7 @@ special PExpr
                                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