X-Git-Url: http://nitlanguage.org diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 09d05e6..12a54de 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -114,43 +114,26 @@ class NaiveInterpreter # Set this mark to skip the evaluation until the end of the specified method frame var returnmark: nullable Frame = null - # Is a break executed? - # Set this mark to skip the evaluation until a labeled statement catch it with `is_break` - var breakmark: nullable EscapeMark = null - - # Is a continue executed? - # Set this mark to skip the evaluation until a labeled statement catch it with `is_continue` - var continuemark: nullable EscapeMark = null + # Is 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 # 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 breakmark != null or continuemark != null + fun is_escaping: Bool do return returnmark != null or escapemark != null # The value associated with the current return/break/continue, if any. # Set the value when you set a escapemark. # Read the value when you catch a mark or reach the end of a method var escapevalue: nullable Instance = null - # If there is a break and is associated with `escapemark`, then return true an clear the mark. - # If there is no break or if `escapemark` is null then return false. - # Use this function to catch a potential break. - fun is_break(escapemark: nullable EscapeMark): Bool - do - if escapemark != null and self.breakmark == escapemark then - self.breakmark = null - return true - else - return false - end - end - - # If there is a continue and is associated with `escapemark`, then return true an clear the mark. - # If there is no continue or if `escapemark` is null then return false. - # Use this function to catch a potential continue. - fun is_continue(escapemark: nullable EscapeMark): Bool + # If there is a break/continue and is associated with `escapemark`, then return true and clear the mark. + # If there is no break/continue or if `escapemark` is null then return false. + # Use this function to catch a potential break/continue. + fun is_escape(escapemark: nullable EscapeMark): Bool do - if escapemark != null and self.continuemark == escapemark then - self.continuemark = null + if escapemark != null and self.escapemark == escapemark then + self.escapemark = null return true else return false @@ -336,35 +319,48 @@ class NaiveInterpreter # Store known methods, used to trace methods as they are reached var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef] - # Common code for calls to injected methods and normal methods - fun call_commons(mpropdef: MMethodDef, args: Array[Instance]): Array[Instance] + # Evaluate `args` as expressions in the call of `mpropdef` on `recv`. + # 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] do - var vararg_rank = mpropdef.msignature.vararg_rank - if vararg_rank >= 0 then - assert args.length >= mpropdef.msignature.arity + 1 # because of self - var rawargs = args - args = new Array[Instance] - - args.add(rawargs.first) # recv + var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null) + var res = new Array[Instance] + res.add(recv) - for i in [0..vararg_rank[ do - args.add(rawargs[i+1]) - end + if args.is_empty then return res - var vararg_lastrank = vararg_rank + rawargs.length-1-mpropdef.msignature.arity - var vararg = new Array[Instance] - for i in [vararg_rank..vararg_lastrank] do - vararg.add(rawargs[i+1]) - end - # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis - var elttype = mpropdef.msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, args.first.mtype.as(MClassType)) - args.add(self.array_instance(vararg, elttype)) + var vararg_rank = msignature.vararg_rank + var vararg_len = args.length - msignature.arity + if vararg_len < 0 then vararg_len = 0 - for i in [vararg_lastrank+1..rawargs.length-1[ do - args.add(rawargs[i+1]) + 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) end end - return args + return res end # Execute `mpropdef` for a `args` (where `args[0]` is the receiver). @@ -372,16 +368,6 @@ class NaiveInterpreter # The call is direct/static. There is no message-sending/late-binding. fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance do - args = call_commons(mpropdef, args) - return call_without_varargs(mpropdef, args) - end - - # Common code to call and this function - # - # Call only executes the variadic part, this avoids - # double encapsulation of variadic parameters into an Array - fun call_without_varargs(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance - do if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then self.discover_call_trace.add mpropdef self.debug("Discovered {mpropdef}") @@ -395,7 +381,7 @@ class NaiveInterpreter var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef] self.parameter_check(npropdef, mpropdef, args) return npropdef.call(self, mpropdef, args) - else if mproperty.name == "init" then + 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) @@ -722,7 +708,7 @@ redef class AMethPropdef if auto_super_call then # standard call-next-method var superpd = mpropdef.lookup_next_definition(v.mainmodule, arguments.first.mtype) - v.call_without_varargs(superpd, arguments) + v.call(superpd, arguments) end if mpropdef.is_intern or mpropdef.is_extern then @@ -778,7 +764,7 @@ redef class AMethPropdef else if pname == "is_same_type" then return v.bool_instance(args[0].mtype == args[1].mtype) else if pname == "is_same_instance" then - return v.bool_instance(args[1] != null and args[0].eq_is(args[1])) + return v.bool_instance(args[0].eq_is(args[1])) else if pname == "exit" then exit(args[1].to_i) abort @@ -905,7 +891,7 @@ redef class AMethPropdef return v.bool_instance(args[0].to_f.is_inf != 0) end else if cname == "NativeString" then - if pname == "init" then + if pname == "new" then return v.native_string_instance("!" * args[1].to_i) end var recvval = args.first.val.as(Buffer) @@ -966,7 +952,7 @@ redef class AMethPropdef else if pname == "calloc_string" then return v.native_string_instance("!" * args[1].to_i) else if cname == "NativeArray" then - if pname == "init" then + if pname == "new" then var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i) return new PrimitiveInstance[Array[Instance]](args[0].mtype, val) end @@ -1127,7 +1113,7 @@ redef class AClassdef if not mpropdef.is_intro then # standard call-next-method var superpd = mpropdef.lookup_next_definition(v.mainmodule, args.first.mtype) - v.call_without_varargs(superpd, args) + v.call(superpd, args) end return null else @@ -1227,20 +1213,7 @@ redef class ASelfExpr end end -redef class AContinueExpr - redef fun stmt(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.continuemark = self.escapemark - end -end - -redef class ABreakExpr +redef class AEscapeExpr redef fun stmt(v) do var ne = self.n_expr @@ -1249,7 +1222,7 @@ redef class ABreakExpr if i == null then return v.escapevalue = i end - v.breakmark = self.escapemark + v.escapemark = self.escapemark end end @@ -1315,7 +1288,7 @@ redef class ADoExpr redef fun stmt(v) do v.stmt(self.n_block) - v.is_break(self.escapemark) # Clear the break (if any) + v.is_escape(self.break_mark) # Clear the break (if any) end end @@ -1327,8 +1300,8 @@ redef class AWhileExpr if cond == null then return if not cond.is_true then return v.stmt(self.n_block) - if v.is_break(self.escapemark) then return - v.is_continue(self.escapemark) # Clear the break + if v.is_escape(self.break_mark) then return + v.is_escape(self.continue_mark) # Clear the break if v.is_escaping then return end end @@ -1339,8 +1312,8 @@ redef class ALoopExpr do loop v.stmt(self.n_block) - if v.is_break(self.escapemark) then return - v.is_continue(self.escapemark) # Clear the break + if v.is_escape(self.break_mark) then return + v.is_escape(self.continue_mark) # Clear the break if v.is_escaping then return end end @@ -1372,8 +1345,8 @@ redef class AForExpr abort end v.stmt(self.n_block) - if v.is_break(self.escapemark) then break - v.is_continue(self.escapemark) # Clear the break + 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 @@ -1625,12 +1598,8 @@ redef class ASendExpr do var recv = v.expr(self.n_expr) if recv == null then return null - var args = [recv] - for a in self.raw_arguments do - var i = v.expr(a) - if i == null then return null - args.add(i) - end + var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments) + if args == null then return null var res = v.callsite(callsite, args) return res @@ -1642,12 +1611,8 @@ redef class ASendReassignFormExpr do var recv = v.expr(self.n_expr) if recv == null then return - var args = [recv] - for a in self.raw_arguments do - var i = v.expr(a) - if i == null then return - args.add(i) - end + var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments) + if args == null then return var value = v.expr(self.n_value) if value == null then return @@ -1667,15 +1632,11 @@ redef class ASuperExpr redef fun expr(v) do var recv = v.frame.arguments.first - var args = [recv] - for a in self.n_args.n_exprs do - var i = v.expr(a) - if i == null then return null - args.add(i) - end 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 for i in [0..callsite.msignature.arity[ do @@ -1687,14 +1648,17 @@ redef class ASuperExpr return res end - if args.length == 1 then - args = v.frame.arguments - end - # standard call-next-method var mpropdef = self.mpropdef mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype) - var res = v.call_without_varargs(mpropdef, args) + + var args = v.varargize(mpropdef, recv, self.n_args.n_exprs) + if args == null then return null + + if args.length == 1 then + args = v.frame.arguments + end + var res = v.call(mpropdef, args) return res end end @@ -1702,15 +1666,11 @@ end redef class ANewExpr redef fun expr(v) do - var mtype = v.unanchor_type(self.mtype.as(not null)) + var mtype = v.unanchor_type(self.recvtype.as(not null)) var recv: Instance = new MutableInstance(mtype) v.init_instance(recv) - var args = [recv] - for a in self.n_args.n_exprs do - var i = v.expr(a) - if i == null then return null - args.add(i) - end + var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs) + if args == null then return null var res2 = v.callsite(callsite, args) if res2 != null then #self.debug("got {res2} from {mproperty}. drop {recv}")