modelize: add and use method mpropdef2node
[nit.git] / src / interpreter / naive_interpreter.nit
index cbdb607..da8d02e 100644 (file)
@@ -20,10 +20,11 @@ module naive_interpreter
 import literal
 import semantize
 private import parser::tables
+import mixin
 
 redef class ToolContext
        # --discover-call-trace
-       var opt_discover_call_trace: OptionBool = new OptionBool("Trace calls of the first invocation of a method", "--discover-call-trace")
+       var opt_discover_call_trace = new OptionBool("Trace calls of the first invocation of a method", "--discover-call-trace")
 
        redef init
        do
@@ -57,7 +58,7 @@ class NaiveInterpreter
        # The modelbuilder that know the AST and its associations with the model
        var modelbuilder: ModelBuilder
 
-       # The main moduleof the program (used to lookup methoda
+       # The main module of the program (used to lookup method)
        var mainmodule: MModule
 
        # The command line arguments of the interpreted program
@@ -65,15 +66,15 @@ class NaiveInterpreter
        # arguments[1] is the first argument
        var arguments: Array[String]
 
-       var mainobj: nullable Instance
+       # The main Sys instance
+       var mainobj: nullable Instance is noinit
 
-       init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
+       init
        do
-               self.modelbuilder = modelbuilder
-               self.mainmodule = mainmodule
-               self.arguments = arguments
                self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
+               init_instance_primitive(self.true_instance)
                self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
+               init_instance_primitive(self.false_instance)
                self.null_instance = new MutableInstance(mainmodule.model.null_type)
        end
 
@@ -112,43 +113,26 @@ class NaiveInterpreter
        # Set this mark to skip the evaluation until the end of the specified method frame
        var returnmark: nullable Frame = null
 
-       # Is a break executed?
-       # Set this mark to skip the evaluation until a labeled statement catch it with `is_break`
-       var breakmark: nullable EscapeMark = null
-
-       # Is a continue executed?
-       # Set this mark to skip the evaluation until a labeled statement catch it with `is_continue`
-       var continuemark: nullable EscapeMark = null
+       # Is a break or a continue executed?
+       # Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
+       var escapemark: nullable EscapeMark = null
 
        # Is a return or a break or a continue executed?
        # Use this function to know if you must skip the evaluation of statements
-       fun is_escaping: Bool do return returnmark != null or breakmark != null or continuemark != null
+       fun is_escaping: Bool do return returnmark != null or escapemark != null
 
        # The value associated with the current return/break/continue, if any.
        # Set the value when you set a escapemark.
        # Read the value when you catch a mark or reach the end of a method
        var escapevalue: nullable Instance = null
 
-       # If there is a break and is associated with `escapemark`, then return true an clear the mark.
-       # If there is no break or if `escapemark` is null then return false.
-       # Use this function to catch a potential break.
-       fun is_break(escapemark: nullable EscapeMark): Bool
-       do
-               if escapemark != null and self.breakmark == escapemark then
-                       self.breakmark = null
-                       return true
-               else
-                       return false
-               end
-       end
-
-       # If there is a continue and is associated with `escapemark`, then return true an clear the mark.
-       # If there is no continue or if `escapemark` is null then return false.
-       # Use this function to catch a potential continue.
-       fun is_continue(escapemark: nullable EscapeMark): Bool
+       # If there is a break/continue and is associated with `escapemark`, then return true and clear the mark.
+       # If there is no break/continue or if `escapemark` is null then return false.
+       # Use this function to catch a potential break/continue.
+       fun is_escape(escapemark: nullable EscapeMark): Bool
        do
-               if escapemark != null and self.continuemark == escapemark then
-                       self.continuemark = null
+               if escapemark != null and self.escapemark == escapemark then
+                       self.escapemark = null
                        return true
                else
                        return false
@@ -207,53 +191,75 @@ class NaiveInterpreter
        # Return the integer instance associated with `val`.
        fun int_instance(val: Int): Instance
        do
-               var ic = self.mainmodule.get_primitive_class("Int")
-               return new PrimitiveInstance[Int](ic.mclass_type, val)
+               var ic = get_primitive_class("Int")
+               var instance = new PrimitiveInstance[Int](ic.mclass_type, val)
+               init_instance_primitive(instance)
+               return instance
        end
 
        # Return the char instance associated with `val`.
        fun char_instance(val: Char): Instance
        do
