interpreter: use SignatureMap to make varargize more robust
authorJean Privat <jean@pryen.org>
Thu, 16 Apr 2015 09:57:27 +0000 (16:57 +0700)
committerJean Privat <jean@pryen.org>
Fri, 17 Apr 2015 15:57:47 +0000 (22:57 +0700)
Signed-off-by: Jean Privat <jean@pryen.org>

src/interpreter/naive_interpreter.nit

index 7d7cab9..c1bd59b 100644 (file)
@@ -370,42 +370,48 @@ class NaiveInterpreter
        # This method is used to manage varargs in signatures and returns the real array
        # of instances to use in the call.
        # Return `null` if one of the evaluation of the arguments return null.
-       fun varargize(mpropdef: MMethodDef, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
+       fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
        do
                var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
                var res = new Array[Instance]
                res.add(recv)
 
-               if args.is_empty then return res
+               if msignature.arity == 0 then return res
+
+               if map == null then
+                       assert args.length == msignature.arity else debug("Expected {msignature.arity} args, got {args.length}")
+                       for ne in args do
+                               var e = self.expr(ne)
+                               if e == null then return null
+                               res.add e
+                       end
+                       return res
+               end
+
+               # Eval in order of arguments, not parameters
+               var exprs = new Array[Instance].with_capacity(args.length)
+               for ne in args do
+                       var e = self.expr(ne)
+                       if e == null then return null
+                       exprs.add e
+               end
 
-               var vararg_rank = msignature.vararg_rank
-               var vararg_len = args.length - msignature.arity
-               if vararg_len < 0 then vararg_len = 0
 
+               # Fill `res` with the result of the evaluation according to the mapping
                for i in [0..msignature.arity[ do
-                       if i == vararg_rank then
-                               var ne = args[i]
-                               if ne isa AVarargExpr then
-                                       var e = self.expr(ne.n_expr)
-                                       if e == null then return null
-                                       res.add(e)
-                                       continue
-                               end
-                               var vararg = new Array[Instance]
-                               for j in [vararg_rank..vararg_rank+vararg_len] do
-                                       var e = self.expr(args[j])
-                                       if e == null then return null
-                                       vararg.add(e)
-                               end
-                               var elttype = msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
-                               res.add(self.array_instance(vararg, elttype))
-                       else
-                               var j = i
-                               if i > vararg_rank then j += vararg_len
-                               var e = self.expr(args[j])
-                               if e == null then return null
-                               res.add(e)
+                       var param = msignature.mparameters[i]
+                       var j = map.map.get_or_null(i)
+                       if j == null then
+                               continue
+                       end
+                       if param.is_vararg and map.vararg_decl > 0 then
+                               var vararg = exprs.sub(j, map.vararg_decl)
+                               var elttype = param.mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
+                               var arg = self.array_instance(vararg, elttype)
+                               res.add(arg)
+                               continue
                        end
+                       res.add exprs[j]
                end
                return res
        end
@@ -1740,7 +1746,7 @@ redef class ASendExpr
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return null
-               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
                if args == null then return null
 
                var res = v.callsite(callsite, args)
@@ -1753,7 +1759,7 @@ redef class ASendReassignFormExpr
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return
-               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
                if args == null then return
                var value = v.expr(self.n_value)
                if value == null then return
@@ -1777,29 +1783,35 @@ redef class ASuperExpr
 
                var callsite = self.callsite
                if callsite != null then
-                       var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
-                       if args == null then return null
-                       # Add additional arguments for the super init call
-                       if args.length == 1 then
+                       var args
+                       if self.n_args.n_exprs.is_empty then
+                               # Add automatic arguments for the super init call
+                               args = [recv]
                                for i in [0..callsite.msignature.arity[ do
                                        args.add(v.frame.arguments[i+1])
                                end
+                       else
+                               args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
+                               if args == null then return null
                        end
+
                        # Super init call
                        var res = v.callsite(callsite, args)
                        return res
                end
 
-               # standard call-next-method
+               # Standard call-next-method
                var mpropdef = self.mpropdef
                mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
 
-               var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
-               if args == null then return null
-
-               if args.length == 1 then
+               var args
+               if self.n_args.n_exprs.is_empty then
                        args = v.frame.arguments
+               else
+                       args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
+                       if args == null then return null
                end
+
                var res = v.call(mpropdef, args)
                return res
        end
@@ -1814,7 +1826,7 @@ redef class ANewExpr
                var callsite = self.callsite
                if callsite == null then return recv
 
-               var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
                if args == null then return null
                var res2 = v.callsite(callsite, args)
                if res2 != null then
@@ -1876,6 +1888,13 @@ redef class AIssetAttrExpr
        end
 end
 
+redef class AVarargExpr
+       redef fun expr(v)
+       do
+               return v.expr(self.n_expr)
+       end
+end
+
 redef class ADebugTypeExpr
        redef fun stmt(v)
        do