Example #1
0
        /// <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);
        }
Example #2
0
        private static IEnumerable <object> ReplaceSymbolWithValueInExpression(LispVariant symbol, object symbolValue, IEnumerable <object> expression, bool macroArgsReplace, ref bool replacedAnything)
        {
            var ret = new List <object>();

            foreach (var elem in expression)
            {
                // is the current element the symbol which should be replaced? --> Yes
                if (symbol.SymbolCompare(elem))
                {
                    IEnumerable <object> l = symbolValue as IEnumerable <object>;
                    if (l != null && macroArgsReplace)
                    {
                        ret.AddRange(l);
                    }
                    else
                    {
                        ret.Add(symbolValue);
                    }
                    replacedAnything = true;
                }
                // is it an expression? --> recursive call
                else if (LispEnvironment.IsExpression(elem))
                {
                    IEnumerable <object> temp = ReplaceSymbolWithValueInExpression(symbol, symbolValue, LispEnvironment.GetExpression(elem) /*.ToArray()*/, macroArgsReplace, ref replacedAnything);
                    ret.Add(temp);
                }
                // current element is not the symbol which should by replaced !
                else
                {
                    ret.Add(elem);
                }
            }
            return(ret);
        }
Example #3
0
        static private Exception CreateInvalidOperationException(string operation, LispVariant l, LispVariant r)
        {
            var exception = new LispException(string.Format(NoOperatorForTypes, operation, l.Type, r.Type));

            exception.AddTokenInfos(l.Token);
            return(exception);
        }
Example #4
0
 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);
 }
Example #5
0
        private static object ConvertLispVariantListToListIfNeeded(object something)
        {
            LispVariant variant = something as LispVariant;

            if (variant != null && variant.IsList)
            {
                return(variant.ListRef);
            }

            return(something);
        }
Example #6
0
 private static string ExpandItemForContainer(object item)
 {
     if (item is LispVariant)
     {
         LispVariant variant = (LispVariant)item;
         if (variant.IsString)
         {
             return(variant.ToStringDebugger());
         }
     }
     return(item.ToString());
 }
Example #7
0
 /// <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]);
 }
Example #8
0
        private static void UpdateFunctionCache(LispVariant elemAsVariant, object value, bool isFirst)
        {
            LispVariant valueAsVariant = value as LispVariant;

            if (isFirst && elemAsVariant != null && valueAsVariant != null && valueAsVariant.IsFunction)
            {
                //if (elemAsVariant.CachedFunction != null)
                //{
                //    throw new LispException("Cache already set !!!");
                //}
                elemAsVariant.CachedFunction = valueAsVariant;
            }
        }
Example #9
0
        /// <summary>
        /// See interface.
        /// </summary>
        public LispVariant DebuggerLoop(string script, string moduleName, bool tracing = false)
        {
            LispVariant result   = null;
            var         bRestart = true;

            while (bRestart)
            {
                // save the source code if the script is transfered via command line
                if (moduleName == LispUtils.CommandLineModule)
                {
                    CommandLineScript = script;
                }

                var globalScope = LispEnvironment.CreateDefaultScope();
                globalScope.Input    = Input;
                globalScope.Output   = Output;
                globalScope.Debugger = this;

                try
                {
                    result = Lisp.Eval(script, globalScope, moduleName, tracing: tracing);
                    Reset();
                }
                catch (LispStopDebuggerException)
                {
                    bRestart = false;
                }
                catch (Exception exception)
                {
                    Output.WriteLine("\nException: {0}", exception);
                    string stackInfo = exception.Data.Contains(LispUtils.StackInfo) ? (string)exception.Data[LispUtils.StackInfo] : string.Empty;
                    Output.WriteLine("\nStack:\n{0}", stackInfo);
                    bRestart = InteractiveLoop(this, globalScope, startedFromMain: true);
                }

                if (bRestart)
                {
                    Output.WriteLine("restart program");

                    // process empty script --> just start interactive loop
                    if (result == null)
                    {
                        bRestart = InteractiveLoop(this, globalScope, startedFromMain: true);
                    }
                }

                globalScope.Debugger = null;
            }

            return(result);
        }
