private void DoStepOut(LispScope currentScope) { var currentCallStackSize = currentScope.GetCallStackSize(); IsStopStepFcn = (scope) => currentCallStackSize - 1 >= scope.GetCallStackSize(); IsProgramStop = true; }
private void DoStepOver(LispScope currentScope) { var currentCallStackSize = currentScope.GetCallStackSize(); IsStopStepFcn = (scope) => (currentCallStackSize >= scope.GetCallStackSize()) && !scope.IsInEval; IsProgramStop = true; }
/// <summary> /// Evals the specified lisp code. /// An exception may occure if the lisp code is invalid. /// </summary> /// <param name="lispCode">The lisp code.</param> /// <param name="scope">The scope.</param> /// <param name="moduleName">The module name and path.</param> /// <param name="tracing">if set to <c>true</c> [tracing].</param> /// <param name="onlyMacroExpand">if set to <c>true</c> [macro expanding].</param> /// <param name="nativeItems">The dictionary with native items.</param> /// <returns>The result of the script evaluation</returns> public static LispVariant Eval(string lispCode, LispScope scope = null, string moduleName = null, bool tracing = false, bool onlyMacroExpand = false, Dictionary <string, object> nativeItems = null) { // first create global scope, needed for macro expanding var currentScope = scope ?? LispEnvironment.CreateDefaultScope(); currentScope.ModuleName = moduleName; currentScope.Tracing = tracing; RegisterNativeObjects(nativeItems, currentScope); int offset; string code = LispUtils.DecorateWithBlock(lispCode, out offset); var ast = LispParser.Parse(code, offset, currentScope); #if ENABLE_COMPILE_TIME_MACROS var expandedAst = LispInterpreter.ExpandMacros(ast, currentScope); #else var expandedAst = ast; #endif LispVariant result = null; if (onlyMacroExpand) { result = new LispVariant(expandedAst); } else { result = LispInterpreter.EvalAst(expandedAst, currentScope); } return(result); }
private bool HitsBreakpoint(int lineNo, string moduleName, LispScope scope) { foreach (var breakpoint in Breakpoints) { bool isSameModule = IsSameModule(breakpoint.ModuleName, scope != null ? scope.ModuleName : moduleName); if (isSameModule && (lineNo == breakpoint.LineNo)) { if (breakpoint.Condition.Length > 0 && scope != null) { try { LispVariant result = Lisp.Eval(breakpoint.Condition, scope, scope.ModuleName); return(result.BoolValue); } catch { Output.WriteLine("Error: bad condition for line {0}: {1}", breakpoint.LineNo, breakpoint.Condition); return(false); } } return(true); } } return(false); }
private static string ResolveFunction(object astItem, LispScope globalScope) { LispFunctionWrapper fw = ((LispVariant)globalScope[astItem.ToString()]).FunctionValue; Func <object[], LispScope, LispVariant> func = fw.Function; MethodInfo method = func.Method; return(method.Name); }
/// <summary> /// Initializes a new instance of the <see cref="LispException"/> class. /// </summary> /// <param name="text">The text.</param> /// <param name="scope">The scope.</param> public LispException(string text, LispScope scope = null) : base(text) { if (scope != null) { this.AddModuleNameAndStackInfos(scope.ModuleName, scope.DumpStackToString()); this.AddTokenInfos(scope.CurrentToken); } }
/// <summary> /// See interface. /// </summary> public bool NeedsBreak(LispScope scope, LispBreakpointPosition posInfosOfCurrentAstItem) { if ((IsProgramStop && IsStopStepFcn(scope)) || HitsBreakpoint(posInfosOfCurrentAstItem.Item3, scope.ModuleName, scope)) { IsProgramStop = false; return(true); } return(false); }
private static Tuple <string, string> Compile(object ast, LispScope globalScope, string shift, string saveReturn, string scopeName) { if (ast is IEnumerable <object> ) { return(Compile((IEnumerable <object>)ast, globalScope, string.Empty, saveReturn, scopeName)); } var value = ast as LispVariant; var temp = value != null?value.ToStringCompiler() : ast.ToString(); return(new Tuple <string, string>(temp, string.Empty)); }
public int GetCallStackSize() { LispScope current = this; int i = 0; do { current = current.Previous; i++; } while (current != null); return(i); }
public static object ExpandMacros(object ast, LispScope globalScope) { object result = ast; bool anyMacroReplaced; do { anyMacroReplaced = false; result = ExpandMacros(result, globalScope, ref anyMacroReplaced); } while (anyMacroReplaced); return(result); }
/// <summary> /// Gets the additional arguments from the scope. /// </summary> /// <param name="scope">The scope.</param> /// <returns>The result.</returns> public static object[] GetAdditionalArgs(this LispScope scope) { if (scope.ContainsKey(LispEnvironment.ArgsMeta)) { LispVariant variant = scope[LispEnvironment.ArgsMeta] as LispVariant; if (variant != null) { return(variant.ListValue.ToArray()); } } return(new object[0]); }
/// <summary> /// Initializes a new instance of the <see cref="LispScope"/> class. /// </summary> /// <param name="fcnName">Name of the FCN.</param> /// <param name="globalScope">The global scope.</param> /// <param name="moduleName">The current module name for the scope.</param> public LispScope(string fcnName, LispScope globalScope = null, string moduleName = null) { Name = fcnName; GlobalScope = globalScope ?? this; ModuleName = moduleName; if (ModuleName == null && globalScope != null) { ModuleName = globalScope.ModuleName; } CurrentToken = null; Input = Console.In; Output = Console.Out; }
/// <summary> /// See interface. /// </summary> public void InteractiveLoop(LispScope initialTopScope, IList <object> currentAst = null, bool startedFromMain = false, bool tracing = false) { if (currentAst != null) { var lineNumber = initialTopScope != null ? initialTopScope.CurrentLineNo : -1; var startPos = initialTopScope != null ? initialTopScope.CurrentToken.StartPos : -1; var stopPos = initialTopScope != null ? initialTopScope.CurrentToken.StopPos : -1; var moduleName = initialTopScope != null ? initialTopScope.ModuleName : "?"; var tokenTxt = initialTopScope != null?initialTopScope.CurrentToken.ToString() : "?"; Output.WriteLine("--> " + currentAst[0] + " line=" + lineNumber + " start=" + startPos + " stop=" + stopPos + " module=" + moduleName + " token=" + tokenTxt); } InteractiveLoop(this, initialTopScope, startedFromMain, tracing); }
public string DumpStackToString(int currentLevel = -1) { string ret = string.Empty; LispScope current = this; int i = GetCallStackSize(); do { string currentItem = currentLevel == i ? "-->" : " "; ret = string.Format("{0,3}{1,5} name={2,-35} lineno={3,-4} module={4}\n", currentItem, i, current.Name, current.CurrentLineNo, current.ModuleName) + ret; current = current.Previous; i--; } while (current != null); return(ret); }
/// <summary> /// Determines whether the given name is available in the closure chain. /// </summary> /// <param name="name">The name.</param> /// <param name="closureScopeFound">The closure scope found.</param> /// <param name="value">The found value.</param> /// <returns>True if name was found.</returns> private bool IsInClosureChain(string name, out LispScope closureScopeFound, out object value) { if (ClosureChain != null) { if (ClosureChain.TryGetValue(name, out value)) { closureScopeFound = ClosureChain; return(true); } return(ClosureChain.IsInClosureChain(name, out closureScopeFound, out value)); } closureScopeFound = null; value = null; return(false); }
/// <summary> /// Parses the specified code. /// string ==> List(Tokens) ==> List(object) mit object == List(object), LispVariant(string, int, double, and ==> for unquoting Symbols) /// </summary> /// <param name="code">The code.</param> /// <param name="offset">The position offset.</param> /// <param name="scope">The scope.</param> /// <returns>Abstract syntax tree as container</returns> public static object Parse(string code, int offset = 0, LispScope scope = null) { object parseResult = null; string moduleName = string.Empty; // set tokens at LispScope to improve debugging and // support displaying of error position var tokens = LispTokenizer.Tokenize(code, offset).ToList(); if (scope != null) { scope.Tokens = tokens; moduleName = scope.ModuleName; } ParseTokens(moduleName, tokens, 0, ref parseResult, isToplevel: true); return(parseResult); }
/// <summary> /// Resolves the items of the ast in the given scope. /// </summary> /// <param name="scope"></param> /// <param name="astAsList"></param> /// <param name="compile"></param> /// <returns></returns> public static List <object> ResolveArgsInScopes(LispScope scope, IEnumerable <object> astAsList, bool compile) { var astWithResolvedValues = new List <object>(); var firstElement = astAsList.FirstOrDefault(); bool?isSpecialForm = null; foreach (var elem in astAsList) { object resolvedElem; if ((isSpecialForm != null && (bool)isSpecialForm) || !IsSymbol(elem)) { resolvedElem = elem; } else { resolvedElem = scope.ResolveInScopes(elem, elem == firstElement); } astWithResolvedValues.Add(resolvedElem); if (isSpecialForm == null) { var firstElem = new LispFunctionWrapper(); object first = null; try { first = astWithResolvedValues.First(); firstElem = ((LispVariant)first).FunctionValue; } catch (LispException) { if (!compile) { throw new LispException("Function \"" + first + "\" not found", scope); } } isSpecialForm = firstElem.IsSpecialForm; } } return(astWithResolvedValues); }
private static IEnumerable <object> ReplaceFormalArgumentsInExpression(IEnumerable <object> formalArguments, IList <object> astAsList, IEnumerable <object> expression, LispScope scope, ref bool anyMacroReplaced) { // replace (quoted-macro-args) --> '(<real_args>) int i = 1; bool replaced = false; IEnumerable <object> realArguments = astAsList.Skip(1).ToList(); List <object> quotedRealArguments = new List <object>() { new LispVariant(LispType.Symbol, LispEnvironment.Quote), realArguments }; expression = ReplaceSymbolWithValueInExpression(new LispVariant(LispType.Symbol, "quoted-macro-args"), quotedRealArguments, expression, true, ref replaced); foreach (var formalArgument in formalArguments) { object value; if (astAsList[i] is IEnumerable <object> ) { value = ExpandMacros(astAsList[i], scope, ref anyMacroReplaced); if (value is LispVariant) { var vairantValue = value as LispVariant; if (vairantValue.IsList) { value = vairantValue.ListValue; } } } else { value = new LispVariant(astAsList[i]); } expression = ReplaceSymbolWithValueInExpression((LispVariant)formalArgument, value, expression, false, ref anyMacroReplaced); i++; } return(expression); }
private static object ExpandMacros(object ast, LispScope globalScope, ref bool anyMacroReplaced) { if (ast == null || ast is LispVariant) { return(ast); } var astAsList = ((IEnumerable <object>)ast).ToList(); if (astAsList.Count == 0) { return(ast); } // compile time macro: process define-macro statements ==> call special form, this will add macro to global scope as side effect var function = astAsList.First(); var functionName = function.ToString(); if (globalScope != null && globalScope.ContainsKey(functionName)) { var fcn = ((LispVariant)globalScope[functionName]).FunctionValue; if (fcn.IsEvalInExpand) { var args = new List <object>(astAsList); args.RemoveAt(0); // process compile time macro definition // --> side effect: add macro definition to internal macro scope fcn.Function(args.ToArray(), globalScope); // compile time macros definitions will be removed from code in expand macro phase // because only the side effect above is needed for further macro replacements return(null); } } // compile time macros: process macro expansion in an expression which calls a macro if (LispEnvironment.IsMacro(function, globalScope)) { var macro = LispEnvironment.GetMacro(function, globalScope); if (macro is LispMacroCompileTimeExpand) { anyMacroReplaced = true; var macroExpand = (LispMacroCompileTimeExpand)macro; var astWithReplacedArguments = ReplaceFormalArgumentsInExpression(macroExpand.FormalArguments, astAsList, macroExpand.Expression, globalScope, ref anyMacroReplaced).ToList(); // PATCH // process recursive macro expands (do not wrap list as LispVariant at this point) return(ConvertLispVariantListToListIfNeeded(EvalAst(astWithReplacedArguments, globalScope))); } } var expandedAst = new List <object>(); // Expand recursively and handle enumarations (make them flat !) foreach (var elem in astAsList) { var expandResult = ExpandMacros(elem, globalScope); // ignore code which is removed in macro expand phase if (expandResult != null) { // process recursive macro expands (do not wrap list as LispVariant at this point) expandedAst.Add(ConvertLispVariantListToListIfNeeded(expandResult)); } } return(expandedAst); }
private static void RegisterNativeObjects(Dictionary <string, object> nativeItems, LispScope currentScope) { if (nativeItems != null) { foreach (KeyValuePair <string, object> item in nativeItems) { currentScope[item.Key] = new LispVariant(LispType.NativeObject, item.Value); } } }
public void PushNextScope(LispScope nextScope) { Next = nextScope; nextScope.Previous = this; }
private static Tuple <string, string> Compile(IEnumerable <object> ast, LispScope globalScope, string shift, string saveReturn, string scopeName) { string code = string.Empty; string functions = string.Empty; var astWithResolvedValues = LispInterpreter.ResolveArgsInScopes(globalScope, ast, true); // do --> sequence, d. h. ignorieren // defn --> funktion deklarieren // def --> variable deklarieren ==> LispVariant a = value; // quote // setf --> variable zuweisen // while // lambda // if // weitere special forms speziell behandeln... // --> and, or, apply, quasiquote, definemacro object first = null; string args = string.Empty; string separator = ", "; string closeStatement = ""; for (int i = 0; i < astWithResolvedValues.Count; i++) { var elem = astWithResolvedValues[i]; if (first == null) { first = elem; var func = (LispVariant)first; if (func.IsSymbol) { // process normal function call string cast = GetFunctionCast(astWithResolvedValues.Count - i - 1); code += shift + "/*local_func*/((" + cast + ")" + ast.First() + ")("; separator = ", "; closeStatement = ", " + scopeName + ")"; } else { LispFunctionWrapper function = ((LispVariant)first).FunctionValue; if (function.Function == LispEnvironment.def_form) { var compileResult = Compile(astWithResolvedValues[i + 2], globalScope, string.Empty, null, scopeName); // TODO --> ggf. nur einfache datentypen dekorieren !? siehe bei arg code += shift + "/*def_form*/LispVariant " + astWithResolvedValues[i + 1] + " = new LispVariant( (object)" + compileResult.Item1 + ")"; functions += compileResult.Item2; separator = ""; closeStatement = ""; i += 2; } else if (function.Function == LispEnvironment.defn_form) { // process normal function call functions += shift + "/*defn*/private static LispVariant " + astWithResolvedValues[i + 1] + "("; var argStrg = string.Empty; foreach (var arg in (IEnumerable <object>)astWithResolvedValues[i + 2]) { if (argStrg.Length > 0) { argStrg += ", "; } argStrg += "LispVariant " + arg; } functions += argStrg + ", LispScope " + scopeName + ")\n"; functions += shift + "{\n"; functions += shift + "LispVariant __return__;\n"; functions += Compile(astWithResolvedValues[i + 3], globalScope, string.Empty, "__return__", scopeName).Item1; functions += shift + ";\n"; functions += shift + "\nreturn __return__;\n"; functions += shift + "}\n"; separator = ""; closeStatement = ""; i += 3; } else if (function.Function == LispEnvironment.quote_form) { // (quote (1 2 3)) --> new object[] { 1, 2, 3 } // (quote 'something) --> new LispVariant(LispType.Symbol, "something") code += "/*quote*/new object[] { "; var temp = string.Empty; if (astWithResolvedValues[i + 1] is IEnumerable <object> ) { var aList = (IEnumerable <object>)astWithResolvedValues[i + 1]; foreach (var item in aList) { if (temp.Length > 0) { temp += ", "; } temp += "new LispVariant( "; temp += Compile(item, globalScope, string.Empty, null, scopeName).Item1; temp += " )"; } } else { LispVariant variant = (LispVariant)astWithResolvedValues[i + 1]; temp += "new LispVariant( LispType.Symbol, \""; temp += variant.ToString(); temp += "\" )"; } code += temp + " }"; i++; } else if (function.Function == LispEnvironment.quasiquote_form) { // (quasiquote (1 2 3 ,a)) --> new object[] { 1, 2, 3, 42 } // TODO korrekt implementieren !!! code += "/*quasiquote*/new object[] { "; var aList = (IEnumerable <object>)astWithResolvedValues[i + 1]; var temp = string.Empty; foreach (var item in aList) { if (temp.Length > 0) { temp += ", "; } temp += "new LispVariant( "; temp += Compile(item, globalScope, string.Empty, null, scopeName).Item1; temp += " )"; } code += temp + " }"; i++; } else if (function.Function == LispEnvironment.do_form) { // process do_form separator = "\n"; closeStatement = ""; int j; string temp = "{ /*do*/\n"; for (j = i + 1; j < astWithResolvedValues.Count; j++) { var compileResult = Compile(astWithResolvedValues[j], globalScope, shift, saveReturn, scopeName); functions += compileResult.Item2; temp += compileResult.Item1; if (temp.Length > 0) { temp += ";\n"; } } i = j; code += temp + "/*do*/ }\n"; } else if (function.Function == LispEnvironment.if_form) { code += "if( "; code += Compile(astWithResolvedValues[i + 1], globalScope, string.Empty, null, scopeName).Item1; code += ".ToBool() )\n{\n"; code += Compile(astWithResolvedValues[i + 2], globalScope, " ", null, scopeName).Item1; code += ";\n}\n"; if (astWithResolvedValues.Count > i + 3) { code += "else\n{\n"; code += Compile(astWithResolvedValues[i + 3], globalScope, " ", null, scopeName).Item1; code += ";\n}\n"; i += 3; } else { i += 2; } } else if (function.Function == LispEnvironment.while_form) { code += "while( "; code += Compile(astWithResolvedValues[i + 1], globalScope, string.Empty, null, scopeName).Item1; code += ".ToBool() )\n{\n"; code += Compile(astWithResolvedValues[i + 2], globalScope, " ", null, scopeName).Item1; code += ";}\n"; i += 2; } else if (function.Function == LispEnvironment.setf_form) { code += Compile(astWithResolvedValues[i + 1], globalScope, string.Empty, null, scopeName).Item1; code += " = new LispVariant("; code += Compile(astWithResolvedValues[i + 2], globalScope, string.Empty, null, scopeName).Item1; code += ")"; i += 2; } else if (function.Function == LispEnvironment.fn_form) { code += "/*fn*/new LispVariant( LispType.Function, new LispFunctionWrapper( ("; var argNames = (IEnumerable <object>)astWithResolvedValues[i + 1]; var temp = string.Empty; foreach (var name in argNames) { if (temp.Length > 0) { temp += ", "; } temp += "LispVariant " + name; } code += temp; code += ", LispScope _scope) => { LispVariant __ret__; "; code += Compile(astWithResolvedValues[i + 2], globalScope, string.Empty, "__ret__", "_scope").Item1; code += "; return __ret__; }, /*signature*/string.Empty, /*documentation*/string.Empty, false ) )"; i += 2; } else { // process normal function call code += shift; if (!string.IsNullOrEmpty(saveReturn)) { code += saveReturn + " = "; } code += "/*func*/LispEnvironment." + ResolveFunction(ast.First(), globalScope) + "( new object[] { "; separator = ", "; closeStatement = " }, " + scopeName + ")"; } } } else { if (args.Length > 0) { args += separator; } if (elem is IEnumerable <object> ) { var compileResult = Compile((IEnumerable <object>)elem, globalScope, shift, saveReturn, scopeName); args += compileResult.Item1; functions += compileResult.Item2; } else { // decorate simple data types with LispVariant var temp = (LispVariant)elem; var elemType = temp.Type; if (elemType == LispType.Bool || elemType == LispType.Int || elemType == LispType.Double || elemType == LispType.String) { args += "/*arg*/new LispVariant( (object)" + temp.ToStringCompiler() + " )"; } else { args += "/*arg*/" + elem; } } } } code += args + closeStatement; return(new Tuple <string, string>(code, functions)); }
/// <summary> /// Processing of the interactive loop of the debugger. /// </summary> /// <param name="debugger">The debugger.</param> /// <param name="initialTopScope">The initial top scope.</param> /// <param name="startedFromMain">if set to <c>true</c> [started from main].</param> /// <param name="tracing">if set to <c>true</c> tracing is enabled.</param> /// <returns>True if program should be restarted.</returns> /// <exception cref="LispStopDebuggerException"></exception> /// <exception cref="CsLisp.LispStopDebuggerException"></exception> public static bool InteractiveLoop(LispDebugger debugger = null, LispScope initialTopScope = null, bool startedFromMain = false, bool tracing = false) { string interactiveScript = string.Empty; startedFromMain = startedFromMain || debugger == null; if (debugger == null) { debugger = new LispDebugger(); } var globalScope = initialTopScope != null ? initialTopScope.GlobalScope : LispEnvironment.CreateDefaultScope(); // do not switch off tracing if already enabled if (!globalScope.Tracing) { globalScope.Tracing = tracing; } var topScope = initialTopScope != null ? initialTopScope : globalScope; var currentScope = topScope; var bContinueWithNextStatement = false; var bRestart = false; do { debugger.Output.Write(debugger != null ? DbgPrompt : Prompt); // Warning: // QProcess and .NET >3.5 does not work correclty reading from input !!! // see: http://www.qtcentre.org/threads/62415-QProcess-not-communicating-with-net-framework-gt-3-5 // ==> CsLisp is now using .NET 3.5 ! var cmd = debugger.Input.ReadLine(); cmd = cmd != null?cmd.Trim() : null; if (cmd == null || cmd.Equals("exit") || cmd.Equals("quit") || cmd.Equals("q")) { bContinueWithNextStatement = true; bRestart = false; if (!startedFromMain) { throw new LispStopDebuggerException(); } } else if (cmd.Equals("help") || cmd.Equals("h")) { ShowInteractiveCmds(debugger.Output); } else if (cmd.Equals("about")) { LispUtils.ShowAbout(debugger.Output); } else if (cmd.Equals("funcs")) { globalScope.DumpFunctions(); } else if (cmd.Equals("macros")) { globalScope.DumpMacros(); } else if (cmd.Equals("builtins")) { globalScope.DumpBuiltinFunctions(); } else if (cmd.StartsWith("doc")) { var items = cmd.Split(' '); if (items.Length > 1) { string docCmd = "(doc '" + items[1] + ")"; LispVariant result = Lisp.Eval(docCmd, currentScope, currentScope.ModuleName); debugger.Output.WriteLine("{0}", result); } else { globalScope.DumpBuiltinFunctionsHelp(); } } else if (cmd.StartsWith("searchdoc")) { var items = cmd.Split(' '); if (items.Length > 1) { string docCmd = "(searchdoc '" + items[1] + ")"; LispVariant result = Lisp.Eval(docCmd, currentScope, currentScope.ModuleName); debugger.Output.WriteLine("{0}", result); } else { globalScope.DumpBuiltinFunctionsHelp(); } } else if (cmd.Equals("modules")) { globalScope.DumpModules(); } else if (cmd.StartsWith("clear")) { ClearBreakpoints(debugger, cmd); } else if (cmd.Equals("stack") || cmd.StartsWith("k")) { topScope.DumpStack(currentScope.GetCallStackSize()); } else if (cmd.Equals("code") || cmd.StartsWith("c")) { var script = string.Empty; var moduleName = currentScope.ModuleName; if (moduleName == null) { script = interactiveScript; } else { script = moduleName.StartsWith(LispEnvironment.EvalStrTag) ? moduleName.Substring(LispEnvironment.EvalStrTag.Length + moduleName.IndexOf(":", LispEnvironment.EvalStrTag.Length)) : LispUtils.ReadFileOrEmptyString(moduleName); } // use the script given on command line if no valid module name was set if (string.IsNullOrEmpty(script)) { script = debugger.CommandLineScript; } ShowSourceCode(debugger, script, currentScope.ModuleName, currentScope.CurrentLineNo); } else if (cmd.StartsWith("list") || cmd.StartsWith("t")) { debugger.ShowBreakpoints(); } else if (cmd.StartsWith("break ") || cmd.StartsWith("b ")) { AddBreakpoint(debugger, cmd, currentScope.ModuleName); } else if (cmd.Equals("up") || cmd.StartsWith("u")) { if (currentScope.Next != null) { currentScope = currentScope.Next; } } else if (cmd.Equals("down") || cmd.StartsWith("d")) { if (currentScope.Previous != null) { currentScope = currentScope.Previous; } } else if (cmd.Equals("step") || cmd.Equals("s")) { debugger.DoStep(currentScope); bContinueWithNextStatement = true; } else if (cmd.Equals("over") || cmd.Equals("v")) { debugger.DoStepOver(currentScope); bContinueWithNextStatement = true; } else if (cmd.Equals("out") || cmd.Equals("o")) { debugger.DoStepOut(currentScope); bContinueWithNextStatement = true; } else if (cmd.Equals("run") || cmd.Equals("r")) { debugger.DoRun(); bContinueWithNextStatement = true; } else if (cmd.Equals("locals") || cmd.StartsWith("l")) { currentScope.DumpVars(); } else if (cmd.Equals("globals") || cmd.StartsWith("g")) { globalScope.DumpVars(); } else if (cmd.Equals("restart")) { bContinueWithNextStatement = true; bRestart = true; } else if (cmd.Equals("version") || cmd.Equals("ver")) { LispUtils.ShowVersion(debugger.Output); } else { try { LispVariant result = Lisp.Eval(cmd, currentScope, currentScope.ModuleName); debugger.Output.WriteLine("result={0}", result); interactiveScript += cmd + '\n'; } catch (Exception ex) { debugger.Output.WriteLine("Exception: " + ex.Message); } } } while (!bContinueWithNextStatement); return(bRestart); }
/// <summary> /// Evaluates the given ast. /// </summary> /// <param name="ast">The ast.</param> /// <param name="scope">The scope.</param> /// <returns>The result of ast evaluation.</returns> /// <exception cref="System.Exception">Unexpected macro modus!</exception> public static LispVariant EvalAst(object ast, LispScope scope) { if (ast == null) { return(null); } IList <object> astAsList; if (ast is LispVariant) { var item = (LispVariant)ast; // evaluate the value for the symbol if (item.IsSymbol) { item = new LispVariant(scope.ResolveInScopes(item, false)); return(item); } else if (item.IsList && !item.IsNil) { astAsList = item.ListValue.ToList(); } else { return(item); } } else { astAsList = ((IEnumerable <object>)ast).ToList(); } if (astAsList.Count == 0) { return(new LispVariant(LispType.Nil)); } // is this function a macro ==> process the macro and return if (LispEnvironment.IsMacro(astAsList.First(), scope.GlobalScope)) { // check the macro modus: evaluate or expand or lambda var macro = LispEnvironment.GetMacro(astAsList.First(), scope.GlobalScope); // evaluate macro at run time: if (macro is LispMacroRuntimeEvaluate) { // Example for macro at runtime handling: // // macro definition: // (define-macro-eval my-setf (x value) (setf x value)) // // call (ast): // (my-setf a (+ \"blub\" \"xyz\")) // | | // v v // x value // // Result: // (setf a (+ \"blub\" \"xyz\")) <-- replace formal arguments (as symbol) bool anyMacroReplaced = false; var runtimeMacro = (LispMacroRuntimeEvaluate)macro; var expression = ReplaceFormalArgumentsInExpression(runtimeMacro.FormalArguments, astAsList, runtimeMacro.Expression, scope, ref anyMacroReplaced); return(EvalAst(expression, scope)); } // expand macro at compile time: --> nothing to do at run time ! // code not needed, because code for compile time macros will be removed in ExpandMacro phase //if (macro is LispMacroCompileTimeExpand) //{ // return new LispVariant(); //} throw new Exception("Unexpected macro modus!"); } // for debugging: update the current line number at the current scope var currentToken = ((LispVariant)(astAsList.First())).Token; scope.CurrentToken = currentToken != null ? currentToken : scope.CurrentToken; // resolve values via local and global scope var astWithResolvedValues = ResolveArgsInScopes(scope, astAsList, false); // get first element --> this is the function ! var function = astWithResolvedValues.First(); // normal evaluation... LispFunctionWrapper functionWrapper = ((LispVariant)function).FunctionValue; // trace current function (if tracing is enabled) if (scope.GlobalScope.Tracing) { scope.GlobalScope.Output.WriteLine("--> {0}", astAsList.First()); } // evaluate arguments, but allow recursive lists var arguments = new object[astWithResolvedValues.Count - 1]; for (var i = 1; i < arguments.Length + 1; i++) { //var asContainer = LispUtils.GetAsContainer(astWithResolvedValues[i]); //var needEvaluation = (asContainer != null) && !functionWrapper.IsSpecialForm; //arguments[i - 1] = needEvaluation ? EvalAst(asContainer, scope) : astWithResolvedValues[i]; var needEvaluation = (astWithResolvedValues[i] is IEnumerable <object>) && !functionWrapper.IsSpecialForm; var result = needEvaluation ? EvalAst(astWithResolvedValues[i], scope) : astWithResolvedValues[i]; // process statemens like this: `,@l with l = (1 2 3) LispVariant variant = result as LispVariant; if (variant != null) { if (variant.IsUnQuoted == LispUnQuoteModus.UnQuoteSplicing && variant.IsList) { var lst = variant.ListRef; var newArguments = new object[arguments.Length + lst.Count - 1]; arguments.CopyTo(newArguments, 0); foreach (var elem in lst) { newArguments[i - 1] = elem; i++; } arguments = newArguments; break; } } arguments[i - 1] = result; } // debugger processing var debugger = scope.GlobalScope.Debugger; if (debugger != null && debugger.NeedsBreak(scope, GetPosInfo(astAsList[0]))) { debugger.InteractiveLoop(scope, astAsList); } // call the function with the arguments return(functionWrapper.Function(arguments, scope)); }
// ReSharper disable once UnusedParameter.Local private void DoStep(LispScope currentScope) { IsStopStepFcn = (scope) => true; IsProgramStop = true; }