Example #1
0
        private SObject ExecuteAssignment(ScriptStatement statement)
        {
            var exp = statement.Code;

            var leftSide           = "";
            var rightSide          = "";
            var assignmentOperator = "";

            // Get left and right side of the assignment:
            {
                var depth = 0;
                var index = 0;
                StringEscapeHelper escaper = new LeftToRightStringEscapeHelper(exp, 0);

                while (index < exp.Length && assignmentOperator.Length == 0)
                {
                    var t = exp[index];
                    escaper.CheckStartAt(index);

                    if (!escaper.IsString)
                    {
                        if (t == '(' || t == '[' || t == '{')
                        {
                            depth++;
                        }
                        else if (t == ')' || t == ']' || t == '}')
                        {
                            depth--;
                        }
                        else if (t == '=' && depth == 0)
                        {
                            var previous = ' ';
                            if (index > 0)
                            {
                                previous = exp[index - 1];
                            }

                            if (previous == '+' || previous == '-' || previous == '/' || previous == '*')
                            {
                                assignmentOperator = previous.ToString();
                                leftSide           = exp.Substring(0, index - 1).TrimEnd();
                            }
                            else
                            {
                                assignmentOperator = "=";
                                leftSide           = exp.Substring(0, index).TrimEnd();
                            }

                            rightSide = exp.Substring(index + 1).TrimStart();
                        }
                    }

                    index++;
                }
            }

            // This means it's a function call, which cannot be assigned to:
            if (leftSide.EndsWith(")") || leftSide.Length == 0)
            {
                return(ErrorHandler.ThrowError(ErrorType.ReferenceError, ErrorHandler.MessageReferenceInvalidAssignmentLeft));
            }

            var isIndexer = false;
            var host      = "";
            var member    = "";

            if (leftSide.EndsWith("]"))
            {
                var indexerStartIndex = 0;
                var index             = leftSide.Length - 1;
                var depth             = 0;

                StringEscapeHelper escaper = new RightToLeftStringEscapeHelper(leftSide, index);
                while (index > 0 && !isIndexer)
                {
                    var t = leftSide[index];
                    escaper.CheckStartAt(index);

                    if (!escaper.IsString)
                    {
                        if (t == '(' || t == '{')
                        {
                            depth--;
                        }
                        else if (t == ')' || t == ']' || t == '}')
                        {
                            depth++;
                        }
                        else if (t == '[')
                        {
                            depth--;
                            if (depth == 0 && index > 0)
                            {
                                isIndexer         = true;
                                indexerStartIndex = index;
                            }
                        }
                    }

                    index--;
                }

                if (isIndexer)
                {
                    member = leftSide.Substring(indexerStartIndex + 1);
                    member = member.Remove(member.Length - 1, 1);
                    host   = leftSide.Remove(indexerStartIndex);
                }
            }
            else
            {
                var foundMember = false;

                if (leftSide.Contains("."))
                {
                    var index = leftSide.Length - 1;
                    var depth = 0;
                    StringEscapeHelper escaper = new RightToLeftStringEscapeHelper(leftSide, index);

                    while (index > 0 && !foundMember)
                    {
                        var t = leftSide[index];
                        escaper.CheckStartAt(index);

                        if (!escaper.IsString)
                        {
                            if (t == '(' || t == '[' || t == '{')
                            {
                                depth--;
                            }
                            else if (t == ')' || t == ']' || t == '}')
                            {
                                depth++;
                            }
                            else if (t == '.' && depth == 0)
                            {
                                foundMember = true;
                                host        = leftSide.Substring(0, index);
                                member      = leftSide.Remove(0, index + 1);
                            }
                        }

                        index--;
                    }
                }

                if (!foundMember)
                {
                    host   = SObject.LiteralThis;
                    member = leftSide;
                }
            }

            // When it's an indexer, we parse it as statement:
            var accessor = isIndexer ? SObject.Unbox(ExecuteStatement(new ScriptStatement(member))) : CreateString(member);

            var memberHost = ExecuteStatement(new ScriptStatement(host));
            var value      = SObject.Unbox(ExecuteStatement(new ScriptStatement(rightSide)));

            if (assignmentOperator == "=")
            {
                memberHost.SetMember(this, accessor, isIndexer, value);
            }
            else
            {
                var memberContent = memberHost.GetMember(this, accessor, isIndexer);

                var result = "";

                switch (assignmentOperator)
                {
                case "+":
                    result = ObjectOperators.AddOperator(this, memberContent, value);
                    break;

                case "-":
                    result = ObjectOperators.SubtractOperator(this, memberContent, value);
                    break;

                case "*":
                    result = ObjectOperators.MultiplyOperator(this, memberContent, value);
                    break;

                case "/":
                    result = ObjectOperators.DivideOperator(this, memberContent, value);
                    break;
                }

                memberHost.SetMember(this, accessor, isIndexer, ToScriptObject(result));
            }

            return(value);
        }
