import semantize
private import parser::tables
import mixin
+import primitive_types
redef class ToolContext
# --discover-call-trace
var arguments: Array[String]
# The main Sys instance
- var mainobj: nullable 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)
+ if mainmodule.model.get_mclasses_by_name("Bool") != null then
+ self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
+ init_instance_primitive(self.true_instance)
+ self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
+ init_instance_primitive(self.false_instance)
+ end
+ self.null_instance = new PrimitiveInstance[nullable Object](mainmodule.model.null_type, null)
end
# Starts the interpreter on the main module of a program
# Subtype test in the context of the mainmodule
fun is_subtype(sub, sup: MType): Bool
do
- return sub.is_subtype(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType), sup)
+ return sub.is_subtype(self.mainmodule, current_receiver_class, sup)
end
+ # Get a primitive method in the context of the main module
fun force_get_primitive_method(name: String, recv: MType): MMethod
do
assert recv isa MClassType
- return self.modelbuilder.force_get_primitive_method(self.frame.current_node, name, recv.mclass, self.mainmodule)
+ return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
end
# 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`
# If `n` cannot be evaluated, then aborts.
fun stmt(n: nullable AExpr)
do
- if n != null then
- var frame = self.frame
- var old = frame.current_node
- frame.current_node = n
- #n.debug("Execute stmt")
- n.stmt(self)
- frame.current_node = old
+ if n == null then return
+
+ if n.comprehension != null then
+ var comprehension = frame.comprehension.as(not null)
+ var i = expr(n)
+ if i != null then comprehension.add(i)
+ return
end
+
+ var frame = self.frame
+ var old = frame.current_node
+ frame.current_node = n
+ n.stmt(self)
+ frame.current_node = old
end
# Map used to store values of nodes that must be evaluated once in the system (`AOnceExpr`)
# Return the integer instance associated with `val`.
fun int_instance(val: Int): Instance
do
- var ic = self.mainmodule.get_primitive_class("Int")
- return 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 = self.mainmodule.get_primitive_class("Char")
- return 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 = self.mainmodule.get_primitive_class("Float")
- return 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
# The unique instance of the `true` value.
- var true_instance: Instance
+ var true_instance: Instance is noinit
# The unique instance of the `false` value.
- var false_instance: Instance
+ var false_instance: Instance is noinit
# The unique instance of the `null` value.
- var null_instance: Instance
+ var null_instance: Instance is noinit
# Return a new array made of `values`.
# The dynamic type of the result is Array[elttype].
fun array_instance(values: Array[Instance], elttype: MType): Instance
do
assert not elttype.need_anchor
- var nat = new PrimitiveInstance[Array[Instance]](self.mainmodule.get_primitive_class("NativeArray").get_mtype([elttype]), values)
- var mtype = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
+ var nat = new PrimitiveInstance[Array[Instance]](mainmodule.native_array_type(elttype), values)
+ init_instance_primitive(nat)
+ 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)])
return res
end
+ # Return a instance associated to a primitive class
+ # Current primitive classes are `Int`, `Bool`, and `String`
fun value_instance(object: Object): Instance
do
if object isa Int then
do
var val = new FlatBuffer.from(txt)
val.add('\0')
- var ic = self.mainmodule.get_primitive_class("NativeString")
- return 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 a new String instance for `txt`
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 b.to_s
end
+ # The current node, used to print errors, debug and stack-traces
+ fun current_node: nullable ANode
+ do
+ if frames.is_empty then return null
+ return frames.first.current_node
+ end
+
+ # The dynamic type of the current `self`
+ fun current_receiver_class: MClassType
+ do
+ 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
- if frames.is_empty then
+ var node = current_node
+ if node == null then
print message
else
- self.frame.current_node.fatal(self, message)
+ node.fatal(self, message)
end
exit(1)
end
# Debug on the current node
fun debug(message: String)
do
- if frames.is_empty then
+ var node = current_node
+ if node == null then
print message
else
- self.frame.current_node.debug(message)
+ node.debug(message)
end
end
# 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
assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
# 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.is_root_init then
- var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
- self.parameter_check(nclassdef, mpropdef, args)
- return nclassdef.call(self, mpropdef, args)
+
+ var node = modelbuilder.mpropdef2node(mpropdef)
+ if mpropdef.is_abstract then
+ if node != null then
+ self.frames.unshift new_frame(node, mpropdef, args)
+ end
+ fatal("Abstract method `{mpropdef.mproperty.name}` called on `{args.first.mtype}`")
+ abort
+ end
+
+ if node isa APropdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.call(self, mpropdef, args)
+ else if node isa AClassdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.call(self, mpropdef, args)
+ else if node != null then
+ fatal("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
+ abort
else if val != null then
return value_instance(val)
else
end
end
- # Generate type checks in the C code to check covariant parameters
+ # Execute type checks of covariant parameters
fun parameter_check(node: ANode, mpropdef: MMethodDef, args: Array[Instance])
do
var msignature = mpropdef.msignature
var origmtype = mpropdef.mproperty.intro.msignature.mparameters[i].mtype
if not origmtype.need_anchor then continue
+ #print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
+
# get the parameter type
var mtype = msignature.mparameters[i].mtype
var anchor = args.first.mtype.as(MClassType)
fun send_commons(mproperty: MMethod, args: Array[Instance], mtype: MType): nullable Instance
do
if mtype isa MNullType then
- if mproperty.name == "==" then
+ if mproperty.name == "==" or mproperty.name == "is_same_instance" then
return self.bool_instance(args[0] == args[1])
else if mproperty.name == "!=" then
return self.bool_instance(args[0] != args[1])
self.send(p, args)
else if p isa MAttribute then
assert recv isa MutableInstance
- recv.attributes[p] = arguments[i]
+ write_attribute(p, recv, arguments[i])
i += 1
else abort
end
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
- res.add(npropdef)
- end
- end
+ res.add_all(modelbuilder.collect_attr_propdef(cd))
end
cache[mtype] = res
end
end
- # This function determine the correct type according the reciever of the current definition (self).
+ # A hook to initialize a `PrimitiveInstance`
+ fun init_instance_primitive(recv: Instance) do end
+
+ # This function determines the correct type according to the receiver of the current propdef (self).
fun unanchor_type(mtype: MType): MType
do
- return mtype.anchor_to(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType))
+ return mtype.anchor_to(self.mainmodule, current_receiver_class)
end
# Placebo instance used to mark internal error result when `null` already have a meaning.
# The real value encapsulated if the instance is primitive.
# Else aborts.
- fun val: Object do abort
+ fun val: nullable Object do abort
end
# A instance with attribute (standards objects)
# Special instance to handle primitives values (int, bool, etc.)
# The trick it just to encapsulate the <<real>> value
-class PrimitiveInstance[E: Object]
+class PrimitiveInstance[E]
super Instance
# 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
redef fun ==(o)
do
- if not o isa PrimitiveInstance[Object] then return false
+ if not o isa PrimitiveInstance[nullable Object] then return false
return self.val == o.val
end
redef fun eq_is(o)
do
- if not o isa PrimitiveInstance[Object] then return false
+ if not o isa PrimitiveInstance[nullable Object] then return false
return self.val.is_same_instance(o.val)
end
- redef fun to_s do return "{mtype}#{val.object_id}({val})"
+ redef fun to_s do return "{mtype}#{val.object_id}({val or else "null"})"
redef fun to_i do return val.as(Int)
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]
end
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
v.write_variable(variable, arguments[i+1])
end
- if mpropdef.is_abstract then
- v.fatal("Abstract method `{mpropdef.mproperty.name}` called on `{arguments.first.mtype}`")
- abort
- end
-
# Call the implicit super-init
var auto_super_inits = self.auto_super_inits
if auto_super_inits != null then
else if pname == "exit" then
exit(args[1].to_i)
abort
+ else if pname == "buffer_mode_full" then
+ return v.int_instance(sys.buffer_mode_full)
+ else if pname == "buffer_mode_line" then
+ return v.int_instance(sys.buffer_mode_line)
+ else if pname == "buffer_mode_none" then
+ return v.int_instance(sys.buffer_mode_none)
else if pname == "sys" then
return v.mainobj
else if cname == "Int" 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 == "int_to_s_len" then
+ return v.int_instance(recvval.to_s.length)
else if pname == "native_int_to_s" then
- return v.native_string_instance(recvval.to_s)
+ var s = recvval.to_s
+ var srecv = args[1].val.as(Buffer)
+ srecv.clear
+ srecv.append(s)
+ srecv.add('\0')
+ return null
else if pname == "strerror_ext" then
return v.native_string_instance(recvval.strerror)
end
return v.bool_instance(args[0].to_f.is_nan)
else if pname == "is_inf_extern" then
return v.bool_instance(args[0].to_f.is_inf != 0)
+ else if pname == "round" then
+ return v.float_instance(args[0].to_f.round)
end
else if cname == "NativeString" then
if pname == "new" then
if fromval < 0 then
debug("Illegal access on {recvval} for element {fromval}/{recvval.length}")
end
- if fromval + lenval >= recvval.length then
+ if fromval + lenval > recvval.length then
debug("Illegal access on {recvval} for element {fromval}+{lenval}/{recvval.length}")
end
if toval < 0 then
debug("Illegal access on {destval} for element {toval}/{destval.length}")
end
- if toval + lenval >= destval.length then
+ if toval + lenval > destval.length then
debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
end
recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
else if pname == "atof" then
return v.float_instance(recvval.to_f)
end
+ else if cname == "String" then
+ var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
+ var str = cs.val.to_s
+ 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.mainmodule.string_type)
+ end
else if pname == "calloc_string" then
return v.native_string_instance("!" * args[1].to_i)
else if cname == "NativeArray" 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)
+ var instance = new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+ v.init_instance_primitive(instance)
+ return instance
end
var recvval = args.first.val.as(Array[Instance])
if pname == "[]" then
else if pname == "length" then
return v.int_instance(recvval.length)
else if pname == "copy_to" then
- recvval.copy(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
+ recvval.copy_to(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
return null
end
else if cname == "NativeFile" then
if pname == "native_stdout" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+ var inst = new PrimitiveNativeFile.native_stdout
+ var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_stdin" then
- return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+ var inst = new PrimitiveNativeFile.native_stdin
+ var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_stderr" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+ var inst = new PrimitiveNativeFile.native_stderr
+ var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "io_open_read" then
var a1 = args[1].val.as(Buffer)
- return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+ var inst = new PrimitiveNativeFile.io_open_read(a1.to_s)
+ var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "io_open_write" then
var a1 = args[1].val.as(Buffer)
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+ var inst = new PrimitiveNativeFile.io_open_write(a1.to_s)
+ var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
+ v.init_instance_primitive(instance)
+ return instance
end
var recvval = args.first.val
if pname == "io_write" then
var a1 = args[1].val.as(Buffer)
- recvval.as(OStream).write(a1.substring(0, args[2].to_i).to_s)
- return args[2]
+ return v.int_instance(recvval.as(PrimitiveNativeFile).io_write(a1.to_cstring, args[2].to_i))
else if pname == "io_read" then
- var str = recvval.as(IStream).read(args[2].to_i)
var a1 = args[1].val.as(Buffer)
- new FlatBuffer.from(str).copy(0, str.length, a1.as(FlatBuffer), 0)
- return v.int_instance(str.length)
+ var ns = new NativeString(a1.length)
+ var len = recvval.as(PrimitiveNativeFile).io_read(ns, args[2].to_i)
+ a1.clear
+ a1.append(ns.to_s_with_length(len))
+ return v.int_instance(len)
+ else if pname == "flush" then
+ recvval.as(PrimitiveNativeFile).flush
+ return null
else if pname == "io_close" then
- recvval.as(IOS).close
- return v.int_instance(0)
- else if pname == "address_is_null" then
- return v.false_instance
+ return v.int_instance(recvval.as(PrimitiveNativeFile).io_close)
+ 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.mainmodule.get_primitive_class("ArrayCapable"))
- mtype = mtype.arguments.first
- var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
- return new PrimitiveInstance[Array[Instance]](v.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype]), val)
else if pname == "native_argc" then
return v.int_instance(v.arguments.length)
else if pname == "native_argv" then
return v.native_string_instance(txt)
else if pname == "get_time" then
return v.int_instance(get_time)
+ else if pname == "srand" then
+ srand
+ return null
else if pname == "srand_from" then
srand_from(args[1].to_i)
return null
else if pname == "errno" then
return v.int_instance(sys.errno)
else if pname == "address_is_null" then
+ var recv = args[0]
+ if recv isa PrimitiveInstance[PrimitiveNativeFile] then
+ return v.bool_instance(recv.val.address_is_null)
+ end
return v.false_instance
end
return v.error_instance
end
end
-redef class AbstractArray[E]
- fun copy(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
- do
- self.copy_to(start, len, dest, new_start)
- end
-end
-
redef class AAttrPropdef
redef fun call(v, mpropdef, args)
do
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])
private fun init_expr(v: NaiveInterpreter, recv: Instance)
do
if is_lazy then return
- var nexpr = self.n_expr
- if nexpr != null then
- evaluate_expr(v, recv)
+ if has_value then
+ var f = v.new_frame(self, mpropdef.as(not null), [recv])
+ evaluate_expr(v, recv, f)
return
end
- var mtype = self.mpropdef.static_mtype.as(not null)
+ var mpropdef = self.mpropdef
+ if mpropdef == null then return
+ var mtype = mpropdef.static_mtype.as(not null)
mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType))
if mtype isa MNullableType then
v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
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 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)
# Return a possible value
# NOTE: Do not call this method directly, but use `v.expr`
# This method is here to be implemented by subclasses.
- private fun expr(v: NaiveInterpreter): nullable Instance
+ protected fun expr(v: NaiveInterpreter): nullable Instance
do
fatal(v, "NOT YET IMPLEMENTED expr {class_name}")
abort
# Evaluate the node as a statement.
# NOTE: Do not call this method directly, but use `v.stmt`
# This method is here to be implemented by subclasses (no need to return something).
- private fun stmt(v: NaiveInterpreter)
+ protected fun stmt(v: NaiveInterpreter)
do
expr(v)
end
redef fun expr(v)
do
var val = new Array[Instance]
- for nexpr in self.n_exprs.n_exprs do
- var i = v.expr(nexpr)
- if i == null then return null
- val.add(i)
+ var old_comprehension = v.frame.comprehension
+ v.frame.comprehension = val
+ for nexpr in self.n_exprs do
+ if nexpr isa AForExpr then
+ v.stmt(nexpr)
+ else
+ var i = v.expr(nexpr)
+ if i == null then return null
+ val.add(i)
+ end
end
+ v.frame.comprehension = old_comprehension
var mtype = v.unanchor_type(self.mtype.as(not null)).as(MClassType)
var elttype = mtype.arguments.first
return v.array_instance(val, elttype)
if i == null then return null
array.add(i)
end
- var i = v.array_instance(array, v.mainmodule.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