# 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
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
# 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.
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
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]
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
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
+ assert mtype != null
+ var inst = new CallrefInstance(mtype.as(not null), recv, callsite.as(not null))
+ return inst
+ end
end
redef class ASendReassignFormExpr