src: update most tools to new constructors
[nit.git] / src / interpreter / naive_interpreter.nit
index 917606a..c6687c7 100644 (file)
@@ -24,7 +24,7 @@ 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
@@ -58,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
@@ -66,13 +66,11 @@ 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)
                self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
                self.null_instance = new MutableInstance(mainmodule.model.null_type)
@@ -113,43 +111,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
+       # 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.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
-       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
@@ -226,14 +207,14 @@ class NaiveInterpreter
                return new PrimitiveInstance[Float](ic.mclass_type, val)
        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].
@@ -248,6 +229,19 @@ class NaiveInterpreter
                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
@@ -270,9 +264,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
@@ -319,55 +313,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]
+               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               var res = new Array[Instance]
+               res.add(recv)
 
-                       args.add(rawargs.first) # recv
+               if args.is_empty then return res
 
-                       for i in [0..vararg_rank[ do
-                               args.add(rawargs[i+1])
-                       end
-
-                       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}")
@@ -376,14 +373,17 @@ class NaiveInterpreter
 
                # Look for the AST node that implements the property
                var mproperty = mpropdef.mproperty
+               var val = mpropdef.constant_value
                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
+               else if mproperty.is_root_init then
                        var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
                        self.parameter_check(nclassdef, mpropdef, args)
                        return nclassdef.call(self, mpropdef, args)
+               else if val != null then
+                       return value_instance(val)
                else
                        fatal("Fatal Error: method {mpropdef} not found in the AST")
                        abort
@@ -428,7 +428,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
@@ -457,8 +457,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
@@ -518,7 +518,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.
@@ -586,12 +586,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
@@ -705,7 +699,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
@@ -754,14 +748,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
@@ -888,7 +882,7 @@ redef class AMethPropdef
                                return v.bool_instance(args[0].to_f.is_inf != 0)
                        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)
@@ -949,7 +943,7 @@ 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)
                        end
@@ -1073,8 +1067,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
@@ -1088,12 +1081,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)
@@ -1110,7 +1117,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
@@ -1210,20 +1217,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
@@ -1232,7 +1226,7 @@ redef class ABreakExpr
                        if i == null then return
                        v.escapevalue = i
                end
-               v.breakmark = self.escapemark
+               v.escapemark = self.escapemark
        end
 end
 
@@ -1298,7 +1292,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
 
@@ -1310,8 +1304,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
@@ -1322,8 +1316,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
@@ -1341,7 +1335,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}")
@@ -1355,11 +1349,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
 
@@ -1571,7 +1569,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
@@ -1605,12 +1602,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
@@ -1622,12 +1615,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
 
@@ -1647,16 +1636,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])
@@ -1667,14 +1652,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
@@ -1682,15 +1670,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}")