-               var ic = self.mainmodule.get_primitive_class("Char")
-               return new PrimitiveInstance[Char](ic.mclass_type, val)
+               var ic = get_primitive_class("Char")
+               var instance = new PrimitiveInstance[Char](ic.mclass_type, val)
+               init_instance_primitive(instance)
+               return instance
        end
 
        # Return the float instance associated with `val`.
        fun float_instance(val: Float): Instance
        do
-               var ic = self.mainmodule.get_primitive_class("Float")
-               return new PrimitiveInstance[Float](ic.mclass_type, val)
+               var ic = get_primitive_class("Float")
+               var instance = new PrimitiveInstance[Float](ic.mclass_type, val)
+               init_instance_primitive(instance)
+               return instance
        end
 
-       # The unique intance of the `true` value.
-       var true_instance: Instance
+       # The unique instance of the `true` value.
+       var true_instance: Instance is noinit
 
-       # The unique intance of the `false` value.
-       var false_instance: Instance
+       # The unique instance of the `false` value.
+       var false_instance: Instance is noinit
 
-       # The unique intance of the `null` value.
-       var null_instance: Instance
+       # The unique instance of the `null` value.
+       var null_instance: Instance is noinit
 
        # Return a new array made of `values`.
        # The dynamic type of the result is Array[elttype].
        fun array_instance(values: Array[Instance], elttype: MType): Instance
        do
                assert not elttype.need_anchor
-               var nat = new PrimitiveInstance[Array[Instance]](self.mainmodule.get_primitive_class("NativeArray").get_mtype([elttype]), values)
-               var mtype = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
+               var nat = new PrimitiveInstance[Array[Instance]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
+               init_instance_primitive(nat)
+               var mtype = get_primitive_class("Array").get_mtype([elttype])
                var res = new MutableInstance(mtype)
                self.init_instance(res)
                self.send(self.force_get_primitive_method("with_native", mtype), [res, nat, self.int_instance(values.length)])
                return res
        end
 
+       fun value_instance(object: Object): Instance
+       do
+               if object isa Int then
+                       return int_instance(object)
+               else if object isa Bool then
+                       return bool_instance(object)
+               else if object isa String then
+                       return string_instance(object)
+               else
+                       abort
+               end
+       end
+
        # Return a new native string initialized with `txt`
        fun native_string_instance(txt: String): Instance
        do
                var val = new FlatBuffer.from(txt)
                val.add('\0')
-               var ic = self.mainmodule.get_primitive_class("NativeString")
-               return new PrimitiveInstance[Buffer](ic.mclass_type, val)
+               var ic = get_primitive_class("NativeString")
+               var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val)
+               init_instance_primitive(instance)
+               return instance
        end
 
        # Return a new String instance for `txt`
@@ -269,9 +275,9 @@ class NaiveInterpreter
        fun frame: Frame do return frames.first
 
        # The stack of all frames. The first one is the current one.
-       var frames: List[Frame] = new List[Frame]
+       var frames = new List[Frame]
 
-       # Return a stack stace. One line per function
+       # Return a stack trace. One line per function
        fun stack_trace: String
        do
                var b = new FlatBuffer
@@ -318,55 +324,58 @@ class NaiveInterpreter
                f.map[v] = value
        end
 
-       # Store known method, used to trace methods as thez are reached
+       # Store known methods, used to trace methods as they are reached
        var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef]
 
-       # Common code for calls to injected methods and normal methods
-       fun call_commons(mpropdef: MMethodDef, args: Array[Instance]): Array[Instance]
+       # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
+       # 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]
        do
-               var vararg_rank = mpropdef.msignature.vararg_rank
-               if vararg_rank >= 0 then
-                       assert args.length >= mpropdef.msignature.arity + 1 # because of self
-                       var rawargs = args
-                       args = new Array[Instance]
-
-                       args.add(rawargs.first) # recv
+               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               var res = new Array[Instance]
+               res.add(recv)
 
