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)); }
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); } }
public virtual ILispNode Eval(CallStack callStack, params object [] args) { return(this); }
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)); } }
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"); } }))); }
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"); } }))); }
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)); }
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(); } }
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; } }))); }