X-Git-Url: http://nitlanguage.org diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 9b4fb1c..7557da7 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -71,6 +71,9 @@ class NaiveInterpreter # The main Sys instance var mainobj: nullable Instance is noinit + # Name of all supported functional names + var routine_types: Set[String] = new HashSet[String] + init do if mainmodule.model.get_mclasses_by_name("Bool") != null then @@ -80,6 +83,15 @@ class NaiveInterpreter init_instance_primitive(self.false_instance) end self.null_instance = new PrimitiveInstance[nullable Object](mainmodule.model.null_type, null) + + routine_types.add("RoutineRef") + for name in ["Proc", "Fun", "ProcRef", "FunRef"] do + # 20 is a magic number = upper limit of the arity of each functional class. + # i.e. Proc0, Proc1, ... Proc19 + for i in [0..20[ do + routine_types.add("{name}{i}") + end + end end # Starts the interpreter on the main module of a program @@ -456,6 +468,22 @@ class NaiveInterpreter # Store known methods, used to trace methods as they are reached var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef] + # Consumes an iterator of expressions and tries to map each element to + # its corresponding Instance. + # + # If any AExprs doesn't resolve to an Instance, then it returns null. + # Otherwise return an array of instances + fun aexprs_to_instances(aexprs: Iterator[AExpr]): nullable Array[Instance] + do + var accumulator = new Array[Instance] + for aexpr in aexprs do + var instance = expr(aexpr) + if instance == null then return null + accumulator.push(instance) + end + return accumulator + end + # 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. @@ -470,21 +498,15 @@ class NaiveInterpreter 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 + var rest_args = aexprs_to_instances(args.iterator) + if rest_args == null then return null + res.append(rest_args) 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 + var exprs = aexprs_to_instances(args.iterator) + if exprs == null then return null # Fill `res` with the result of the evaluation according to the mapping for i in [0..msignature.arity[ do @@ -775,6 +797,27 @@ class MutableInstance var attributes: Map[MAttribute, Instance] = new HashMap[MAttribute, Instance] end +# An instance with the original receiver and callsite (for function reference) +class CallrefInstance + super Instance + + # The original receiver + # + # ~~~nitish + # var a = new A + # var f = &a.toto # `a` is the original receiver + # ~~~ + var recv: Instance + + # The original callsite + # + # ~~~nitish + # var a = new A + # var f = &a.toto # `toto` is the original callsite + # ~~~ + var callsite: CallSite +end + # Special instance to handle primitives values (int, bool, etc.) # The trick is just to encapsulate the “real” value. class PrimitiveInstance[E] @@ -960,6 +1003,19 @@ redef class AMethPropdef do var pname = mpropdef.mproperty.name var cname = mpropdef.mclassdef.mclass.name + + if pname == "call" and v.routine_types.has(cname) then + var routine = args.shift + assert routine isa CallrefInstance + # Swap the receiver position with the original recv of the call form. + args.unshift routine.recv + var res = v.callsite(routine.callsite, args) + # recover the old args state + args.shift + args.unshift routine + return res + end + if pname == "output" then var recv = args.first recv.val.output @@ -2229,18 +2285,24 @@ redef class ASendExpr var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments) if args == null then return null - var res = v.callsite(callsite, args) return res end end redef class ACallrefExpr - redef fun expr(v) - do - fatal(v, "NOT YET IMPLEMENTED callref expressions.") - return null - end + redef fun expr(v) + do + var recv = v.expr(self.n_expr) + if recv == null then return null + var mtype = self.mtype + assert mtype != null + # In case we are in generic class where formal parameter can not + # be resolved. + var mtype2 = v.unanchor_type(mtype) + var inst = new CallrefInstance(mtype2, recv, callsite.as(not null)) + return inst + end end redef class ASendReassignFormExpr