Example #10
0
        /// <summary>
        /// Resolves the given element in this scope.
        /// </summary>
        /// <param name="elem">The element.</param>
        /// <param name="isFirst">Is the element the first one in the list.</param>
        /// <returns>Resolved value or null</returns>
        public object ResolveInScopes(object elem, bool isFirst)
        {
            object result;

            // try to access the cached function value (speed optimization)
            LispVariant elemAsVariant = elem as LispVariant;

            if (elemAsVariant != null && elemAsVariant.CachedFunction != null)
            {
                return(elemAsVariant.CachedFunction);
            }

            var       name = elem.ToString();
            LispScope foundClosureScope;

            // first try to resolve in this scope
            if (TryGetValue(name, out result))
            {
                UpdateFunctionCache(elemAsVariant, result, isFirst);
            }
            // then try to resolve in global scope
            else if (GlobalScope != null &&
                     GlobalScope.TryGetValue(name, out result))
            {
                UpdateFunctionCache(elemAsVariant, result, isFirst);
            }
            // then try to resolve in closure chain scope(s)
            else if (IsInClosureChain(name, out foundClosureScope, out result))
            {
                UpdateFunctionCache(elemAsVariant, result, isFirst);
            }
            // then try to resolve in scope of loaded modules
            else if (LispEnvironment.IsInModules(name, GlobalScope))
            {
                result = LispEnvironment.GetFunctionInModules(name, GlobalScope);
            }
            else
            {
                // activate this code if symbols must be resolved in parameter evaluation --> (println blub)
                //if (elemAsVariant != null && elemAsVariant.IsSymbol && name != "fuellib")
                //{
                //    throw new LispException($"Could not resolve symbol {name}");
                //}
                result = elem;
            }

            return(result);
        }
Example #11
0
 public static bool EqualOp(LispVariant l, LispVariant r)
 {
     if (l.IsNativeObject && r.IsNativeObject)
     {
         return(l.NativeObjectValue == r.NativeObjectValue);
     }
     if (l.IsSymbol || r.IsSymbol)
     {
         return(l.IsSymbol && r.IsSymbol && (l.ToString() == r.ToString()));
     }
     if (l.IsBool && r.IsBool)
     {
         return(l.BoolValue == r.BoolValue);
     }
     if (l.IsNil || r.IsNil)
     {
         return(l.IsNil && r.IsNil);
     }
     if (l.IsList && r.IsList)
     {
         return(l.ListValue.SequenceEqual(r.ListValue));
     }
     if (l.IsUndefined || r.IsUndefined)
     {
         return(l.IsUndefined && r.IsUndefined);
     }
     if (l.IsString || r.IsString)
     {
         return(l.ToString() == r.ToString());
     }
     if (l.IsDouble || r.IsDouble)
     {
         return(Math.Abs(l.ToDouble() - r.ToDouble()) < Tolerance);
     }
     if (l.IsInt || r.IsInt)
     {
         return(l.ToInt() == r.ToInt());
     }
     throw CreateInvalidOperationException("==", l, r);
 }
Example #12
0
        /// <summary>
        /// Evals the specified lisp code.
        /// All exceptions will be filtered and an error value will be returned.
        /// </summary>
        /// <param name="lispCode">The lisp code.</param>
        /// <param name="moduleName">The current module name.</param>
        /// <param name="verboseErrorOutput">if set to <c>true</c> [verbose error output].</param>
        /// <param name="tracing">if set to <c>true</c> [tracing].</param>
        /// <param name="onlyMacroExpand">if set to <c>true</c> [macro expanding].</param>
        /// <returns>The result</returns>
        public static LispVariant SaveEval(string lispCode, string moduleName = null, bool verboseErrorOutput = false, bool tracing = false, bool onlyMacroExpand = false)
        {
            LispVariant result;

            try
            {
                result = Eval(lispCode, scope: null, moduleName: moduleName, tracing: tracing, onlyMacroExpand: onlyMacroExpand);
            }
            catch (Exception exc)
            {
                Console.WriteLine("\nError executing script.\n\n{0} --> line={1} start={2} stop={3} module={4}", exc.Message, exc.Data[LispUtils.LineNo], exc.Data[LispUtils.StartPos], exc.Data[LispUtils.StopPos], exc.Data[LispUtils.ModuleName]);
                var stackInfo = exc.Data[LispUtils.StackInfo];
                Console.WriteLine("\nCallstack:\n{0}", stackInfo != null ? stackInfo : "<not available>");
                if (verboseErrorOutput)
                {
                    Console.WriteLine("\nNative callstack:");
                    Console.WriteLine("Exception in eval(): {0} \ndata={1}", exc, exc.Data);
                }
                result = LispVariant.CreateErrorValue(exc.Message);
            }
            return(result);
        }
