# Is a return executed?
# Set this mark to skip the evaluation until the end of the specified method frame
- var returnmark: nullable Frame = null
+ var returnmark: nullable FRAME = null
# Is a break or a continue executed?
# Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
# Return the integer instance associated with `val`.
fun int_instance(val: Int): Instance
do
- var ic = get_primitive_class("Int")
- var instance = new PrimitiveInstance[Int](ic.mclass_type, val)
+ var t = mainmodule.int_type
+ var instance = new PrimitiveInstance[Int](t, val)
init_instance_primitive(instance)
return instance
end
# Return the char instance associated with `val`.
fun char_instance(val: Char): Instance
do
- var ic = get_primitive_class("Char")
- var instance = new PrimitiveInstance[Char](ic.mclass_type, val)
+ var t = mainmodule.char_type
+ var instance = new PrimitiveInstance[Char](t, val)
init_instance_primitive(instance)
return instance
end
# Return the float instance associated with `val`.
fun float_instance(val: Float): Instance
do
- var ic = get_primitive_class("Float")
- var instance = new PrimitiveInstance[Float](ic.mclass_type, val)
+ var t = mainmodule.float_type
+ var instance = new PrimitiveInstance[Float](t, val)
init_instance_primitive(instance)
return instance
end
fun array_instance(values: Array[Instance], elttype: MType): Instance
do
assert not elttype.need_anchor
- var nat = new PrimitiveInstance[Array[Instance]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
+ var nat = new PrimitiveInstance[Array[Instance]](mainmodule.native_array_type(elttype), values)
init_instance_primitive(nat)
- var mtype = get_primitive_class("Array").get_mtype([elttype])
+ var mtype = mainmodule.array_type(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)])
do
var val = new FlatBuffer.from(txt)
val.add('\0')
- var ic = get_primitive_class("NativeString")
- var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val)
+ var t = mainmodule.native_string_type
+ var instance = new PrimitiveInstance[Buffer](t, val)
init_instance_primitive(instance)
return instance
end
return res
end
+ # The virtual type of the frames used in the execution engine
+ type FRAME: Frame
+
# The current frame used to store local variables of the current method executed
- fun frame: Frame do return frames.first
+ fun frame: FRAME do return frames.first
# The stack of all frames. The first one is the current one.
- var frames = new List[Frame]
+ var frames = new List[FRAME]
# Return a stack trace. One line per function
fun stack_trace: String
return frames.first.arguments.first.mtype.as(MClassType)
end
+ # Initialize the environment for a call and return a new Frame
+ # *`node` The AST node
+ # *`mpropdef` The corresponding mpropdef
+ # *`args` Arguments of the call
+ fun new_frame(node: ANode, mpropdef: MPropDef, args: Array[Instance]): FRAME
+ do
+ return new InterpreterFrame(node, mpropdef, args)
+ end
+
# Exit the program with a message
fun fatal(message: String)
do
# Retrieve the value of the variable in the current frame
fun read_variable(v: Variable): Instance
do
- var f = frames.first
+ var f = frames.first.as(InterpreterFrame)
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
+ var f = frames.first.as(InterpreterFrame)
f.map[v] = value
end
var node = modelbuilder.mpropdef2node(mpropdef)
if mpropdef.is_abstract then
if node != null then
- self.frames.unshift new Frame(node, mpropdef, args)
+ self.frames.unshift new_frame(node, mpropdef, args)
end
fatal("Abstract method `{mpropdef.mproperty.name}` called on `{args.first.mtype}`")
abort
# 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 determines the correct type according to the receiver of the current propdef (self).
fun unanchor_type(mtype: MType): MType
do
end
# Information about local variables in a running method
-class Frame
+abstract class Frame
# The current visited node
# The node is stored by frame to keep a stack trace
var current_node: ANode
var mpropdef: MPropDef
# Arguments of the method (the first is the receiver)
var arguments: Array[Instance]
+ # Indicate if the expression has an array comprehension form
+ var comprehension: nullable Array[Instance] = null
+end
+
+# Implementation of a Frame with a Hashmap to store local variables
+class InterpreterFrame
+ super Frame
+
# Mapping between a variable and the current value
private var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
- var comprehension: nullable Array[Instance] = null
end
redef class ANode
redef fun call(v, mpropdef, args)
do
- var f = new Frame(self, self.mpropdef.as(not null), args)
+ var f = v.new_frame(self, mpropdef, args)
var res = call_commons(v, mpropdef, args, f)
v.frames.shift
if v.returnmark == f then
return v.int_instance(res)
else if pname == "atof" then
return v.float_instance(recvval.to_f)
+ else if pname == "fast_cstring" then
+ var ns = recvval.to_cstring.to_s.substring_from(args[1].to_i)
+ return v.native_string_instance(ns)
end
else if cname == "String" then
var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
if pname == "files" then
var res = new Array[Instance]
for f in str.files do res.add v.string_instance(f)
- return v.array_instance(res, v.get_primitive_class("String").mclass_type)
+ return v.array_instance(res, v.mainmodule.string_type)
end
else if pname == "calloc_string" then
return v.native_string_instance("!" * args[1].to_i)
else if pname == "set_buffering_type" then
return v.int_instance(recvval.as(PrimitiveNativeFile).set_buffering_type(args[1].to_i, args[2].to_i))
end
- else if pname == "calloc_array" then
- var recvtype = args.first.mtype.as(MClassType)
- var mtype: MType
- 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)
- 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
if mpropdef == mreadpropdef then
assert args.length == 1
if not is_lazy or v.isset_attribute(attr, recv) then return v.read_attribute(attr, recv)
- return evaluate_expr(v, recv)
+ var f = v.new_frame(self, mpropdef, args)
+ return evaluate_expr(v, recv, f)
else if mpropdef == mwritepropdef then
assert args.length == 2
v.write_attribute(attr, recv, args[1])
do
if is_lazy then return
if has_value then
- evaluate_expr(v, recv)
+ var f = v.new_frame(self, mpropdef.as(not null), [recv])
+ evaluate_expr(v, recv, f)
return
end
var mpropdef = self.mpropdef
end
end
- private fun evaluate_expr(v: NaiveInterpreter, recv: Instance): Instance
+ private fun evaluate_expr(v: NaiveInterpreter, recv: Instance, f: Frame): Instance
do
assert recv isa MutableInstance
- var f = new Frame(self, self.mpropdef.as(not null), [recv])
v.frames.unshift(f)
var val
if i == null then return null
array.add(i)
end
- var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
+ var i = v.array_instance(array, v.mainmodule.object_type)
var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
assert res != null
return res