Example #2
0
        /// <summary>
        /// Captures an element left from the starting index.
        /// </summary>
        private static ElementCapture CaptureLeft(string exp, int index)
        {
            if (string.IsNullOrWhiteSpace(exp))
            {
                return new ElementCapture()
                       {
                           Length = 0, StartIndex = 0, Identifier = "", Depth = 0
                       }
            }
            ;

            var identifier         = "";
            var foundSeparatorChar = false;
            var depth = 0;
            StringEscapeHelper escaper = new RightToLeftStringEscapeHelper(exp, index);

            while (index >= 0 && !foundSeparatorChar)
            {
                var t = exp[index];

                escaper.CheckStartAt(index);

                if (!escaper.IsString)
                {
                    if (t == ')' || t == ']' || t == '}')
                    {
                        depth++;
                    }
                    else if (t == '(' || t == '[' || t == '{')
                    {
                        depth--;
                    }
                }

                if (depth < 0)
                {
                    // this is when we walk out of the capture area because we are inside some area and a )]} appeared.
                    foundSeparatorChar = true;
                }
                else
                {
                    if (!escaper.IsString && depth == 0)
                    {
                        if (t == '.')
                        {
                            // Check if the '.' is not a decimal separator:
                            if (!Regex.IsMatch(identifier.Trim(), RegexNumrightdot))
                            {
                                foundSeparatorChar = true;
                            }
                        }
                        else if (IdentifierSeparators.Contains(t))
                        {
                            foundSeparatorChar = true;
                        }
                    }

                    // Append the char to the identifier:
                    if (!foundSeparatorChar)
                    {
                        identifier = t + identifier;
                    }
                }

                index--;
            }

            // Check for a minus in front of the identifier to indicate a negative number:
            if (index >= -1 && exp[index + 1] == '-' && !string.IsNullOrWhiteSpace(identifier))
            {
                identifier = "-" + identifier;
                index--;
            }

            if (foundSeparatorChar)
            {
                return new ElementCapture()
                       {
                           StartIndex = index + 2, Length = identifier.Length, Identifier = identifier, Depth = depth
                       }
            }
            ;
            else
            {
                return new ElementCapture()
                       {
                           StartIndex = index + 1, Length = identifier.Length, Identifier = identifier, Depth = depth
                       }
            };
        }
