Пример #1
0
        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");
        }
Пример #2
0
 public StackFrame(StackFrame original)
 {
     this.Evaluated = original.Evaluated;
     this.Unevaluated = original.Unevaluated;
     this.CurrentEnv = original.CurrentEnv;
 }
Пример #3
0
        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...");
        }