import semantize
private import parser::tables
import mixin
+import primitive_types
+private import model::serialize_model
+private import frontend::explain_assert_api
redef class ToolContext
# --discover-call-trace
- var opt_discover_call_trace = new OptionBool("Trace calls of the first invocation of a method", "--discover-call-trace")
+ var opt_discover_call_trace = new OptionBool("Trace calls of the first invocation of methods", "--discover-call-trace")
redef init
do
var modelbuilder: ModelBuilder
# The main module of the program (used to lookup method)
- var mainmodule: MModule
+ var mainmodule: MModule is writable
# The command line arguments of the interpreted program
# arguments.first is the program name
init
do
- 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)
+ 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
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
-
- # Is a break or a continue executed?
+ # Is a return, a break or a continue executed?
# Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
var escapemark: nullable EscapeMark = null
+ # The count of `catch` blocs that have been encountered and can catch an abort
+ var catch_count = 0 is writable
+
+ # The last error thrown on abort/runtime error where catch_count > 0
+ var last_error: nullable FatalError = null
+
# Is a return or a break or a continue executed?
# Use this function to know if you must skip the evaluation of statements
- fun is_escaping: Bool do return returnmark != null or escapemark != null
+ fun is_escaping: Bool do return escapemark != null
# The value associated with the current return/break/continue, if any.
# Set the value when you set a escapemark.
n.debug("inconsitance: no value and not escaping.")
end
var implicit_cast_to = n.implicit_cast_to
- if implicit_cast_to != null then
+ if i != null and implicit_cast_to != null then
var mtype = self.unanchor_type(implicit_cast_to)
if not self.is_subtype(i.mtype, mtype) then n.fatal(self, "Cast failed. Expected `{implicit_cast_to}`, got `{i.mtype}`")
end
# 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 = 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 byte instance associated with `val`.
+ fun byte_instance(val: Byte): Instance
+ do
+ var t = mainmodule.byte_type
+ var instance = new PrimitiveInstance[Byte](t, val)
+ init_instance_primitive(instance)
+ return instance
+ end
+
+ # Return the int8 instance associated with `val`.
+ fun int8_instance(val: Int8): Instance
+ do
+ var t = mainmodule.int8_type
+ var instance = new PrimitiveInstance[Int8](t, val)
+ init_instance_primitive(instance)
+ return instance
+ end
+
+ # Return the int16 instance associated with `val`.
+ fun int16_instance(val: Int16): Instance
+ do
+ var t = mainmodule.int16_type
+ var instance = new PrimitiveInstance[Int16](t, val)
+ init_instance_primitive(instance)
+ return instance
+ end
+
+ # Return the uint16 instance associated with `val`.
+ fun uint16_instance(val: UInt16): Instance
+ do
+ var t = mainmodule.uint16_type
+ var instance = new PrimitiveInstance[UInt16](t, val)
+ init_instance_primitive(instance)
+ return instance
+ end
+
+ # Return the int32 instance associated with `val`.
+ fun int32_instance(val: Int32): Instance
+ do
+ var t = mainmodule.int32_type
+ var instance = new PrimitiveInstance[Int32](t, val)
+ init_instance_primitive(instance)
+ return instance
+ end
+
+ # Return the uint32 instance associated with `val`.
+ fun uint32_instance(val: UInt32): Instance
+ do
+ var t = mainmodule.uint32_type
+ var instance = new PrimitiveInstance[UInt32](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)])
end
end
- # Return a new native string initialized with `txt`
- fun native_string_instance(txt: String): Instance
+ # Return a new C string initialized with `txt`
+ fun c_string_instance(txt: String): Instance
+ do
+ var instance = c_string_instance_len(txt.byte_length+1)
+ var val = instance.val
+ val[txt.byte_length] = 0u8
+ txt.to_cstring.copy_to(val, txt.byte_length, 0, 0)
+
+ return instance
+ end
+
+ # Return a new C string initialized with `txt`
+ fun c_string_instance_from_ns(txt: CString, len: Int): Instance
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 instance = c_string_instance_len(len)
+ var val = instance.val
+ txt.copy_to(val, len, 0, 0)
+
+ return instance
+ end
+
+ # Return a new C string initialized of `length`
+ fun c_string_instance_len(length: Int): PrimitiveInstance[CString]
+ do
+ var val = new CString(length)
+
+ var t = mainmodule.c_string_type
+ var instance = new PrimitiveInstance[CString](t, val)
init_instance_primitive(instance)
return instance
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)])
+ var nat = c_string_instance(txt)
+ var res = self.send(self.force_get_primitive_method("to_s_unsafe", nat.mtype), [nat, self.int_instance(txt.byte_length), self.int_instance(txt.length), self.false_instance, self.false_instance])
assert res != null
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
# This method is used to manage varargs in signatures and returns the real array
# of instances to use in the call.
# Return `null` if one of the evaluation of the arguments return null.
- fun varargize(mpropdef: MMethodDef, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
+ fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
do
var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
var res = new Array[Instance]
res.add(recv)
- if args.is_empty then return res
+ if msignature.arity == 0 then return res
- var vararg_rank = msignature.vararg_rank
- var vararg_len = args.length - msignature.arity
- if vararg_len < 0 then vararg_len = 0
+ if map == null then
+ assert args.length == msignature.arity else debug("Expected {msignature.arity} args, got {args.length}")
+ for ne in args do
+ var e = self.expr(ne)
+ if e == null then return null
+ res.add e
+ end
+ return res
+ end
+ # Eval in order of arguments, not parameters
+ var exprs = new Array[Instance].with_capacity(args.length)
+ for ne in args do
+ var e = self.expr(ne)
+ if e == null then return null
+ exprs.add e
+ end
+
+
+ # Fill `res` with the result of the evaluation according to the mapping
for i in [0..msignature.arity[ do
- if i == vararg_rank then
- var ne = args[i]
- if ne isa AVarargExpr then
- var e = self.expr(ne.n_expr)
- if e == null then return null
- res.add(e)
- continue
- end
- var vararg = new Array[Instance]
- for j in [vararg_rank..vararg_rank+vararg_len] do
- var e = self.expr(args[j])
- if e == null then return null
- vararg.add(e)
- end
- var elttype = msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
- res.add(self.array_instance(vararg, elttype))
- else
- var j = i
- if i > vararg_rank then j += vararg_len
- var e = self.expr(args[j])
- if e == null then return null
- res.add(e)
+ var param = msignature.mparameters[i]
+ var j = map.map.get_or_null(i)
+ if j == null then
+ # default value
+ res.add(null_instance)
+ continue
+ end
+ if param.is_vararg and args[i].vararg_decl > 0 then
+ var vararg = exprs.sub(j, args[i].vararg_decl)
+ var elttype = param.mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
+ var arg = self.array_instance(vararg, elttype)
+ res.add(arg)
+ continue
end
+ res.add exprs[j]
end
return res
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
# Execute type checks of covariant parameters
fun parameter_check(node: ANode, mpropdef: MMethodDef, args: Array[Instance])
do
- var msignature = mpropdef.msignature
+ var msignature = mpropdef.msignature.as(not null)
for i in [0..msignature.arity[ do
+ var mp = msignature.mparameters[i]
+
# skip test for vararg since the array is instantiated with the correct polymorphic type
- if msignature.vararg_rank == i then continue
+ if mp.is_vararg then continue
# skip if the cast is not required
var origmtype = mpropdef.mproperty.intro.msignature.mparameters[i].mtype
#print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
# get the parameter type
- var mtype = msignature.mparameters[i].mtype
+ var mtype = mp.mtype
var anchor = args.first.mtype.as(MClassType)
var amtype = mtype.anchor_to(self.mainmodule, anchor)
if not args[i+1].mtype.is_subtype(self.mainmodule, anchor, amtype) then
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])
# Use this method, instead of `send` to execute and control the additional behavior of the call-sites
fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
do
+ if callsite == null then return null
var initializers = callsite.mpropdef.initializers
if not initializers.is_empty then
var recv = arguments.first
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
# 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
var error_instance = new MutableInstance(modelbuilder.model.null_type) is lazy
end
+# A runtime error
+class FatalError
+ # The error message
+ var message: String
+
+ # The problematic node, if any
+ var node: nullable ANode
+end
+
# An instance represents a value of the executed program.
abstract class Instance
# The dynamic type of the instance
# ASSERT: not self.mtype.is_anchored
var mtype: MType
- # return true if the instance is the true value.
- # return false if the instance is the true value.
- # else aborts
+ # Return `true` if the instance is the `true` value.
+ #
+ # Return `false` if the instance is the `false` value.
+ # Abort if the instance is not a boolean value.
fun is_true: Bool do abort
# Return true if `self` IS `o` (using the Nit semantic of is)
# else aborts
fun to_f: Float do abort
+ # Return the integer value if the instance is a byte.
+ # else aborts
+ fun to_b: Byte do abort
+
+ # Return the integer value if the instance is a int8.
+ # else aborts
+ fun to_i8: Int8 do abort
+
+ # Return the integer value if the instance is a int16.
+ # else aborts
+ fun to_i16: Int16 do abort
+
+ # Return the integer value if the instance is a uint16.
+ # else aborts
+ fun to_u16: UInt16 do abort
+
+ # Return the integer value if the instance is a int32.
+ # else aborts
+ fun to_i32: Int32 do abort
+
+ # Return the integer value if the instance is a uint32.
+ # else aborts
+ fun to_u32: UInt32 do abort
+
# The real value encapsulated if the instance is primitive.
# Else aborts.
fun val: nullable Object do abort
end
# Special instance to handle primitives values (int, bool, etc.)
-# The trick it just to encapsulate the <<real>> value
+# The trick is just to encapsulate the “real” value.
class PrimitiveInstance[E]
super Instance
redef fun to_i do return val.as(Int)
redef fun to_f do return val.as(Float)
+
+ redef fun to_b do return val.as(Byte)
+
+ redef fun to_i8 do return val.as(Int8)
+
+ redef fun to_i16 do return val.as(Int16)
+
+ redef fun to_u16 do return val.as(UInt16)
+
+ redef fun to_i32 do return val.as(Int32)
+
+ redef fun to_u32 do return val.as(UInt32)
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 map: Map[Variable, Instance] = new HashMap[Variable, Instance]
end
redef class ANode
# `v` is used to know if a colored message is displayed or not
fun fatal(v: NaiveInterpreter, message: String)
do
- if v.modelbuilder.toolcontext.opt_no_color.value == true then
+ # Abort if there is a `catch` block
+ if v.catch_count > 0 then
+ v.last_error = new FatalError(message, self)
+ abort
+ end
+
+ if v.modelbuilder.toolcontext.opt_no_color.value then
sys.stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
else
sys.stderr.write("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
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.returnmark = null
+ if v.is_escape(self.return_mark) then
res = v.escapevalue
- v.escapevalue = null
return res
end
return res
end
- private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
+ # Execution of the body of the method
+ #
+ # It handle the common special cases: super, intern, extern
+ fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
do
v.frames.unshift(f)
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
v.call(superpd, arguments)
end
+ # First, try intern
if mpropdef.is_intern or mpropdef.is_extern then
var res = intern_call(v, mpropdef, arguments)
if res != v.error_instance then return res
end
-
+ # Then, try extern
+ if mpropdef.is_extern then
+ var res = call_extern(v, mpropdef, arguments, f)
+ if res != v.error_instance then return res
+ end
+ # Else try block
if n_block != null then
v.stmt(self.n_block)
return null
end
+ # Fail if nothing succeed
if mpropdef.is_intern then
fatal(v, "NOT YET IMPLEMENTED intern {mpropdef}")
else if mpropdef.is_extern then
abort
end
+ # Call this extern method
+ protected fun call_extern(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
+ do
+ return v.error_instance
+ end
+
# Interprets a intern or a shortcut extern method.
# Returns the result for a function, `null` for a procedure, or `error_instance` if the method is unknown.
private fun intern_call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
else if pname == "native_class_name" then
var recv = args.first
var txt = recv.mtype.to_s
- return v.native_string_instance(txt)
+ return v.c_string_instance(txt)
else if pname == "==" then
# == is correctly redefined for instances
return v.bool_instance(args[0] == args[1])
return v.bool_instance(args[0].mtype == args[1].mtype)
else if pname == "is_same_instance" then
return v.bool_instance(args[0].eq_is(args[1]))
+ else if pname == "class_inheritance_metamodel_json" then
+ return v.c_string_instance(v.mainmodule.flatten_mclass_hierarchy.to_thin_json)
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
var recvval = args[0].to_i
if pname == "unary -" then
- return v.int_instance(-args[0].to_i)
+ return v.int_instance(-recvval)
+ else if pname == "unary +" then
+ return args[0]
+ else if pname == "+" then
+ return v.int_instance(recvval + args[1].to_i)
+ else if pname == "-" then
+ return v.int_instance(recvval - args[1].to_i)
+ else if pname == "*" then
+ return v.int_instance(recvval * args[1].to_i)
+ else if pname == "%" then
+ return v.int_instance(recvval % args[1].to_i)
+ else if pname == "/" then
+ return v.int_instance(recvval / args[1].to_i)
+ else if pname == "<" then
+ return v.bool_instance(recvval < args[1].to_i)
+ else if pname == ">" then
+ return v.bool_instance(recvval > args[1].to_i)
+ else if pname == "<=" then
+ return v.bool_instance(recvval <= args[1].to_i)
+ else if pname == ">=" then
+ return v.bool_instance(recvval >= args[1].to_i)
+ else if pname == "<=>" then
+ return v.int_instance(recvval <=> args[1].to_i)
+ else if pname == "&" then
+ return v.int_instance(recvval & args[1].to_i)
+ else if pname == "|" then
+ return v.int_instance(recvval | args[1].to_i)
+ else if pname == "to_f" then
+ return v.float_instance(recvval.to_f)
+ else if pname == "to_b" then
+ return v.byte_instance(recvval.to_b)
+ else if pname == "<<" then
+ return v.int_instance(recvval << args[1].to_i)
+ else if pname == ">>" then
+ return v.int_instance(recvval >> args[1].to_i)
+ else if pname == "to_i8" then
+ return v.int8_instance(recvval.to_i8)
+ else if pname == "to_i16" then
+ return v.int16_instance(recvval.to_i16)
+ else if pname == "to_u16" then
+ return v.uint16_instance(recvval.to_u16)
+ else if pname == "to_i32" then
+ return v.int32_instance(recvval.to_i32)
+ else if pname == "to_u32" then
+ return v.uint32_instance(recvval.to_u32)
+ end
+ else if cname == "Byte" then
+ var recvval = args[0].to_b
+ if pname == "unary -" then
+ return v.byte_instance(-recvval)
+ else if pname == "unary +" then
+ return args[0]
else if pname == "+" then
- return v.int_instance(args[0].to_i + args[1].to_i)
+ return v.byte_instance(recvval + args[1].to_b)
else if pname == "-" then
- return v.int_instance(args[0].to_i - args[1].to_i)
+ return v.byte_instance(recvval - args[1].to_b)
else if pname == "*" then
- return v.int_instance(args[0].to_i * args[1].to_i)
+ return v.byte_instance(recvval * args[1].to_b)
else if pname == "%" then
- return v.int_instance(args[0].to_i % args[1].to_i)
+ return v.byte_instance(recvval % args[1].to_b)
else if pname == "/" then
- return v.int_instance(args[0].to_i / args[1].to_i)
+ return v.byte_instance(recvval / args[1].to_b)
else if pname == "<" then
- return v.bool_instance(args[0].to_i < args[1].to_i)
+ return v.bool_instance(recvval < args[1].to_b)
else if pname == ">" then
- return v.bool_instance(args[0].to_i > args[1].to_i)
+ return v.bool_instance(recvval > args[1].to_b)
else if pname == "<=" then
- return v.bool_instance(args[0].to_i <= args[1].to_i)
+ return v.bool_instance(recvval <= args[1].to_b)
else if pname == ">=" then
- return v.bool_instance(args[0].to_i >= args[1].to_i)
+ return v.bool_instance(recvval >= args[1].to_b)
else if pname == "<=>" then
- return v.int_instance(args[0].to_i <=> args[1].to_i)
- else if pname == "ascii" then
- return v.char_instance(args[0].to_i.ascii)
+ return v.int_instance(recvval <=> args[1].to_b)
+ else if pname == "&" then
+ return v.byte_instance(recvval & args[1].to_b)
+ else if pname == "|" then
+ return v.byte_instance(recvval | args[1].to_b)
else if pname == "to_f" then
- return v.float_instance(args[0].to_i.to_f)
- else if pname == "lshift" 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 == "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
- return v.native_string_instance(recvval.strerror)
+ return v.float_instance(recvval.to_f)
+ else if pname == "to_i" then
+ return v.int_instance(recvval.to_i)
+ else if pname == "<<" then
+ return v.byte_instance(recvval << args[1].to_i)
+ else if pname == ">>" then
+ return v.byte_instance(recvval >> args[1].to_i)
+ else if pname == "to_i8" then
+ return v.int8_instance(recvval.to_i8)
+ else if pname == "to_i16" then
+ return v.int16_instance(recvval.to_i16)
+ else if pname == "to_u16" then
+ return v.uint16_instance(recvval.to_u16)
+ else if pname == "to_i32" then
+ return v.int32_instance(recvval.to_i32)
+ else if pname == "to_u32" then
+ return v.uint32_instance(recvval.to_u32)
+ else if pname == "byte_to_s_len" then
+ return v.int_instance(recvval.to_s.length)
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 == "successor" then
+ 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))
var recv = args[0].to_f
if pname == "unary -" then
return v.float_instance(-recv)
+ else if pname == "unary +" then
+ return args[0]
else if pname == "+" then
return v.float_instance(recv + args[1].to_f)
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 == "to_b" then
+ return v.byte_instance(recv.to_b)
+ else if pname == "to_i8" then
+ return v.int8_instance(recv.to_i8)
+ else if pname == "to_i16" then
+ return v.int16_instance(recv.to_i16)
+ else if pname == "to_u16" then
+ return v.uint16_instance(recv.to_u16)
+ else if pname == "to_i32" then
+ return v.int32_instance(recv.to_i32)
+ else if pname == "to_u32" then
+ return v.uint32_instance(recv.to_u32)
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.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
else if pname == "round" then
return v.float_instance(args[0].to_f.round)
end
- else if cname == "NativeString" then
+ else if cname == "CString" then
if pname == "new" then
- return v.native_string_instance("!" * args[1].to_i)
+ return v.c_string_instance_len(args[1].to_i)
end
- var recvval = args.first.val.as(Buffer)
+ var recvval = args.first.val.as(CString)
if pname == "[]" then
var arg1 = args[1].to_i
- if arg1 >= recvval.length or arg1 < 0 then
- debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
- end
- return v.char_instance(recvval.chars[arg1])
+ return v.byte_instance(recvval[arg1])
else if pname == "[]=" then
var arg1 = args[1].to_i
- if arg1 >= recvval.length or arg1 < 0 then
- debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
- end
- recvval.chars[arg1] = args[2].val.as(Char)
+ recvval[arg1] = args[2].val.as(Byte)
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(FlatBuffer)
+ # sig= copy_to(dest: CString, length: Int, from: Int, to: Int)
+ var destval = args[1].val.as(CString)
var lenval = args[2].to_i
var fromval = args[3].to_i
var toval = args[4].to_i
- if fromval < 0 then
- debug("Illegal access on {recvval} for element {fromval}/{recvval.length}")
- end
- 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
- debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
- end
- recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
+ recvval.copy_to(destval, lenval, fromval, 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 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.get_primitive_class("String").mclass_type)
+ return v.int_instance(recvval.atoi)
+ else if pname == "fast_cstring" then
+ var ns = recvval.fast_cstring(args[1].to_i)
+ return v.c_string_instance(ns.to_s)
+ else if pname == "fetch_4_chars" then
+ return v.uint32_instance(args[0].val.as(CString).fetch_4_chars(args[1].to_i))
+ else if pname == "fetch_4_hchars" then
+ return v.uint32_instance(args[0].val.as(CString).fetch_4_hchars(args[1].to_i))
+ else if pname == "utf8_length" then
+ return v.int_instance(args[0].val.as(CString).utf8_length(args[1].to_i, args[2].to_i))
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)
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
- debug("Illegal access on {recvval} for element {args[1].to_i}/{recvval.length}")
- end
return recvval[args[1].to_i]
else if pname == "[]=" then
recvval[args[1].to_i] = args[2]
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
- var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
- v.init_instance_primitive(instance)
- return instance
- else if pname == "native_stdin" then
- var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
- v.init_instance_primitive(instance)
- return instance
- else if pname == "native_stderr" then
- var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
- v.init_instance_primitive(instance)
- return instance
- else if pname == "io_open_read" then
- var a1 = args[1].val.as(Buffer)
- var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
- v.init_instance_primitive(instance)
- return instance
- else if pname == "io_open_write" then
- var a1 = args[1].val.as(Buffer)
- var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
- v.init_instance_primitive(instance)
- return instance
+ else if cname == "Int8" then
+ var recvval = args[0].to_i8
+ if pname == "unary -" then
+ return v.int8_instance(-recvval)
+ else if pname == "unary +" then
+ return args[0]
+ else if pname == "+" then
+ return v.int8_instance(recvval + args[1].to_i8)
+ else if pname == "-" then
+ return v.int8_instance(recvval - args[1].to_i8)
+ else if pname == "*" then
+ return v.int8_instance(recvval * args[1].to_i8)
+ else if pname == "%" then
+ return v.int8_instance(recvval % args[1].to_i8)
+ else if pname == "/" then
+ return v.int8_instance(recvval / args[1].to_i8)
+ else if pname == "<" then
+ return v.bool_instance(recvval < args[1].to_i8)
+ else if pname == ">" then
+ return v.bool_instance(recvval > args[1].to_i8)
+ else if pname == "<=" then
+ return v.bool_instance(recvval <= args[1].to_i8)
+ else if pname == ">=" then
+ return v.bool_instance(recvval >= args[1].to_i8)
+ else if pname == "<=>" then
+ return v.int_instance(recvval <=> args[1].to_i8)
+ else if pname == "to_f" then
+ return v.float_instance(recvval.to_f)
+ else if pname == "to_i" then
+ return v.int_instance(recvval.to_i)
+ else if pname == "to_b" then
+ return v.byte_instance(recvval.to_b)
+ else if pname == "to_i16" then
+ return v.int16_instance(recvval.to_i16)
+ else if pname == "to_u16" then
+ return v.uint16_instance(recvval.to_u16)
+ else if pname == "to_i32" then
+ return v.int32_instance(recvval.to_i32)
+ else if pname == "to_u32" then
+ return v.uint32_instance(recvval.to_u32)
+ else if pname == "<<" then
+ return v.int8_instance(recvval << (args[1].to_i))
+ else if pname == ">>" then
+ return v.int8_instance(recvval >> (args[1].to_i))
+ else if pname == "&" then
+ return v.int8_instance(recvval & args[1].to_i8)
+ else if pname == "|" then
+ return v.int8_instance(recvval | args[1].to_i8)
+ else if pname == "^" then
+ return v.int8_instance(recvval ^ args[1].to_i8)
+ else if pname == "unary ~" then
+ return v.int8_instance(~recvval)
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]
- 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)
- 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
+ else if cname == "Int16" then
+ var recvval = args[0].to_i16
+ if pname == "unary -" then
+ return v.int16_instance(-recvval)
+ else if pname == "unary +" then
+ return args[0]
+ else if pname == "+" then
+ return v.int16_instance(recvval + args[1].to_i16)
+ else if pname == "-" then
+ return v.int16_instance(recvval - args[1].to_i16)
+ else if pname == "*" then
+ return v.int16_instance(recvval * args[1].to_i16)
+ else if pname == "%" then
+ return v.int16_instance(recvval % args[1].to_i16)
+ else if pname == "/" then
+ return v.int16_instance(recvval / args[1].to_i16)
+ else if pname == "<" then
+ return v.bool_instance(recvval < args[1].to_i16)
+ else if pname == ">" then
+ return v.bool_instance(recvval > args[1].to_i16)
+ else if pname == "<=" then
+ return v.bool_instance(recvval <= args[1].to_i16)
+ else if pname == ">=" then
+ return v.bool_instance(recvval >= args[1].to_i16)
+ else if pname == "<=>" then
+ return v.int_instance(recvval <=> args[1].to_i16)
+ else if pname == "to_f" then
+ return v.float_instance(recvval.to_f)
+ else if pname == "to_i" then
+ return v.int_instance(recvval.to_i)
+ else if pname == "to_b" then
+ return v.byte_instance(recvval.to_b)
+ else if pname == "to_i8" then
+ return v.int8_instance(recvval.to_i8)
+ else if pname == "to_u16" then
+ return v.uint16_instance(recvval.to_u16)
+ else if pname == "to_i32" then
+ return v.int32_instance(recvval.to_i32)
+ else if pname == "to_u32" then
+ return v.uint32_instance(recvval.to_u32)
+ else if pname == "<<" then
+ return v.int16_instance(recvval << (args[1].to_i))
+ else if pname == ">>" then
+ return v.int16_instance(recvval >> (args[1].to_i))
+ else if pname == "&" then
+ return v.int16_instance(recvval & args[1].to_i16)
+ else if pname == "|" then
+ return v.int16_instance(recvval | args[1].to_i16)
+ else if pname == "^" then
+ return v.int16_instance(recvval ^ args[1].to_i16)
+ else if pname == "unary ~" then
+ return v.int16_instance(~recvval)
+ end
+ else if cname == "UInt16" then
+ var recvval = args[0].to_u16
+ if pname == "unary -" then
+ return v.uint16_instance(-recvval)
+ else if pname == "unary +" then
+ return args[0]
+ else if pname == "+" then
+ return v.uint16_instance(recvval + args[1].to_u16)
+ else if pname == "-" then
+ return v.uint16_instance(recvval - args[1].to_u16)
+ else if pname == "*" then
+ return v.uint16_instance(recvval * args[1].to_u16)
+ else if pname == "%" then
+ return v.uint16_instance(recvval % args[1].to_u16)
+ else if pname == "/" then
+ return v.uint16_instance(recvval / args[1].to_u16)
+ else if pname == "<" then
+ return v.bool_instance(recvval < args[1].to_u16)
+ else if pname == ">" then
+ return v.bool_instance(recvval > args[1].to_u16)
+ else if pname == "<=" then
+ return v.bool_instance(recvval <= args[1].to_u16)
+ else if pname == ">=" then
+ return v.bool_instance(recvval >= args[1].to_u16)
+ else if pname == "<=>" then
+ return v.int_instance(recvval <=> args[1].to_u16)
+ else if pname == "to_f" then
+ return v.float_instance(recvval.to_f)
+ else if pname == "to_i" then
+ return v.int_instance(recvval.to_i)
+ else if pname == "to_b" then
+ return v.byte_instance(recvval.to_b)
+ else if pname == "to_i8" then
+ return v.int8_instance(recvval.to_i8)
+ else if pname == "to_i16" then
+ return v.int16_instance(recvval.to_i16)
+ else if pname == "to_i32" then
+ return v.int32_instance(recvval.to_i32)
+ else if pname == "to_u32" then
+ return v.uint32_instance(recvval.to_u32)
+ else if pname == "<<" then
+ return v.uint16_instance(recvval << (args[1].to_i))
+ else if pname == ">>" then
+ return v.uint16_instance(recvval >> (args[1].to_i))
+ else if pname == "&" then
+ return v.uint16_instance(recvval & args[1].to_u16)
+ else if pname == "|" then
+ return v.uint16_instance(recvval | args[1].to_u16)
+ else if pname == "^" then
+ return v.uint16_instance(recvval ^ args[1].to_u16)
+ else if pname == "unary ~" then
+ return v.uint16_instance(~recvval)
+ end
+ else if cname == "Int32" then
+ var recvval = args[0].to_i32
+ if pname == "unary -" then
+ return v.int32_instance(-recvval)
+ else if pname == "unary +" then
+ return args[0]
+ else if pname == "+" then
+ return v.int32_instance(recvval + args[1].to_i32)
+ else if pname == "-" then
+ return v.int32_instance(recvval - args[1].to_i32)
+ else if pname == "*" then
+ return v.int32_instance(recvval * args[1].to_i32)
+ else if pname == "%" then
+ return v.int32_instance(recvval % args[1].to_i32)
+ else if pname == "/" then
+ return v.int32_instance(recvval / args[1].to_i32)
+ else if pname == "<" then
+ return v.bool_instance(recvval < args[1].to_i32)
+ else if pname == ">" then
+ return v.bool_instance(recvval > args[1].to_i32)
+ else if pname == "<=" then
+ return v.bool_instance(recvval <= args[1].to_i32)
+ else if pname == ">=" then
+ return v.bool_instance(recvval >= args[1].to_i32)
+ else if pname == "<=>" then
+ return v.int_instance(recvval <=> args[1].to_i32)
+ else if pname == "to_f" then
+ return v.float_instance(recvval.to_f)
+ else if pname == "to_i" then
+ return v.int_instance(recvval.to_i)
+ else if pname == "to_b" then
+ return v.byte_instance(recvval.to_b)
+ else if pname == "to_i8" then
+ return v.int8_instance(recvval.to_i8)
+ else if pname == "to_i16" then
+ return v.int16_instance(recvval.to_i16)
+ else if pname == "to_u16" then
+ return v.uint16_instance(recvval.to_u16)
+ else if pname == "to_u32" then
+ return v.uint32_instance(recvval.to_u32)
+ else if pname == "<<" then
+ return v.int32_instance(recvval << (args[1].to_i))
+ else if pname == ">>" then
+ return v.int32_instance(recvval >> (args[1].to_i))
+ else if pname == "&" then
+ return v.int32_instance(recvval & args[1].to_i32)
+ else if pname == "|" then
+ return v.int32_instance(recvval | args[1].to_i32)
+ else if pname == "^" then
+ return v.int32_instance(recvval ^ args[1].to_i32)
+ else if pname == "unary ~" then
+ return v.int32_instance(~recvval)
+ end
+ else if cname == "UInt32" then
+ var recvval = args[0].to_u32
+ if pname == "unary -" then
+ return v.uint32_instance(-recvval)
+ else if pname == "unary +" then
+ return args[0]
+ else if pname == "+" then
+ return v.uint32_instance(recvval + args[1].to_u32)
+ else if pname == "-" then
+ return v.uint32_instance(recvval - args[1].to_u32)
+ else if pname == "*" then
+ return v.uint32_instance(recvval * args[1].to_u32)
+ else if pname == "%" then
+ return v.uint32_instance(recvval % args[1].to_u32)
+ else if pname == "/" then
+ return v.uint32_instance(recvval / args[1].to_u32)
+ else if pname == "<" then
+ return v.bool_instance(recvval < args[1].to_u32)
+ else if pname == ">" then
+ return v.bool_instance(recvval > args[1].to_u32)
+ else if pname == "<=" then
+ return v.bool_instance(recvval <= args[1].to_u32)
+ else if pname == ">=" then
+ return v.bool_instance(recvval >= args[1].to_u32)
+ else if pname == "<=>" then
+ return v.int_instance(recvval <=> args[1].to_u32)
+ else if pname == "to_f" then
+ return v.float_instance(recvval.to_f)
+ else if pname == "to_i" then
+ return v.int_instance(recvval.to_i)
+ else if pname == "to_b" then
+ return v.byte_instance(recvval.to_b)
+ else if pname == "to_i8" then
+ return v.int8_instance(recvval.to_i8)
+ else if pname == "to_i16" then
+ return v.int16_instance(recvval.to_i16)
+ else if pname == "to_u16" then
+ return v.uint16_instance(recvval.to_u16)
+ else if pname == "to_i32" then
+ return v.int32_instance(recvval.to_i32)
+ else if pname == "<<" then
+ return v.uint32_instance(recvval << (args[1].to_i))
+ else if pname == ">>" then
+ return v.uint32_instance(recvval >> (args[1].to_i))
+ else if pname == "&" then
+ return v.uint32_instance(recvval & args[1].to_u32)
+ else if pname == "|" then
+ return v.uint32_instance(recvval | args[1].to_u32)
+ else if pname == "^" then
+ return v.uint32_instance(recvval ^ args[1].to_u32)
+ else if pname == "unary ~" then
+ return v.uint32_instance(~recvval)
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
- 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
var txt = v.arguments[args[1].to_i]
- 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 == "atan2" then
- return v.float_instance(atan2(args[1].to_f, args[2].to_f))
- else if pname == "pi" then
- return v.float_instance(pi)
+ return v.c_string_instance(txt)
else if pname == "lexer_goto" then
return v.int_instance(lexer_goto(args[1].to_i, args[2].to_i))
else if pname == "lexer_accept" then
return v.int_instance(parser_goto(args[1].to_i, args[2].to_i))
else if pname == "parser_action" 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
return v.error_instance
end
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])
+ var arg = args[1]
+ if is_optional and arg.mtype isa MNullType then
+ var f = v.new_frame(self, mpropdef, args)
+ arg = evaluate_expr(v, recv, f)
+ end
+ v.write_attribute(attr, recv, arg)
return null
else
abort
# Evaluate and set the default value of the attribute in `recv`
private fun init_expr(v: NaiveInterpreter, recv: Instance)
do
- if is_lazy then return
+ if is_lazy or is_optional then return
if has_value then
- evaluate_expr(v, recv)
+ var f = v.new_frame(self, mreadpropdef.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 = self.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 f = new Frame(self, self.mpropdef.as(not null), [recv])
v.frames.unshift(f)
var val
val = v.expr(nexpr)
else if nblock != null then
v.stmt(nblock)
- assert v.returnmark == f
+ assert v.escapemark == return_mark
val = v.escapevalue
- v.returnmark = null
- v.escapevalue = null
+ v.escapemark = null
else
abort
end
redef class AClassdef
# Execute an implicit `mpropdef` associated with the current node.
- private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
+ private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance]): nullable Instance
do
if mpropdef.mproperty.is_root_init then
- assert args.length == 1
+ assert arguments.length == 1
if not mpropdef.is_intro then
# standard call-next-method
- var superpd = mpropdef.lookup_next_definition(v.mainmodule, args.first.mtype)
- v.call(superpd, args)
+ var superpd = mpropdef.lookup_next_definition(v.mainmodule, arguments.first.mtype)
+ v.call(superpd, arguments)
end
return null
else
# 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
end
redef class AVardeclExpr
- redef fun stmt(v)
+ redef fun expr(v)
do
var ne = self.n_expr
if ne != null then
var i = v.expr(ne)
- if i == null then return
+ if i == null then return null
v.write_variable(self.variable.as(not null), i)
+ return i
end
+ return null
end
end
end
end
-redef class AEscapeExpr
- redef fun stmt(v)
+redef class AImplicitSelfExpr
+ redef fun expr(v)
do
- var ne = self.n_expr
- if ne != null then
- var i = v.expr(ne)
- if i == null then return
- v.escapevalue = i
- end
- v.escapemark = self.escapemark
+ if not is_sys then return super
+ return v.mainobj
end
end
-redef class AReturnExpr
+redef class AEscapeExpr
redef fun stmt(v)
do
var ne = self.n_expr
var i = v.expr(ne)
if i == null then return
v.escapevalue = i
+ else
+ v.escapevalue = null
end
- v.returnmark = v.frame
+ v.escapemark = self.escapemark
end
end
redef class ADoExpr
redef fun stmt(v)
do
- v.stmt(self.n_block)
- v.is_escape(self.break_mark) # Clear the break (if any)
+ # If this bloc has a catch, handle it with a do ... catch ... end
+ if self.n_catch != null then
+ var frame = v.frame
+ v.catch_count += 1
+ do
+ v.stmt(self.n_block)
+ v.is_escape(self.break_mark) # Clear the break (if any)
+ v.catch_count -= 1
+ catch
+ # Restore the current frame if needed
+ while v.frame != frame do v.frames.shift
+ v.catch_count -= 1
+ v.stmt(self.n_catch)
+ end
+ else
+ v.stmt(self.n_block)
+ v.is_escape(self.break_mark)
+ end
end
end
redef class AForExpr
redef fun stmt(v)
do
- var col = v.expr(self.n_expr)
- if col == null then return
- if col.mtype isa MNullType then fatal(v, "Receiver is null")
+ var iters = new Array[Instance]
+
+ for g in n_groups do
+ var col = v.expr(g.n_expr)
+ if col == null then return
+ if col.mtype isa MNullType then fatal(v, "Receiver is null")
+
+ var iter = v.callsite(g.method_iterator, [col]).as(not null)
+ iters.add iter
+ end
- #self.debug("col {col}")
- var iter = v.callsite(method_iterator, [col]).as(not null)
- #self.debug("iter {iter}")
loop
- var isok = v.callsite(method_is_ok, [iter]).as(not null)
- 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.write_variable(self.variables.first, item)
- else if self.variables.length == 2 then
- var key = v.callsite(method_key, [iter]).as(not null)
- v.write_variable(self.variables[0], key)
- var item = v.callsite(method_item, [iter]).as(not null)
- v.write_variable(self.variables[1], item)
- else
- abort
+ for g in n_groups, iter in iters do
+ var isok = v.callsite(g.method_is_ok, [iter]).as(not null)
+ if not isok.is_true then break label
+ if g.variables.length == 1 then
+ var item = v.callsite(g.method_item, [iter]).as(not null)
+ #self.debug("item {item}")
+ v.write_variable(g.variables.first, item)
+ else if g.variables.length == 2 then
+ var key = v.callsite(g.method_key, [iter]).as(not null)
+ v.write_variable(g.variables[0], key)
+ var item = v.callsite(g.method_item, [iter]).as(not null)
+ v.write_variable(g.variables[1], item)
+ else
+ abort
+ end
end
v.stmt(self.n_block)
if v.is_escape(self.break_mark) then break
v.is_escape(self.continue_mark) # Clear the break
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])
+ for g in n_groups, iter in iters do
+ v.callsite(g.method_next, [iter])
+ end
+ end label
+ for g in n_groups, iter in iters do
+ var method_finish = g.method_finish
+ if method_finish != null then
+ v.callsite(method_finish, [iter])
+ end
end
end
end
+redef class AWithExpr
+ redef fun stmt(v)
+ do
+ var expr = v.expr(self.n_expr)
+ if expr == null then return
+
+ v.callsite(method_start, [expr])
+ v.stmt(self.n_block)
+ v.is_escape(self.break_mark) # Clear the break
+
+ # Execute the finally without an escape
+ var old_mark = v.escapemark
+ v.escapemark = null
+ v.callsite(method_finish, [expr])
+ # Restore the escape unless another escape was provided
+ if v.escapemark == null then v.escapemark = old_mark
+ end
+end
+
redef class AAssertExpr
redef fun stmt(v)
do
if not cond.is_true then
v.stmt(self.n_else)
if v.is_escaping then return
+
+ # Explain assert if it fails
+ var explain_assert_str = explain_assert_str
+ if explain_assert_str != null then
+ var i = v.expr(explain_assert_str)
+ if i isa MutableInstance then
+ var res = v.send(v.force_get_primitive_method("to_cstring", i.mtype), [i])
+ if res != null then
+ var val = res.val
+ if val != null then
+ print_error "Runtime assert: {val.to_s}"
+ end
+ end
+ end
+ end
+
var nid = self.n_id
if nid != null then
fatal(v, "Assert '{nid.text}' failed")
end
end
-redef class AIntExpr
+redef class AIntegerExpr
redef fun expr(v)
do
- return v.int_instance(self.value.as(not null))
+ if value isa Int then return v.int_instance(value.as(Int))
+ if value isa Byte then return v.byte_instance(value.as(Byte))
+ if value isa Int8 then return v.int8_instance(value.as(Int8))
+ if value isa Int16 then return v.int16_instance(value.as(Int16))
+ if value isa UInt16 then return v.uint16_instance(value.as(UInt16))
+ if value isa Int32 then return v.int32_instance(value.as(Int32))
+ if value isa UInt32 then return v.uint32_instance(value.as(UInt32))
+ return null
end
end
redef class ACharExpr
redef fun expr(v)
do
+ if is_ascii then return v.byte_instance(self.value.as(not null).ascii)
+ if is_code_point then return v.int_instance(self.value.as(not null).code_point)
return v.char_instance(self.value.as(not null))
end
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)
end
end
+redef class AugmentedStringFormExpr
+ # Factorize the making of a `Regex` object from a literal prefixed string
+ fun make_re(v: NaiveInterpreter, rs: Instance): nullable Instance do
+ var tore = to_re
+ assert tore != null
+ var res = v.callsite(tore, [rs])
+ if res == null then
+ print "Cannot call property `to_re` on {self}"
+ abort
+ end
+ for j in suffix.chars do
+ if j == 'i' then
+ var prop = ignore_case
+ assert prop != null
+ v.callsite(prop, [res, v.bool_instance(true)])
+ continue
+ end
+ if j == 'm' then
+ var prop = newline
+ assert prop != null
+ v.callsite(prop, [res, v.bool_instance(true)])
+ continue
+ end
+ if j == 'b' then
+ var prop = extended
+ assert prop != null
+ v.callsite(prop, [res, v.bool_instance(false)])
+ continue
+ end
+ # Should not happen, this needs to be updated
+ # along with the addition of new suffixes
+ abort
+ end
+ return res
+ end
+end
+
redef class AStringFormExpr
- redef fun expr(v)
- do
- var txt = self.value.as(not null)
- return v.string_instance(txt)
+ redef fun expr(v) do return v.string_instance(value)
+end
+
+redef class AStringExpr
+ redef fun expr(v) do
+ var s = v.string_instance(value)
+ if is_string then return s
+ if is_bytestring then
+ var ns = v.c_string_instance_from_ns(bytes.items, bytes.length)
+ var ln = v.int_instance(bytes.length)
+ var prop = to_bytes_with_copy
+ assert prop != null
+ var res = v.callsite(prop, [ns, ln])
+ if res == null then
+ print "Cannot call property `to_bytes` on {self}"
+ abort
+ end
+ s = res
+ else if is_re then
+ var res = make_re(v, s)
+ assert res != null
+ s = res
+ else
+ print "Unimplemented prefix or suffix for {self}"
+ abort
+ end
+ return s
end
end
if i == null then return null
array.add(i)
end
- var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
- var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
+ var i = v.array_instance(array, v.mainmodule.object_type)
+ var res = v.send(v.force_get_primitive_method("plain_to_s", i.mtype), [i])
assert res != null
+ if is_re then res = make_re(v, res)
return res
end
end
do
var recv = v.expr(self.n_expr)
if recv == null then return null
- var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+ var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
if args == null then return null
var res = v.callsite(callsite, args)
do
var recv = v.expr(self.n_expr)
if recv == null then return
- var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+ var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
if args == null then return
var value = v.expr(self.n_value)
if value == null then return
var callsite = self.callsite
if callsite != null then
- var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
- if args == null then return null
- # Add additional arguments for the super init call
- if args.length == 1 then
+ var args
+ if self.n_args.n_exprs.is_empty then
+ # Add automatic arguments for the super init call
+ args = [recv]
for i in [0..callsite.msignature.arity[ do
args.add(v.frame.arguments[i+1])
end
+ else
+ args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
+ if args == null then return null
end
+
# Super init call
var res = v.callsite(callsite, args)
return res
end
- # standard call-next-method
+ # Standard call-next-method
var mpropdef = self.mpropdef
mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
- var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
- if args == null then return null
-
- if args.length == 1 then
+ var args
+ if self.n_args.n_exprs.is_empty then
args = v.frame.arguments
+ else
+ args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
+ if args == null then return null
end
+
var res = v.call(mpropdef, args)
return res
end
var mtype = v.unanchor_type(self.recvtype.as(not null))
var recv: Instance = new MutableInstance(mtype)
v.init_instance(recv)
- var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+ var callsite = self.callsite
+ if callsite == null then return recv
+
+ var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
if args == null then return null
var res2 = v.callsite(callsite, args)
if res2 != null then
end
end
+redef class AVarargExpr
+ redef fun expr(v)
+ do
+ return v.expr(self.n_expr)
+ end
+end
+
+redef class ANamedargExpr
+ redef fun expr(v)
+ do
+ return v.expr(self.n_expr)
+ end
+end
+
redef class ADebugTypeExpr
redef fun stmt(v)
do