Example #13
0
        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);
        }
Example #14
0
        private static int ParseTokens(string moduleName, IList <LispToken> tokens, int startIndex, ref object parseResult, bool isToplevel)
        {
            int           i;
            List <object> current   = null;
            var           listStack = new Stack <List <object> >();

            for (i = startIndex; i < tokens.Count; i++)
            {
                LispToken token = tokens[i];
                if (token.Type == LispTokenType.ListStart)
                {
                    current = new List <object>();
                    listStack.Push(current);
                }
                else if (token.Type == LispTokenType.ListEnd)
                {
                    var temp = current;
                    listStack.Pop();
                    if (listStack.Count > 0)
                    {
                        listStack.Peek().Add(temp);
                        current = listStack.Peek();
                    }
                    else
                    {
                        if (isToplevel && i + 1 < tokens.Count && !OnlyCommentTokensFrom(tokens, i + 1))
                        {
                            throw new LispException(BracketsOutOfBalanceOrUnexpectedScriptCode, token, moduleName);
                        }
                        parseResult = current;
                        return(i);
                    }
                }
                else if (token.Type == LispTokenType.Quote || token.Type == LispTokenType.QuasiQuote)
                {
                    var quote = new List <object>();
                    quote.Add(new LispVariant(LispType.Symbol, token.Type == LispTokenType.Quote ? LispEnvironment.Quote : LispEnvironment.Quasiquote));

                    object quotedList = null;
                    i = ParseTokens(moduleName, tokens, i + 1, ref quotedList, isToplevel: false);
                    quote.Add(quotedList);

                    if (current != null)
                    {
                        current.Add(quote);
                    }
                }
                else if (token.Type == LispTokenType.UnQuote || token.Type == LispTokenType.UnQuoteSplicing)
                {
                    var unquote = new List <object>();
                    LispUnQuoteModus unquotedModus = token.Type == LispTokenType.UnQuote ? LispUnQuoteModus.UnQuote : LispUnQuoteModus.UnQuoteSplicing;
                    unquote.Add(new LispVariant(LispType.Symbol, token.Type == LispTokenType.UnQuote ? LispEnvironment.UnQuote : LispEnvironment.UnQuoteSplicing));

                    object quotedList = null;
                    i = ParseTokens(moduleName, tokens, i + 1, ref quotedList, isToplevel: false);
                    unquote.Add(quotedList);

                    if (current != null)
                    {
                        current.Add(unquote);
                    }
                    else
                    {
                        parseResult = unquote;
                        return(i);
                    }
                }
                else if (token.Type == LispTokenType.Comment)
                {
                    // just ignore comment
                }
                else
                {
                    if (!isToplevel && current == null)
                    {
                        parseResult = new LispVariant(token);
                        return(i);
                    }
                    if (current == null)
                    {
                        throw new LispException(UnexpectedToken, token, moduleName);
                    }
                    current.Add(new LispVariant(token));
                }
            }

            if (isToplevel && tokens.Count > 0)
            {
                LispToken token = tokens.Last();
                throw new LispException(BracketsOutOfBalance, token, moduleName);
            }

            parseResult = current;
            return(i);
        }
Example #15
0
        /// <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);
        }
Example #16
0
        /// <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));
        }
Example #17
0
        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));
        }