public static DotFunc Equals() { return(DotFunc.From( args => { switch (args) { case DotSymbol _: return DotBool.True(); case DotList l: { // TODO: extend equality to objects! var numbers = l.Expressions.Cast <DotNumber>().ToList(); if (numbers.Count == 0) { throw new EvaluatorException("Nothing to compare."); } var first = numbers[0]; var(_, result) = numbers.Skip(1).Aggregate( seed: (first, true), func: (tuple, b) => { var(a, resultSoFar) = tuple; if (!resultSoFar) { return (b, false); } var predicateStillTrue = a.GetValue() == b.GetValue(); return (b, predicateStillTrue); }); return new DotBool(result); } } return DotBool.False(); })); }
public static DotExpression Expand(DotExpression expression, bool topLevel = false) { if (!(expression is DotList l)) { // constants can't be expanded return(expression); } if (l.Expressions.Count == 0) { throw new ParserException( "An empty list needs to be quoted!", l.Line, l.Column); } var args = l.Expressions.Skip(1).ToList(); // if (!(l.Expressions.First() is DotSymbol op)) // { // throw new EvaluatorException( // "Function or special form expected!"); // } if (l.Expressions.First() is DotSymbol op) { if (op.Name == "quote") { return(expression); } // TODO Find a generic way to check function and procedure argument length and type if (op.Name == "def" || op.Name == "defmacro") { if (args.Count != 2) { throw new ParserException("name and body expected!", op.Line, op.Column); } var defBody = Expand(args.ElementAt(1)); if (op.Name == "defmacro") { if (!topLevel) { throw new ParserException( "'defmacro' only allowed at top level!", op.Line, op.Column); } var procedure = Evaluator.Eval(defBody); if (!(procedure is DotProcedure dp)) { throw new ParserException( "A macro must be a procedure", op.Line, op.Column); } // Add macro GlobalEnvironment.MacroTable.Add( (args.ElementAt(0) as DotSymbol).Name, dp ); return(DotBool.True()); } var expandedDefinition = new LinkedList <DotExpression>(); expandedDefinition.AddLast(op); expandedDefinition.AddLast(args.First()); expandedDefinition.AddLast(defBody); return(new DotList() { Expressions = expandedDefinition }); } if (op.Name == "quasiquote") { return(ExpandQuasiquote(args.First())); } if (GlobalEnvironment.MacroTable.ContainsKey(op.Name)) { // call macro var macro = GlobalEnvironment.MacroTable[op.Name]; var macroArgs = new DotList() { Expressions = args.ToLinkedList() }; return(Expand(macro.Call(macroArgs), topLevel)); } } l.Expressions = l.Expressions .Select(exp => Expand(exp, false)) .ToLinkedList(); return(l); }
public static DotBool ToDotBool(this bool val) { return(val ? DotBool.True() : DotBool.False()); }