X-Git-Url: http://nitlanguage.org diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 34fd8f1..01c872d 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -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 @@ -293,6 +318,20 @@ private class NaiveInterpreter end end + # Retrieve the value of the variable in the current frame + fun read_variable(v: Variable): Instance + do + var f = frames.first + return f.map[v] + end + + # Assign the value of the variable in the current frame + fun write_variable(v: Variable, value: Instance) + do + var f = frames.first + f.map[v] = value + end + # Store known method, used to trace methods as thez are reached var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef] @@ -350,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) @@ -358,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 @@ -479,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 @@ -592,23 +635,23 @@ 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 # The executed property. # A Method in case of a call, an attribute in case of a default initialization. var mpropdef: MPropDef - # Arguments of the method (the first is te receiver + # Arguments of the method (the first is the receiver) var arguments: Array[Instance] - # Mapping betwen a variable an the current value - var map: Map[Variable, Instance] = new HashMap[Variable, Instance] + # Mapping between a variable and the current value + 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") @@ -649,14 +692,14 @@ redef class AMethPropdef private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance do + v.frames.unshift(f) + for i in [0..mpropdef.msignature.arity[ do var variable = self.n_signature.n_params[i].variable assert variable != null - f.map[variable] = arguments[i+1] + v.write_variable(variable, arguments[i+1]) end - v.frames.unshift(f) - if mpropdef.is_abstract then v.fatal("Abstract method `{mpropdef.mproperty.name}` called on `{arguments.first.mtype}`") abort @@ -781,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 @@ -1139,7 +1184,7 @@ redef class AVardeclExpr if ne != null then var i = v.expr(ne) if i == null then return - v.frame.map[self.variable.as(not null)] = i + v.write_variable(self.variable.as(not null), i) end end end @@ -1147,7 +1192,7 @@ end redef class AVarExpr redef fun expr(v) do - return v.frame.map[self.variable.as(not null)] + return v.read_variable(self.variable.as(not null)) end end @@ -1156,7 +1201,7 @@ redef class AVarAssignExpr do var i = v.expr(self.n_value) if i == null then return null - v.frame.map[self.variable.as(not null)] = i + v.write_variable(self.variable.as(not null), i) return i end end @@ -1164,12 +1209,13 @@ end redef class AVarReassignExpr redef fun stmt(v) do - var vari = v.frame.map[self.variable.as(not null)] + var variable = self.variable.as(not null) + var vari = v.read_variable(variable) var value = v.expr(self.n_value) if value == null then return var res = v.callsite(reassign_callsite, [vari, value]) assert res != null - v.frame.map[self.variable.as(not null)] = res + v.write_variable(variable, res) end end @@ -1315,12 +1361,12 @@ redef class AForExpr if self.variables.length == 1 then var item = v.callsite(method_item, [iter]).as(not null) #self.debug("item {item}") - v.frame.map[self.variables.first] = item + v.write_variable(self.variables.first, item) else if self.variables.length == 2 then var key = v.callsite(method_key, [iter]).as(not null) - v.frame.map[self.variables[0]] = key + v.write_variable(self.variables[0], key) var item = v.callsite(method_item, [iter]).as(not null) - v.frame.map[self.variables[1]] = item + v.write_variable(self.variables[1], item) else abort end @@ -1441,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