Пример #1
0
        public static CodeNode Parse(ParseInfo state, ref int position)
        {
            var i = position;

            if (!Parser.ValidateRegex(state.Code, ref i, false))
            {
                return(null);
            }

            string value = state.Code.Substring(position, i - position);

            position = i;

            state.Code = Tools.removeComments(state.SourceCode, i);
            var    s     = value.LastIndexOf('/') + 1;
            string flags = value.Substring(s);

            try
            {
                return(new RegExpExpression(value.Substring(1, s - 2), flags)); // объекты должны быть каждый раз разные
            }
            catch (Exception e)
            {
                if (state.message != null)
                {
                    state.message(MessageLevel.Error, CodeCoordinates.FromTextPosition(state.Code, i - value.Length, value.Length), string.Format(Strings.InvalidRegExp, value));
                }
                return(new ExpressionWrapper(new Throw(e)));
            }
        }
Пример #2
0
        internal static void ThrowUnknownToken(string code, int index)
        {
            var cord = CodeCoordinates.FromTextPosition(code, index, 0);

            Throw(new SyntaxError(string.Format(
                                      Strings.UnknowIdentifier,
                                      code.Substring(index, System.Math.Min(50, code.Length - index)).Split(Tools.TrimChars).FirstOrDefault(),
                                      cord)));
        }
Пример #3
0
 public JSException(Error data, CodeNode exceptionMaker, string code)
 {
     Error          = Context.CurrentGlobalContext.ProxyValue(data);
     ExceptionMaker = exceptionMaker;
     Code           = code;
     if (code != null)
     {
         CodeCoordinates = CodeCoordinates.FromTextPosition(code, exceptionMaker.Position, exceptionMaker.Length);
     }
 }
Пример #4
0
        public static CodeNode Parse(ParseInfo state, ref int index)
        {
            var i = index;

            if (!Parser.Validate(state.Code, "new", ref i) || !Parser.IsIdentifierTerminator(state.Code[i]))
            {
                return(null);
            }
            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            var result = (Expression)ExpressionTree.Parse(state, ref i, true, false, true, true, false);

            if (result == null)
            {
                var cord = CodeCoordinates.FromTextPosition(state.Code, i, 0);
                ExceptionHelper.Throw((new SyntaxError("Invalid prefix operation. " + cord)));
            }
            if (result is Call)
            {
                result = new New(result as Call)
                {
                    Position = index, Length = i - index
                }
            }
            ;
            else
            {
                if (state.message != null)
                {
                    state.message(MessageLevel.Warning, index, 0, "Missed brackets in a constructor invocation.");
                }
                result = new Expressions.New(new Call(result, new Expression[0])
                {
                    Position = result.Position, Length = result.Length
                })
                {
                    Position = index, Length = i - index
                };
            }
            index = i;
            return(result);
        }
Пример #5
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            if (!Parser.ValidateName(state.Code, ref i, state.strict))
            {
                return(null);
            }
            int l = i;

            if (i >= state.Code.Length || (!Parser.Validate(state.Code, " :", ref i) && state.Code[i++] != ':'))
            {
                return(null);
            }

            var label = state.Code.Substring(index, l - index);

            state.Labels.Add(label);
            int oldlc = state.LabelsCount;

            state.LabelsCount++;
            var stat = Parser.Parse(state, ref i, 0);

            state.Labels.Remove(label);
            state.LabelsCount = oldlc;
            if (stat is FunctionDefinition)
            {
                if (state.message != null)
                {
                    state.message(MessageLevel.CriticalWarning, CodeCoordinates.FromTextPosition(state.Code, stat.Position, stat.Length), "Labeled function. Are you sure?");
                }
            }
            var pos = index;

            index = i;
            return(new LabeledStatement()
            {
                statement = stat,
                label = label,
                Position = pos,
                Length = index - pos
            });
        }
Пример #6
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            if (!Parser.Validate(state.Code, "with (", ref i) && !Parser.Validate(state.Code, "with(", ref i))
            {
                return(null);
            }
            if (state.strict)
            {
                ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("WithStatement is not allowed in strict mode.")));
            }

            if (state.message != null)
            {
                state.message(MessageLevel.CriticalWarning, CodeCoordinates.FromTextPosition(state.Code, index, 4), "Do not use \"with\".");
            }

            var obj = Parser.Parse(state, ref i, CodeFragmentType.Expression);

            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (state.Code[i] != ')')
            {
                ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("Invalid syntax WithStatement.")));
            }
            do
            {
                i++;
            }while (Tools.IsWhiteSpace(state.Code[i]));

            CodeNode body = null;

            VariableDescriptor[] vars = null;
            var oldVariablesCount     = state.Variables.Count;

            state.lexicalScopeLevel++;
            var oldCodeContext = state.CodeContext;

            state.CodeContext |= CodeContext.InWith;
            try
            {
                body = Parser.Parse(state, ref i, 0);
                vars = CodeBlock.extractVariables(state, oldVariablesCount);
                body = new CodeBlock(new[] { body })
                {
                    _variables = vars,
                    Position   = body.Position,
                    Length     = body.Length
                };
            }
            finally
            {
                state.lexicalScopeLevel--;
                state.CodeContext = oldCodeContext;
            }

            var pos = index;

            index = i;
            return(new With()
            {
                _scope = obj,
                _body = body,
                Position = pos,
                Length = index - pos
            });
        }
