mixin: introduce -D option to redefine functions from the command-line
[nit.git] / src / interpreter / naive_interpreter.nit
index 6c65469..01c872d 100644 (file)
@@ -20,6 +20,7 @@ module naive_interpreter
 import literal
 import semantize
 private import parser::tables
+import mixin
 
 redef class ToolContext
        # --discover-call-trace
@@ -45,32 +46,15 @@ redef class ModelBuilder
                self.toolcontext.info("*** START INTERPRETING ***", 1)
 
                var interpreter = new NaiveInterpreter(self, mainmodule, arguments)
-               init_naive_interpreter(interpreter, mainmodule)
+               interpreter.start(mainmodule)
 
                var time1 = get_time
                self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2)
        end
-
-       private fun init_naive_interpreter(interpreter: NaiveInterpreter, mainmodule: MModule) do
-               var sys_type = mainmodule.sys_type
-               if sys_type == null then return # no class Sys
-               var mainobj = new MutableInstance(sys_type)
-               interpreter.mainobj = mainobj
-               interpreter.init_instance(mainobj)
-               var initprop = mainmodule.try_get_primitive_method("init", sys_type.mclass)
-               if initprop != null then
-                       interpreter.send(initprop, [mainobj])
-               end
-               var mainprop = mainmodule.try_get_primitive_method("run", sys_type.mclass) or else
-                       mainmodule.try_get_primitive_method("main", sys_type.mclass)
-               if mainprop != null then
-                       interpreter.send(mainprop, [mainobj])
-               end
-       end
 end
 
 # The visitor that interprets the Nit Program by walking on the AST
-private class NaiveInterpreter
+class NaiveInterpreter
        # The modelbuilder that know the AST and its associations with the model
        var modelbuilder: ModelBuilder
 
@@ -94,6 +78,25 @@ private class NaiveInterpreter
                self.null_instance = new MutableInstance(mainmodule.model.null_type)
        end
 
+       # Starts the interpreter on the main module of a program
+       fun start(mainmodule: MModule) do
+               var interpreter = self
+               var sys_type = mainmodule.sys_type
+               if sys_type == null then return # no class Sys
+               var mainobj = new MutableInstance(sys_type)
+               interpreter.mainobj = mainobj
+               interpreter.init_instance(mainobj)
+               var initprop = mainmodule.try_get_primitive_method("init", sys_type.mclass)
+               if initprop != null then
+                       interpreter.send(initprop, [mainobj])
+               end
+               var mainprop = mainmodule.try_get_primitive_method("run", sys_type.mclass) or else
+                       mainmodule.try_get_primitive_method("main", sys_type.mclass)
+               if mainprop != null then
+                       interpreter.send(mainprop, [mainobj])
+               end
+       end
+
        # Subtype test in the context of the mainmodule
        fun is_subtype(sub, sup: MType): Bool
        do
@@ -245,6 +248,19 @@ private 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
@@ -254,6 +270,15 @@ private class NaiveInterpreter
                return new PrimitiveInstance[Buffer](ic.mclass_type, val)
        end
 
+       # Return a new String instance for `txt`
+       fun string_instance(txt: String): Instance
+       do
+               var nat = native_string_instance(txt)
+               var res = self.send(self.force_get_primitive_method("to_s_with_length", nat.mtype), [nat, self.int_instance(txt.length)])
+               assert res != null
+               return res
+       end
+
        # The current frame used to store local variables of the current method executed
        fun frame: Frame do return frames.first
 
@@ -364,6 +389,7 @@ private 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)
@@ -372,6 +398,8 @@ private class NaiveInterpreter
                        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
@@ -493,6 +521,7 @@ private 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
@@ -606,7 +635,7 @@ class PrimitiveInstance[E: Object]
 end
 
 # Information about local variables in a running method
-private class Frame
+class Frame
        # The current visited node
        # The node is stored by frame to keep a stack trace
        var current_node: ANode
@@ -616,13 +645,13 @@ private class Frame
        # Arguments of the method (the first is the receiver)
        var arguments: Array[Instance]
        # Mapping between a variable and the current value
-       var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
+       private var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
 end
 
 redef class ANode
        # Aborts the program with a message
        # `v` is used to know if a colored message is displayed or not
-       private fun fatal(v: NaiveInterpreter, message: String)
+       fun fatal(v: NaiveInterpreter, message: String)
        do
                if v.modelbuilder.toolcontext.opt_no_color.value == true then
                        sys.stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
@@ -795,6 +824,8 @@ redef class AMethPropdef
                                return v.int_instance(args[0].to_i.bin_or(args[1].to_i))
                        else if pname == "bin_xor" then
                                return v.int_instance(args[0].to_i.bin_xor(args[1].to_i))
+                       else if pname == "bin_not" then
+                               return v.int_instance(args[0].to_i.bin_not)
                        else if pname == "native_int_to_s" then
                                return v.native_string_instance(recvval.to_s)
                        else if pname == "strerror_ext" then
@@ -1091,7 +1122,6 @@ redef class AClassdef
        private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
        do
                if mpropdef.mproperty.is_root_init then
-                       assert self.super_inits == null
                        assert args.length == 1
                        if not mpropdef.is_intro then
                                # standard call-next-method
@@ -1099,27 +1129,9 @@ redef class AClassdef
                                v.call_without_varargs(superpd, args)
                        end
                        return null
+               else
+                       abort
                end
-
-               var super_inits = self.super_inits
-               if super_inits != null then
-                       var args_of_super = args
-                       if args.length > 1 then args_of_super = [args.first]
-                       for su in super_inits do
-                               v.send(su, args_of_super)
-                       end
-               end
-               var recv = args.first
-               assert recv isa MutableInstance
-               var i = 1
-               # Collect undefined attributes
-               for npropdef in self.n_propdefs do
-                       if npropdef isa AAttrPropdef and not npropdef.noinit and npropdef.n_expr == null then
-                               v.write_attribute(npropdef.mpropdef.mproperty, recv, args[i])
-                               i += 1
-                       end
-               end
-               return null
        end
 end
 
@@ -1475,9 +1487,7 @@ redef class AStringFormExpr
        redef fun expr(v)
        do
                var txt = self.value.as(not null)
-               var nat = v.native_string_instance(txt)
-               var res = v.send(v.force_get_primitive_method("to_s", nat.mtype), [nat]).as(not null)
-               return res
+               return v.string_instance(txt)
        end
 end