示例#1
0
        // eq: indicates whether its (two) arguments are equal.
        private PLObject eq_fun(PLObject a, PLObject b)
        {
            if ((a is PLAtom) && (b is PLAtom))
            {
                // Two atoms compare by value
                return(BoolToExpr(a.Equals(b)));
            }
            else
            {
                // Two empty lists are equal
                if ((a is PLList) && (((PLList)a).Count == 0) &&
                    (b is PLList) && (((PLList)b).Count == 0))
                {
                    return(BoolToExpr(true));
                }
            }

            return(BoolToExpr(false));
        }
示例#2
0
 // Convert a ProtoLisp expression to a native C# bool value
 private bool ExprToBool(PLObject expr)
 {
     // Anything that is not "t" is false
     return((expr is PLStringAtom) && (expr.Equals("t")));
 }
示例#3
0
        public PLObject Eval(PLObject expr, PLEnvironment localEnv, Stream traceStream)
        {
            if (traceStream != null)
            {
                StreamWriteLine(traceStream, "** Evaluating: " + ExpressionToString(expr));
            }

            if (expr is PLAtom)
            {
                PLAtom atomExpr = (PLAtom)expr;

                if (atomExpr is PLNumberAtom)
                {
                    // Numbers eval to themselves
                    return(atomExpr);
                }
                else
                {
                    if (atomExpr.Equals("t"))
                    {
                        // "t" (True) evals to itself
                        return(atomExpr);
                    }
                    else if (atomExpr.Equals("nil"))
                    {
                        // Return whatever our native representation for false is
                        return(BoolToExpr(false));
                    }
                    else
                    {
                        PLObject retval = Lookup(atomExpr.ToString(), localEnv);

                        if (retval == null)
                        {
                            throw new Exception("The symbolic name \"" + atomExpr + "\" is not bound.");
                        }

                        return(retval);
                    }
                }
            }
            else if (expr is PLList)
            {
                PLList listExpr = ((PLList)expr);

                // The empty list evaluates to itself
                if (listExpr.Count == 0)
                {
                    return(listExpr);
                }

                PLObject carVal = car_fun(listExpr);

                // Check for special-case primitives
                if (carVal is PLStringAtom)
                {
                    if (carVal.Equals("cond"))
                    {
                        if (listExpr.Count < 2)
                        {
                            throw new Exception("Must pass at least one argument to the 'cond' primitive");
                        }

                        return(cond_fun(cdr_fun(listExpr), localEnv, traceStream));
                    }
                    else if (carVal.Equals("quote"))
                    {
                        if (listExpr.Count != 2)
                        {
                            throw new Exception("Incorrect number of arguments passed to the 'quote' primitive");
                        }

                        // Return the second portion of the list
                        return(listExpr[1]);
                    }
                    else if (carVal.Equals("define"))
                    {
                        if (listExpr.Count != 3)
                        {
                            throw new Exception("Incorrect number of arguments passed to the 'define' primitive");
                        }

                        if (!(listExpr[1] is PLStringAtom))
                        {
                            throw new Exception("The first argument passed to the 'define' primitive was not a string");
                        }

                        return(define_fun(((PLStringAtom)listExpr[1]).ToString(),
                                          Eval(listExpr[2], localEnv, traceStream)));
                    }
                    else if (carVal.Equals("lambda"))
                    {
                        if (listExpr.Count != 3)
                        {
                            throw new Exception("Incorrect number of arguments passed to the 'lambda' primitive");
                        }

                        if (!(listExpr[1] is PLList))
                        {
                            throw new Exception("The first argument to the 'lambda' primitive was not a list");
                        }

                        return(lambda_fun((PLList)listExpr[1], listExpr[2], localEnv));
                    }
                    else if (carVal.Equals("defun"))
                    {
                        // Syntactic sugar for (define <name> (lambda ...
                        if (listExpr.Count != 4)
                        {
                            throw new Exception("Incorrect number of arguments passed to the 'defun' primitive");
                        }

                        if (!(listExpr[1] is PLStringAtom))
                        {
                            throw new Exception("The first argument passed to the 'defun' primitive was not a simple name");
                        }

                        if (!(listExpr[2] is PLList))
                        {
                            throw new Exception("The second argument passed to the 'defun' argument was not a list");
                        }

                        return(define_fun(((PLStringAtom)listExpr[1]).ToString(),
                                          lambda_fun((PLList)listExpr[2], listExpr[3], localEnv)));
                    }
                }

                // Assume a general function invocation. Evaluate all the
                // arguments and invoke.
                PLList args = EvalPLList(cdr_fun(listExpr), localEnv, traceStream);
                return(Apply(listExpr[0], args, localEnv, traceStream));
            }
            else
            {
                throw new Exception("Unrecognized type passed to Eval()");
            }
        }
