internal ScriptContext(ScriptProcessor processor, ScriptContext parent) { _processor = processor; Parent = parent; This = parent != null ? parent.This : new GlobalContextObject(this); }
private SObject ExecuteAsync(ScriptStatement statement) { // statement inside async block gets executed in its own thread. // cannot rely on any variables from outside being set on time. string taskName = statement.Code.Remove(0, statement.Code.IndexOf("(") + 1); taskName = taskName.Remove(taskName.LastIndexOf(")")).Trim(); if (string.IsNullOrWhiteSpace(taskName)) taskName = Guid.NewGuid().ToString(); _index++; var nextStatement = _statements[_index]; var processor = new ScriptProcessor(Context, GetLineNumber()); lock (Context.AsyncTasks) Context.AsyncTasks.Add(taskName); Console.WriteLine($"Start async task ({taskName})"); Task.Run(() => { processor.ExecuteStatement(nextStatement); lock (Context.AsyncTasks) Context.AsyncTasks.Remove(taskName); }); return Undefined; }
static void Main(string[] args) { bool exit = false; var processor = new ScriptProcessor(); while (!exit) { Console.Write("< "); string input = Console.ReadLine(); var result = processor.Run(input); if (result.TypeOf() == Types.SObject.LITERAL_TYPE_ERROR) { Console.ForegroundColor = ConsoleColor.Red; Types.SError error = (Types.SError)result; Console.WriteLine("x " + ((Types.SString)error.Members["type"].Data).Value + ": " + ((Types.SString)error.Members["message"].Data).Value); Console.ForegroundColor = ConsoleColor.White; } else { Console.ForegroundColor = ConsoleColor.Gray; Console.WriteLine("> " + result.ToScriptSource()); Console.ForegroundColor = ConsoleColor.White; } } }
/// <summary> /// Creates a new <see cref="ScriptProcessor"/> and runs the provided source code. /// </summary> internal static ScriptProcessor GetRun(string source) { var processor = new ScriptProcessor(); processor.Run(source); return processor; }
private static ScriptProcessor CreateProcessor() { var processor = new ScriptProcessor(_prototypeBuffer); ScriptContextManipulator.SetCallbackExecuteMethod(processor, ExecuteMethod); return processor; }
public static SObject getEntity(ScriptProcessor processor, SObject[] parameters) { object[] netObjects; if (EnsureTypeContract(parameters, new[] { typeof(string) }, out netObjects)) { var entity = new EntityWrapper {id = (string)netObjects[0]}; return ScriptInAdapter.Translate(processor, entity); } return ScriptInAdapter.GetUndefined(processor); }
public static SObject Eval(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) return processor.Undefined; string code; if (parameters[0] is SString) code = ((SString)parameters[0]).Value; else code = parameters[0].ToString(processor).Value; var evalProcessor = new ScriptProcessor(processor.Context); return evalProcessor.Run(code); }
public static SObject ToComplex(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) return processor.Undefined; if (parameters[0] is SString) return processor.Context.CreateInstance("String", new SObject[] { parameters[0] }); else if (parameters[0] is SNumber) return processor.Context.CreateInstance("Number", new SObject[] { parameters[0] }); else if (parameters[0] is SBool) return processor.Context.CreateInstance("Boolean", new SObject[] { parameters[0] }); else return parameters[0]; // returns the input object, if no conversion was conducted. }
private static void InitializePrototypeBuffer() { // load all defined prototypes once to store them in a buffer. // these prototypes get added to all newly created ScriptProcessors. _prototypeBuffer = new List<SObject>(); var processor = new ScriptProcessor(); foreach (var assembly in GetSourceAssemblies()) { foreach (var t in assembly.GetTypes().Where(t => t.GetCustomAttributes(typeof(ScriptPrototypeAttribute), true).Length > 0)) _prototypeBuffer.Add(ScriptInAdapter.Translate(processor, t)); } }
public static SObject load(ScriptProcessor processor, SObject[] parameters) { object[] netObjects; if (EnsureTypeContract(parameters, new[] { typeof(string), typeof(Vector3Wrapper) }, out netObjects)) { var screen = (OverworldScreen)GameProvider.GameInstance.GetService<ScreenManager>().CurrentScreen; var position = netObjects[1] as Vector3Wrapper; if (position != null) screen.ActiveWorld.LoadMap(netObjects[0] as string, position.X, position.Y, position.Z); } return ScriptInAdapter.GetUndefined(processor); }
public static SObject NameOf(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) return processor.Undefined; if (parameters[0] is SProtoObject) { var protoObj = (SProtoObject)parameters[0]; return processor.CreateString(protoObj.IsProtoInstance ? protoObj.Prototype.Name : protoObj.TypeOf()); } else { return processor.CreateString(parameters[0].TypeOf()); } }
private static SObject ExecuteMethod(ScriptProcessor processor, string className, string methodName, SObject[] parameters) { if (_apiClasses.ContainsKey(className)) { var method = _apiClasses[className].FirstOrDefault(m => m.Name == methodName); if (method != null) { var result = method.Invoke(null, new object[] { processor, parameters }); return (SObject)result; } } // fallback, in case no class/method was found: return ScriptInAdapter.GetUndefined(processor); }
public static SObject NameOf(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) { return(processor.Undefined); } if (parameters[0] is SProtoObject) { var protoObj = (SProtoObject)parameters[0]; return(processor.CreateString(protoObj.IsProtoInstance ? protoObj.Prototype.Name : protoObj.TypeOf())); } else { return(processor.CreateString(parameters[0].TypeOf())); } }
public static SObject show(ScriptProcessor processor, SObject[] parameters) { object[] netObjects; if (EnsureTypeContract(parameters, new[] { typeof(string) }, out netObjects)) { var text = (string)netObjects[0]; var screen = (OverworldScreen)GameProvider.GameInstance.GetService<ScreenManager>().CurrentScreen; var uiElement = new MessageOverworldUIElement(text); screen.AddUiElement(uiElement); uiElement.IsActive = true; BlockThreadUntilCondition(() => !uiElement.IsActive); screen.RemoveUiElement(uiElement); } return ScriptInAdapter.GetUndefined(processor); }
public static SObject IsFinite(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) { return(processor.Undefined); } double dbl; if (parameters[0] is SNumber) { dbl = ((SNumber)parameters[0]).Value; } else { dbl = parameters[0].ToNumber(processor).Value; } return(processor.CreateBool(!(double.IsNaN(dbl) || double.IsInfinity(dbl)))); }
public static SObject DoSync(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { string[] tasks = processor.Context.Parent.AsyncTasks.ToArray(); if (parameters.Length >= 1) { var param = SObject.Unbox(parameters[0]); if (param is SString) { tasks = new[] { (param as SString).Value } } ; else if (param is SArray) { tasks = (param as SArray).ArrayMembers.Select(m => m.ToString(processor).Value).ToArray(); } } Console.WriteLine($"Sync tasks: ({string.Join(",", tasks)})"); SpinWait.SpinUntil(() => tasks.All(t => !processor.Context.Parent.AsyncTasks.Contains(t))); return(processor.Undefined); }
public static SObject Eval(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) { return(processor.Undefined); } string code; if (parameters[0] is SString) { code = ((SString)parameters[0]).Value; } else { code = parameters[0].ToString(processor).Value; } var evalProcessor = new ScriptProcessor(processor.Context); return(evalProcessor.Run(code)); }
public static SObject ToPrimitive(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) { return(processor.Undefined); } if (parameters[0] is SString) { return(processor.CreateString(((SString)parameters[0]).Value)); } else if (parameters[0] is SNumber) { return(processor.CreateNumber(((SNumber)parameters[0]).Value)); } else if (parameters[0] is SBool) { return(processor.CreateBool(((SBool)parameters[0]).Value)); } else { return(parameters[0]); // returns the input object, if no conversion was conducted. } }
public static SObject ToComplex(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) { return(processor.Undefined); } if (parameters[0] is SString) { return(processor.Context.CreateInstance("String", new SObject[] { parameters[0] })); } else if (parameters[0] is SNumber) { return(processor.Context.CreateInstance("Number", new SObject[] { parameters[0] })); } else if (parameters[0] is SBool) { return(processor.Context.CreateInstance("Boolean", new SObject[] { parameters[0] })); } else { return(parameters[0]); // returns the input object, if no conversion was conducted. } }
private SObject ExecuteExecutable(ScriptStatement statement) { if (statement.IsCompoundStatement) { var processor = new ScriptProcessor(Context, GetLineNumber()); // Remove { and }: var code = statement.Code.Remove(0, 1); code = code.Remove(code.Length - 1, 1); var returnObject = processor.Run(code); _breakIssued = processor._breakIssued; _continueIssued = processor._continueIssued; _returnIssued = processor._returnIssued; return(returnObject); } else { var exp = ResolveParentheses(statement.Code).Trim(); #region QuickConvert // have quick conversions for small statements here // parameter statements are much faster that way: if (exp == SObject.LITERAL_BOOL_TRUE) { return(CreateBool(true)); } else if (exp == SObject.LITERAL_BOOL_FALSE) { return(CreateBool(false)); } else if (exp == SObject.LITERAL_UNDEFINED || exp == "") { return(Undefined); } else if (exp == SObject.LITERAL_NULL) { return(Null); } else if (exp.StartsWith("\"") && exp.EndsWith("\"") && !exp.Remove(exp.Length - 1, 1).Remove(0, 1).Contains("\"")) { return(CreateString(exp.Remove(exp.Length - 1, 1).Remove(0, 1))); } else if (exp.All(char.IsDigit)) { double num; SNumber.TryParse(exp, out num); return(CreateNumber(num)); } #endregion if (exp.Contains("=>")) { exp = EvaluateLambda(exp); } if (exp.Contains(".")) { exp = EvaluateOperator(exp, "."); } if (exp.Contains("++")) { exp = EvaluateOperator(exp, "++"); } if (exp.Contains("--")) { exp = EvaluateOperator(exp, "--"); } if (exp.Contains("!")) { exp = EvaluateReverseBool(exp); } if (exp.Contains("**")) { exp = EvaluateOperator(exp, "**"); } if (exp.Contains("*")) { exp = EvaluateOperator(exp, "*"); } if (exp.Contains("/")) { exp = EvaluateOperator(exp, "/"); } if (exp.Contains("%")) { exp = EvaluateOperator(exp, "%"); } if (exp.Contains("+")) { exp = EvaluateOperator(exp, "+"); } if (exp.Contains("-")) { exp = EvaluateOperator(exp, "-"); } if (exp.Contains("<=")) { exp = EvaluateOperator(exp, "<="); } if (exp.Contains(">=")) { exp = EvaluateOperator(exp, ">="); } if (exp.Contains("<")) { exp = EvaluateOperator(exp, "<"); } if (exp.Contains(">")) { exp = EvaluateOperator(exp, ">"); } if (exp.Contains("===")) { exp = EvaluateOperator(exp, "==="); } if (exp.Contains("!==")) { exp = EvaluateOperator(exp, "!=="); } if (exp.Contains("==")) { exp = EvaluateOperator(exp, "=="); } if (exp.Contains("!=")) { exp = EvaluateOperator(exp, "!="); } if (exp.Contains("&&")) { exp = EvaluateOperator(exp, "&&"); } if (exp.Contains("||")) { exp = EvaluateOperator(exp, "||"); } return(ToScriptObject(exp)); } }
private SObject ExecuteFor(ScriptStatement statement) { var exp = statement.Code; var forCode = exp.Remove(0, exp.IndexOf("for") + "for".Length).Trim().Remove(0, 1); // Remove "for" and "(". forCode = forCode.Remove(forCode.Length - 1, 1); // Remove ")". var forStatements = StatementProcessor.GetStatements(this, forCode); if (forStatements.Length == 0) return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, ")"); else if (forStatements.Length == 1) return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FOR_INITIALIZER); else if (forStatements.Length == 2) return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FOR_CONDITION); else if (forStatements.Length > 3) return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FOR_CONTROL); var processor = new ScriptProcessor(Context, GetLineNumber()); var forInitializer = forStatements[0]; var forCondition = forStatements[1]; var forControl = forStatements[2]; if (forInitializer.Code.Length > 0) processor.ExecuteStatement(forInitializer); _index++; if (_statements.Length > _index) { var stayInFor = true; var executeStatement = _statements[_index]; var returnObject = Undefined; while (stayInFor) { if (forCondition.Code.Length > 0) { var conditionResult = processor.ExecuteStatement(forCondition); if (conditionResult is SBool) stayInFor = ((SBool)conditionResult).Value; else stayInFor = conditionResult.ToBool(this).Value; } if (stayInFor) { returnObject = processor.ExecuteStatement(executeStatement); if (processor._returnIssued || processor._breakIssued) { _breakIssued = false; _returnIssued = processor._returnIssued; stayInFor = false; } else if (forControl.Code.Length > 0) { processor.ExecuteStatement(forControl); } } } return returnObject; } else { return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script"); } }
public static SObject ToPrimitive(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) return processor.Undefined; if (parameters[0] is SString) return processor.CreateString(((SString)parameters[0]).Value); else if (parameters[0] is SNumber) return processor.CreateNumber(((SNumber)parameters[0]).Value); else if (parameters[0] is SBool) return processor.CreateBool(((SBool)parameters[0]).Value); else return parameters[0]; // returns the input object, if no conversion was conducted. }
public static SObject TypeOf(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) => parameters.Length == 0 ? processor.Undefined : processor.CreateString(parameters[0].TypeOf());
private SObject ExecuteExecutable(ScriptStatement statement) { if (statement.IsCompoundStatement) { var processor = new ScriptProcessor(Context, GetLineNumber()); // Remove { and }: var code = statement.Code.Remove(0, 1); code = code.Remove(code.Length - 1, 1); var returnObject = processor.Run(code); _breakIssued = processor._breakIssued; _continueIssued = processor._continueIssued; _returnIssued = processor._returnIssued; return returnObject; } else { var exp = ResolveParentheses(statement.Code).Trim(); #region QuickConvert // have quick conversions for small statements here // parameter statements are much faster that way: if (exp == SObject.LITERAL_BOOL_TRUE) { return CreateBool(true); } else if (exp == SObject.LITERAL_BOOL_FALSE) { return CreateBool(false); } else if (exp == SObject.LITERAL_UNDEFINED || exp == "") { return Undefined; } else if (exp == SObject.LITERAL_NULL) { return Null; } else if (exp.StartsWith("\"") && exp.EndsWith("\"") && !exp.Remove(exp.Length - 1, 1).Remove(0, 1).Contains("\"")) { return CreateString(exp.Remove(exp.Length - 1, 1).Remove(0, 1)); } else if (exp.All(char.IsDigit)) { double num; SNumber.TryParse(exp, out num); return CreateNumber(num); } #endregion if (exp.Contains("=>")) exp = EvaluateLambda(exp); if (exp.Contains(".")) exp = EvaluateOperator(exp, "."); if (exp.Contains("++")) exp = EvaluateOperator(exp, "++"); if (exp.Contains("--")) exp = EvaluateOperator(exp, "--"); if (exp.Contains("!")) exp = EvaluateReverseBool(exp); if (exp.Contains("**")) exp = EvaluateOperator(exp, "**"); if (exp.Contains("*")) exp = EvaluateOperator(exp, "*"); if (exp.Contains("/")) exp = EvaluateOperator(exp, "/"); if (exp.Contains("%")) exp = EvaluateOperator(exp, "%"); if (exp.Contains("+")) exp = EvaluateOperator(exp, "+"); if (exp.Contains("-")) exp = EvaluateOperator(exp, "-"); if (exp.Contains("<=")) exp = EvaluateOperator(exp, "<="); if (exp.Contains(">=")) exp = EvaluateOperator(exp, ">="); if (exp.Contains("<")) exp = EvaluateOperator(exp, "<"); if (exp.Contains(">")) exp = EvaluateOperator(exp, ">"); if (exp.Contains("===")) exp = EvaluateOperator(exp, "==="); if (exp.Contains("!==")) exp = EvaluateOperator(exp, "!=="); if (exp.Contains("==")) exp = EvaluateOperator(exp, "=="); if (exp.Contains("!=")) exp = EvaluateOperator(exp, "!="); if (exp.Contains("&&")) exp = EvaluateOperator(exp, "&&"); if (exp.Contains("||")) exp = EvaluateOperator(exp, "||"); return ToScriptObject(exp); } }
public static SObject SizeOf(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) => parameters.Length == 0 ? processor.Undefined : processor.CreateNumber(parameters[0].SizeOf());
public static SObject IsFinite(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { if (parameters.Length == 0) return processor.Undefined; double dbl; if (parameters[0] is SNumber) dbl = ((SNumber)parameters[0]).Value; else dbl = parameters[0].ToNumber(processor).Value; return processor.CreateBool(!(double.IsNaN(dbl) || double.IsInfinity(dbl))); }
public static SObject DoSync(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) { string[] tasks = processor.Context.Parent.AsyncTasks.ToArray(); if (parameters.Length >= 1) { var param = SObject.Unbox(parameters[0]); if (param is SString) tasks = new[] { (param as SString).Value }; else if (param is SArray) { tasks = (param as SArray).ArrayMembers.Select(m => m.ToString(processor).Value).ToArray(); } } Console.WriteLine($"Sync tasks: ({string.Join(",", tasks)})"); SpinWait.SpinUntil(() => tasks.All(t => !processor.Context.Parent.AsyncTasks.Contains(t))); return processor.Undefined; }
private SObject ExecuteTry(ScriptStatement statement) { var exp = statement.Code; if (exp != "try") return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_BEFORE_TRY); _index++; if (_statements.Length > _index) { var executeStatement = _statements[_index]; var encounteredError = false; var foundCatch = false; var foundFinally = false; var foundMatchingCatch = false; SObject errorObject = null; var returnObject = Undefined; try { returnObject = ExecuteStatement(executeStatement); } catch (ScriptException ex) { encounteredError = true; errorObject = ex.ErrorObject; } if (encounteredError) { var endedCatchSearch = false; var findCatchIndex = _index + 1; while (findCatchIndex < _statements.Length && !endedCatchSearch) { if (_statements[findCatchIndex].StatementType == StatementType.Catch) { _index = findCatchIndex + 1; if (_statements.Length > _index) { if (!foundMatchingCatch) { var catchExecuteStatement = _statements[_index]; foundCatch = true; var catchCode = _statements[findCatchIndex].Code; var errorVarName = ""; if (catchCode != "catch") { catchCode = catchCode.Remove(0, "catch".Length).Trim().Remove(0, 1); catchCode = catchCode.Remove(catchCode.Length - 1, 1); errorVarName = catchCode.Trim(); } if (Regex.IsMatch(catchCode, REGEX_CATCHCONDITION)) { errorVarName = catchCode.Remove(catchCode.IndexOf(" ")); string conditionCode = catchCode.Remove(0, catchCode.IndexOf("if") + 3); var processor = new ScriptProcessor(Context, GetLineNumber()); processor.Context.AddVariable(errorVarName, errorObject); var conditionResult = processor.ExecuteStatement(new ScriptStatement(conditionCode)); if (conditionResult is SBool) foundMatchingCatch = ((SBool)conditionResult).Value; else foundMatchingCatch = conditionResult.ToBool(this).Value; if (foundMatchingCatch) returnObject = processor.ExecuteStatement(catchExecuteStatement); } else { foundMatchingCatch = true; var processor = new ScriptProcessor(Context, GetLineNumber()); processor.Context.AddVariable(errorVarName, errorObject); returnObject = processor.ExecuteStatement(catchExecuteStatement); } } } else { return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script"); } } else { // end search if different statement type appears: endedCatchSearch = true; } findCatchIndex += 2; } } else { var findCatchIndex = _index + 1; while (findCatchIndex < _statements.Length) { if (_statements[findCatchIndex].StatementType == StatementType.Catch) { foundCatch = true; _index = findCatchIndex + 1; } else { findCatchIndex = _statements.Length; } findCatchIndex += 2; } } // if no matching catch was found when an error occurred, it was not caught: throw it! if (encounteredError && !foundMatchingCatch) return ErrorHandler.ThrowError(errorObject); // now, try to find finally statement: var findFinallyIndex = _index + 1; while (findFinallyIndex < _statements.Length && !foundFinally) { if (_statements[findFinallyIndex].StatementType == StatementType.Finally) { _index = findFinallyIndex + 1; if (_statements.Length > _index) { var finallyExecuteStatement = _statements[_index]; foundFinally = true; returnObject = ExecuteStatement(finallyExecuteStatement); } else { return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script"); } } else { findFinallyIndex = _statements.Length; } findFinallyIndex += 2; } if (!foundCatch && !foundFinally) // when no catch or finally block has been found, throw an error. return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_CATCH_OR_FINALLY); else return returnObject; } else { return ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script"); } }
public ErrorHandler(ScriptProcessor processor) { _processor = processor; }
private SObject ExecuteFor(ScriptStatement statement) { var exp = statement.Code; var forCode = exp.Remove(0, exp.IndexOf("for") + "for".Length).Trim().Remove(0, 1); // Remove "for" and "(". forCode = forCode.Remove(forCode.Length - 1, 1); // Remove ")". var forStatements = StatementProcessor.GetStatements(this, forCode); if (forStatements.Length == 0) { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, ")")); } else if (forStatements.Length == 1) { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FOR_INITIALIZER)); } else if (forStatements.Length == 2) { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FOR_CONDITION)); } else if (forStatements.Length > 3) { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_FOR_CONTROL)); } var processor = new ScriptProcessor(Context, GetLineNumber()); var forInitializer = forStatements[0]; var forCondition = forStatements[1]; var forControl = forStatements[2]; if (forInitializer.Code.Length > 0) { processor.ExecuteStatement(forInitializer); } _index++; if (_statements.Length > _index) { var stayInFor = true; var executeStatement = _statements[_index]; var returnObject = Undefined; while (stayInFor) { if (forCondition.Code.Length > 0) { var conditionResult = processor.ExecuteStatement(forCondition); if (conditionResult is SBool) { stayInFor = ((SBool)conditionResult).Value; } else { stayInFor = conditionResult.ToBool(this).Value; } } if (stayInFor) { returnObject = processor.ExecuteStatement(executeStatement); if (processor._returnIssued || processor._breakIssued) { _breakIssued = false; _returnIssued = processor._returnIssued; stayInFor = false; } else if (forControl.Code.Length > 0) { processor.ExecuteStatement(forControl); } } } return(returnObject); } else { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script")); } }
private SObject ExecuteTry(ScriptStatement statement) { var exp = statement.Code; if (exp != "try") { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_BEFORE_TRY)); } _index++; if (_statements.Length > _index) { var executeStatement = _statements[_index]; var encounteredError = false; var foundCatch = false; var foundFinally = false; var foundMatchingCatch = false; SObject errorObject = null; var returnObject = Undefined; try { returnObject = ExecuteStatement(executeStatement); } catch (ScriptException ex) { encounteredError = true; errorObject = ex.ErrorObject; } if (encounteredError) { var endedCatchSearch = false; var findCatchIndex = _index + 1; while (findCatchIndex < _statements.Length && !endedCatchSearch) { if (_statements[findCatchIndex].StatementType == StatementType.Catch) { _index = findCatchIndex + 1; if (_statements.Length > _index) { if (!foundMatchingCatch) { var catchExecuteStatement = _statements[_index]; foundCatch = true; var catchCode = _statements[findCatchIndex].Code; var errorVarName = ""; if (catchCode != "catch") { catchCode = catchCode.Remove(0, "catch".Length).Trim().Remove(0, 1); catchCode = catchCode.Remove(catchCode.Length - 1, 1); errorVarName = catchCode.Trim(); } if (Regex.IsMatch(catchCode, REGEX_CATCHCONDITION)) { errorVarName = catchCode.Remove(catchCode.IndexOf(" ")); string conditionCode = catchCode.Remove(0, catchCode.IndexOf("if") + 3); var processor = new ScriptProcessor(Context, GetLineNumber()); processor.Context.AddVariable(errorVarName, errorObject); var conditionResult = processor.ExecuteStatement(new ScriptStatement(conditionCode)); if (conditionResult is SBool) { foundMatchingCatch = ((SBool)conditionResult).Value; } else { foundMatchingCatch = conditionResult.ToBool(this).Value; } if (foundMatchingCatch) { returnObject = processor.ExecuteStatement(catchExecuteStatement); } } else { foundMatchingCatch = true; var processor = new ScriptProcessor(Context, GetLineNumber()); processor.Context.AddVariable(errorVarName, errorObject); returnObject = processor.ExecuteStatement(catchExecuteStatement); } } } else { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script")); } } else { // end search if different statement type appears: endedCatchSearch = true; } findCatchIndex += 2; } } else { var findCatchIndex = _index + 1; while (findCatchIndex < _statements.Length) { if (_statements[findCatchIndex].StatementType == StatementType.Catch) { foundCatch = true; _index = findCatchIndex + 1; } else { findCatchIndex = _statements.Length; } findCatchIndex += 2; } } // if no matching catch was found when an error occurred, it was not caught: throw it! if (encounteredError && !foundMatchingCatch) { return(ErrorHandler.ThrowError(errorObject)); } // now, try to find finally statement: var findFinallyIndex = _index + 1; while (findFinallyIndex < _statements.Length && !foundFinally) { if (_statements[findFinallyIndex].StatementType == StatementType.Finally) { _index = findFinallyIndex + 1; if (_statements.Length > _index) { var finallyExecuteStatement = _statements[_index]; foundFinally = true; returnObject = ExecuteStatement(finallyExecuteStatement); } else { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script")); } } else { findFinallyIndex = _statements.Length; } findFinallyIndex += 2; } if (!foundCatch && !foundFinally) // when no catch or finally block has been found, throw an error. { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_CATCH_OR_FINALLY)); } else { return(returnObject); } } else { return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script")); } }
internal static ScriptStatement[] GetStatements(ScriptProcessor processor, string code) { var statements = new List<ScriptStatement>(); var statement = new StringBuilder(); var index = 0; var depth = 0; var lineNumber = 1; var lineNumberBuffer = 0; // buffers line counts from the start of a statement. var isComment = false; var isControlStatement = false; // If the current statement is a control statement. var isCompoundStatement = false; // If the current statement is bunch of statements wrapped in { ... } StringEscapeHelper escaper = new LeftToRightStringEscapeHelper(code, 0); while (index < code.Length) { var t = code[index]; if (!isComment) escaper.CheckStartAt(index); else escaper.JumpTo(index); if (!escaper.IsString) { // Check if a block comment is starting (/*): if (!isComment && t == '/' && index + 1 < code.Length && code[index + 1] == '*') { isComment = true; index++; // Jump over * char. } if (!isComment) { // Check if a line comment is starting (//): if (t == '/' && index + 1 < code.Length && code[index + 1] == '/') { // We jump to the end of the line and ignore everything between the current index and the end of the line: if (code.IndexOf("\n", index + 1) > -1) index = code.IndexOf("\n", index + 1) + 1; else index = code.Length; continue; } statement.Append(t); if (t == '(') { depth++; } else if (t == ')') { depth--; if (isControlStatement) { var statementStr = statement.ToString(); var s = statementStr.Trim(); if (s.StartsWith("if") || s.StartsWith("else if") || s.StartsWith("function") || s.StartsWith("for") || s.StartsWith("while") || s.StartsWith("catch")) { var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines statements.Add(new ScriptStatement(s, GetStatementType(s, true), lineNumber + extraLines)); statement.Clear(); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; isControlStatement = false; } } } else if (t == '{') { depth++; if (depth == 1) { var statementStr = statement.ToString(); var s = statementStr.Trim(); if (isControlStatement) { var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines s = s.Remove(s.Length - 1, 1).Trim(); statements.Add(new ScriptStatement(s, GetStatementType(s, true), lineNumber + extraLines)); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; statement.Clear(); statement.Append('{'); isCompoundStatement = true; isControlStatement = false; } else { if (s == "{") { isCompoundStatement = true; } } } } else if (t == '}') { depth--; if (depth == 0 && isCompoundStatement) { // This could also be an object declaration... // In the case that the statement started with "{" (example statement: {} + []), this will happen. // To check if this is in fact an object, we look right and see if there is: // - an operator => object ("+*-/&|<>.[(") // - nothing => statement var foundOperator = false; var charFindIndex = index + 1; while (!foundOperator && charFindIndex < code.Length) { var testChar = code[charFindIndex]; if (OBJECT_DISCOVER_TOKEN.Contains(testChar)) { if (testChar == '/' && // next statement is actually a comment, not a / operator (followed by / or *) charFindIndex + 1 < code.Length && (code[charFindIndex + 1] == '/' || code[charFindIndex + 1] == '*')) charFindIndex = code.Length; else foundOperator = true; } else if (!char.IsWhiteSpace(testChar)) // We found something that is not an operator or whitespace, so this is the end of a compound statement. { charFindIndex = code.Length; } charFindIndex++; } if (!foundOperator) { var statementStr = statement.ToString(); var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines var s = statementStr.Trim(); statements.Add(new ScriptStatement(s, StatementType.Executable, lineNumber + extraLines) { IsCompoundStatement = true }); statement.Clear(); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; } isCompoundStatement = false; } } else if (t == ';' && depth == 0) { var statementStr = statement.ToString(); var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines var s = statementStr.Trim().TrimEnd(new char[] { ';' }); statements.Add(new ScriptStatement(s, GetStatementType(s, false), lineNumber + extraLines)); statement.Clear(); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; } else if (!isCompoundStatement && !isControlStatement) { var statementStr = statement.ToString(); var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines var s = statementStr.TrimStart(); var nextChar = 'X'; // Set to something that is not matching with the condition below. if (code.Length > index + 1) nextChar = code[index + 1]; // Check if it's actually a control statement by looking if the next char matches (whitespace, ";" or "(") if ((char.IsWhiteSpace(nextChar) || nextChar == ';' || nextChar == '(') && ControlStatements.Contains(s)) { isControlStatement = true; if (s.StartsWith("else")) { if (index + 3 < code.Length) { var check = code.Substring(index + 1, 3); if (check != " if") { statements.Add(new ScriptStatement("else", StatementType.Else, lineNumber + extraLines)); statement.Clear(); isControlStatement = false; lineNumber += lineNumberBuffer; lineNumberBuffer = 0; } } } } } } else { // Check if a block comment is ending (/*): if (t == '*' && index + 1 < code.Length && code[index + 1] == '/') { isComment = false; index++; // Jump over / char. } } } else { statement.Append(t); } if (t == '\n') lineNumberBuffer++; index++; } if (isCompoundStatement) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_END_OF_COMPOUND_STATEMENT); if (isComment) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_UNTERMINATED_COMMENT); if (isControlStatement) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script"); // an executable statement not closed with ";" is getting added here: var leftOver = statement.ToString().Trim(); if (leftOver.Length > 0) { statements.Add(new ScriptStatement(leftOver, GetStatementType(leftOver, false), lineNumber)); } return statements.ToArray(); }
internal static ScriptStatement[] GetStatements(ScriptProcessor processor, string code) { var statements = new List <ScriptStatement>(); var statement = new StringBuilder(); var index = 0; var depth = 0; var lineNumber = 1; var lineNumberBuffer = 0; // buffers line counts from the start of a statement. var isComment = false; var isControlStatement = false; // If the current statement is a control statement. var isCompoundStatement = false; // If the current statement is bunch of statements wrapped in { ... } StringEscapeHelper escaper = new LeftToRightStringEscapeHelper(code, 0); while (index < code.Length) { var t = code[index]; if (!isComment) { escaper.CheckStartAt(index); } else { escaper.JumpTo(index); } if (!escaper.IsString) { // Check if a block comment is starting (/*): if (!isComment && t == '/' && index + 1 < code.Length && code[index + 1] == '*') { isComment = true; index++; // Jump over * char. } if (!isComment) { // Check if a line comment is starting (//): if (t == '/' && index + 1 < code.Length && code[index + 1] == '/') { // We jump to the end of the line and ignore everything between the current index and the end of the line: if (code.IndexOf("\n", index + 1) > -1) { index = code.IndexOf("\n", index + 1) + 1; } else { index = code.Length; } continue; } statement.Append(t); if (t == '(') { depth++; } else if (t == ')') { depth--; if (isControlStatement) { var statementStr = statement.ToString(); var s = statementStr.Trim(); if (s.StartsWith("if") || s.StartsWith("else if") || s.StartsWith("function") || s.StartsWith("for") || s.StartsWith("while") || s.StartsWith("catch")) { var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines statements.Add(new ScriptStatement(s, GetStatementType(s, true), lineNumber + extraLines)); statement.Clear(); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; isControlStatement = false; } } } else if (t == '{') { depth++; if (depth == 1) { var statementStr = statement.ToString(); var s = statementStr.Trim(); if (isControlStatement) { var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines s = s.Remove(s.Length - 1, 1).Trim(); statements.Add(new ScriptStatement(s, GetStatementType(s, true), lineNumber + extraLines)); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; statement.Clear(); statement.Append('{'); isCompoundStatement = true; isControlStatement = false; } else { if (s == "{") { isCompoundStatement = true; } } } } else if (t == '}') { depth--; if (depth == 0 && isCompoundStatement) { // This could also be an object declaration... // In the case that the statement started with "{" (example statement: {} + []), this will happen. // To check if this is in fact an object, we look right and see if there is: // - an operator => object ("+*-/&|<>.[(") // - nothing => statement var foundOperator = false; var charFindIndex = index + 1; while (!foundOperator && charFindIndex < code.Length) { var testChar = code[charFindIndex]; if (OBJECT_DISCOVER_TOKEN.Contains(testChar)) { if (testChar == '/' && // next statement is actually a comment, not a / operator (followed by / or *) charFindIndex + 1 < code.Length && (code[charFindIndex + 1] == '/' || code[charFindIndex + 1] == '*')) { charFindIndex = code.Length; } else { foundOperator = true; } } else if (!char.IsWhiteSpace(testChar)) // We found something that is not an operator or whitespace, so this is the end of a compound statement. { charFindIndex = code.Length; } charFindIndex++; } if (!foundOperator) { var statementStr = statement.ToString(); var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines var s = statementStr.Trim(); statements.Add(new ScriptStatement(s, StatementType.Executable, lineNumber + extraLines) { IsCompoundStatement = true }); statement.Clear(); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; } isCompoundStatement = false; } } else if (t == ';' && depth == 0) { var statementStr = statement.ToString(); var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines var s = statementStr.Trim().TrimEnd(new char[] { ';' }); statements.Add(new ScriptStatement(s, GetStatementType(s, false), lineNumber + extraLines)); statement.Clear(); lineNumber += lineNumberBuffer; lineNumberBuffer = 0; } else if (!isCompoundStatement && !isControlStatement) { var statementStr = statement.ToString(); var extraLines = statementStr.Replace("\r", "").TakeWhile(c => c == '\n').Count(); // count the starting lines var s = statementStr.TrimStart(); var nextChar = 'X'; // Set to something that is not matching with the condition below. if (code.Length > index + 1) { nextChar = code[index + 1]; } // Check if it's actually a control statement by looking if the next char matches (whitespace, ";" or "(") if ((char.IsWhiteSpace(nextChar) || nextChar == ';' || nextChar == '(') && ControlStatements.Contains(s)) { isControlStatement = true; if (s.StartsWith("else")) { if (index + 3 < code.Length) { var check = code.Substring(index + 1, 3); if (check != " if") { statements.Add(new ScriptStatement("else", StatementType.Else, lineNumber + extraLines)); statement.Clear(); isControlStatement = false; lineNumber += lineNumberBuffer; lineNumberBuffer = 0; } } } } } } else { // Check if a block comment is ending (/*): if (t == '*' && index + 1 < code.Length && code[index + 1] == '/') { isComment = false; index++; // Jump over / char. } } } else { statement.Append(t); } if (t == '\n') { lineNumberBuffer++; } index++; } if (isCompoundStatement) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_END_OF_COMPOUND_STATEMENT); } if (isComment) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_UNTERMINATED_COMMENT); } if (isControlStatement) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_EXPECTED_EXPRESSION, "end of script"); } // an executable statement not closed with ";" is getting added here: var leftOver = statement.ToString().Trim(); if (leftOver.Length > 0) { statements.Add(new ScriptStatement(leftOver, GetStatementType(leftOver, false), lineNumber)); } return(statements.ToArray()); }
public void ObjectTranslateTest() { var processor = new ScriptProcessor(); ScriptContextManipulator.AddPrototype(processor, typeof(Pokemon)); processor.Run("var p = new Pokemon(); p.SetName(\"Pika\");"); object objp = ScriptContextManipulator.GetVariableTranslated(processor, "p"); Assert.IsTrue(objp.GetType() == typeof(Pokemon)); Pokemon p = (Pokemon)objp; Assert.AreEqual("Pikachu", p.OriginalName); Assert.AreEqual("Pika", p.Name); }