-                       for i in [0..vararg_rank[ do
-                               args.add(rawargs[i+1])
-                       end
+               if args.is_empty then return res
 
-                       var vararg_lastrank = vararg_rank + rawargs.length-1-mpropdef.msignature.arity
-                       var vararg = new Array[Instance]
-                       for i in [vararg_rank..vararg_lastrank] do
-                               vararg.add(rawargs[i+1])
-                       end
-                       # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
-                       var elttype = mpropdef.msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, args.first.mtype.as(MClassType))
-                       args.add(self.array_instance(vararg, elttype))
+               var vararg_rank = msignature.vararg_rank
+               var vararg_len = args.length - msignature.arity
+               if vararg_len < 0 then vararg_len = 0
 
-                       for i in [vararg_lastrank+1..rawargs.length-1[ do
-                               args.add(rawargs[i+1])
+               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)
                        end
                end
-               return args
+               return res
        end
 
        # Execute `mpropdef` for a `args` (where `args[0]` is the receiver).
-       # Return a falue if `mpropdef` is a function, or null if it is a procedure.
-       # The call is direct/static. There is no message-seding/late-binding.
+       # Return a value if `mpropdef` is a function, or null if it is a procedure.
+       # The call is direct/static. There is no message-sending/late-binding.
        fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
        do
-               args = call_commons(mpropdef, args)
-               return call_without_varargs(mpropdef, args)
-       end
-
-       # Common code to call and this function
-       #
-       # Call only executes the variadic part, this avoids
-       # double encapsulation of variadic parameters into an Array
-       fun call_without_varargs(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
-       do
                if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then
                        self.discover_call_trace.add mpropdef
                        self.debug("Discovered {mpropdef}")
@@ -374,15 +383,20 @@ class NaiveInterpreter
                assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
 
                # Look for the AST node that implements the property
-               var mproperty = mpropdef.mproperty
-               if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
-                       var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
-                       self.parameter_check(npropdef, mpropdef, args)
-                       return npropdef.call(self, mpropdef, args)
-               else if mproperty.name == "init" then
-                       var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
-                       self.parameter_check(nclassdef, mpropdef, args)
-                       return nclassdef.call(self, mpropdef, args)
+               var val = mpropdef.constant_value
+
+               var node = modelbuilder.mpropdef2node(mpropdef)
+               if node isa APropdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.call(self, mpropdef, args)
+               else if node isa AClassdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.call(self, mpropdef, args)
+               else if node != null then
+                       fatal("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
+                       abort
+               else if val != null then
+                       return value_instance(val)
                else
                        fatal("Fatal Error: method {mpropdef} not found in the AST")
                        abort
@@ -427,7 +441,7 @@ class NaiveInterpreter
        end
 
        # Execute a full `callsite` for given `args`
-       # Use this method, instead of `send` to execute and control the aditionnal behavior of the call-sites
+       # Use this method, instead of `send` to execute and control the additional behavior of the call-sites
        fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
        do
                var initializers = callsite.mpropdef.initializers
@@ -456,8 +470,8 @@ class NaiveInterpreter
        end
 
        # Execute `mproperty` for a `args` (where `args[0]` is the receiver).
-       # Return a falue if `mproperty` is a function, or null if it is a procedure.
-       # The call is polimotphic. There is a message-seding/late-bindng according to te receiver (args[0]).
+       # Return a value if `mproperty` is a function, or null if it is a procedure.
+       # The call is polymorphic. There is a message-sending/late-binding according to the receiver (args[0]).
        fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance
        do
                var recv = args.first
@@ -504,6 +518,7 @@ class NaiveInterpreter
                var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
                self.mainmodule.linearize_mclassdefs(cds)
                for cd in cds do
+                       if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
                        var n = self.modelbuilder.mclassdef2nclassdef[cd]
                        for npropdef in n.n_propdefs do
                                if npropdef isa AAttrPropdef then
@@ -516,7 +531,7 @@ class NaiveInterpreter
                return res
        end
 
-       var collect_attr_propdef_cache = new HashMap[MType, Array[AAttrPropdef]]
+       private var collect_attr_propdef_cache = new HashMap[MType, Array[AAttrPropdef]]
 
        # Fill the initial values of the newly created instance `recv`.
        # `recv.mtype` is used to know what must be filled.
@@ -527,6 +542,16 @@ class NaiveInterpreter
                end
        end
 
+       # A hook to initialize a `PrimitiveInstance`
+       fun init_instance_primitive(recv: Instance) do end
+
+       # Return the primitive `MClass` corresponding to the `name` given in parameter
+       # `name` : name of the primitive class
+       fun get_primitive_class(name: String): MClass
+       do
+               return mainmodule.get_primitive_class(name)
+       end
+
        # This function determine the correct type according the reciever of the current definition (self).
        fun unanchor_type(mtype: MType): MType
        do
@@ -584,12 +609,6 @@ class PrimitiveInstance[E: Object]
        # The real value encapsulated
        redef var val: E
 
-       init(mtype: MType, val: E)
-       do
-               super(mtype)
-               self.val = val
-       end
-
        redef fun is_true
        do
                if val == true then return true
@@ -703,7 +722,7 @@ redef class AMethPropdef
                if auto_super_call then
                        # standard call-next-method
                        var superpd = mpropdef.lookup_next_definition(v.mainmodule, arguments.first.mtype)
-                       v.call_without_varargs(superpd, arguments)
+                       v.call(superpd, arguments)
                end
 
                if mpropdef.is_intern or mpropdef.is_extern then
@@ -752,14 +771,14 @@ redef class AMethPropdef
                        var txt = recv.mtype.to_s
                        return v.native_string_instance(txt)
                else if pname == "==" then
-                       # == is correclt redefined for instances
+                       # == is correctly redefined for instances
                        return v.bool_instance(args[0] == args[1])
                else if pname == "!=" then
                        return v.bool_instance(args[0] != args[1])
                else if pname == "is_same_type" then
                        return v.bool_instance(args[0].mtype == args[1].mtype)
                else if pname == "is_same_instance" then
-                       return v.bool_instance(args[1] != null and args[0].eq_is(args[1]))
+                       return v.bool_instance(args[0].eq_is(args[1]))
                else if pname == "exit" then
                        exit(args[1].to_i)
                        abort
@@ -884,9 +903,11 @@ redef class AMethPropdef
                                return v.bool_instance(args[0].to_f.is_nan)
                        else if pname == "is_inf_extern" then
                                return v.bool_instance(args[0].to_f.is_inf != 0)
+                       else if pname == "round" then
+                               return v.float_instance(args[0].to_f.round)
                        end
                else if cname == "NativeString" then
-                       if pname == "init" then
+                       if pname == "new" then
                                return v.native_string_instance("!" * args[1].to_i)
                        end
                        var recvval = args.first.val.as(Buffer)
@@ -947,9 +968,11 @@ redef class AMethPropdef
                else if pname == "calloc_string" then
                        return v.native_string_instance("!" * args[1].to_i)
                else if cname == "NativeArray" then
-                       if pname == "init" then
+                       if pname == "new" then
                                var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
-                               return new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+                               var instance = new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+                               v.init_instance_primitive(instance)
+                               return instance
                        end
                        var recvval = args.first.val.as(Array[Instance])
                        if pname == "[]" then
@@ -968,17 +991,27 @@ redef class AMethPropdef
                        end
                else if cname == "NativeFile" then
                        if pname == "native_stdout" then
-                               return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+                               var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+                               v.init_instance_primitive(instance)
+                               return instance
                        else if pname == "native_stdin" then
-                               return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+                               var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+                               v.init_instance_primitive(instance)
+                               return instance
                        else if pname == "native_stderr" then
-                               return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+                               var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+                               v.init_instance_primitive(instance)
+                               return instance
                        else if pname == "io_open_read" then
                                var a1 = args[1].val.as(Buffer)
-                               return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+                               var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+                               v.init_instance_primitive(instance)
+                               return instance
                        else if pname == "io_open_write" then
                                var a1 = args[1].val.as(Buffer)
-                               return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+                               var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+                               v.init_instance_primitive(instance)
+                               return instance
                        end
                        var recvval = args.first.val
                        if pname == "io_write" then
@@ -999,10 +1032,12 @@ redef class AMethPropdef
                else if pname == "calloc_array" then
                        var recvtype = args.first.mtype.as(MClassType)
                        var mtype: MType
-                       mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.mainmodule.get_primitive_class("ArrayCapable"))
+                       mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.get_primitive_class("ArrayCapable"))
                        mtype = mtype.arguments.first
                        var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
-                       return new PrimitiveInstance[Array[Instance]](v.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype]), val)
+                       var instance = new PrimitiveInstance[Array[Instance]](v.get_primitive_class("NativeArray").get_mtype([mtype]), val)
+                       v.init_instance_primitive(instance)
+                       return instance
                else if pname == "native_argc" then
                        return v.int_instance(v.arguments.length)
                else if pname == "native_argv" then