Пример #7
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            Tools.SkipSpaces(state.Code, ref i);

            if (!Parser.Validate(state.Code, "for(", ref i) &&
                (!Parser.Validate(state.Code, "for (", ref i)))
            {
                return(null);
            }

            Tools.SkipSpaces(state.Code, ref i);

            var result = new ForOf()
            {
                _labels = state.Labels.GetRange(state.Labels.Count - state.LabelsCount, state.LabelsCount).ToArray()
            };

            VariableDescriptor[] vars = null;
            var oldVariablesCount     = state.Variables.Count;

            state.lexicalScopeLevel++;
            try
            {
                var vStart            = i;
                var variableName      = "";
                var variableNameStart = 0;
                var variableDef       = VariableDefinition.Parse(state, ref i, true);
                if (variableDef == null)
                {
                    if (state.Code[i] == ';')
                    {
                        return(null);
                    }

                    Tools.SkipSpaces(state.Code, ref i);

                    variableNameStart = i;
                    if (!Parser.ValidateName(state.Code, ref i, state.strict))
                    {
                        return(null);
                    }

                    variableName = Tools.Unescape(state.Code.Substring(variableNameStart, i - variableNameStart), state.strict);

                    variableDef = new Variable(variableName, state.lexicalScopeLevel)
                    {
                        Position   = variableNameStart,
                        Length     = i - variableNameStart,
                        ScopeLevel = state.lexicalScopeLevel
                    };

                    Tools.SkipSpaces(state.Code, ref i);

                    if (state.Code[i] == '=')
                    {
                        Tools.SkipSpaces(state.Code, ref i);

                        var defVal = ExpressionTree.Parse(state, ref i, false, false, false, true, true);
                        if (defVal == null)
                        {
                            return(defVal);
                        }

                        Expression exp = new AssignmentOperatorCache(variableDef as Variable);
                        exp = new Assignment(exp, defVal)
                        {
                            Position = exp.Position,
                            Length   = defVal.EndPosition - exp.Position
                        };

                        if (variableDef == exp._left._left)
                        {
                            variableDef = exp;
                        }

                        Tools.SkipSpaces(state.Code, ref i);
                    }
                }
                else
                {
                    variableName = (variableDef as VariableDefinition)._variables[0].name;
                }

                if (!Parser.Validate(state.Code, "of", ref i))
                {
                    if (oldVariablesCount < state.Variables.Count)
                    {
                        state.Variables.RemoveRange(oldVariablesCount, state.Variables.Count - oldVariablesCount);
                    }

                    return(null);
                }

                if (state.strict)
                {
                    if (variableName == "arguments" || variableName == "eval")
                    {
                        ExceptionHelper.ThrowSyntaxError(
                            "Parameters name may not be \"arguments\" or \"eval\" in strict mode at ",
                            state.Code,
                            variableDef.Position,
                            variableDef.Length);
                    }
                }

                if (variableDef is VariableDefinition)
                {
                    if ((variableDef as VariableDefinition)._variables.Length > 1)
                    {
                        ExceptionHelper.ThrowSyntaxError("Too many variables in for-of loop", state.Code, i);
                    }
                }


                result._variable = variableDef;

                state.LabelsCount = 0;
                Tools.SkipSpaces(state.Code, ref i);

                result._source = Parser.Parse(state, ref i, CodeFragmentType.Expression);
                Tools.SkipSpaces(state.Code, ref i);

                if (state.Code[i] != ')')
                {
                    ExceptionHelper.Throw((new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }

                i++;
                state.AllowBreak.Push(true);
                state.AllowContinue.Push(true);
                result._body = Parser.Parse(state, ref i, 0);
                state.AllowBreak.Pop();
                state.AllowContinue.Pop();
                result.Position = index;
                result.Length   = i - index;
                index           = i;
                vars            = CodeBlock.extractVariables(state, oldVariablesCount);
            }
            finally
            {
                state.lexicalScopeLevel--;
            }

            return(new CodeBlock(new[] { result })
            {
                _variables = vars,
                Position = result.Position,
                Length = result.Length
            });
        }
Пример #8
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            string code = state.Code;
            int    i    = index;

            if (!Parser.Validate(code, "class", ref i))
            {
                return(null);
            }
            while (Tools.IsWhiteSpace(code[i]))
            {
                i++;
            }
            string     name     = null;
            Expression baseType = null;

            if (!Parser.Validate(code, "extends ", i))
            {
                var n = i;
                if (Parser.ValidateName(code, ref i, true))
                {
                    name = code.Substring(n, i - n);
                }

                while (Tools.IsWhiteSpace(code[i]))
                {
                    i++;
                }
            }
            if (Parser.Validate(code, "extends ", ref i))
            {
                var n = i;
                if (!Parser.ValidateName(code, ref i, true) && !Parser.Validate(code, "null", ref i))
                {
                    ExceptionHelper.ThrowSyntaxError("Invalid base class name", state.Code, i);
                }

                var baseClassName = code.Substring(n, i - n);
                if (baseClassName == "null")
                {
                    baseType = new Constant(JSValue.@null);
                }
                else
                {
                    baseType = new Variable(baseClassName, 1);
                }

                baseType.Position = n;
                baseType.Length   = i - n;

                while (Tools.IsWhiteSpace(code[i]))
                {
                    i++;
                }
            }
            if (code[i] != '{')
            {
                ExceptionHelper.ThrowSyntaxError(Messages.UnexpectedToken, code, i);
            }

            FunctionDefinition ctor   = null;
            ClassDefinition    result = null;
            var oldStrict             = state.Strict;

            state.Strict = true;
            var flds = new Dictionary <string, MemberDescriptor>();
            var computedProperties = new List <MemberDescriptor>();
            var oldCodeContext     = state.CodeContext;

            state.CodeContext |= CodeContext.InExpression;

            try
            {
                while (code[i] != '}')
                {
                    do
                    {
                        i++;
                    }while (Tools.IsWhiteSpace(code[i]) || code[i] == ';');
                    int s = i;
                    if (state.Code[i] == '}')
                    {
                        break;
                    }

                    bool @static = Parser.Validate(state.Code, "static", ref i);
                    if (@static)
                    {
                        Tools.SkipSpaces(state.Code, ref i);
                        s = i;
                    }

                    bool getOrSet = Parser.Validate(state.Code, "get", ref i) || Parser.Validate(state.Code, "set", ref i);
                    if (getOrSet)
                    {
                        Tools.SkipSpaces(state.Code, ref i);
                    }

                    var asterisk = state.Code[i] == '*';
                    if (asterisk)
                    {
                        do
                        {
                            i++;
                        }while (Tools.IsWhiteSpace(state.Code[i]));
                    }

                    if (Parser.Validate(state.Code, "[", ref i))
                    {
                        var propertyName = ExpressionTree.Parse(state, ref i, false, false, false, true, false);
                        while (Tools.IsWhiteSpace(state.Code[i]))
                        {
                            i++;
                        }
                        if (state.Code[i] != ']')
                        {
                            ExceptionHelper.ThrowSyntaxError("Expected ']'", state.Code, i);
                        }
                        do
                        {
                            i++;
                        }while (Tools.IsWhiteSpace(state.Code[i]));

                        var initializer = state.Code[i] == '(' ? FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.AnonymousGenerator : FunctionKind.AnonymousFunction) : ExpressionTree.Parse(state, ref i);

                        switch (state.Code[s])
                        {
                        case 'g':
                        {
                            computedProperties.Add(new MemberDescriptor(propertyName, new PropertyPair((Expression)initializer, null), @static));
                            break;
                        }

                        case 's':
                        {
                            computedProperties.Add(new MemberDescriptor(propertyName, new PropertyPair(null, (Expression)initializer), @static));
                            break;
                        }

                        default:
                        {
                            computedProperties.Add(new MemberDescriptor(propertyName, (Expression)initializer, @static));
                            break;
                        }
                        }
                    }
                    else if (getOrSet)
                    {
                        i = s;
                        var mode             = state.Code[i] == 's' ? FunctionKind.Setter : FunctionKind.Getter;
                        var propertyAccessor = FunctionDefinition.Parse(state, ref i, mode) as FunctionDefinition;
                        var accessorName     = (@static ? "static " : "") + propertyAccessor.Name;
                        if (!flds.ContainsKey(accessorName))
                        {
                            var propertyPair = new PropertyPair
                                               (
                                mode == FunctionKind.Getter ? propertyAccessor : null,
                                mode == FunctionKind.Setter ? propertyAccessor : null
                                               );
                            flds.Add(accessorName, new MemberDescriptor(new Constant(propertyAccessor.Name), propertyPair, @static));
                        }
                        else
                        {
                            var vle = flds[accessorName].Value as PropertyPair;

                            if (vle == null)
                            {
                                ExceptionHelper.Throw((new SyntaxError("Try to define " + mode.ToString().ToLowerInvariant() + " for defined field at " + CodeCoordinates.FromTextPosition(state.Code, s, 0))));
                            }

                            do
                            {
                                if (mode == FunctionKind.Getter)
                                {
                                    if (vle.Getter == null)
                                    {
                                        vle.Getter = propertyAccessor;
                                        break;
                                    }
                                }
                                else
                                {
                                    if (vle.Setter == null)
                                    {
                                        vle.Setter = propertyAccessor;
                                        break;
                                    }
                                }

                                ExceptionHelper.ThrowSyntaxError("Try to redefine " + mode.ToString().ToLowerInvariant() + " of " + propertyAccessor.Name, state.Code, s);
                            }while (false);
                        }
                    }
                    else
                    {
                        i = s;
                        string fieldName = null;
                        if (state.Code[i] == '*')
                        {
                            do
                            {
                                i++;
                            }while (Tools.IsWhiteSpace(code[i]));
                        }

                        if (Parser.ValidateName(state.Code, ref i, false, true, state.Strict))
                        {
                            fieldName = Tools.Unescape(state.Code.Substring(s, i - s), state.Strict);
                        }
                        else if (Parser.ValidateValue(state.Code, ref i))
                        {
                            double d = 0.0;
                            int    n = s;
                            if (Tools.ParseNumber(state.Code, ref n, out d))
                            {
                                fieldName = Tools.DoubleToString(d);
                            }
                            else if (state.Code[s] == '\'' || state.Code[s] == '"')
                            {
                                fieldName = Tools.Unescape(state.Code.Substring(s + 1, i - s - 2), state.Strict);
                            }
                        }

                        if (fieldName == null)
                        {
                            ExceptionHelper.Throw((new SyntaxError("Invalid member name at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s))));
                        }

                        if (fieldName == "constructor")
                        {
                            if (@static)
                            {
                                ExceptionHelper.ThrowSyntaxError(Messages.ConstructorCannotBeStatic, state.Code, s);
                            }
                            if (ctor != null)
                            {
                                ExceptionHelper.ThrowSyntaxError("Trying to redefinition constructor", state.Code, s);
                            }

                            state.CodeContext |= CodeContext.InClassConstructor;
                        }
                        else if (@static)
                        {
                            fieldName          = "static " + fieldName;
                            state.CodeContext |= CodeContext.InStaticMember;
                        }
                        if (flds.ContainsKey(fieldName))
                        {
                            ExceptionHelper.Throw(new SyntaxError("Trying to redefinition member \"" + fieldName + "\" at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s)));
                        }

                        state.CodeContext |= CodeContext.InClassDefenition;
                        state.CodeContext &= ~CodeContext.InGenerator;

                        i = s;
                        var method = FunctionDefinition.Parse(state, ref i, FunctionKind.Method) as FunctionDefinition;
                        if (method == null)
                        {
                            ExceptionHelper.ThrowSyntaxError("Unable to parse constructor", state.Code, i);
                        }

                        if (fieldName == "constructor")
                        {
                            ctor = method;
                        }
                        else
                        {
                            flds[fieldName] = new MemberDescriptor(new Constant(method.Name), method, @static);
                        }
                    }

                    code = state.Code;
                }

                if (ctor == null)
                {
                    string ctorCode;
                    int    ctorIndex = 0;
                    if (baseType != null && !(baseType is Constant))
                    {
                        ctorCode = "constructor(...args) { super(...args); }";
                    }
                    else
                    {
                        ctorCode = "constructor(...args) { }";
                    }
                    ctor = (FunctionDefinition)FunctionDefinition.Parse(
                        new ParseInfo(ctorCode, ctorCode, null)
                    {
                        Strict      = true,
                        CodeContext = CodeContext.InClassConstructor | CodeContext.InClassDefenition
                    },
                        ref ctorIndex,
                        FunctionKind.Method);
                }

                result = new ClassDefinition(name, baseType, new List <MemberDescriptor>(flds.Values).ToArray(), ctor, computedProperties.ToArray());

                if ((oldCodeContext & CodeContext.InExpression) == 0)
                {
                    if (string.IsNullOrEmpty(name))
                    {
                        ExceptionHelper.ThrowSyntaxError("Class must have name", state.Code, index);
                    }
                    if (state.Strict && state.FunctionScopeLevel != state.LexicalScopeLevel)
                    {
                        ExceptionHelper.ThrowSyntaxError("In strict mode code, class can only be declared at top level or immediately within other function.", state.Code, index);
                    }

                    state.Variables.Add(result.Reference._descriptor);
                }
            }
            finally
            {
                state.CodeContext = oldCodeContext;
                state.Strict      = oldStrict;
            }
            index = i + 1;
            return(result);
        }
Пример #9
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (!Parser.Validate(state.Code, "for(", ref i) && (!Parser.Validate(state.Code, "for (", ref i)))
            {
                return(null);
            }
            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            CodeNode init      = null;
            CodeNode body      = null;
            CodeNode condition = null;
            CodeNode post      = null;
            CodeNode result    = null;

            var labelsCount       = state.LabelsCount;
            var oldVariablesCount = state.Variables.Count;

            state.LabelsCount = 0;
            state.lexicalScopeLevel++;
            try
            {
                init = VariableDefinition.Parse(state, ref i, true);
                if (init == null)
                {
                    init = ExpressionTree.Parse(state, ref i, forForLoop: true);
                }
                if ((init is ExpressionTree) &&
                    (init as ExpressionTree).Type == OperationType.None &&
                    (init as ExpressionTree)._right == null)
                {
                    init = (init as ExpressionTree)._left;
                }
                if (state.Code[i] != ';')
                {
                    ExceptionHelper.Throw((new SyntaxError("Expected \";\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }
                do
                {
                    i++;
                }while (Tools.IsWhiteSpace(state.Code[i]));
                condition = state.Code[i] == ';' ? null as CodeNode : ExpressionTree.Parse(state, ref i, forForLoop: true);
                if (state.Code[i] != ';')
                {
                    ExceptionHelper.Throw((new SyntaxError("Expected \";\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }
                do
                {
                    i++;
                }while (Tools.IsWhiteSpace(state.Code[i]));
                post = state.Code[i] == ')' ? null as CodeNode : ExpressionTree.Parse(state, ref i, forForLoop: true);
                while (Tools.IsWhiteSpace(state.Code[i]))
                {
                    i++;
                }
                if (state.Code[i] != ')')
                {
                    ExceptionHelper.Throw((new SyntaxError("Expected \";\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }

                i++;
                Tools.SkipSpaces(state.Code, ref i);

                state.AllowBreak.Push(true);
                state.AllowContinue.Push(true);
                try
                {
                    body = Parser.Parse(state, ref i, 0);
                    var vds = body as VariableDefinition;
                    if (vds != null)
                    {
                        if (vds.Kind >= VariableKind.ConstantInLexicalScope)
                        {
                            ExceptionHelper.ThrowSyntaxError("Block scope variables can not be declared in for-loop directly", state.Code, body.Position);
                        }

                        if (state.message != null)
                        {
                            state.message(MessageLevel.Warning, body.Position, body.Length, "Do not declare variables in for-loop directly");
                        }
                    }
                }
                finally
                {
                    state.AllowBreak.Pop();
                    state.AllowContinue.Pop();
                }

                int startPos = index;
                index = i;

                result = new For()
                {
                    _body        = body,
                    _condition   = condition,
                    _initializer = init,
                    _post        = post,
                    labels       = state.Labels.GetRange(state.Labels.Count - labelsCount, labelsCount).ToArray(),
                    Position     = startPos,
                    Length       = index - startPos
                };

                var vars = CodeBlock.extractVariables(state, oldVariablesCount);
                result = new CodeBlock(new[] { result })
                {
                    _variables = vars, Position = result.Position, Length = result.Length
                };
            }
            finally
            {
                state.lexicalScopeLevel--;
            }

            return(result);
        }
Пример #10
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            if (!Parser.Validate(state.Code, "if (", ref i) && !Parser.Validate(state.Code, "if(", ref i))
            {
                return(null);
            }
            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            var condition = (Expression)ExpressionTree.Parse(state, ref i);

            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (state.Code[i] != ')')
            {
                throw new ArgumentException("code (" + i + ")");
            }
            do
            {
                i++;
            }while (Tools.IsWhiteSpace(state.Code[i]));
            CodeNode body = Parser.Parse(state, ref i, 0);

            if (body is FunctionDefinition)
            {
                if (state.strict)
                {
                    ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("In strict mode code, functions can only be declared at top level or immediately within another function.")));
                }
                if (state.message != null)
                {
                    state.message(MessageLevel.CriticalWarning, CodeCoordinates.FromTextPosition(state.Code, body.Position, body.Length), "Do not declare function in nested blocks.");
                }
                body = new CodeBlock(new[] { body }); // для того, чтобы не дублировать код по декларации функции,
                // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию.
            }
            CodeNode elseBody = null;
            var      pos      = i;

            while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (i < state.Code.Length && !(body is CodeBlock) && (state.Code[i] == ';'))
            {
                do
                {
                    i++;
                }while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]));
            }

            if (Parser.Validate(state.Code, "else", ref i))
            {
                while (Tools.IsWhiteSpace(state.Code[i]))
                {
                    i++;
                }
                elseBody = Parser.Parse(state, ref i, 0);
                if (elseBody is FunctionDefinition)
                {
                    if (state.strict)
                    {
                        ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("In strict mode code, functions can only be declared at top level or immediately within another function.")));
                    }
                    if (state.message != null)
                    {
                        state.message(MessageLevel.CriticalWarning, CodeCoordinates.FromTextPosition(state.Code, elseBody.Position, elseBody.Length), "Do not declare function in nested blocks.");
                    }
                    elseBody = new CodeBlock(new[] { elseBody }); // для того, чтобы не дублировать код по декларации функции,
                    // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию.
                }
            }
            else
            {
                i = pos;
            }
            pos   = index;
            index = i;
            return(new IfElse()
            {
                then = body,
                condition = condition,
                @else = elseBody,
                Position = pos,
                Length = index - pos
            });
        }
Пример #11
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            if (!Parser.Validate(state.Code, "try", ref i) || !Parser.IsIdentifierTerminator(state.Code[i]))
            {
                return(null);
            }
            while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (i >= state.Code.Length)
            {
                ExceptionHelper.Throw(new SyntaxError(Strings.UnexpectedEndOfSource));
            }
            if (state.Code[i] != '{')
            {
                ExceptionHelper.Throw((new SyntaxError("Invalid try statement definition at " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
            }
            var b = CodeBlock.Parse(state, ref i);

            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            CodeNode cb    = null;
            string   exptn = null;

            if (Parser.Validate(state.Code, "catch (", ref i) || Parser.Validate(state.Code, "catch(", ref i))
            {
                Tools.SkipSpaces(state.Code, ref i);

                int s = i;
                if (!Parser.ValidateName(state.Code, ref i, state.Strict))
                {
                    ExceptionHelper.Throw((new SyntaxError("Catch block must contain variable name " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }

                exptn = Tools.Unescape(state.Code.Substring(s, i - s), state.Strict);
                if (state.Strict)
                {
                    if (exptn == "arguments" || exptn == "eval")
                    {
                        ExceptionHelper.Throw((new SyntaxError("Varible name can not be \"arguments\" or \"eval\" in strict mode at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s))));
                    }
                }

                Tools.SkipSpaces(state.Code, ref i);

                if (!Parser.Validate(state.Code, ")", ref i))
                {
                    ExceptionHelper.Throw((new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }
                while (Tools.IsWhiteSpace(state.Code[i]))
                {
                    i++;
                }
                if (state.Code[i] != '{')
                {
                    ExceptionHelper.Throw((new SyntaxError("Invalid catch block statement definition at " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }
                state.LexicalScopeLevel++;
                try
                {
                    cb = CodeBlock.Parse(state, ref i);
                }
                finally
                {
                    state.LexicalScopeLevel--;
                }
                while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]))
                {
                    i++;
                }
            }
            CodeNode f = null;

            if (Parser.Validate(state.Code, "finally", i) && Parser.IsIdentifierTerminator(state.Code[i + 7]))
            {
                i += 7;
                while (Tools.IsWhiteSpace(state.Code[i]))
                {
                    i++;
                }
                if (state.Code[i] != '{')
                {
                    ExceptionHelper.Throw((new SyntaxError("Invalid finally block statement definition at " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }
                f = CodeBlock.Parse(state, ref i);
            }
            if (cb == null && f == null)
            {
                ExceptionHelper.ThrowSyntaxError("try block must contain 'catch' or/and 'finally' block", state.Code, index);
            }

            var pos = index;

            index = i;
            return(new TryCatch()
            {
                body = (CodeBlock)b,
                catchBody = (CodeBlock)cb,
                finallyBody = (CodeBlock)f,
                catchVariableDesc = new VariableDescriptor(exptn, state.LexicalScopeLevel + 1),
                Position = pos,
                Length = index - pos
            });
        }
Пример #12
0
        internal static void ThrowVariableIsNotDefined(string variableName, string code, int position, int length, CodeNode exceptionMaker)
        {
            var cord = CodeCoordinates.FromTextPosition(code, position, 0);

            Throw(new ReferenceError(string.Format(Strings.VariableNotDefined, variableName)), exceptionMaker, code);
        }
Пример #13
0
            public static CodeNode Parse(ParseInfo state, ref int position)
            {
                if (!Parser.Validate(state.Code, "using", ref position))
                {
                    return(null);
                }

                while (char.IsWhiteSpace(state.Code, position))
                {
                    position++;
                }

                int start = position;

                while (Parser.ValidateName(state.Code, ref position) && state.Code[position] == '.')
                {
                    position++;
                }

                if (state.Code[position] != ' ')
                {
                    throw new JSException(new SyntaxError("Unexpected char at " + CodeCoordinates.FromTextPosition(state.Code, position, 0)));
                }

                var namespaceName = state.Code.Substring(start, position - start);

                while (char.IsWhiteSpace(state.Code, position))
                {
                    position++;
                }

                if (!Parser.Validate(state.Code, "as", ref position))
                {
                    throw new JSException(new SyntaxError("Expected \"as\" at " + CodeCoordinates.FromTextPosition(state.Code, position, 2)));
                }

                while (char.IsWhiteSpace(state.Code, position))
                {
                    position++;
                }

                start = position;
                if (!Parser.ValidateName(state.Code, ref position))
                {
                    throw new JSException(new SyntaxError("Expected identifier name at " + CodeCoordinates.FromTextPosition(state.Code, position, 0)));
                }

                var aliasName = state.Code.Substring(start, position - start);

                while (char.IsWhiteSpace(state.Code, position))
                {
                    position++;
                }

                if (state.Code[position] != ';')
                {
                    throw new JSException(new SyntaxError("Expected \";\" at " + CodeCoordinates.FromTextPosition(state.Code, position, 1)));
                }

                return(new UsingStatement(namespaceName, aliasName));
            }
Пример #14
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            if (state.Code[index] != '{')
            {
                throw new ArgumentException("Invalid JSON definition");
            }
            var flds = new Dictionary <string, Expression>();
            var computedProperties = new List <KeyValuePair <Expression, Expression> >();
            int i = index;

            while (state.Code[i] != '}')
            {
                i++;
                Tools.SkipSpaces(state.Code, ref i);
                int s = i;
                if (state.Code[i] == '}')
                {
                    break;
                }

                bool getOrSet = Parser.Validate(state.Code, "get", ref i) || Parser.Validate(state.Code, "set", ref i);
                Tools.SkipSpaces(state.Code, ref i);
                if (getOrSet && state.Code[i] == '(')  // function with name 'get' or 'set'
                {
                    getOrSet = false;
                    i        = s;
                }

                var asterisk = state.Code[i] == '*';
                Tools.SkipSpaces(state.Code, ref i);

                if (Parser.Validate(state.Code, "[", ref i))
                {
                    var name = ExpressionTree.Parse(state, ref i, false, false, false, true, false);
                    while (Tools.IsWhiteSpace(state.Code[i]))
                    {
                        i++;
                    }
                    if (state.Code[i] != ']')
                    {
                        ExceptionHelper.ThrowSyntaxError("Expected ']'", state.Code, i);
                    }
                    do
                    {
                        i++;
                    }while (Tools.IsWhiteSpace(state.Code[i]));

                    Tools.SkipSpaces(state.Code, ref i);
                    if (state.Code[s] != 'g' && state.Code[s] != 's')
                    {
                        if (!Parser.Validate(state.Code, ":", ref i))
                        {
                            ExceptionHelper.ThrowSyntaxError(Messages.UnexpectedToken, state.Code, i);
                        }
                        Tools.SkipSpaces(state.Code, ref i);
                    }

                    CodeNode initializer;
                    initializer = state.Code[i] == '(' ? FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.AnonymousGenerator : FunctionKind.AnonymousFunction) : ExpressionTree.Parse(state, ref i);

                    switch (state.Code[s])
                    {
                    case 'g':
                    {
                        computedProperties.Add(new KeyValuePair <Expression, Expression>(name, new PropertyPair((Expression)initializer, null)));
                        break;
                    }

                    case 's':
                    {
                        computedProperties.Add(new KeyValuePair <Expression, Expression>(name, new PropertyPair(null, (Expression)initializer)));
                        break;
                    }

                    default:
                    {
                        computedProperties.Add(new KeyValuePair <Expression, Expression>(name, (Expression)initializer));
                        break;
                    }
                    }
                }
                else if (getOrSet && state.Code[i] != ':')
                {
                    i = s;
                    var mode             = state.Code[i] == 's' ? FunctionKind.Setter : FunctionKind.Getter;
                    var propertyAccessor = FunctionDefinition.Parse(state, ref i, mode) as FunctionDefinition;
                    var accessorName     = propertyAccessor.Name;
                    if (!flds.ContainsKey(accessorName))
                    {
                        var propertyPair = new PropertyPair
                                           (
                            mode == FunctionKind.Getter ? propertyAccessor : null,
                            mode == FunctionKind.Setter ? propertyAccessor : null
                                           );
                        flds.Add(accessorName, propertyPair);
                    }
                    else
                    {
                        var vle = flds[accessorName] as PropertyPair;

                        if (vle == null)
                        {
                            ExceptionHelper.ThrowSyntaxError("Try to define " + mode.ToString().ToLowerInvariant() + " for defined field", state.Code, s);
                        }

                        do
                        {
                            if (mode == FunctionKind.Getter)
                            {
                                if (vle.Getter == null)
                                {
                                    vle.Getter = propertyAccessor;
                                    break;
                                }
                            }
                            else
                            {
                                if (vle.Setter == null)
                                {
                                    vle.Setter = propertyAccessor;
                                    break;
                                }
                            }

                            ExceptionHelper.ThrowSyntaxError("Try to redefine " + mode.ToString().ToLowerInvariant() + " of " + propertyAccessor.Name, state.Code, s);
                        }while (false);
                    }
                }
                else
                {
                    if (asterisk)
                    {
                        do
                        {
                            i++;
                        }while (Tools.IsWhiteSpace(state.Code[i]));
                    }

                    i = s;
                    var fieldName = "";
                    if (Parser.ValidateName(state.Code, ref i, false, true, state.Strict))
                    {
                        fieldName = Tools.Unescape(state.Code.Substring(s, i - s), state.Strict);
                    }
                    else if (Parser.ValidateValue(state.Code, ref i))
                    {
                        if (state.Code[s] == '-')
                        {
                            ExceptionHelper.Throw(new SyntaxError("Invalid char \"-\" at " + CodeCoordinates.FromTextPosition(state.Code, s, 1)));
                        }
                        double d = 0.0;
                        int    n = s;
                        if (Tools.ParseNumber(state.Code, ref n, out d))
                        {
                            fieldName = Tools.DoubleToString(d);
                        }
                        else if (state.Code[s] == '\'' || state.Code[s] == '"')
                        {
                            fieldName = Tools.Unescape(state.Code.Substring(s + 1, i - s - 2), state.Strict);
                        }
                        else if (flds.Count != 0)
                        {
                            ExceptionHelper.Throw((new SyntaxError("Invalid field name at " + CodeCoordinates.FromTextPosition(state.Code, s, i - s))));
                        }
                        else
                        {
                            return(null);
                        }
                    }
                    else
                    {
                        return(null);
                    }

                    while (Tools.IsWhiteSpace(state.Code[i]))
                    {
                        i++;
                    }

                    Expression initializer = null;

                    if (state.Code[i] == '(')
                    {
                        i           = s;
                        initializer = FunctionDefinition.Parse(state, ref i, asterisk ? FunctionKind.MethodGenerator : FunctionKind.Method);
                    }
                    else
                    {
                        if (asterisk)
                        {
                            ExceptionHelper.ThrowSyntaxError("Unexpected token", state.Code, i);
                        }

                        if (state.Code[i] != ':' && state.Code[i] != ',' && state.Code[i] != '}')
                        {
                            ExceptionHelper.ThrowSyntaxError("Expected ',', ';' or '}'", state.Code, i);
                        }

                        Expression aei = null;
                        if (flds.TryGetValue(fieldName, out aei))
                        {
                            if (state.Strict ? (!(aei is Constant) || (aei as Constant).value != JSValue.undefined) : aei is PropertyPair)
                            {
                                ExceptionHelper.ThrowSyntaxError("Try to redefine field \"" + fieldName + "\"", state.Code, s, i - s);
                            }

                            state.Message?.Invoke(MessageLevel.Warning, i, 0, "Duplicate key \"" + fieldName + "\"");
                        }

                        if (state.Code[i] == ',' || state.Code[i] == '}')
                        {
                            if (!Parser.ValidateName(fieldName, 0))
                            {
                                ExceptionHelper.ThrowSyntaxError("Invalid variable name", state.Code, i);
                            }

                            initializer = new Variable(fieldName, state.LexicalScopeLevel);
                        }
                        else
                        {
                            do
                            {
                                i++;
                            }while (Tools.IsWhiteSpace(state.Code[i]));
                            initializer = ExpressionTree.Parse(state, ref i, false, false);
                        }
                    }
                    flds[fieldName] = initializer;
                }

                while (Tools.IsWhiteSpace(state.Code[i]))
                {
                    i++;
                }

                if ((state.Code[i] != ',') && (state.Code[i] != '}'))
                {
                    return(null);
                }
            }

            i++;
            var pos = index;

            index = i;
            return(new ObjectDefinition(flds, computedProperties.ToArray())
            {
                Position = pos,
                Length = index - pos
            });
        }
Пример #15
0
        public static Script Parse(string code, CompilerMessageCallback messageCallback = null, Options options = Options.None)
        {
            if (code == null)
            {
                throw new ArgumentNullException();
            }

            if (code == "")
            {
                return(new Script
                {
                    Root = new CodeBlock(new CodeNode[0]),
                    Code = ""
                });
            }

            var internalCallback = messageCallback != null ?
                                   (level, position, length, message) => messageCallback(level, CodeCoordinates.FromTextPosition(code, position, length), message)
                : null as InternalCompilerMessageCallback;

            int i    = 0;
            var root = (CodeBlock)CodeBlock.Parse(new ParseInfo(Parser.RemoveComments(code, 0), code, internalCallback), ref i);

            var stat = new FunctionInfo();

            Parser.Build(ref root, 0, new Dictionary <string, VariableDescriptor>(), CodeContext.None, internalCallback, stat, options);
            var body = root as CodeBlock;

            body._suppressScopeIsolation = SuppressScopeIsolationMode.Suppress;

            for (var vi = 0; vi < body._variables.Length; vi++)
            {
                body._variables[vi].captured = true;
            }

            var tv = stat.WithLexicalEnvironment ? null : new Dictionary <string, VariableDescriptor>();

            body.RebuildScope(stat, tv, body._variables.Length == 0 || !stat.WithLexicalEnvironment ? 1 : 0);
            var bd = body as CodeNode;

            body.Optimize(ref bd, null, internalCallback, options, stat);
            if (tv != null)
            {
                body._variables = new List <VariableDescriptor>(tv.Values).ToArray();
            }

            if (stat.NeedDecompose)
            {
                body.Decompose(ref bd);
            }

            return(new Script()
            {
                Code = code, Root = root
            });
        }
Пример #16
0
        internal static void ThrowReferenceError(string message, string code, int position, int length)
        {
            var cord = CodeCoordinates.FromTextPosition(code, position, 0);

            Throw(new ReferenceError(message + " " + cord));
        }
Пример #17
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }

            if (!Parser.Validate(state.Code, "do", ref i) || !Parser.IsIdentifierTerminator(state.Code[i]))
            {
                return(null);
            }

            int labelsCount = state.LabelsCount;

            state.LabelsCount = 0;
            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            state.AllowBreak.Push(true);
            state.AllowContinue.Push(true);
            int ccs  = state.continiesCount;
            int cbs  = state.breaksCount;
            var body = Parser.Parse(state, ref i, 0);

            if (body is FunctionDefinition)
            {
                if (state.message != null)
                {
                    state.message(MessageLevel.CriticalWarning, body.Position, body.Length, Strings.DoNotDeclareFunctionInNestedBlocks);
                }
                body = new CodeBlock(new[] { body }); // для того, чтобы не дублировать код по декларации функции,
                // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию.
            }
            state.AllowBreak.Pop();
            state.AllowContinue.Pop();
            if (!(body is CodeBlock) && state.Code[i] == ';')
            {
                i++;
            }
            while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (i >= state.Code.Length)
            {
                ExceptionHelper.ThrowSyntaxError(Strings.UnexpectedEndOfSource);
            }
            if (!Parser.Validate(state.Code, "while", ref i))
            {
                ExceptionHelper.Throw((new SyntaxError("Expected \"while\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
            }
            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (state.Code[i] != '(')
            {
                ExceptionHelper.Throw((new SyntaxError("Expected \"(\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
            }
            do
            {
                i++;
            }while (Tools.IsWhiteSpace(state.Code[i]));
            var condition = Parser.Parse(state, ref i, CodeFragmentType.Expression);

            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (state.Code[i] != ')')
            {
                ExceptionHelper.Throw((new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
            }
            i++;
            var pos = index;

            index = i;
            return(new DoWhile()
            {
                allowRemove = ccs == state.continiesCount && cbs == state.breaksCount,
                body = body,
                condition = condition,
                labels = state.Labels.GetRange(state.Labels.Count - labelsCount, labelsCount).ToArray(),
                Position = pos,
                Length = index - pos
            });
        }
Пример #18
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            if (!Parser.Validate(state.Code, "switch (", ref i) && !Parser.Validate(state.Code, "switch(", ref i))
            {
                return(null);
            }

            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }

            var      body   = new List <CodeNode>();
            var      funcs  = new List <FunctionDefinition>();
            var      cases  = new List <SwitchCase>();
            CodeNode result = null;

            cases.Add(new SwitchCase()
            {
                index = int.MaxValue
            });
            state.AllowBreak.Push(true);
            var oldVariablesCount = state.Variables.Count;

            VariableDescriptor[] vars = null;
            state.LexicalScopeLevel++;
            try
            {
                var image = ExpressionTree.Parse(state, ref i);

                if (state.Code[i] != ')')
                {
                    ExceptionHelper.Throw((new SyntaxError("Expected \")\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }

                do
                {
                    i++;
                }while (Tools.IsWhiteSpace(state.Code[i]));

                if (state.Code[i] != '{')
                {
                    ExceptionHelper.Throw((new SyntaxError("Expected \"{\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                }

                do
                {
                    i++;
                }while (Tools.IsWhiteSpace(state.Code[i]));

                while (state.Code[i] != '}')
                {
                    do
                    {
                        if (Parser.Validate(state.Code, "case", i) && Parser.IsIdentifierTerminator(state.Code[i + 4]))
                        {
                            i += 4;
                            while (Tools.IsWhiteSpace(state.Code[i]))
                            {
                                i++;
                            }
                            var sample = ExpressionTree.Parse(state, ref i);
                            if (state.Code[i] != ':')
                            {
                                ExceptionHelper.Throw((new SyntaxError("Expected \":\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                            }
                            i++;
                            cases.Add(new SwitchCase()
                            {
                                index = body.Count, statement = sample
                            });
                        }
                        else if (Parser.Validate(state.Code, "default", i) && Parser.IsIdentifierTerminator(state.Code[i + 7]))
                        {
                            i += 7;
                            while (Tools.IsWhiteSpace(state.Code[i]))
                            {
                                i++;
                            }
                            if (cases[0].index != int.MaxValue)
                            {
                                ExceptionHelper.Throw((new SyntaxError("Duplicate default case in switch at " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                            }
                            if (state.Code[i] != ':')
                            {
                                ExceptionHelper.Throw((new SyntaxError("Expected \":\" at + " + CodeCoordinates.FromTextPosition(state.Code, i, 0))));
                            }
                            i++;
                            cases[0].index = body.Count;
                        }
                        else
                        {
                            break;
                        }
                        while (Tools.IsWhiteSpace(state.Code[i]) || (state.Code[i] == ';'))
                        {
                            i++;
                        }
                    } while (true);
                    if (cases.Count == 1 && cases[0].index == int.MaxValue)
                    {
                        ExceptionHelper.Throw((new SyntaxError("Switch statement must contain cases. " + CodeCoordinates.FromTextPosition(state.Code, index, 0))));
                    }

                    var t = Parser.Parse(state, ref i, 0);
                    if (t == null)
                    {
                        continue;
                    }

                    body.Add(t);
                    while (Tools.IsWhiteSpace(state.Code[i]) || (state.Code[i] == ';'))
                    {
                        i++;
                    }
                }
                state.AllowBreak.Pop();
                i++;
                var pos = index;
                index  = i;
                result = new Switch(body.ToArray())
                {
                    functions = funcs.ToArray(),
                    cases     = cases.ToArray(),
                    image     = image,
                    Position  = pos,
                    Length    = index - pos
                };
                vars = CodeBlock.extractVariables(state, oldVariablesCount);
            }
            finally
            {
                state.LexicalScopeLevel--;
            }

            return(new CodeBlock(new[] { result })
            {
                _variables = vars,
                Position = result.Position,
                Length = result.Length
            });
        }
Пример #19
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int  position = index;
            bool sroot    = position == 0 && state.AllowDirectives;

            if (!sroot)
            {
                if (state.Code[position] != '{')
                {
                    throw new ArgumentException("code (" + position + ")");
                }
                position++;
            }

            Tools.SkipSpaces(state.Code, ref position);

            var              body            = new List <CodeNode>();
            bool             strictSwitch    = false;
            bool             allowDirectives = state.AllowDirectives;
            HashSet <string> directives      = null;

            state.AllowDirectives = false;

            var oldFunctionScopeLevel = state.functionScopeLevel;

            state.lexicalScopeLevel++;
            if (allowDirectives)
            {
                state.functionScopeLevel = state.lexicalScopeLevel;
            }

            var oldVariablesCount = state.Variables.Count;

            VariableDescriptor[] variables = null;
            state.LabelsCount = 0;
            try
            {
                if (allowDirectives)
                {
                    int start = position;
                    do
                    {
                        var s = position;
                        if (position >= state.Code.Length)
                        {
                            break;
                        }
                        if (Parser.ValidateValue(state.Code, ref position))
                        {
                            while (position < state.Code.Length && Tools.IsWhiteSpace(state.Code[position]))
                            {
                                position++;
                            }
                            if (position < state.Code.Length && (Parser.IsOperator(state.Code[position]) ||
                                                                 Parser.Validate(state.Code, "instanceof", position) ||
                                                                 Parser.Validate(state.Code, "in", position)))
                            {
                                position = s;
                                break;
                            }
                            var t = s;
                            if (Parser.ValidateString(state.Code, ref t, true))
                            {
                                var str = state.Code.Substring(s + 1, t - s - 2);
                                if (!strictSwitch && str == "use strict" && !state.strict)
                                {
                                    state.strict = true;
                                    strictSwitch = true;
                                }
                                if (directives == null)
                                {
                                    directives = new HashSet <string>();
                                }
                                directives.Add(str);
                            }
                            else
                            {
                                position = s;
                                break;
                            }
                        }
                        else if (state.Code[position] == ';')
                        {
                            if (directives == null)
                            {
                                break;
                            }
                            do
                            {
                                position++;
                            }while (position < state.Code.Length && Tools.IsWhiteSpace(state.Code[position]));
                        }
                        else
                        {
                            break;
                        }
                    }while (true);
                    position = start;
                }

                for (var j = body.Count; j-- > 0;)
                {
                    (body[j] as Constant).value._oValue = Tools.Unescape((body[j] as Constant).value._oValue.ToString(), state.strict);
                }

                bool expectSemicolon = false;
                while ((sroot && position < state.Code.Length) || (!sroot && state.Code[position] != '}'))
                {
                    var t = Parser.Parse(state, ref position, 0);
                    if (t == null)
                    {
                        if (position < state.Code.Length)
                        {
                            if (sroot && state.Code[position] == '}')
                            {
                                ExceptionHelper.Throw(new SyntaxError("Unexpected symbol \"}\" at " + CodeCoordinates.FromTextPosition(state.Code, position, 0)));
                            }

                            if ((state.Code[position] == ';' || state.Code[position] == ','))
                            {
                                if (state.message != null && !expectSemicolon)
                                {
                                    state.message(MessageLevel.Warning, position, 1, "Unnecessary semicolon.");
                                }

                                position++;
                            }

                            expectSemicolon = false;
                        }

                        continue;
                    }

                    expectSemicolon = !(t is EntityDefinition);

                    body.Add(t);
                }
            }
            finally
            {
                if (oldVariablesCount != state.Variables.Count)
                {
                    variables = extractVariables(state, oldVariablesCount);
                }

                state.functionScopeLevel = oldFunctionScopeLevel;
                state.lexicalScopeLevel--;
            }

            if (!sroot)
            {
                position++;
            }

            int startPos = index;

            index = position;
            return(new CodeBlock(body.ToArray())
            {
                _strict = (state.strict ^= strictSwitch) || strictSwitch,
                _variables = variables ?? emptyVariables,
                Position = startPos,
                code = state.SourceCode,
                Length = position - startPos,
#if DEBUG
                directives = directives
#endif
            });
        }
Пример #20
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            int i = index;

            if (!Parser.Validate(state.Code, "throw", ref i) || (!Parser.IsIdentifierTerminator(state.Code[i])))
            {
                return(null);
            }
            while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]) && !Tools.IsLineTerminator(state.Code[i]))
            {
                i++;
            }
            var b = state.Code[i] == ';' || Tools.IsLineTerminator(state.Code[i]) ? null : (Expression)Parser.Parse(state, ref i, CodeFragmentType.Expression);

            if (b is Empty)
            {
                ExceptionHelper.Throw((new SyntaxError("Can't throw result of EmptyStatement " + CodeCoordinates.FromTextPosition(state.Code, i - 1, 0))));
            }
            var pos = index;

            index = i;
            return(new Throw(b)
            {
                Position = pos,
                Length = index - pos
            });
        }
Пример #21
0
        /// <summary>
        /// Initializes a new Module with specified code, callback for output compiler messages and compiler options.
        /// </summary>
        /// <param name="path">Path to file with script. Used for resolving paths to other modules for importing via import directive. Can be null or empty</param>
        /// <param name="code">JavaScript code.</param>
        /// <param name="messageCallback">Callback used to output compiler messages or null</param>
        /// <param name="options">Compiler options</param>
        public Module(string path, string code, CompilerMessageCallback messageCallback, Options options)
        {
            if (code == null)
            {
                throw new ArgumentNullException();
            }

            Code            = code;
            Context         = new Context(Context.CurrentGlobalContext, true, null);
            Context._module = this;
            if (!string.IsNullOrWhiteSpace(path))
            {
                lock (_modulesCache)
                {
                    if (!_modulesCache.ContainsKey(path))
                    {
                        _modulesCache[path] = this;
                    }
                }

                FilePath = path;
            }

            if (code == "")
            {
                return;
            }

            var internalCallback = messageCallback != null ?
                                   (level, position, length, message) => messageCallback(level, CodeCoordinates.FromTextPosition(code, position, length), message)
                : null as InternalCompilerMessageCallback;

            int i = 0;

            _root = (CodeBlock)CodeBlock.Parse(new ParseInfo(Parser.RemoveComments(code, 0), Code, internalCallback), ref i);

            var stat = new FunctionInfo();

            Parser.Build(ref _root, 0, new Dictionary <string, VariableDescriptor>(), CodeContext.None, internalCallback, stat, options);
            var body = _root as CodeBlock;

            body._suppressScopeIsolation = SuppressScopeIsolationMode.Suppress;
            Context._thisBind            = new GlobalObject(Context);
            Context._strict = body._strict;

            var tv = stat.WithLexicalEnvironment ? null : new Dictionary <string, VariableDescriptor>();

            body.RebuildScope(stat, tv, body._variables.Length == 0 || !stat.WithLexicalEnvironment ? 1 : 0);
            var bd = body as CodeNode;

            body.Optimize(ref bd, null, internalCallback, options, stat);
            if (tv != null)
            {
                body._variables = new List <VariableDescriptor>(tv.Values).ToArray();
            }

            if (stat.NeedDecompose)
            {
                body.Decompose(ref bd);
            }
        }
Пример #22
0
        internal static CodeNode Parse(ParseInfo state, ref int index, bool forForLoop)
        {
            int position = index;

            Tools.SkipSpaces(state.Code, ref position);

            VariableKind mode;

            if (Parser.Validate(state.Code, "var ", ref position))
            {
                mode = VariableKind.FunctionScope;
            }
            else if (Parser.Validate(state.Code, "let ", ref position))
            {
                mode = VariableKind.LexicalScope;
            }
            else if (Parser.Validate(state.Code, "const ", ref position))
            {
                mode = VariableKind.ConstantInLexicalScope;
            }
            else
            {
                return(null);
            }

            var level        = mode <= VariableKind.FunctionScope ? state.FunctionScopeLevel : state.LexicalScopeLevel;
            var initializers = new List <Expression>();
            var names        = new List <string>();
            int s            = position;

            while ((state.Code[position] != ';') && (state.Code[position] != '}') && !Tools.IsLineTerminator(state.Code[position]))
            {
                Tools.SkipSpaces(state.Code, ref position);

                if (state.Code[position] != '[' && state.Code[position] != '{' && !Parser.ValidateName(state.Code, position, state.Strict))
                {
                    if (Parser.ValidateName(state.Code, ref position, false, true, state.Strict))
                    {
                        ExceptionHelper.ThrowSyntaxError('\"' + Tools.Unescape(state.Code.Substring(s, position - s), state.Strict) + "\" is a reserved word, but used as a variable. " + CodeCoordinates.FromTextPosition(state.Code, s, position - s));
                    }
                    ExceptionHelper.ThrowSyntaxError("Invalid variable definition at " + CodeCoordinates.FromTextPosition(state.Code, s, position - s));
                }

                var expression = ExpressionTree.Parse(state, ref position, processComma: false, forForLoop: forForLoop);
                if (expression is VariableReference)
                {
                    var name = expression.ToString();
                    if (state.Strict)
                    {
                        if (name == "arguments" || name == "eval")
                        {
                            ExceptionHelper.ThrowSyntaxError("Varible name cannot be \"arguments\" or \"eval\" in strict mode", state.Code, s, position - s);
                        }
                    }

                    names.Add(name);
                    initializers.Add(expression);
                }
                else
                {
                    var valid = false;
                    var expr  = expression as ExpressionTree;
                    if (expr != null)
                    {
                        if (expr.Type == OperationType.None && expr._right == null)
                        {
                            expr = expr._left as ExpressionTree;
                        }
                        valid |= expr != null && expr.Type == OperationType.Assignment;

                        if (valid)
                        {
                            if (expr._left is ObjectDesctructor)
                            {
                                var expressions = (expr._left as ObjectDesctructor).GetTargetVariables();
                                for (var i = 0; i < expressions.Count; i++)
                                {
                                    names.Add(expressions[i].ToString());
                                    initializers.Add(expressions[i]);
                                }

                                initializers.Add(expr);
                            }
                            else
                            {
                                names.Add(expr._left.ToString());
                                initializers.Add(expression);
                            }
                        }
                    }
                    else
                    {
                        var cnst = expression as Constant;
                        valid = cnst != null && cnst.value == JSValue.undefined;
                        if (valid)
                        {
                            initializers.Add(expression);
                            names.Add(cnst.value.ToString());
                        }
                    }

                    if (!valid)
                    {
                        ExceptionHelper.ThrowSyntaxError("Invalid variable initializer", state.Code, position);
                    }
                }

                s = position;

                if (position >= state.Code.Length)
                {
                    break;
                }

                Tools.SkipSpaces(state.Code, ref s);
                if (s >= state.Code.Length)
                {
                    break;
                }
                if (state.Code[s] == ',')
                {
                    position = s + 1;
                    Tools.SkipSpaces(state.Code, ref position);
                }
                else
                {
                    break;
                }
            }

            if (names.Count == 0)
            {
                throw new InvalidOperationException("code (" + position + ")");
            }

            if (!forForLoop && position < state.Code.Length && state.Code[position] == ';')
            {
                position++;
            }
            else
            {
                position = s;
            }

            var variables = new VariableDescriptor[names.Count];

            for (int i = 0, skiped = 0; i < names.Count; i++)
            {
                bool skip = false;
                for (var j = 0; j < state.Variables.Count - i + skiped; j++)
                {
                    if (state.Variables[j].name == names[i] && state.Variables[j].definitionScopeLevel >= level)
                    {
                        if (state.Variables[j].lexicalScope || mode > VariableKind.FunctionScope)
                        {
                            ExceptionHelper.ThrowSyntaxError(string.Format(Strings.IdentifierAlreadyDeclared, names[i]), state.Code, index);
                        }

                        skip         = true;
                        variables[i] = state.Variables[j];
                        skiped++;
                        break;
                    }
                }

                if (skip)
                {
                    continue;
                }

                variables[i] = new VariableDescriptor(names[i], level)
                {
                    lexicalScope = mode > VariableKind.FunctionScope,
                    isReadOnly   = mode == VariableKind.ConstantInLexicalScope
                };

                state.Variables.Add(variables[i]);
            }

            var pos = index;

            index = position;
            return(new VariableDefinition(variables, initializers.ToArray(), mode)
            {
                Position = pos,
                Length = index - pos
            });
        }
Пример #23
0
        /// <summary>
        /// Evaluate script
        /// </summary>
        /// <param name="code">Code in JavaScript</param>
        /// <param name="suppressScopeCreation">If true, scope will not be created. All variables, which will be defined via let, const or class will not be destructed after evalution</param>
        /// <returns>Result of last evaluated operation</returns>
        public JSValue Eval(string code, JSValue thisBind, bool suppressScopeCreation = false)
        {
            if (_parent == null)
            {
                throw new InvalidOperationException("Cannot execute script in global context");
            }

            if (string.IsNullOrEmpty(code))
            {
                return(JSValue.undefined);
            }

            // чистить кэш тут не достаточно.
            // Мы не знаем, где объявлена одноимённая переменная
            // и в тех случаях, когда она пришла из функции выше
            // или даже глобального контекста, её кэш может быть
            // не сброшен вовремя и значение будет браться из контекста
            // eval'а, а не того контекста, в котором её позовут.

            /*
             * function a(){
             *  var c = 1;
             *  function b(){
             *      eval("var c = 2");
             *      // переменная объявлена в контексте b, значит и значение должно быть из
             *      // контекста b, но если по выходу из b кэш этой переменной сброшен не будет,
             *      // то в a её значение будет 2
             *  }
             * }
             */

            var mainFunctionContext = this;
            var stack = GetCurrectContextStack();

            while (stack != null &&
                   stack.Count > 1 &&
                   stack[stack.Count - 2] == mainFunctionContext._parent &&
                   stack[stack.Count - 2]._owner == mainFunctionContext._owner)
            {
                mainFunctionContext = mainFunctionContext._parent;
            }

            int    index = 0;
            string c     = Parser.RemoveComments(code, 0);
            var    ps    = new ParseInfo(c, code, null)
            {
                strict          = _strict,
                AllowDirectives = true,
                CodeContext     = CodeContext.InEval
            };

            var body = CodeBlock.Parse(ps, ref index) as CodeBlock;

            if (index < c.Length)
            {
                throw new ArgumentException("Invalid char");
            }
            var variables = new Dictionary <string, VariableDescriptor>();
            var stats     = new FunctionInfo();

            CodeNode cb = body;

            Parser.Build(ref cb, 0, variables, (_strict ? CodeContext.Strict : CodeContext.None) | CodeContext.InEval, null, stats, Options.None);

            var tv = stats.WithLexicalEnvironment ? null : new Dictionary <string, VariableDescriptor>();

            body.RebuildScope(stats, tv, body._variables.Length == 0 || !stats.WithLexicalEnvironment ? 1 : 0);
            if (tv != null)
            {
                var newVarDescs = new VariableDescriptor[tv.Values.Count];
                tv.Values.CopyTo(newVarDescs, 0);
                body._variables = newVarDescs;
                body._suppressScopeIsolation = SuppressScopeIsolationMode.DoNotSuppress;
            }

            body.Optimize(ref cb, null, null, Options.SuppressUselessExpressionsElimination | Options.SuppressConstantPropogation, stats);
            body = cb as CodeBlock ?? body;

            if (stats.NeedDecompose)
            {
                body.Decompose(ref cb);
            }

            body._suppressScopeIsolation = SuppressScopeIsolationMode.Suppress;

            var debugging = _debugging;

            _debugging = false;
            var runned = this.Activate();

            try
            {
                var context = suppressScopeCreation || (!stats.WithLexicalEnvironment && !body._strict && !_strict) ? this : new Context(this, false, _owner)
                {
                    _strict = _strict || body._strict
                };

                if (suppressScopeCreation || (!_strict && !body._strict))
                {
                    for (var i = 0; i < body._variables.Length; i++)
                    {
                        if (!body._variables[i].lexicalScope)
                        {
                            JSValue variable;
                            var     cc = mainFunctionContext;
                            while (cc._parent._parent != null &&
                                   (cc._variables == null || !cc._variables.TryGetValue(body._variables[i].name, out variable)))
                            {
                                cc = cc._parent;
                            }

                            if (cc._definedVariables != null)
                            {
                                for (var j = 0; j < cc._definedVariables.Length; j++)
                                {
                                    if (cc._definedVariables[j].name == body._variables[i].name)
                                    {
                                        cc._definedVariables[j].definitionScopeLevel = -1;
                                    }
                                }
                            }

                            variable = mainFunctionContext.DefineVariable(body._variables[i].name, !suppressScopeCreation);

                            if (body._variables[i].initializer != null)
                            {
                                variable.Assign(body._variables[i].initializer.Evaluate(context));
                            }

                            // блокирует создание переменной в конктексте eval
                            body._variables[i].lexicalScope = true;

                            // блокирует кеширование
                            body._variables[i].definitionScopeLevel = -1;
                        }
                    }
                }

                if (body._lines.Length == 0)
                {
                    return(JSValue.undefined);
                }

                var oldThisBind      = ThisBind;
                var runContextOfEval = context.Activate();
                context._thisBind = thisBind;
                try
                {
                    return(body.Evaluate(context) ?? context._lastResult ?? JSValue.notExists);
                }
                catch (JSException e)
                {
                    if ((e.Code == null || e.CodeCoordinates == null) && e.ExceptionMaker != null)
                    {
                        e.Code            = code;
                        e.CodeCoordinates = CodeCoordinates.FromTextPosition(code, e.ExceptionMaker.Position, e.ExceptionMaker.Length);
                    }

                    throw;
                }
                finally
                {
                    context._thisBind = oldThisBind;
                    if (runContextOfEval)
                    {
                        context.Deactivate();
                    }
                }
            }
            finally
            {
                if (runned)
                {
                    this.Deactivate();
                }
                this._debugging = debugging;
            }
        }
Пример #24
0
        internal static CodeNode Parse(ParseInfo state, ref int index)
        {
            //string code = state.Code;
            int i = index;

            if (!Parser.Validate(state.Code, "while (", ref i) && !Parser.Validate(state.Code, "while(", ref i))
            {
                return(null);
            }
            int labelsCount = state.LabelsCount;

            state.LabelsCount = 0;
            while (Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            var condition = Parser.Parse(state, ref i, CodeFragmentType.Expression);

            while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]))
            {
                i++;
            }
            if (i >= state.Code.Length)
            {
                ExceptionHelper.Throw(new SyntaxError("Unexpected end of line."));
            }
            if (state.Code[i] != ')')
            {
                throw new ArgumentException("code (" + i + ")");
            }
            do
            {
                i++;
            }while (i < state.Code.Length && Tools.IsWhiteSpace(state.Code[i]));
            if (i >= state.Code.Length)
            {
                ExceptionHelper.Throw(new SyntaxError("Unexpected end of line."));
            }
            state.AllowBreak.Push(true);
            state.AllowContinue.Push(true);
            int ccs  = state.continiesCount;
            int cbs  = state.breaksCount;
            var body = Parser.Parse(state, ref i, 0);

            if (body is FunctionDefinition)
            {
                if (state.strict)
                {
                    ExceptionHelper.Throw((new NiL.JS.BaseLibrary.SyntaxError("In strict mode code, functions can only be declared at top level or immediately within another function.")));
                }
                if (state.message != null)
                {
                    state.message(MessageLevel.CriticalWarning, CodeCoordinates.FromTextPosition(state.Code, body.Position, body.Length), "Do not declare function in nested blocks.");
                }
                body = new CodeBlock(new[] { body }); // для того, чтобы не дублировать код по декларации функции,
                // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию.
            }
            state.AllowBreak.Pop();
            state.AllowContinue.Pop();
            var pos = index;

            index = i;
            return(new While()
            {
                allowRemove = ccs == state.continiesCount && cbs == state.breaksCount,
                body = body,
                condition = condition,
                labels = state.Labels.GetRange(state.Labels.Count - labelsCount, labelsCount).ToArray(),
                Position = pos,
                Length = index - pos
            });
        }