import auto_super_init
import frontend
import common_ffi
+private import parser::tables
redef class ToolContext
# --discover-call-trace
if initprop != null then
interpreter.send(initprop, [mainobj])
end
- var mainprop = mainmodule.try_get_primitive_method("main", sys_type.mclass)
+ 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
# Return a new native string initialized with `txt`
fun native_string_instance(txt: String): Instance
do
- var val = new Buffer.from(txt)
+ 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)
# Return a stack stace. One line per function
fun stack_trace: String
do
- var b = new Buffer
+ var b = new FlatBuffer
b.append(",---- Stack trace -- - - -\n")
for f in frames do
b.append("| {f.mpropdef} ({f.current_node.location})\n")
return recv.attributes[mproperty]
end
+ # Replace in `recv` the value of the attribute `mproperty` by `value`
+ fun write_attribute(mproperty: MAttribute, recv: Instance, value: Instance)
+ do
+ assert recv isa MutableInstance
+ recv.attributes[mproperty] = value
+ end
+
+ # Is the attribute `mproperty` initialized the instance `recv`?
+ fun isset_attribute(mproperty: MAttribute, recv: Instance): Bool
+ do
+ assert recv isa MutableInstance
+ return recv.attributes.has_key(mproperty)
+ end
+
# Collect attributes of a type in the order of their init
fun collect_attr_propdef(mtype: MType): Array[AAttrPropdef]
do
private fun fatal(v: NaiveInterpreter, message: String)
do
if v.modelbuilder.toolcontext.opt_no_color.value == true then
- stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
+ sys.stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
else
- stderr.write("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
- stderr.write(v.stack_trace)
- stderr.write("\n")
+ sys.stderr.write("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
+ sys.stderr.write(v.stack_trace)
+ sys.stderr.write("\n")
end
exit(1)
end
end
end
-redef class AConcreteMethPropdef
+redef class AMethPropdef
+ super TablesCapable
redef fun call(v, mpropdef, args)
do
var f = new Frame(self, self.mpropdef.as(not null), args)
- call_commons(v, mpropdef, args, f)
+ var res = call_commons(v, mpropdef, args, f)
v.frames.shift
if v.returnmark == f then
v.returnmark = null
- var res = v.escapevalue
+ res = v.escapevalue
v.escapevalue = null
return res
end
- return null
+ return res
end
- private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame)
+ private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
do
for i in [0..mpropdef.msignature.arity[ do
var variable = self.n_signature.n_params[i].variable
v.frames.unshift(f)
+ 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
end
end
- v.stmt(self.n_block)
+ if n_block != null then
+ v.stmt(self.n_block)
+ return null
+ else
+ return intern_call(v, mpropdef, arguments)
+ end
end
-end
-redef class AInternMethPropdef
- redef fun call(v, mpropdef, args)
+ private fun intern_call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
do
var pname = mpropdef.mproperty.name
var cname = mpropdef.mclassdef.mclass.name
else if pname == "sys" then
return v.mainobj
else if cname == "Int" then
+ var recvval = args[0].to_i
if pname == "unary -" then
return v.int_instance(-args[0].to_i)
- else if pname == "succ" then
- return v.int_instance(args[0].to_i + 1)
- else if pname == "prec" then
- return v.int_instance(args[0].to_i - 1)
else if pname == "+" then
return v.int_instance(args[0].to_i + args[1].to_i)
else if pname == "-" then
return v.int_instance(args[0].to_i.lshift(args[1].to_i))
else if pname == "rshift" then
return v.int_instance(args[0].to_i.rshift(args[1].to_i))
+ else if pname == "rand" then
+ var res = recvval.rand
+ return v.int_instance(res)
+ else if pname == "bin_and" then
+ return v.int_instance(args[0].to_i.bin_and(args[1].to_i))
+ else if pname == "bin_or" then
+ 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 == "native_int_to_s" then
+ return v.native_string_instance(recvval.to_s)
+ else if pname == "strerror_ext" then
+ return v.native_string_instance(recvval.strerror)
end
else if cname == "Char" then
var recv = args[0].val.as(Char)
if pname == "ascii" then
return v.int_instance(recv.ascii)
- else if pname == "succ" then
- return v.char_instance(recv.succ)
- else if pname == "prec" then
- return v.char_instance(recv.prec)
+ else if pname == "successor" then
+ return v.char_instance(recv.successor(args[1].to_i))
+ else if pname == "predecessor" then
+ return v.char_instance(recv.predecessor(args[1].to_i))
else if pname == "<" then
return v.bool_instance(recv < args[1].val.as(Char))
else if pname == ">" then
return v.bool_instance(recv >= args[1].to_f)
else if pname == "to_i" then
return v.int_instance(recv.to_i)
+ else if pname == "cos" then
+ return v.float_instance(args[0].to_f.cos)
+ else if pname == "sin" then
+ return v.float_instance(args[0].to_f.sin)
+ else if pname == "tan" then
+ return v.float_instance(args[0].to_f.tan)
+ else if pname == "acos" then
+ return v.float_instance(args[0].to_f.acos)
+ else if pname == "asin" then
+ return v.float_instance(args[0].to_f.asin)
+ else if pname == "atan" then
+ return v.float_instance(args[0].to_f.atan)
+ else if pname == "sqrt" then
+ return v.float_instance(args[0].to_f.sqrt)
+ else if pname == "exp" then
+ return v.float_instance(args[0].to_f.exp)
+ else if pname == "log" then
+ return v.float_instance(args[0].to_f.log)
+ else if pname == "pow" then
+ return v.float_instance(args[0].to_f.pow(args[1].to_f))
+ else if pname == "rand" then
+ return v.float_instance(args[0].to_f.rand)
+ else if pname == "abs" then
+ return v.float_instance(args[0].to_f.abs)
+ else if pname == "hypot_with" then
+ return v.float_instance(args[0].to_f.hypot_with(args[1].to_f))
+ else if pname == "is_nan" then
+ 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)
end
else if cname == "NativeString" then
+ if pname == "init" then
+ return v.native_string_instance("!" * args[1].to_i)
+ end
var recvval = args.first.val.as(Buffer)
if pname == "[]" then
var arg1 = args[1].to_i
return null
else if pname == "copy_to" then
# sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
- var destval = args[1].val.as(Buffer)
+ var destval = args[1].val.as(FlatBuffer)
var lenval = args[2].to_i
var fromval = args[3].to_i
var toval = args[4].to_i
if toval + lenval >= destval.length then
debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
end
- recvval.copy(fromval, lenval, destval, toval)
+ recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
return null
else if pname == "atoi" then
return v.int_instance(recvval.to_i)
+ else if pname == "file_exists" then
+ return v.bool_instance(recvval.to_s.file_exists)
+ else if pname == "file_mkdir" then
+ recvval.to_s.mkdir
+ return null
+ else if pname == "file_chdir" then
+ recvval.to_s.chdir
+ return null
+ else if pname == "file_realpath" then
+ return v.native_string_instance(recvval.to_s.realpath)
+ else if pname == "get_environ" then
+ var txt = recvval.to_s.environ
+ return v.native_string_instance(txt)
+ else if pname == "system" then
+ var res = sys.system(recvval.to_s)
+ return v.int_instance(res)
+ else if pname == "atof" then
+ return v.float_instance(recvval.to_f)
end
else if pname == "calloc_string" then
return v.native_string_instance("!" * args[1].to_i)
else if cname == "NativeArray" then
+ if pname == "init" then
+ var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
+ return new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+ end
var recvval = args.first.val.as(Array[Instance])
if pname == "[]" then
if args[1].to_i >= recvval.length or args[1].to_i < 0 then
else if pname == "[]=" then
recvval[args[1].to_i] = args[2]
return null
+ 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)
return null
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
- var txt = v.arguments[args[1].to_i]
- return v.native_string_instance(txt)
- end
- fatal(v, "NOT YET IMPLEMENTED intern {mpropdef}")
- abort
- 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 AExternInitPropdef
- redef fun call(v, mpropdef, args)
- do
- var pname = mpropdef.mproperty.name
- var cname = mpropdef.mclassdef.mclass.name
- if pname == "native_stdout" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, stdout)
- else if pname == "native_stdin" then
- return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, stdin)
- else if pname == "native_stderr" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, stderr)
- 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))
- 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))
- end
- fatal(v, "NOT YET IMPLEMENTED extern init {mpropdef}")
- abort
- end
-end
-
-redef class AExternMethPropdef
- super TablesCapable
- redef fun call(v, mpropdef, args)
- do
- var pname = mpropdef.mproperty.name
- var cname = mpropdef.mclassdef.mclass.name
- if cname == "Int" then
- var recvval = args.first.val.as(Int)
- if pname == "rand" then
- var res = recvval.rand
- return v.int_instance(res)
- else if pname == "native_int_to_s" then
- return v.native_string_instance(recvval.to_s)
- end
else if cname == "NativeFile" then
+ if pname == "native_stdout" then
+ return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+ else if pname == "native_stdin" then
+ return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+ else if pname == "native_stderr" then
+ return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+ 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))
+ 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))
+ 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))
+ recvval.as(OStream).write(a1.substring(0, args[2].to_i).to_s)
return args[2]
else if pname == "io_read" then
var str = recvval.as(IStream).read(args[2].to_i)
var a1 = args[1].val.as(Buffer)
- new Buffer.from(str).copy(0, str.length, a1, 0)
+ new FlatBuffer.from(str).copy(0, str.length, a1.as(FlatBuffer), 0)
return v.int_instance(str.length)
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
end
- else if cname == "NativeString" then
- var recvval = args.first.val.as(Buffer)
- if pname == "file_exists" then
- return v.bool_instance(recvval.to_s.file_exists)
- else if pname == "file_mkdir" then
- recvval.to_s.mkdir
- return null
- else if pname == "file_chdir" then
- recvval.to_s.chdir
- return null
- else if pname == "file_realpath" then
- return v.native_string_instance(recvval.to_s.realpath)
- else if pname == "get_environ" then
- var txt = recvval.to_s.environ
- return v.native_string_instance(txt)
- else if pname == "system" then
- var res = sys.system(recvval.to_s)
- return v.int_instance(res)
- else if pname == "atof" then
- return v.float_instance(recvval.to_f)
- end
- else if cname == "Int" then
- if pname == "rand" then
- return v.int_instance(args[0].to_i.rand)
- end
- else if cname == "Float" then
- if pname == "cos" then
- return v.float_instance(args[0].to_f.cos)
- else if pname == "sin" then
- return v.float_instance(args[0].to_f.sin)
- else if pname == "tan" then
- return v.float_instance(args[0].to_f.tan)
- else if pname == "acos" then
- return v.float_instance(args[0].to_f.acos)
- else if pname == "asin" then
- return v.float_instance(args[0].to_f.asin)
- else if pname == "atan" then
- return v.float_instance(args[0].to_f.atan)
- else if pname == "sqrt" then
- return v.float_instance(args[0].to_f.sqrt)
- else if pname == "exp" then
- return v.float_instance(args[0].to_f.exp)
- else if pname == "log" then
- return v.float_instance(args[0].to_f.log)
- else if pname == "pow" then
- return v.float_instance(args[0].to_f.pow(args[1].to_f))
- else if pname == "rand" then
- return v.float_instance(args[0].to_f.rand)
- 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
+ var txt = v.arguments[args[1].to_i]
+ return v.native_string_instance(txt)
else if pname == "native_argc" then
return v.int_instance(v.arguments.length)
else if pname == "native_argv" then
return v.int_instance(parser_action(args[1].to_i, args[2].to_i))
else if pname == "file_getcwd" then
return v.native_string_instance(getcwd)
+ else if pname == "errno" then
+ return v.int_instance(sys.errno)
+ else if pname == "address_is_null" then
+ return v.false_instance
+ end
+ if mpropdef.is_intern then
+ fatal(v, "NOT YET IMPLEMENTED intern {mpropdef}")
+ else if mpropdef.is_extern then
+ fatal(v, "NOT YET IMPLEMENTED extern {mpropdef}")
+ else
+ fatal(v, "NOT YET IMPLEMENTED <wat?> {mpropdef}")
end
- fatal(v, "NOT YET IMPLEMENTED extern {mpropdef}")
abort
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
var recv = args.first
assert recv isa MutableInstance
var attr = self.mpropdef.mproperty
- if args.length == 1 then
- return v.read_attribute(attr, recv)
- else
+ 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)
+ else if mpropdef == mwritepropdef then
assert args.length == 2
- recv.attributes[attr] = args[1]
+ v.write_attribute(attr, recv, args[1])
return null
+ else
+ abort
end
end
# Evaluate and set the default value of the attribute in `recv`
private fun init_expr(v: NaiveInterpreter, recv: Instance)
do
- assert recv isa MutableInstance
+ if is_lazy then return
var nexpr = self.n_expr
if nexpr != null then
- var f = new Frame(self, self.mpropdef.as(not null), [recv])
- v.frames.unshift(f)
- var val = v.expr(nexpr)
- assert val != null
- v.frames.shift
- assert not v.is_escaping
- recv.attributes[self.mpropdef.mproperty] = val
+ evaluate_expr(v, recv)
return
end
var mtype = self.mpropdef.static_mtype.as(not null)
mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType))
if mtype isa MNullableType then
- recv.attributes[self.mpropdef.mproperty] = v.null_instance
+ v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
end
end
-end
-redef class ADeferredMethPropdef
- redef fun call(v, mpropdef, args)
+ private fun evaluate_expr(v: NaiveInterpreter, recv: Instance): Instance
do
- fatal(v, "Abstract method `{mpropdef.mproperty.name}` called on `{args.first.mtype}`")
- abort
+ 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)
+ assert val != null
+ v.frames.shift
+ assert not v.is_escaping
+ v.write_attribute(self.mpropdef.mproperty, recv, val)
+ return val
end
end
do
var super_inits = self.super_inits
if super_inits != null then
- assert args.length == 1
+ 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)
+ v.send(su, args_of_super)
end
- return null
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 npropdef.n_expr == null then
- recv.attributes[npropdef.mpropdef.mproperty] = args[i]
+ 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
if col.mtype isa MNullType then fatal(v, "Receiver is null")
#self.debug("col {col}")
- var iter = v.send(v.force_get_primitive_method("iterator", col.mtype), [col]).as(not null)
+ var iter = v.callsite(method_iterator, [col]).as(not null)
#self.debug("iter {iter}")
loop
- var isok = v.send(v.force_get_primitive_method("is_ok", iter.mtype), [iter]).as(not null)
+ var isok = v.callsite(method_is_ok, [iter]).as(not null)
if not isok.is_true then return
if self.variables.length == 1 then
- var item = v.send(v.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
+ var item = v.callsite(method_item, [iter]).as(not null)
#self.debug("item {item}")
v.frame.map[self.variables.first] = item
else if self.variables.length == 2 then
- var key = v.send(v.force_get_primitive_method("key", iter.mtype), [iter]).as(not null)
+ var key = v.callsite(method_key, [iter]).as(not null)
v.frame.map[self.variables[0]] = key
- var item = v.send(v.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
+ var item = v.callsite(method_item, [iter]).as(not null)
v.frame.map[self.variables[1]] = item
else
abort
if v.is_break(self.escapemark) then return
v.is_continue(self.escapemark) # Clear the break
if v.is_escaping then return
- v.send(v.force_get_primitive_method("next", iter.mtype), [iter])
+ v.callsite(method_next, [iter])
end
end
end
var mtype = v.unanchor_type(self.mtype.as(not null))
var res = new MutableInstance(mtype)
v.init_instance(res)
- v.send(v.force_get_primitive_method("init", mtype), [res, e1, e2])
+ v.callsite(init_callsite, [res, e1, e2])
return res
end
end
var mtype = v.unanchor_type(self.mtype.as(not null))
var res = new MutableInstance(mtype)
v.init_instance(res)
- v.send(v.force_get_primitive_method("without_last", mtype), [res, e1, e2])
+ v.callsite(init_callsite, [res, e1, e2])
return res
end
end
var recv = v.expr(self.n_expr)
if recv == null then return null
var args = [recv]
- for a in self.raw_arguments.as(not null) do
+ for a in self.raw_arguments do
var i = v.expr(a)
if i == null then return null
args.add(i)
var recv = v.expr(self.n_expr)
if recv == null then return
var args = [recv]
- for a in self.raw_arguments.as(not null) do
+ for a in self.raw_arguments do
var i = v.expr(a)
if i == null then return
args.add(i)
if callsite != null then
# Add additionnals arguments for the super init call
if args.length == 1 then
- for i in [0..callsite.mproperty.intro.msignature.arity[ do
+ for i in [0..callsite.msignature.arity[ do
args.add(v.frame.arguments[i+1])
end
end
end
# stantard call-next-method
- var mpropdef = v.frame.mpropdef
+ var mpropdef = self.mpropdef
mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
- assert mpropdef isa MMethodDef
var res = v.call_without_varargs(mpropdef, args)
return res
end
var i = v.expr(self.n_value)
if i == null then return
var mproperty = self.mproperty.as(not null)
- assert recv isa MutableInstance
- recv.attributes[mproperty] = i
+ v.write_attribute(mproperty, recv, i)
end
end
var attr = v.read_attribute(mproperty, recv)
var res = v.callsite(reassign_callsite, [attr, value])
assert res != null
- assert recv isa MutableInstance
- recv.attributes[mproperty] = res
+ v.write_attribute(mproperty, recv, res)
end
end
if recv == null then return null
if recv.mtype isa MNullType then fatal(v, "Receiver is null")
var mproperty = self.mproperty.as(not null)
- assert recv isa MutableInstance
- return v.bool_instance(recv.attributes.has_key(mproperty))
+ return v.bool_instance(v.isset_attribute(mproperty, recv))
end
end