@@ -1015,6 +1050,9 @@ redef class AMethPropdef
                        return v.native_string_instance(txt)
                else if pname == "get_time" then
                        return v.int_instance(get_time)
+               else if pname == "srand" then
+                       srand
+                       return null
                else if pname == "srand_from" then
                        srand_from(args[1].to_i)
                        return null
@@ -1071,8 +1109,7 @@ redef class AAttrPropdef
        private fun init_expr(v: NaiveInterpreter, recv: Instance)
        do
                if is_lazy then return
-               var nexpr = self.n_expr
-               if nexpr != null then
+               if has_value then
                        evaluate_expr(v, recv)
                        return
                end
@@ -1086,12 +1123,26 @@ redef class AAttrPropdef
        private fun evaluate_expr(v: NaiveInterpreter, recv: Instance): Instance
        do
                assert recv isa MutableInstance
-               var nexpr = self.n_expr
-               assert nexpr != null
                var f = new Frame(self, self.mpropdef.as(not null), [recv])
                v.frames.unshift(f)
-               var val = v.expr(nexpr)
+
+               var val
+
+               var nexpr = self.n_expr
+               var nblock = self.n_block
+               if nexpr != null then
+                       val = v.expr(nexpr)
+               else if nblock != null then
+                       v.stmt(nblock)
+                       assert v.returnmark == f
+                       val = v.escapevalue
+                       v.returnmark = null
+                       v.escapevalue = null
+               else
+                       abort
+               end
                assert val != null
