Beispiel #1
0
        public ILispNode Map(MapFunc map, CallStack callStack, params object [] args)
        {
            var rgMapped = this.Select(x => map(x, callStack, args));

            var missing = rgMapped.Aggregate(
                new LispMissing(),
                (r, x) => (x is LispMissing)
                    ? r.Merge(x as LispMissing)
                    : r);

            if (missing.Count() > 0)
            {
                return(missing);
            }

            return(new LispList(null, rgMapped));
        }
Beispiel #2
0
        public ILispNode Eval(CallStack callStack, params object [] args)
        {
            try
            {
                // ()
                if (Count == 0)
                {
                    return(_nil);
                }

                var functor = this[0].Eval(callStack, false);
                // ( =>nil )
                if (functor is LispNil)
                {
                    return(_nil);
                }
                // ( =>missing )
                if (functor is LispMissing)
                {
                    return(functor);
                }

                var arguments = new LispList();
                do
                {
                    if (IsImproperList)
                    {
                        arguments.Add(this[1] as LispAtom);
                        continue;
                    }

                    arguments = new LispList(null, this.Skip(1));
                }while (false);

                // ( =>(lambda) ) and ( =>'funcname' )
                return(Functor.Apply(functor, arguments, callStack, args));
            }
            catch (LispException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new LispException(this, "Exception while applying functor to arguments", ex);
            }
        }
Beispiel #3
0
 public virtual ILispNode Eval(CallStack callStack, params object [] args)
 {
     return(this);
 }
Beispiel #4
0
        public ILispNode Eval(CallStack callStack, params object [] args)
        {
            if (EvalComplete)
            {
                return(this);
            }

            EvalComplete = true;

            var fResolve = (args.Length > 0)
                ? (bool)args[0]
                : true;

            if (IsNil)
            {
                return(new LispNil());
            }

            switch (Token)
            {
            case Token.ValidNumber:
            {
                return(SetValue(TokenValue));
            }

            case Token.Text:
            case Token.SingleQuotedText:
            case Token.DoubleQuotedText:
            {
                return(SetValue(TokenValue));
            }

            case Token.ValidName:
            {
                if (fResolve)
                {
                    switch (TokenValue.ToLower())
                    {
                    case "true":
                    case "t":
                    case "#t":
                    {
                        return(SetValue(true));
                    }

                    case "f":
                    case "#f":
                    case "false":
                    {
                        return(SetValue(false));
                    }

                    case "nil":
                    {
                        return(new LispNil());
                    }

                    case "today":
                    {
                        return(SetValue(DateTime.Today));
                    }

                    case "now":
                    {
                        return(SetValue(DateTime.Now));
                    }

                    default:
                        break;
                    }
                }
                break;
            }

            case Token.MAX:
            {
                return(SetValue(RawValue));
            }
            }

            try
            {
                if (fResolve)
                {
                    var resolvedValue = callStack[TokenValue];
                    if (resolvedValue != null)
                    {
                        return(SetValue(resolvedValue));
                    }

                    throw new KeyNotFoundException();
                }

                return(SetValue(TokenValue));
            }
            catch (KeyNotFoundException)
            {
                EvalComplete = false;
                return((new LispMissing()).Register(TokenValue));
            }
        }
Beispiel #5
0
        public static ILispNode MergeAsDateTime(this ILispNode root, IList <ILispNode> arguments, CallStack callStack, int arity, IMerger merger)
        {
            if (arguments.Count < arity)
            {
                throw new Exception("Not enough arguments");
            }

            var fFirst = true;
            var fUnary = (arity == 1);

            return(new LispAtom(
                       arguments.Aggregate(
                           DateTime.MinValue,
                           (result, xArg) =>
            {
                var xEval = xArg.Eval(callStack, true);

                if ((xEval is LispNil) && (merger.MergeNil != null))
                {
                    return (DateTime)merger.MergeNil(result, xEval as LispNil);
                }

                if ((xEval is LispMissing) && (merger.MergeMissing != null))
                {
                    return (DateTime)merger.MergeMissing(result, xEval as LispMissing);
                }

                if ((xEval is LispList) && (merger.MergeList != null))
                {
                    return (DateTime)merger.MergeList(result, xEval as LispList);
                }

                Debug.Assert(xEval is LispAtom, "Argument does not evaluate to an Atom!");

                try
                {
                    // if fUnary, it means the function has only the first argument, which must be merged
                    // otherwise, we can prime the pump with the value of the first argument
                    if (fFirst && !fUnary)
                    {
                        if (!(xEval as LispAtom).IsDateTime)
                        {
                            throw new Exception("The first argument to DateTime functions should be of type DateTime");
                        }

                        result = (xEval as LispAtom).ValueAsDateTime;
                        fFirst = false;

                        return result;
                    }

                    try
                    {
                        var ts = TimeSpan.Parse((xEval as LispAtom).ValueAsString);
                        return (DateTime)merger.MergeAtom(result, ts);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Subsequent arguments to DateTime functions should be of type TimeSpan", ex);
                    }
                }
                catch
                {
                    throw new Exception("Argument does not evaluate to a DateTime");
                }
            })));
        }