Example #3
0
        private SObject InvokeMethod(SObject owner, string methodName)
        {
            var exp   = methodName;
            var index = exp.Length - 1;
            var argumentStartIndex = -1;
            var This = owner;

            if (exp.EndsWith("()"))
            {
                argumentStartIndex = exp.Length - 2;
                index = argumentStartIndex - 1;
            }
            else
            {
                var depth                  = 0;
                var foundArguments         = false;
                StringEscapeHelper escaper = new RightToLeftStringEscapeHelper(exp, index);

                while (index > 0 && !foundArguments)
                {
                    var t = exp[index];
                    escaper.CheckStartAt(index);

                    if (!escaper.IsString)
                    {
                        if (t == ')' || t == '}' || t == ']')
                        {
                            depth++;
                        }
                        else if (t == '(' || t == '{' || t == '[')
                        {
                            depth--;
                        }

                        if (depth == 0)
                        {
                            if (index > 0)
                            {
                                foundArguments     = true;
                                argumentStartIndex = index;
                            }
                        }
                    }

                    index--;
                }
            }

            methodName = exp.Remove(argumentStartIndex);
            var argumentCode = exp.Remove(0, argumentStartIndex + 1);

            argumentCode = argumentCode.Remove(argumentCode.Length - 1, 1).Trim();
            var parameters = ParseParameters(argumentCode);

            if (methodName == CallLiteral && owner is SFunction)
            {
                This = Context.This;
            }

            // If it has an indexer, parse it again:
            if (index > 0 && exp[index] == ']')
            {
                var member = InvokeMemberOrMethod(owner, methodName);

                if ((member as SVariable)?.Data is SFunction)
                {
                    return(owner.ExecuteMethod(this, ((SVariable)member).Identifier, owner, This, parameters));
                }
                else
                {
                    return(ErrorHandler.ThrowError(ErrorType.TypeError, ErrorHandler.MessageTypeNotAFunction, methodName));
                }
            }
            else
            {
                return(owner.ExecuteMethod(this, methodName, owner, This, parameters));
            }
        }
Example #4
0
        /// <summary>
        /// Converts a string expression into a script object.
        /// </summary>
        private SObject ToScriptObject(string exp)
        {
            exp = exp.Trim();

            // This means it's either an indexer or an array
            if (exp.EndsWith("]"))
            {
                if (!(exp.StartsWith("[") && !exp.Remove(0, 1).Contains("["))) // When there's no "[" besides the start, and it starts with [, then it is an array. Otherwise, do real check.
                {
                    // It is possible that we are having a simple array declaration here.
                    // We check that by looking if we can find a "[" before the expression ends:

                    var depth                  = 0;
                    var index                  = exp.Length - 2;
                    var indexerStartIndex      = 0;
                    var foundIndexer           = false;
                    StringEscapeHelper escaper = new RightToLeftStringEscapeHelper(exp, index);

                    while (index > 0 && !foundIndexer)
                    {
                        var t = exp[index];
                        escaper.CheckStartAt(index);

                        if (!escaper.IsString)
                        {
                            if (t == ')' || t == '}' || t == ']')
                            {
                                depth++;
                            }
                            else if (t == '(' || t == '{')
                            {
                                depth--;
                            }
                            else if (t == '[')
                            {
                                if (depth == 0)
                                {
                                    if (index > 0)
                                    {
                                        indexerStartIndex = index;
                                        foundIndexer      = true;
                                    }
                                }
                                else
                                {
                                    depth--;
                                }
                            }
                        }

                        index--;
                    }

                    if (foundIndexer)
                    {
                        var indexerCode = exp.Substring(indexerStartIndex + 1, exp.Length - indexerStartIndex - 2);

                        var identifier = exp.Remove(indexerStartIndex);

                        var statementResult = ExecuteStatement(new ScriptStatement(indexerCode));
                        return(ToScriptObject(identifier).GetMember(this, statementResult, true));
                    }
                }
            }

            // Normal object return procedure:

            // Negative number:
            var isNegative = false;

            if (exp.StartsWith("-"))
            {
                exp        = exp.Remove(0, 1);
                isNegative = true;
            }

            SObject returnObject;

            if (exp == SObject.LiteralNull)
            {
                returnObject = Null;
            }
            else if (exp == SObject.LiteralUndefined)
            {
                returnObject = Undefined;
            }
            else if (exp == SObject.LiteralBoolFalse)
            {
                returnObject = CreateBool(false);
            }
            else if (exp == SObject.LiteralBoolTrue)
            {
                returnObject = CreateBool(true);
            }
            else if (exp == SObject.LiteralNan)
            {
                returnObject = CreateNumber(double.NaN);
            }
            else if (exp == SObject.LiteralThis)
            {
                returnObject = Context.This;
            }
            else if (SNumber.TryParse(exp, out var dblResult))
            {
                returnObject = CreateNumber(dblResult);
            }
            else if (exp.StartsWith("\"") && exp.EndsWith("\"") || exp.StartsWith("\'") && exp.EndsWith("\'"))
            {
                returnObject = CreateString(exp.Remove(exp.Length - 1, 1).Remove(0, 1), true, false);
            }
            else if (exp.StartsWith("$\"") && exp.EndsWith("\"") || exp.StartsWith("$\'") && exp.EndsWith("\'"))
            {
                returnObject = CreateString(exp.Remove(exp.Length - 1, 1).Remove(0, 2), true, true);
            }
            else if (exp.StartsWith("@\"") && exp.EndsWith("\"") || exp.StartsWith("@\'") && exp.EndsWith("\'"))
            {
                returnObject = CreateString(exp.Remove(exp.Length - 1, 1).Remove(0, 2), false, false);
            }
            else if (exp.StartsWith("{") && exp.EndsWith("}"))
            {
                returnObject = SProtoObject.Parse(this, exp);
            }
            else if (exp.StartsWith("[") && exp.EndsWith("]"))
            {
                returnObject = SArray.Parse(this, exp);
            }
            else if (exp.StartsWith("function") && Regex.IsMatch(exp, RegexFunction))
            {
                returnObject = new SFunction(this, exp);
            }
            else if (Context.IsApiUsing(exp))
            {
                returnObject = Context.GetApiUsing(exp);
            }
            else if (Context.IsVariable(exp))
            {
                returnObject = Context.GetVariable(exp);
            }
            else if (Context.This.HasMember(this, exp))
            {
                returnObject = Context.This.GetMember(this, CreateString(exp), false);
            }
            else if (Context.IsPrototype(exp))
            {
                returnObject = Context.GetPrototype(exp);
            }
            else if (exp.StartsWith("new "))
            {
                returnObject = Context.CreateInstance(exp);
            }
            else if (exp.StartsWith(ObjectBuffer.ObjPrefix))
            {
                var strId = exp.Remove(0, ObjectBuffer.ObjPrefix.Length);

                if (int.TryParse(strId, out var id) && ObjectBuffer.HasObject(id))
                {
                    returnObject = (SObject)ObjectBuffer.GetObject(id);
                }
                else
                {
                    returnObject = ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxInvalidToken, exp);
                }
            }
            else
            {
                returnObject = ErrorHandler.ThrowError(ErrorType.ReferenceError, ErrorHandler.MessageReferenceNotDefined, exp);
            }

            if (isNegative)
            {
                returnObject = ObjectOperators.NegateNumber(this, returnObject);
            }

            return(returnObject);
        }