+
                v.frames.shift
                assert not v.is_escaping
                v.write_attribute(self.mpropdef.mproperty, recv, val)
@@ -1108,7 +1159,7 @@ redef class AClassdef
                        if not mpropdef.is_intro then
                                # standard call-next-method
                                var superpd = mpropdef.lookup_next_definition(v.mainmodule, args.first.mtype)
-                               v.call_without_varargs(superpd, args)
+                               v.call(superpd, args)
                        end
                        return null
                else
@@ -1208,20 +1259,7 @@ redef class ASelfExpr
        end
 end
 
-redef class AContinueExpr
-       redef fun stmt(v)
-       do
-               var ne = self.n_expr
-               if ne != null then
-                       var i = v.expr(ne)
-                       if i == null then return
-                       v.escapevalue = i
-               end
-               v.continuemark = self.escapemark
-       end
-end
-
-redef class ABreakExpr
+redef class AEscapeExpr
        redef fun stmt(v)
        do
                var ne = self.n_expr
@@ -1230,7 +1268,7 @@ redef class ABreakExpr
                        if i == null then return
                        v.escapevalue = i
                end
-               v.breakmark = self.escapemark
+               v.escapemark = self.escapemark
        end
 end
 
@@ -1296,7 +1334,7 @@ redef class ADoExpr
        redef fun stmt(v)
        do
                v.stmt(self.n_block)
-               v.is_break(self.escapemark) # Clear the break (if any)
+               v.is_escape(self.break_mark) # Clear the break (if any)
        end
 end
 
@@ -1308,8 +1346,8 @@ redef class AWhileExpr
                        if cond == null then return
                        if not cond.is_true then return
                        v.stmt(self.n_block)
-                       if v.is_break(self.escapemark) then return
-                       v.is_continue(self.escapemark) # Clear the break
+                       if v.is_escape(self.break_mark) then return
+                       v.is_escape(self.continue_mark) # Clear the break
                        if v.is_escaping then return
                end
        end
@@ -1320,8 +1358,8 @@ redef class ALoopExpr
        do
                loop
                        v.stmt(self.n_block)
