Example #1
0
        public static SObject Eval(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters)
        {
            if (parameters.Length == 0)
            {
                return(processor.Undefined);
            }

            var parameterAsString = parameters[0] as SString;
            var code = parameterAsString != null ? parameterAsString.Value : parameters[0].ToString(processor).Value;

            var evalProcessor = new ScriptProcessor(processor.Context);

            return(evalProcessor.Run(code));
        }
Example #2
0
        public static SObject NameOf(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters)
        {
            if (parameters.Length == 0)
            {
                return(processor.Undefined);
            }

            var parameterAsString = parameters[0] as SProtoObject;

            if (parameterAsString != null)
            {
                return(processor.CreateString(parameterAsString.IsProtoInstance ? parameterAsString.Prototype.Name : parameterAsString.TypeOf()));
            }
            return(processor.CreateString(parameters[0].TypeOf()));
        }
Example #3
0
 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));
     }
     if (parameters[0] is SNumber)
     {
         return(processor.CreateNumber(((SNumber)parameters[0]).Value));
     }
     if (parameters[0] is SBool)
     {
         return(processor.CreateBool(((SBool)parameters[0]).Value));
     }
     return(parameters[0]); // returns the input object, if no conversion was conducted.
 }
Example #4
0
        public static SObject IsNaN(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)));
        }
Example #5
0
        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[] { parameters[0] }));
            }
            if (parameters[0] is SNumber)
            {
                return(processor.Context.CreateInstance("Number", new[] { parameters[0] }));
            }
            if (parameters[0] is SBool)
            {
                return(processor.Context.CreateInstance("Boolean", new[] { parameters[0] }));
            }
            return(parameters[0]); // returns the input object, if no conversion was conducted.
        }
Example #6
0
        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);
        }
Example #7
0
        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.LiteralBoolTrue)
                {
                    return(CreateBool(true));
                }
                else if (exp == SObject.LiteralBoolFalse)
                {
                    return(CreateBool(false));
                }
                else if (exp == SObject.LiteralUndefined || exp == "")
                {
                    return(Undefined);
                }
                else if (exp == SObject.LiteralNull)
                {
                    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));
            }
        }
Example #8
0
        private SObject ExecuteFor(ScriptStatement statement)
        {
            var exp = statement.Code;

            var forCode = exp.Remove(0, exp.IndexOf("for", StringComparison.Ordinal) + "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.MessageSyntaxExpectedExpression, ")"));
            }
            if (forStatements.Length == 1)
            {
                return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingForInitializer));
            }
            if (forStatements.Length == 2)
            {
                return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingForCondition));
            }
            if (forStatements.Length > 3)
            {
                return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingForControl));
            }

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

                        var conditionAsBool = conditionResult as SBool;
                        stayInFor = conditionAsBool?.Value ?? 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.MessageSyntaxExpectedExpression, "end of script"));
            }
        }
Example #9
0
        private SObject ExecuteTry(ScriptStatement statement)
        {
            var exp = statement.Code;

            if (exp != "try")
            {
                return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxMissingBeforeTry));
            }

            _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, RegexCatchcondition))
                                    {
                                        errorVarName = catchCode.Remove(catchCode.IndexOf(" ", StringComparison.Ordinal));
                                        var conditionCode = catchCode.Remove(0, catchCode.IndexOf("if", StringComparison.Ordinal) + 3);

                                        var processor = new ScriptProcessor(Context, GetLineNumber());
                                        processor.Context.AddVariable(errorVarName, errorObject);

                                        var conditionResult = processor.ExecuteStatement(new ScriptStatement(conditionCode));

                                        var conditionAsBool = conditionResult as SBool;
                                        foundMatchingCatch = conditionAsBool?.Value ?? 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.MessageSyntaxExpectedExpression, "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.MessageSyntaxExpectedExpression, "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.MessageSyntaxMissingCatchOrFinally));
                }
                else
                {
                    return(returnObject);
                }
            }
            else
            {
                return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxExpectedExpression, "end of script"));
            }
        }
Example #10
0
        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, StringComparison.Ordinal) > -1)
                            {
                                index = code.IndexOf("\n", index + 1, StringComparison.Ordinal) + 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 (ObjectDiscoverToken.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(';');
                            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.MessageSyntaxMissingEndOfCompoundStatement);
            }

            if (isComment)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxUnterminatedComment);
            }

            if (isControlStatement)
            {
                processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxExpectedExpression, "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());
        }
Example #11
0
 public static SObject TypeOf(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) =>
 parameters.Length == 0 ? processor.Undefined : processor.CreateString(parameters[0].TypeOf());
Example #12
0
 public static SObject SizeOf(ScriptProcessor processor, SObject instance, SObject This, SObject[] parameters) =>
 parameters.Length == 0 ? processor.Undefined : processor.CreateNumber(parameters[0].SizeOf());
Example #13
0
 public ErrorHandler(ScriptProcessor processor)
 {
     _processor = processor;
 }