public IScheminType EvaluateInternal(IScheminType ast) { StackFrame start = new StackFrame(); start.Unevaluated = ast; start.CurrentEnv = this.GlobalEnv; this.Stack.Clear(); this.Stack.Push(start); StackStart: while (this.Stack.Count > 0) { StackFrame current = new StackFrame(this.Stack.Pop()); Environment currentEnv = current.CurrentEnv; IScheminType unevaled = current.Unevaluated; if ((unevaled as ScheminAtom) != null) { if (this.Stack.Count < 1) { return EvalAtom(unevaled, currentEnv); } else { StackFrame previous = this.Stack.Pop(); StackFrame combinedPrevious = new StackFrame(previous); combinedPrevious.Evaluated = ((ScheminPair)combinedPrevious.Evaluated).Append(EvalAtom(unevaled, currentEnv)); this.Stack.Push(combinedPrevious); continue; } } else if (IsEmptyList(current.Unevaluated) && IsEmptyList(current.Evaluated)) { if (this.Stack.Count < 1) { return unevaled; } else { StackFrame previous = this.Stack.Pop(); StackFrame combinedPrevious = new StackFrame(previous); combinedPrevious.Evaluated = ((ScheminPair)combinedPrevious.Evaluated).Append(unevaled); this.Stack.Push(combinedPrevious); continue; } } else if ((unevaled as ScheminPair) != null) { ScheminPair unevaluated = (ScheminPair) unevaled; ScheminPair evaluatedList = (ScheminPair) current.Evaluated; IScheminType function; int currentArg = 0; if (!evaluatedList.Empty) { function = evaluatedList.Car; currentArg += evaluatedList.Length; } else { function = unevaluated.Car; } ScheminPrimitive currentPrimitive = null; if ((function as ScheminAtom) != null) { IScheminType evaledFunction = EvalAtom(function, currentEnv); if ((evaledFunction as ScheminPrimitive) != null) currentPrimitive = (ScheminPrimitive) evaledFunction; } else if ((function as ScheminPrimitive) != null) { currentPrimitive = (ScheminPrimitive)function; } ScheminPair fullArgs = (ScheminPair)current.Evaluated; foreach (IScheminType restArg in (ScheminPair) unevaluated) { fullArgs = fullArgs.Append(restArg); } ScheminPair evaluated = new ScheminPair(); while (!unevaluated.Empty) { IScheminType type = unevaluated.Car; if (currentPrimitive != null) { if ((!EvaluateNextArg(currentPrimitive, currentArg, fullArgs.ListCdr()) && currentArg > 0)) { evaluated = evaluated.Append(type); unevaluated = unevaluated.ListCdr(); currentArg++; continue; } } if ((type as ScheminAtom) != null) { IScheminType atomResult = EvalAtom(type, currentEnv); evaluated = evaluated.Append(atomResult); } else if ((type as ScheminPair) != null) { ScheminPair tempList = (ScheminPair)type; if (tempList.Empty) { evaluated = evaluated.Append(type); unevaluated = unevaluated.ListCdr(); currentArg++; continue; } StackFrame next = new StackFrame(); next.Unevaluated = tempList; next.CurrentEnv = currentEnv; StackFrame newSublist = new StackFrame(current); ScheminPair doneArgs = (ScheminPair)newSublist.Evaluated; foreach (IScheminType evaled in evaluated) { doneArgs = doneArgs.Append(evaled); } newSublist.Evaluated = doneArgs; newSublist.Unevaluated = unevaluated.ListCdr(); this.Stack.Push(newSublist); this.Stack.Push(next); goto StackStart; } else { evaluated = evaluated.Append(type); } unevaluated = unevaluated.ListCdr(); currentArg++; } foreach (IScheminType type in evaluated) { evaluatedList = evaluatedList.Append(type); } current.Evaluated = evaluatedList; current.Unevaluated = unevaluated; IScheminType waiting = evaluatedList.Car; if ((waiting as ScheminAtom) != null) { waiting = EvalAtom(waiting, currentEnv); } if ((waiting as ScheminPrimitive) != null) { ScheminPrimitive prim = (ScheminPrimitive)waiting; this.Stack.Push(current); IScheminType result = EvaluatePrimitive((ScheminPrimitive)waiting, evaluatedList.ListCdr(), currentEnv); this.Stack.Pop(); if (prim.Rewriter) { StackFrame rewritten = new StackFrame(current); rewritten.Unevaluated = result; rewritten.Evaluated = new ScheminPair(); this.Stack.Push(rewritten); continue; } if (this.Stack.Count < 1) { return result; } else { StackFrame previous = this.Stack.Pop(); StackFrame combinedPrevious = new StackFrame(previous); ScheminPair previousDone = (ScheminPair)combinedPrevious.Evaluated; previousDone = previousDone.Append(result); combinedPrevious.Evaluated = previousDone; this.Stack.Push(combinedPrevious); continue; } } else if ((waiting as ScheminLambda) != null) { ScheminLambda lam = (ScheminLambda)waiting; StackFrame next = new StackFrame(); next.Unevaluated = lam.Definition; next.CurrentEnv = lam.MakeEnvironment(evaluatedList.ListCdr(), this); this.Stack.Push(next); continue; } else if ((waiting as ScheminContinuation) != null) { ScheminContinuation con = (ScheminContinuation) waiting; this.Stack = new Stack<StackFrame>(con.PreviousStack); StackFrame continuationStart = new StackFrame(this.Stack.Pop()); if (this.Stack.Count < 1) { return evaluatedList.ListCdr().Car; } else { StackFrame previous = this.Stack.Pop(); StackFrame combinedPrevious = new StackFrame(previous); ScheminPair previousDone = (ScheminPair) combinedPrevious.Evaluated; previousDone = previousDone.Append(evaluatedList.ListCdr().Car); combinedPrevious.Evaluated = previousDone; this.Stack.Push(combinedPrevious); continue; } } else { throw new InvalidOperationException("Non-function in function position: " + waiting.ToString()); } } else { if (this.Stack.Count < 1) { return unevaled; } else { StackFrame previous = this.Stack.Pop(); StackFrame combinedPrevious = new StackFrame(previous); combinedPrevious.Evaluated = ((ScheminPair)combinedPrevious.Evaluated).Append(unevaled); this.Stack.Push(combinedPrevious); continue; } } } throw new Exception("Control escaped evaluator"); }
public StackFrame(StackFrame original) { this.Evaluated = original.Evaluated; this.Unevaluated = original.Unevaluated; this.CurrentEnv = original.CurrentEnv; }
public IScheminType EvaluateList(ScheminList list) { StackFrame start = new StackFrame(); start.WaitingOn = list; start.CurrentEnv = this.GlobalEnv; Stack.Clear(); Stack.Push(start); StackStart: while (Stack.Count > 0) { StackFrame current = Stack.Pop(); Environment CurrentEnv = current.CurrentEnv; ScheminList before = current.Before; ScheminList after = current.After; IScheminType WaitingOn = current.WaitingOn; if ((WaitingOn as ScheminList) == null || WaitingOn.Quoted() == true || IsEmptyList(WaitingOn)) { StackFrame next = new StackFrame(); if (before == null && after == null) { if ((WaitingOn as ScheminAtom) != null && !WaitingOn.Quoted()) { WaitingOn = EvalAtom(WaitingOn, CurrentEnv); } if (Stack.Count < 1) { return WaitingOn; } StackFrame previous = Stack.Pop(); if (previous.Before == null && previous.After == null) { next.WaitingOn = WaitingOn; } else { next.WaitingOn = CombineStackFrame(previous.Before, previous.After, WaitingOn); } // Use the previous environment in this case as well if (Stack.Count > 0) { next.CurrentEnv = Stack.Peek().CurrentEnv; } else { next.CurrentEnv = previous.CurrentEnv; } Stack.Push(next); continue; } // We need to use the PREVIOUS environment here, so peek it.. otherwise we're re-using the same environment for the previous context. StackFrame peeked = Stack.Peek(); next.WaitingOn = CombineStackFrame(before, after, WaitingOn); next.CurrentEnv = peeked.CurrentEnv; Stack.Push(next); continue; } StackFrame completeFrame = new StackFrame(); ScheminPrimitive currentPrimitive = null; ScheminList rest = (ScheminList) WaitingOn; ScheminList pendingBefore = new ScheminList(); pendingBefore.UnQuote(); if ((rest.Car() as ScheminPrimitive) != null) { if (rest.Car().Quoted() == false) { currentPrimitive = (ScheminPrimitive) rest.Car(); } } int currentArg = 0; while (!rest.Empty) { IScheminType type = rest.Car(); if (currentPrimitive != null) { if (!EvaluateNextArg(currentPrimitive, currentArg, ((ScheminList) WaitingOn).Cdr())) { pendingBefore.Append(type); rest = rest.Cdr(); currentArg++; continue; } } if ((type as ScheminAtom) != null) { if (type.Quoted()) { pendingBefore.Append(type); } else { IScheminType atomResult = EvalAtom(type, CurrentEnv); if ((atomResult as ScheminRewriter) != null) { // if we get a quoted rewriter here, we're going to apply it :( pendingBefore.Append(atomResult); QuoteAll(rest.Cdr()); } else { pendingBefore.Append(atomResult); } } } else if ((type as ScheminList) != null) { ScheminList tempList = (ScheminList) type; if (tempList.Quoted() || tempList.Empty) { pendingBefore.Append(type); rest = rest.Cdr(); currentArg++; continue; } StackFrame next = new StackFrame(); next.WaitingOn = type; next.After = rest.Cdr(); next.Before = pendingBefore; next.CurrentEnv = CurrentEnv; Stack.Push(current); Stack.Push(next); goto StackStart; } else { pendingBefore.Append(type); } rest = rest.Cdr(); currentArg++; } IScheminType functionPosition = pendingBefore.Car(); ScheminList functionArgs = pendingBefore.Cdr(); if ((functionPosition as ScheminPrimitive) != null) { ScheminPrimitive prim = (ScheminPrimitive) functionPosition; completeFrame.Before = before; completeFrame.After = after; // Need to pass push the previous frame back on so we can get access to the current continuation via the evaluator's Stack field. // also adding the primitive's name to the exception if it gets thrown. try { Stack.Push(current); completeFrame.WaitingOn = prim.Evaluate(functionArgs, CurrentEnv, this); Stack.Pop(); } catch (BadArgumentsException ba) { Token sourceToken = prim.SourceToken; string line = String.Empty; if (sourceToken != null) { line = " line: " + sourceToken.LineNumber.ToString() + " col: " + sourceToken.ColNumber.ToString(); } throw new BadArgumentsException(prim.ToString() + " " + ba.Message + line); } completeFrame.CurrentEnv = CurrentEnv; Stack.Push(completeFrame); continue; } else if ((functionPosition as ScheminLambda) != null) { ScheminLambda lam = (ScheminLambda) functionPosition; completeFrame.Before = before; completeFrame.After = after; Environment args = lam.MakeEnvironment(functionArgs, this); completeFrame.WaitingOn = lam.Definition; completeFrame.CurrentEnv = args; Stack.Push(completeFrame); continue; } else if ((functionPosition as ScheminContinuation) != null) { ScheminContinuation con = (ScheminContinuation) functionPosition; this.Stack = new Stack<StackFrame>(con.PreviousStack); this.Stack.Peek().WaitingOn = functionArgs.Car(); continue; } else if ((functionPosition as ScheminRewriter) != null) { ScheminRewriter rewriter = (ScheminRewriter) functionPosition; QuoteAll(functionArgs); IScheminType result = rewriter.Rewrite(functionArgs); completeFrame.Before = before; completeFrame.After = after; completeFrame.WaitingOn = result; completeFrame.CurrentEnv = CurrentEnv; this.Stack.Push(completeFrame); continue; } else { throw new InvalidOperationException("Non-function in function position: " + functionPosition.ToString()); } } throw new InvalidOperationException("Control escaped list evaluator..."); }