import literal
import semantize
private import parser::tables
+import mixin
redef class ToolContext
# --discover-call-trace
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
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
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
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
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]
# 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)
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
do
var initializers = callsite.mpropdef.initializers
if not initializers.is_empty then
- assert initializers.length == arguments.length - 1 else debug("expected {initializers.length} got {arguments.length - 1}")
var recv = arguments.first
var i = 1
for p in initializers do
if p isa MMethod then
- self.send(p, [recv, arguments[i]])
+ var args = [recv]
+ for x in p.intro.msignature.mparameters do
+ args.add arguments[i]
+ i += 1
+ end
+ self.send(p, args)
else if p isa MAttribute then
assert recv isa MutableInstance
recv.attributes[p] = arguments[i]
+ i += 1
else abort
- i += 1
end
+ assert i == arguments.length
+
return send(callsite.mproperty, [recv])
end
return send(callsite.mproperty, arguments)
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
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")
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
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
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
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
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
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
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
#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}")
- 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
v.stmt(self.n_block)
- if v.is_break(self.escapemark) then return
+ if v.is_break(self.escapemark) then break
v.is_continue(self.escapemark) # Clear the break
- if v.is_escaping then return
+ 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
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