/// <summary> /// Evalues an AST in the environment. /// /// TODO: refactor to move to <see cref="OpenLisp.Core.StaticClasses.CoreNameSpace"/>. /// </summary> /// <param name="abstractSyntaxTree"></param> /// <param name="environment"></param> /// <returns></returns> public static OpenLispVal EvalAst(OpenLispVal abstractSyntaxTree, Env environment) { var key = abstractSyntaxTree as OpenLispSymbol; if (key != null) { return(environment.Get(key)); } var list = abstractSyntaxTree as OpenLispList; if (list == null) { var map = abstractSyntaxTree as OpenLispHashMap; if (map == null) { return(abstractSyntaxTree); } var newDictionary = map.Value.ToDictionary( entry => entry.Key, entry => Eval(entry.Value, environment)); return(new OpenLispHashMap(newDictionary)); } OpenLispList oldList = list; OpenLispList newList = abstractSyntaxTree.ListQ() ? new OpenLispList() : (OpenLispList) new OpenLispVector(); foreach (OpenLispVal movedValue in oldList.Value) { newList.Conj(Eval(movedValue, environment)); } return(newList); }
/// <summary> /// Constructor accepting an outer <see cref="Env"/> with binds and expressions. /// </summary> /// <param name="outer"><see cref="Env"/></param> /// <param name="binds"><see cref="OpenLispList"/></param> /// <param name="expressions"><see cref="OpenLispList"/></param> public Env(Env outer, OpenLispList binds, OpenLispList expressions) { _outer = outer; for (int i = 0; i < binds.Size; i++) { string symbol = ((OpenLispSymbol)binds.Nth(i)).Value; if (symbol == "&") { _data[((OpenLispSymbol)binds.Nth(i + 1)).Value] = expressions.Slice(i); break; } _data[symbol] = expressions.Nth(i); } }
/// <summary> /// Reads an OpenLisp.NET list expression. /// </summary> /// <param name="reader"></param> /// <param name="openLispList"></param> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public static OpenLispVal ReadList(TokensReader reader, OpenLispList openLispList, char start, char end) { string token = reader.Next(); if (token[0] == start) { while ((token = reader.Peek()) != null && token[0] != end) { openLispList.Conj(ReadForm(reader)); } if (token == null) { throw new ParseError("expected '" + end + "', got EOF"); } reader.Next(); return(openLispList); } throw new ParseError("expected '" + start + "'"); }
/// <summary> /// Evaluate an <see cref="OpenLispVal"/> inside an <seealso cref="Env"/>. /// /// The core namespace is defined in <seealso cref="OpenLisp.Core.StaticClasses.CoreNameSpace"/>. /// /// TODO: refactor the switch over treeHeadSymbol. All symbols of the core language should be defined in the same place. /// </summary> /// <param name="originalAbstractSyntaxTree"></param> /// <param name="environment"></param> /// <returns></returns> public static OpenLispVal Eval(OpenLispVal originalAbstractSyntaxTree, Env environment) { while (true) { //Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true)); if (!originalAbstractSyntaxTree.ListQ()) { return(EvalAst(originalAbstractSyntaxTree, environment)); } // apply list OpenLispVal expanded = MacroExpand(originalAbstractSyntaxTree, environment); if (!expanded.ListQ()) { return(expanded); } OpenLispList abstractSyntaxTree = (OpenLispList)expanded; if (abstractSyntaxTree.Size == 0) { return(abstractSyntaxTree); } var treeHead = abstractSyntaxTree[0]; var symbol = treeHead as OpenLispSymbol; String treeHeadSymbol = symbol?.ToString() ?? "__<*fn*>__"; // Let's get alchemical in our metaphors: OpenLispVal caputPrimus; // The First Head. Here's a vector: [1 lol 2 3 apple]. caputPrimus should be: 1. OpenLispVal caputSecundus; // The Second Head. Here's a list: `(1 lol 2 3 apple). caputSecundus should be: lol. OpenLispVal solutio; switch (treeHeadSymbol) { // TODO: extract this switch out of the REPL and consolidate in the core NS. case "def!": caputPrimus = abstractSyntaxTree[1]; caputSecundus = abstractSyntaxTree[2]; solutio = Eval(caputSecundus, environment); environment.Set((OpenLispSymbol)caputPrimus, solutio); return(solutio); case "let*": caputPrimus = abstractSyntaxTree[1]; caputSecundus = abstractSyntaxTree[2]; OpenLispSymbol key; OpenLispVal value; Env letEnvironment = new Env(environment); // TODO: explain ramifications to memory allocation and protection by creating a new Env object this way. for (int i = 0; i < ((OpenLispList)caputPrimus).Size; i += 2) { key = (OpenLispSymbol)((OpenLispList)caputPrimus)[i]; value = ((OpenLispList)caputPrimus)[i + 1]; letEnvironment.Set(key, Eval(value, letEnvironment)); } originalAbstractSyntaxTree = caputSecundus; environment = letEnvironment; break; case "quote": return(abstractSyntaxTree[1]); case "quasiquote": originalAbstractSyntaxTree = QuasiQuote(abstractSyntaxTree[1]); break; case "defmacro!": caputPrimus = abstractSyntaxTree[1]; caputSecundus = abstractSyntaxTree[2]; solutio = Eval(caputSecundus, environment); ((OpenLispFunc)solutio).Macro = true; environment.Set(((OpenLispSymbol)caputPrimus), solutio); return(solutio); case "macroexpand": caputPrimus = abstractSyntaxTree[1]; return(MacroExpand(caputPrimus, environment)); case "try*": try { return(Eval(abstractSyntaxTree[1], environment)); } catch (Exception caught) { if (abstractSyntaxTree.Size <= 2) { throw caught; } OpenLispVal openLispException; caputSecundus = abstractSyntaxTree[2]; OpenLispVal caputSecundusHead = ((OpenLispList)caputSecundus)[0]; if (((OpenLispSymbol)caputSecundusHead).ToString() != "catch*") { throw caught; } var exception = caught as OpenLispException; openLispException = exception != null ? (OpenLispVal)exception.Value #if TRACE : new OpenLispString(caught.StackTrace); #elif !TRACE : new OpenLispString("Stack Trace not yet available in OS."); #endif return(Eval(((OpenLispList)caputSecundus)[2], new Env(environment, ((OpenLispList)caputSecundus).Slice(1, 2), new OpenLispList(openLispException)))); }
/// <summary> /// Initializes a new instance of the <see cref="T:OpenLisp.Core.DataTypes.Concurrent.OpenLispSkipList"/> class. /// </summary> /// <param name="value">Value.</param> public OpenLispSkipList(OpenLispList value) : this(value.Value) { }
/// <summary> /// Reads a hash map using an instance of <see cref="TokensReader"/>. /// </summary> /// <param name="reader"></param> /// <returns></returns> public static OpenLispVal ReadHashMap(TokensReader reader) { OpenLispList openLispList = (OpenLispList)ReadList(reader, new OpenLispList(), '{', '}'); return(new OpenLispHashMap(openLispList)); }
/// <summary> /// pr-str arguments. /// </summary> /// <param name="args"></param> /// <param name="separator"></param> /// <param name="printReadably"></param> /// <returns></returns> public static string PrStrArgs(OpenLispList args, String separator, bool printReadably) { return(Join(args.Value, separator, printReadably)); }