model: add basic closures
authorJean Privat <jean@pryen.org>
Tue, 3 Jul 2012 16:46:53 +0000 (12:46 -0400)
committerJean Privat <jean@pryen.org>
Tue, 3 Jul 2012 16:46:53 +0000 (12:46 -0400)
Signed-off-by: Jean Privat <jean@pryen.org>

src/model/model.nit
src/modelbuilder.nit
src/scope.nit
src/typing.nit

index ba6906e..be77b5b 100644 (file)
@@ -1083,6 +1083,8 @@ class MSignature
        # The each parameter (in order)
        var mparameters: Array[MParameter]
 
+       var mclosures = new Array[MParameter]
+
        # The return type (null for a procedure)
        var return_mtype: nullable MType
 
@@ -1146,6 +1148,9 @@ class MSignature
                        ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
                end
                var res = new MSignature(params, ret)
+               for p in self.mclosures do
+                       res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
+               end
                return res
        end
 end
index 54961fc..7b326a1 100644 (file)
@@ -1008,9 +1008,32 @@ redef class ASignature
                        if self.ret_type == null then return false # Skip errir
                end
 
+               for nclosure in self.n_closure_decls do
+                       if not nclosure.n_signature.visit_signature(modelbuilder, nclassdef) then return false
+               end
+
                self.is_visited = true
                return true
        end
+
+       # Build a visited signature
+       fun build_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef): nullable MSignature
+       do
+               if param_names.length != param_types.length then
+                       # Some parameters are typed, other parameters are not typed.
+                       modelbuilder.warning(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
+                       return null
+               end
+
+               var mparameters = new Array[MParameter]
+               for i in [0..param_names.length[ do
+                       var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
+                       mparameters.add(mparameter)
+               end
+
+               var msignature = new MSignature(mparameters, ret_type)
+               return msignature
+       end
 end
 
 redef class AMethPropdef
@@ -1145,8 +1168,19 @@ redef class AMethPropdef
                        var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
                        mparameters.add(mparameter)
                end
+
                msignature = new MSignature(mparameters, ret_type)
                mpropdef.msignature = msignature
+
+               if nsig != null then
+                       for nclosure in nsig.n_closure_decls do
+                               var clos_signature = nclosure.n_signature.build_signature(modelbuilder, nclassdef)
+                               if clos_signature == null then return
+                               var mparameter = new MParameter(nclosure.n_id.text, clos_signature, false)
+                               msignature.mclosures.add(mparameter)
+                       end
+               end
+
        end
 
        redef fun check_signature(modelbuilder, nclassdef)
index 95e4d4a..8a90c3f 100644 (file)
@@ -431,6 +431,20 @@ redef class AClosureCallExpr
        var variable: nullable ClosureVariable
 end
 
+redef class ASendExpr
+       # The escape mark used with the closures if any
+       var escapemark: nullable EscapeMark
+
+       redef fun accept_scope_visitor(v)
+       do
+               if self.n_closure_defs.length > 0 then
+                       var escapemark = v.make_escape_mark(self.n_closure_defs.last.n_label, true)
+                       self.escapemark = escapemark
+               end
+               super
+       end
+end
+
 redef class AClosureDef
        # The automatic variables in order
        var variables: nullable Array[Variable]
@@ -451,8 +465,7 @@ redef class AClosureDef
                        variables.add(va)
                end
 
-               var escapemark = v.make_escape_mark(n_label, true)
-               self.escapemark = escapemark
+               self.escapemark = self.parent.as(ASendExpr).escapemark
                v.enter_visit_block(self.n_expr, escapemark)
 
                v.scopes.shift
index 8a36223..b3b8a44 100644 (file)
@@ -405,6 +405,12 @@ redef class AConcreteMethPropdef
                        assert variable != null
                        variable.declared_type = mtype
                end
+               for i in [0..mmethoddef.msignature.mclosures.length[ do
+                       var mclosure = mmethoddef.msignature.mclosures[i]
+                       var variable = self.n_signature.n_closure_decls[i].variable
+                       assert variable != null
+                       variable.declared_type = mclosure.mtype
+               end
                v.visit_stmt(nblock)
 
                if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
@@ -1030,6 +1036,14 @@ redef class ASendExpr
                else
                        self.is_typed = true
                end
+
+               if self.n_closure_defs.length == msignature.mclosures.length then
+                       for i in [0..self.n_closure_defs.length[ do
+                               self.n_closure_defs[i].accept_typing(v, msignature.mclosures[i])
+                       end
+               else
+                       debug("closure: got {self.n_closure_defs.length}, want {msignature.mclosures.length}")
+               end
        end
 
        # The name of the property
@@ -1446,7 +1460,42 @@ end
 redef class AClosureCallExpr
        redef fun accept_typing(v)
        do
-               #TODO
+               var variable = self.variable
+               if variable == null then return # Skip error
+
+               var recvtype = v.nclassdef.mclassdef.bound_mtype
+               var msignature = variable.declared_type.as(MSignature)
+               msignature = v.resolve_signature_for(msignature, recvtype, false)
+
+               var args = n_args.to_a
+               v.check_signature(self, args, variable.name, msignature)
+
+               self.is_typed = true
+               self.mtype = msignature.return_mtype
+       end
+end
+
+redef class AClosureDef
+       var mclosure: nullable MParameter
+
+       private fun accept_typing(v: TypeVisitor, mparameter: MParameter)
+       do
+               var variables = self.variables
+               if variables == null then return
+
+               self.mclosure = mparameter
+               var msignature = mparameter.mtype.as(MSignature)
+
+               if msignature.arity != variables.length then
+                       v.error(self, "Type error: closure {mparameter.name} expects {msignature.arity} parameters, {variables.length} given")
+                       return
+               end
+
+               for i in [0..variables.length[ do
+                       variables[i].declared_type = msignature.mparameters[i].mtype
+               end
+
+               v.visit_stmt(self.n_expr)
        end
 end