X-Git-Url: http://nitlanguage.org diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index f8ffad7..9b821e4 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -21,6 +21,7 @@ import literal import semantize private import parser::tables import mixin +import primitive_types redef class ToolContext # --discover-call-trace @@ -71,11 +72,13 @@ class NaiveInterpreter 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) - 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 @@ -112,7 +115,7 @@ class NaiveInterpreter # 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` @@ -170,14 +173,20 @@ class NaiveInterpreter # 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`) @@ -192,8 +201,8 @@ class NaiveInterpreter # 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 @@ -201,8 +210,8 @@ class NaiveInterpreter # 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 @@ -210,8 +219,8 @@ class NaiveInterpreter # 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 @@ -230,9 +239,9 @@ class NaiveInterpreter 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)]) @@ -259,8 +268,8 @@ class NaiveInterpreter do var val = new FlatBuffer.from(txt) val.add('\0') - var ic = get_primitive_class("NativeString") - var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val) + var t = mainmodule.native_string_type + var instance = new PrimitiveInstance[Buffer](t, val) init_instance_primitive(instance) return instance end @@ -274,11 +283,14 @@ class NaiveInterpreter 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 @@ -305,6 +317,15 @@ class NaiveInterpreter 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 @@ -331,14 +352,14 @@ class NaiveInterpreter # 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 @@ -349,42 +370,50 @@ class NaiveInterpreter # 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 map.vararg_decl > 0 then + var vararg = exprs.sub(j, map.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 @@ -401,16 +430,26 @@ class NaiveInterpreter 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 @@ -419,7 +458,7 @@ class NaiveInterpreter 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 @@ -431,6 +470,8 @@ class NaiveInterpreter 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) @@ -445,7 +486,7 @@ class NaiveInterpreter 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]) @@ -474,7 +515,7 @@ class NaiveInterpreter 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 @@ -534,13 +575,7 @@ class NaiveInterpreter 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 @@ -561,14 +596,7 @@ class NaiveInterpreter # 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 determine the correct type according the reciever of the current definition (self). + # 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, current_receiver_class) @@ -606,7 +634,7 @@ abstract class Instance # 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) @@ -619,7 +647,7 @@ end # Special instance to handle primitives values (int, bool, etc.) # The trick it just to encapsulate the <> value -class PrimitiveInstance[E: Object] +class PrimitiveInstance[E] super Instance # The real value encapsulated @@ -634,17 +662,17 @@ class PrimitiveInstance[E: Object] 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) @@ -652,7 +680,7 @@ class PrimitiveInstance[E: Object] 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 @@ -661,6 +689,14 @@ class Frame 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 @@ -695,7 +731,7 @@ redef class AMethPropdef 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 @@ -717,11 +753,6 @@ redef class AMethPropdef 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 @@ -798,12 +829,20 @@ redef class AMethPropdef 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) + else if pname == "unary +" then + return args[0] else if pname == "+" then return v.int_instance(args[0].to_i + args[1].to_i) else if pname == "-" then @@ -843,8 +882,15 @@ redef class AMethPropdef 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 @@ -871,6 +917,8 @@ redef class AMethPropdef 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 @@ -949,13 +997,13 @@ redef class AMethPropdef 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) @@ -965,11 +1013,11 @@ redef class AMethPropdef 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 + var res = recvval.to_s.mkdir + return v.bool_instance(res == null) else if pname == "file_chdir" then - recvval.to_s.chdir - return null + var res = recvval.to_s.chdir + return v.bool_instance(res == null) else if pname == "file_realpath" then return v.native_string_instance(recvval.to_s.realpath) else if pname == "get_environ" then @@ -980,6 +1028,9 @@ redef class AMethPropdef return v.int_instance(res) else if pname == "atof" then return v.float_instance(recvval.to_f) + else if pname == "fast_cstring" then + var ns = recvval.to_cstring.to_s.substring_from(args[1].to_i) + return v.native_string_instance(ns) end else if cname == "String" then var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first]) @@ -987,7 +1038,7 @@ redef class AMethPropdef if pname == "files" then var res = new Array[Instance] for f in str.files do res.add v.string_instance(f) - return v.array_instance(res, v.get_primitive_class("String").mclass_type) + return v.array_instance(res, v.mainmodule.string_type) end else if pname == "calloc_string" then return v.native_string_instance("!" * args[1].to_i) @@ -1015,53 +1066,52 @@ redef class AMethPropdef end else if cname == "NativeFile" then if pname == "native_stdout" then - var instance = 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 - var instance = 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 - var instance = 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) - var instance = 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) - var instance = 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.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 @@ -1097,6 +1147,10 @@ redef class AMethPropdef 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 @@ -1112,7 +1166,8 @@ redef class AAttrPropdef 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]) @@ -1127,20 +1182,22 @@ redef class AAttrPropdef do if is_lazy then return if has_value then - evaluate_expr(v, recv) + var f = v.new_frame(self, mpropdef.as(not null), [recv]) + evaluate_expr(v, recv, f) return end - var 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 f = new Frame(self, self.mpropdef.as(not null), [recv]) v.frames.unshift(f) var val @@ -1190,7 +1247,7 @@ redef class AExpr # 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 @@ -1199,7 +1256,7 @@ redef class AExpr # 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 @@ -1228,14 +1285,16 @@ redef class ABlockExpr 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 @@ -1276,6 +1335,14 @@ redef class ASelfExpr end end +redef class AImplicitSelfExpr + redef fun expr(v) + do + if not is_sys then return super + return v.mainobj + end +end + redef class AEscapeExpr redef fun stmt(v) do @@ -1420,6 +1487,19 @@ redef class AForExpr 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 + v.callsite(method_finish, [expr]) + end +end + redef class AAssertExpr redef fun stmt(v) do @@ -1513,11 +1593,18 @@ redef class AArrayExpr 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) @@ -1541,7 +1628,7 @@ redef class ASuperstringExpr if i == null then return null array.add(i) end - var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type) + var i = v.array_instance(array, v.mainmodule.object_type) var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i]) assert res != null return res @@ -1661,7 +1748,7 @@ redef class ASendExpr 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) @@ -1674,7 +1761,7 @@ redef class ASendReassignFormExpr 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 @@ -1698,29 +1785,35 @@ redef class ASuperExpr 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 @@ -1732,7 +1825,10 @@ redef class ANewExpr 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 @@ -1794,6 +1890,13 @@ redef class AIssetAttrExpr end end +redef class AVarargExpr + redef fun expr(v) + do + return v.expr(self.n_expr) + end +end + redef class ADebugTypeExpr redef fun stmt(v) do