Example #5
0
        private SObject InvokeMember(SObject owner, string memberName)
        {
            // When we have an indexer at the end of the member name, we get the member variable, then apply the indexer:

            if (memberName.Last() == ']')
            {
                var exp = memberName;

                var depth             = 0;
                var index             = exp.Length - 2;
                var indexerStartIndex = 0;
                var foundIndexer      = false;
                var escaper           = new RightToLeftStringEscapeHelper(exp, index);

                while (index > 0 && !foundIndexer)
                {
                    var t = exp[index];
                    escaper.CheckStartAt(index);

                    if (!escaper.IsString)
                    {
                        if (t == ')' || t == ']' || t == '}')
                        {
                            depth++;
                        }
                        else if (t == '(' || t == '{')
                        {
                            depth--;
                        }
                        else if (t == '[')
                        {
                            if (depth == 0)
                            {
                                if (index > 0)
                                {
                                    indexerStartIndex = index;
                                    foundIndexer      = true;
                                }
                            }
                            else
                            {
                                depth--;
                            }
                        }
                    }
                }

                if (foundIndexer)
                {
                    var indexerCode = exp.Substring(indexerStartIndex + 1, exp.Length - indexerStartIndex - 2);
                    var identifier  = exp.Remove(indexerStartIndex);

                    var indexerObject = ExecuteStatement(new ScriptStatement(indexerCode));

                    return(InvokeMemberOrMethod(owner, identifier).GetMember(this, indexerObject, true));
                }
                else
                {
                    return(ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MessageSyntaxExpectedExpression, "end of string"));
                }
            }
            else
            {
                return(owner.GetMember(this, CreateString(memberName), false));
            }
        }