-                       if v.is_break(self.escapemark) then return
-                       v.is_continue(self.escapemark) # Clear the break
+                       if v.is_escape(self.break_mark) then return
+                       v.is_escape(self.continue_mark) # Clear the break
                        if v.is_escaping then return
                end
        end
@@ -1339,7 +1377,7 @@ redef class AForExpr
                #self.debug("iter {iter}")
                loop
                        var isok = v.callsite(method_is_ok, [iter]).as(not null)
-                       if not isok.is_true then return
+                       if not isok.is_true then break
                        if self.variables.length == 1 then
                                var item = v.callsite(method_item, [iter]).as(not null)
                                #self.debug("item {item}")
@@ -1353,11 +1391,15 @@ redef class AForExpr
                                abort
                        end
                        v.stmt(self.n_block)
-                       if v.is_break(self.escapemark) then return
-                       v.is_continue(self.escapemark) # Clear the break
-                       if v.is_escaping then return
+                       if v.is_escape(self.break_mark) then break
+                       v.is_escape(self.continue_mark) # Clear the break
+                       if v.is_escaping then break
                        v.callsite(method_next, [iter])
                end
+               var method_finish = self.method_finish
+               if method_finish != null then
+                       v.callsite(method_finish, [iter])
+               end
        end
 end
 
@@ -1482,7 +1524,7 @@ redef class ASuperstringExpr
                        if i == null then return null
                        array.add(i)
                end
-               var i = v.array_instance(array, v.mainmodule.get_primitive_class("Object").mclass_type)
+               var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
                var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
                assert res != null
                return res
@@ -1569,7 +1611,6 @@ redef class AAsNotnullExpr
        do
                var i = v.expr(self.n_expr)
                if i == null then return null
-               var mtype = v.unanchor_type(self.mtype.as(not null))
                if i.mtype isa MNullType then
                        fatal(v, "Cast failed")
                end
@@ -1603,12 +1644,8 @@ redef class ASendExpr
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return null
-               var args = [recv]
-               for a in self.raw_arguments do
-                       var i = v.expr(a)
-                       if i == null then return null
-                       args.add(i)
-               end
+               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               if args == null then return null
 
                var res = v.callsite(callsite, args)
                return res
@@ -1620,12 +1657,8 @@ redef class ASendReassignFormExpr
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return
-               var args = [recv]
-               for a in self.raw_arguments do
-                       var i = v.expr(a)
-                       if i == null then return
-                       args.add(i)
-               end
+               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               if args == null then return
                var value = v.expr(self.n_value)
                if value == null then return
 
@@ -1645,16 +1678,12 @@ redef class ASuperExpr
        redef fun expr(v)
        do
                var recv = v.frame.arguments.first
-               var args = [recv]
-               for a in self.n_args.n_exprs do
-                       var i = v.expr(a)
-                       if i == null then return null
-                       args.add(i)
-               end
 
                var callsite = self.callsite
                if callsite != null then
-                       # Add additionnals arguments for the super init call
+                       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
                                for i in [0..callsite.msignature.arity[ do
                                        args.add(v.frame.arguments[i+1])
@@ -1665,14 +1694,17 @@ redef class ASuperExpr
                        return res
                end
 
+               # 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
                        args = v.frame.arguments
                end
-
-               # stantard call-next-method
-               var mpropdef = self.mpropdef
-               mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
-               var res = v.call_without_varargs(mpropdef, args)
+               var res = v.call(mpropdef, args)
                return res
        end
 end
@@ -1680,15 +1712,11 @@ end
 redef class ANewExpr
        redef fun expr(v)
        do
-               var mtype = v.unanchor_type(self.mtype.as(not null))
+               var mtype = v.unanchor_type(self.recvtype.as(not null))
                var recv: Instance = new MutableInstance(mtype)
                v.init_instance(recv)
-               var args = [recv]
-               for a in self.n_args.n_exprs do
-                       var i = v.expr(a)
-                       if i == null then return null
-                       args.add(i)
-               end
+               var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+               if args == null then return null
                var res2 = v.callsite(callsite, args)
                if res2 != null then
                        #self.debug("got {res2} from {mproperty}. drop {recv}")