Beispiel #6
0
        public static ILispNode MergeAsBoolean(this ILispNode root, IList <ILispNode> arguments, CallStack callStack, int arity, IMerger merger)
        {
            if (arguments.Count < arity)
            {
                throw new Exception("Not enough arguments");
            }

            var fFirst = true;
            var fUnary = (arity == 1);

            return(new LispAtom(
                       arguments.Aggregate(
                           false,
                           (result, xArg) =>
            {
                var xEval = xArg.Eval(callStack);

                // nil is treated as false
                if (xEval is LispNil)
                {
                    xEval = new LispAtom(false);
                }

                if ((xEval is LispMissing) && (merger.MergeMissing != null))
                {
                    return (bool)merger.MergeMissing(result, xEval as LispMissing);
                }

                if ((xEval is LispList) && (merger.MergeList != null))
                {
                    return (bool)merger.MergeList(result, xEval as LispList);
                }

                Debug.Assert(xEval is LispAtom, "Argument does not evaluate to an Atom!");

                try
                {
                    if (!(xEval as LispAtom).IsBoolean)
                    {
                        throw new Exception();
                    }

                    // if fUnary, it means the function has only the first argument, which must be merged
                    // otherwise, we can prime the pump with the value of the first argument
                    if (fFirst && !fUnary)
                    {
                        result = (xEval as LispAtom).ValueAsBoolean;
                        fFirst = false;

                        return result;
                    }
                    return (bool)merger.MergeAtom(result, (xEval as LispAtom).ValueAsBoolean);
                }
                catch
                {
                    throw new Exception("Argument does not evaluate to a Boolean");
                }
            })));
        }
Beispiel #7
0
        public static ILispNode Apply(ILispNode functor, LispList arguments, CallStack callStack, params object [] args)
        {
            if (functor is LispNil)
            {
                return(new LispNil());
            }

            if (functor is LispMissing)
            {
                throw new Exception("Cannot apply a Functor of type Missing!");
            }

            Lambda lambda = null;

            do
            {
                if (functor is LispAtom)
                {
                    var functionName = (functor as LispAtom).ValueAsString;
                    if (functionName == String.Empty)
                    {
                        throw new Exception("functor's ValueAsString is Empty!");
                    }

                    var resolvedFunctor = ResolveFunctor(functionName, callStack, args);
                    if (resolvedFunctor.DynamicFunction != null)
                    {
                        lambda = resolvedFunctor.DynamicFunction;
                        break;
                    }

                    foreach (var nativeFunction in resolvedFunctor.NativeFunctions)
                    {
                        try
                        {
#if TRACE_FLOW
                            var strTrace = String.Format("{0}({1} {2})", new String(' ', callStack.NumberOfFrames), functionName, arguments.ToString().Unlist());
                            _calls.Push(strTrace);
#endif
                            var result = nativeFunction.Invoke(functor, arguments, callStack, args);
#if TRACE_FLOW
#if TRACE_FLOW_VERBOSE
                            Console.WriteLine("{0} => {1}\n{2}", Calls.Pop(), result.ToString(), callStack.ToString());
#else
                            Console.WriteLine("{0} => {1}", _calls.Pop(), result);
#endif
#endif
                            return(result);
                        }
#if TRACE_FLOW
                        catch (Exception ex)
                        {
                            Console.WriteLine(
                                "({0} {1}) throws: {2}",
                                nativeFunction.GetType().FullName + "." + nativeFunction.Method.Name,
                                arguments.ToLispArgString(),
                                ex.Message);
                            Console.WriteLine("Stack:\n{0}", _calls.ToList().Aggregate(String.Empty, (r, x) => r + ("\n" + x)));
                            continue;
                        }
#else
                        catch
                        {
                            continue;
                        }
#endif
                    }
                }

                if (functor is LispList)
                {
                    var lambdaExpression = (functor as LispList);
                    lambda = new Lambda(lambdaExpression.Car as LispList, lambdaExpression.Cdr as IList <ILispNode>);
                }
            }while (false);

            try
            {
                return(ApplyDynamicFunction(lambda, arguments, callStack, args));
            }
            catch (Exception ex)
            {
                Console.WriteLine("({0} {1}) throws: {2}", lambda, arguments.ToLispArgString(), ex.Message);
            }

            throw new LispException(functor, String.Format("{0} : All known implementations have failed: ", functor));
        }