示例#4
0
        // Apply the specified argument list to the function indicated
        // by the provided expression. The function expression may simply
        // be the symbolic name of a function, or it may be an evaluatable
        // expression in its own right.
        private PLObject Apply(PLObject func, PLList args, PLEnvironment localEnv, Stream traceStream)
        {
            if (traceStream != null)
            {
                StreamWriteLine(traceStream, "** Evaluating the expression \"" + ExpressionToString(func) + "\" as a function");
            }

            if (func is PLStringAtom)
            {
                // Function is named by a symbol

                if (func.Equals("atom"))
                {
                    if (args.Count != 1)
                    {
                        throw new Exception("Incorrect number of arguments passed to the 'atom' primitive");
                    }

                    return(atom_fun(args[0]));
                }
                else if (func.Equals("eq"))
                {
                    if (args.Count != 2)
                    {
                        throw new Exception("Incorrect number of arguments passed to the 'eq' primitive");
                    }

                    return(eq_fun(args[0], args[1]));
                }
                else if (func.Equals("car"))
                {
                    if (args.Count != 1)
                    {
                        throw new Exception("Incorrect number of arguments passed to the 'car' primitive");
                    }

                    if (!(args[0] is PLList))
                    {
                        throw new Exception("The argument passed to the 'car' primitive was not a list");
                    }

                    return(car_fun((PLList)args[0]));
                }
                else if (func.Equals("cdr"))
                {
                    if (args.Count != 1)
                    {
                        throw new Exception("Incorrect number of arguments passed to the 'cdr' primitive");
                    }

                    if (!(args[0] is PLList))
                    {
                        throw new Exception("The argument passed to the 'cdr' primitive was not a list");
                    }

                    return(cdr_fun((PLList)args[0]));
                }
                else if (func.Equals("cons"))
                {
                    if (args.Count != 2)
                    {
                        throw new Exception("Incorrect number of arguments passed to the 'cons' primitive");
                    }

                    if (!(args[1] is PLList))
                    {
                        throw new Exception("The second argument passed to the 'cons' primitive was not a list");
                    }

                    return(cons_fun(args[0], (PLList)args[1]));
                }
                else if (func.Equals("+"))
                {
                    if (args.Count != 2)
                    {
                        throw new Exception("Incorrect number of arguments pass to the '+' primitive");
                    }

                    if (!(args[0] is PLNumberAtom) ||
                        !(args[1] is PLNumberAtom))
                    {
                        throw new Exception("Both arguments to the '+' primitive must be numbers");
                    }

                    return(plus_fun((PLNumberAtom)args[0], (PLNumberAtom)args[1]));
                }
                else if (func.Equals("-"))
                {
                    if (args.Count != 2)
                    {
                        throw new Exception("Incorrect number of arguments pass to the '-' primitive");
                    }

                    if (!(args[0] is PLNumberAtom) ||
                        !(args[1] is PLNumberAtom))
                    {
                        throw new Exception("Both arguments to the '-' primitive must be numbers");
                    }

                    return(minus_fun((PLNumberAtom)args[0], (PLNumberAtom)args[1]));
                }
                else if (func.Equals("*"))
                {
                    if (args.Count != 2)
                    {
                        throw new Exception("Incorrect number of arguments pass to the '*' primitive");
                    }

                    if (!(args[0] is PLNumberAtom) ||
                        !(args[1] is PLNumberAtom))
                    {
                        throw new Exception("Both arguments to the '*' primitive must be numbers");
                    }

                    return(mult_fun((PLNumberAtom)args[0], (PLNumberAtom)args[1]));
                }
                else if (func.Equals("/"))
                {
                    if (args.Count != 2)
                    {
                        throw new Exception("Incorrect number of arguments pass to the '/' primitive");
                    }

                    if (!(args[0] is PLNumberAtom) ||
                        !(args[1] is PLNumberAtom))
                    {
                        throw new Exception("Both arguments to the '/' primitive must be numbers");
                    }

                    return(div_fun((PLNumberAtom)args[0], (PLNumberAtom)args[1]));
                }

                // The name does not indicate a built-in primitive.
                // Look up the function in our environment
                PLObject funObj = Lookup(func.ToString(), localEnv);

                if (!(funObj is PLClosure))
                {
                    throw new Exception("The symbolic name \"" + func + "\" is not bound to a function");
                }

                // Run the function!
                return(Execute((PLClosure)funObj, args, traceStream));
            }
            else
            {
                // The function is an expression, not just a name. This expression
                // had better evaluate to a closure.
                PLObject funObj = Eval(func, localEnv, traceStream);

                if (!(funObj is PLClosure))
                {
                    throw new Exception("Expression \"" + ExpressionToString(func) + "\" does not evaluate to a function");
                }

                // Run this function expression
                return(Execute((PLClosure)funObj, args, traceStream));
            }
        }
示例#5
0
        public PLObject GetExpression()
        {
            string token = GetToken();

            if (token == null)
            {
                return(null);
            }

            if (token.Equals("'"))
            {
                // The "'" character means "quote", and preserve
                // the next expression.
                PLList retval = new PLList();
                retval.Add(new PLStringAtom("quote"));

                PLObject nextExpr = GetExpression();

                if (nextExpr == null)
                {
                    throw new Exception("'quote' was not followed by a complete expression");
                }

                retval.Add(nextExpr);
                return(retval);
            }

            if (!token.Equals("("))
            {
                // Not the beginning of a list; the expression is
                // simply this token. See if it's a number or a
                // plain string.
                try {
                    return(new PLNumberAtom(token));
                }
                catch (Exception) {
                    // Just treat it as a regular string
                    return(new PLStringAtom(token));
                }
            }
            else
            {
                // We have the beginning of a list, which can contain
                // any number of expressions. Keep building our list
                // until we encounter the closing paren.
                PLList retval = new PLList();

                PLObject nextExpr = GetExpression();

                while (!nextExpr.Equals(")"))
                {
                    retval.Add(nextExpr);

                    nextExpr = GetExpression();

                    if (nextExpr == null)
                    {
                        throw new Exception("Incomplete expression (unbalanced parens?");
                    }
                }

                return(retval);
            }
        }