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 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));
        }