Beispiel #8
0
        public static ILispNode ApplyDynamicFunction(Lambda lambda, LispList arguments, CallStack callStack, params object [] args)
        {
            try
            {
                callStack.PushFrame();

                var functionBodyStatements = lambda.Body;
                var fOptional = false;

                for (var iParam = 0; iParam < lambda.FormalParameters.Count; iParam++)
                {
                    var param = lambda.FormalParameters[iParam];
                    Debug.Assert(param is LispAtom, "Formal Parameter should be an Atom");

                    var paramName = (param as LispAtom).ValueAsString;
                    Debug.Assert(paramName != String.Empty, "Formal Parameter name cannot be a null string");

                    fOptional |= paramName.EndsWith("?");
                    paramName  = paramName.TrimEnd('?');

                    ILispNode paramValue = null;
                    try
                    {
                        paramValue = arguments[iParam].Eval(callStack, true);
                        if (paramValue is LispMissing)
                        {
                            throw new Exception("Value to be bound cannot be evaluated");
                        }
                    }
                    catch
                    {
                        if (!fOptional)
                        {
                            throw new Exception(String.Format("Cannot find value to bind to {0}", paramName));
                        }
                        paramValue = new LispNil();
                    }
                    finally
                    {
                        Debug.Assert(paramValue != null, paramName + " is bound to null");

                        var invocationParamName = String.Format("{0}_{1}", paramName, callStack.NumberOfFrames);
                        callStack[invocationParamName] = paramValue;

                        functionBodyStatements = functionBodyStatements.Select(x => ReplaceParamName(x, paramName, invocationParamName)).ToList();
                    }
                }

                ILispNode result = new LispNil();
                foreach (var statement in functionBodyStatements)
                {
                    result = statement.Eval(callStack);
                }
                return(result);
            }
            finally
            {
                callStack.PopFrame();
            }
        }
Beispiel #9
0
        public static ILispNode WalkAsBoolean(this ILispNode root, IList <ILispNode> arguments, CallStack callStack, int arity, IMerger merger, IWalker walker)
        {
            ILispNode xPrev = null;

            return(new LispAtom(
                       arguments.Aggregate(
                           true,
                           (result, xArg) =>
            {
                var xEval = xArg.Eval(callStack);

                if ((xEval is LispNil) && (merger.MergeNil != null))
                {
                    return (bool)merger.MergeNil(result, xEval as LispNil);
                }

                if ((xEval is LispMissing) && (merger.MergeMissing != null))
                {
                    return (bool)merger.MergeMissing(result, xEval as LispMissing);
                }

                if ((xEval is LispList) && (merger.MergeList != null))
                {
                    return (bool)merger.MergeList(result, xEval as LispList);
                }

                try
                {
                    Debug.Assert(xEval is LispAtom, "Argument does not evaluate to an Atom!");

                    if (walker.ItemTest(xEval))
                    {
                        if (xPrev == null)
                        {
                            walker.First(xEval);
                            return true;
                        }
                        else
                        {
                            return (bool)walker.Sequence(result, xPrev, xEval);
                        }
                    }

                    throw new Exception("ItemTest failed without throwing an exception!");
                }
                catch (Exception ex)
                {
                    throw new Exception("Argument is invalid", ex);
                }
                finally
                {
                    xPrev = xEval;
                }
            })));
        }