void applyClosure(Closure newClosure, Value[] args, ref int pc, ref Code[] code, ref Closure closure, ref Stack <Value> stack, ref Env env, ref Stack <Dump> dump) { dump.Push(new Dump(closure, pc, env, stack.Count)); statistics_.ApLispCount++; pc = 0; var cl = newClosure; var lmd = cl.Lambda; env = new Env(cl.Env); code = cl.Lambda.Code; closure = cl; loadParameters(env, lmd, args); }
void applyContinuation(Continuation cont, Value[] args, ref int pc, ref Code[] code, ref Closure closure, ref Stack <Value> stack, ref Env env, ref Stack <Dump> dump) { pc = cont.Pc; code = cont.Code; closure = cont.Closure; stack = cont.Stack; env = cont.Env; dump = cont.Dump; stack.Pop(); // f をなくす stack.Push(args[0]); }
public Value Apply(Closure closure, params Value[] args) { return(eval_.Apply(closure, args)); }
public Value Execute() { Context ctx = ctx_; int pc = pc_; Code[] code = code_; var closure = closure_; var s = stack_; Env e = env_; var d = dump_; SourceLocation location = new SourceLocation(); EvalStatistics stat = statistics_; restart: try { Code c; while (true) { location = closure.Lambda.Locations[pc]; c = code[pc++]; stat.ExecCount[(int)c.Op]++; stat.MaxStack = Math.Max(stat.MaxStack, s.Count); stat.MaxDump = Math.Max(stat.MaxDump, d.Count); var l = location; if (l.Line == 0) { l = closure.Lambda.DefinedLocation; } //Console.WriteLine("{0} {3} at {1}:{2}", c, l.Filename, l.Line, s.Count); if (Trace) { var stackStr = string.Join(", ", s.ToArray().Select(x => x.ToString())); Console.WriteLine($"{pc}: {c} {d.Count} [{stackStr}]"); } switch (c.Op) { case Operator.Ldc: s.Push(c.Val); break; case Operator.Ld: { if (c.Val.IsSymbol) { var sym = c.Val.AsSymbol; var val = e.Get(sym); s.Push(val); } else { var id = c.Val.AsIdentifier; var val = e.Get(id.Symbol); s.Push(val); } } break; case Operator.Pop: { s.Pop(); } break; case Operator.Def: { var val = s.Peek(); var sym = c.Val.AsSymbol; if (val.IsClosure) { var lmd = val.AsClosure.Lambda; lmd.Name = sym; } e.Define(sym, val); } break; case Operator.Set: { var val = s.Peek(); var sym = c.Val.AsSymbol; e.Set(sym, val); } break; case Operator.Syn: { var val = s.Peek(); var sym = c.Val.AsSymbol; val.AsClosure.IsSyntax = true; val.AsClosure.Lambda.Name = sym; e.Define(sym, val); } break; case Operator.Ldf: { s.Push(new Value(new Closure(c.Val.As <Lambda>(), e))); } break; case Operator.Goto: { pc = c.Val.AsInt; } break; case Operator.Ret: { Dump restored; if (d.TryPop(out restored)) { #if DEBUG if (restored.StackSize != s.Count - 1) { Console.WriteLine($"Invalid stack size {restored.StackSize} {s.Count - 1}"); } #endif closure = restored.Closure; pc = restored.Pc; e = restored.Env; code = closure.Lambda.Code; } else { saveRegisters(pc, code, closure, s, e, d); return(s.Pop()); } } break; case Operator.If: { var val = s.Pop(); if (val.IsNil || val == Value.F) { pc = c.Val.AsInt; } } break; case Operator.Ccc: { var cc = makeContinuation(ref pc, ref code, ref closure, ref s, ref e, ref d); var f = s.Pop(); applyClosure(f.AsClosure, new Value[] { cc }, ref pc, ref code, ref closure, ref s, ref e, ref d); } break; case Operator.Ap: case Operator.Ap1: { int len; Value[] args; if (c.Op == Operator.Ap) { len = c.Val.AsInt; args = popMulti(s, len - 1); } else { var tmpLen = c.Val.AsInt - 1 - 1; // applicant と tail if (tmpLen >= 0) { var tail = Value.ListToArray(s.Pop()); var tmpArgs = popMulti(s, tmpLen); args = new Value[tmpLen + tail.Length]; len = args.Length; for (int i = 0; i < tmpLen; i++) { args[i] = tmpArgs[i]; } for (int i = 0; i < tail.Length; i++) { args[tmpLen + i] = tail[i]; } } else { args = new Value[0]; } } var applicant = s.Pop(); var vt = applicant.ValueType; if (vt == ValueType.Closure) { stat.ApLispCount++; d.Push(new Dump(closure, pc, e, s.Count)); var cl = applicant.AsClosure; var lmd = cl.Lambda; if (lmd.Name != null) { stat.ApplyCount[lmd.Name] = stat.ApplyCount.GetValueOrDefault(lmd.Name, 0) + 1; } e = new Env(cl.Env); code = cl.Lambda.Code; closure = cl; loadParameters(e, lmd, args); pc = 0; } else if (vt == ValueType.LispApi) { stat.ApNativeCount++; var func = applicant.AsLispApi; if (func.Name != null) { stat.ApplyCount[func.Name] = stat.ApplyCount.GetValueOrDefault(func.Name, 0) + 1; } ctx.Env = e; if (func.Arity >= 0) { if (args.Length < func.Arity) { throw new LispException($"Invalid argument length, expect {func.Arity} but {args.Length} for {func.Func}"); } } Value result; switch (func.Arity) { case 0: result = ((LispApi.Func0)func.Func)(ctx); break; case 1: result = ((LispApi.Func1)func.Func)(ctx, args[0]); break; case 2: result = ((LispApi.Func2)func.Func)(ctx, args[0], args[1]); break; case 3: result = ((LispApi.Func3)func.Func)(ctx, args[0], args[1], args[2]); break; case 4: result = ((LispApi.Func4)func.Func)(ctx, args[0], args[1], args[2], args[3]); break; case 5: result = ((LispApi.Func5)func.Func)(ctx, args[0], args[1], args[2], args[3], args[4]); break; default: result = ((LispApi.FuncVararg)func.Func)(ctx, args); break; } s.Push(result); } else if (vt == ValueType.Continuation) { applyContinuation(applicant.AsContinuation, args, ref pc, ref code, ref closure, ref s, ref e, ref d); } else { throw new Exception($"Can't apply {applicant}"); } } break; default: throw new Exception("BUG"); } } } catch (ExitException ex) { throw; } #if !DONT_CATCH_ERROR catch (LispException ex) { // Convert exception to scheme error. ex.SetLocation(location); Closure errorFunc = null; Value found; if (e.TryGet(Symbol.Intern("error"), out found)) { if (found.IsClosure) { errorFunc = found.AsClosure; } } if (errorFunc != null) { applyClosure(errorFunc, new Value[] { new Value(ex.Message) }, ref pc, ref code, ref closure, ref s, ref e, ref d); goto restart; } else { saveRegisters(pc, code, closure, s, e, d); ShowBacktrace(ex); throw; } } #endif }
public Value Run(Closure closure) { return(eval_.Run(closure)); }