// **************************************************************** // *** Test Functions // **************************************************************** // Returns true if the script executes successfully and returns expectedValue. // If expectedValue is null, then the return value is ignored and simply returns // true if there are no other errors. public bool RunTest(string script, object expectedValue, bool verbose = false) { if (verbose) { Log("-> " + script); } List <ParseErrorInst> errors = new List <ParseErrorInst>(); IExpr expr = _Parse(_GetScriptNameFromScript(script), script, ref errors, verbose, false); if (errors.Count > 0) { if (!verbose) { Log("-> " + script); } if (verbose) { if (null == expr) { LogError("Parse failed."); } else { LogError("Parse = " + expr.MyToString("")); } } return(false); } object actualValue = null; if (null != expr) { ScriptResult result; try { result = _EvaluateExpression(expr, false); } catch (Exception e) { if (!verbose) { Log("-> " + script); } LogError(script + "\n Unhandled exception evaluating script: " + e.ToString()); LogError("Parse = " + expr.MyToString("")); return(false); } if (!result.success) { LogError("Parse = " + expr.MyToString("")); return(false); } actualValue = result.value; } if (expectedValue is int) { expectedValue = Convert.ToDouble(expectedValue); } if (actualValue == null) { if (expectedValue == null) { return(true); } if (!verbose) { Log("-> " + script); } LogError("Parse = " + (null == expr ? "null" : expr.MyToString(""))); LogError("Test result is null."); return(false); } else if (actualValue is Exception) { if (!verbose) { Log("-> " + script); } LogError("Parse = " + expr.MyToString("")); LogError("Test return exception: " + actualValue.ToString()); return(false); } if (expectedValue == null) { return(true); } if (expectedValue is double) { if (!(actualValue is double)) { if (!verbose) { Log("-> " + script); } LogError("Parse = " + expr.MyToString("")); LogError("Test result type (" + actualValue.GetType() + ") is not the expected double."); return(false); } else if ((double)expectedValue != (double)actualValue) { if (!verbose) { Log("-> " + script); } LogError("Parse = " + expr.MyToString("")); LogError("Test result number (" + (double)actualValue + ") doesn't match expected result (" + (double)expectedValue + ")."); return(false); } } else if (expectedValue is string) { if ((string)expectedValue != (string)actualValue) { if (!verbose) { Log("-> " + script); } LogError("Parse = " + expr.MyToString("")); LogError("Test result string (" + (string)actualValue + ") doesn't match expected result (" + (string)expectedValue + ")."); return(false); } } else if (expectedValue is bool) { if ((bool)expectedValue != (bool)actualValue) { if (!verbose) { Log("-> " + script); } LogError("Parse = " + expr.MyToString("")); LogError("Test result bool (" + (bool)actualValue + ") doesn't match expected result (" + (bool)expectedValue + ")."); return(false); } } else { if (!verbose) { Log("-> " + script); } LogError("Parse = " + expr.MyToString("")); LogError("Test result returned unrecognized value type (" + expectedValue.GetType().ToString() + ")"); return(false); } return(true); }
private IExpr _Parse(string scriptName, string s, ref List <ParseErrorInst> errors, bool verbose = false, bool createTempScope = true, bool hardTerminal = false) { errors.Clear(); // Save this for LogCompileErrors. _parseErrors = errors; Buffer buffer = new SimpleBuffer(s); Scanner scanner = new Scanner(buffer); Parser parser = new Parser(scanner); parser.context = defaultContext; parser.scriptName = scriptName; parser.Parse(); if (parser.errors.count > 0) { if (logCompileErrors) { for (int ii = 0; ii < parser.errors.errors.Count; ++ii) { LogError(parser.errors.errors[ii].ToString()); } } errors.AddRange(parser.errors.errors); _parseErrors = null; return(null); } IExpr expr = parser._headExpr; if (null == expr) { // This can happen if, for example, you try to parse ";". // Upon reflection I don't think this should be an error. Maybe someone is // compiling a commented out file. //LogCompileError(ParseErrorType.NullExpression, "Script parses to no expression."); //_parseErrors = null; return(null); } defaultContext.BeginCompile(); bool error = false; if (createTempScope) { if (!defaultContext.stack.PushTerminalScope("<Parse>", defaultContext, hardTerminal)) { LogCompileError(ParseErrorType.StackOverflow, "_Parse: stack overflow"); error = true; } } // This is the first pass through the tree. It is where class expressions can add themselves to the type library. // Because it happens earlier than TypeCheck, it allows for code higher in a file than the class declaration to // use the class. // Note that it is a VERY incomplete pass because the only Expr that calls this function on it's child Exprs is Expr_List. // This is because class declarations can ONLY by at the top level, or within Expr_Lists at the top level. // For example, there's no need for Expr_If to call RegisterType on it's true/false blocks because those (currently) // can never contain Expr_Class'es. if (!error) { expr.RegisterTypes(defaultContext, ref error); } // This is the second pass through the tree. It does virtually all the work. if (!error) { expr.TypeCheck(defaultContext, ref error); } if (verbose && !error) { Log(expr.MyToString("")); } // Restore state always. Parsing should never permanently affect the stack. defaultContext.FinishCompile(error); if (error) { _parseErrors = null; return(null); } _parseErrors = null; return(expr); }