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