Beispiel #1
0
        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);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
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));
        }
Beispiel #4
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));
        }