Beispiel #1
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, CodeCoordinates.FromTextPosition(state.Code, 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);
        }
Beispiel #2
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
            });
        }
Beispiel #3
0
        public override bool Build(ref CodeNode _this, int expressionDepth, Dictionary <string, VariableDescriptor> variables, CodeContext codeContext, CompilerMessageCallback message, FunctionInfo stats, Options opts)
        {
            Parser.Build(ref _initializer, 1, variables, codeContext, message, stats, opts);
            var initAsVds = _initializer as VariableDefinition;

            if ((opts & Options.SuppressUselessStatementsElimination) == 0)
            {
                if (initAsVds != null && initAsVds._initializers.Length == 1 && initAsVds.Kind == VariableKind.FunctionScope)
                {
                    _initializer = initAsVds._initializers[0];
                }
            }

            Parser.Build(ref _condition, 2, variables, codeContext | CodeContext.InLoop | CodeContext.InExpression, message, stats, opts);

            if (_post != null)
            {
                Parser.Build(ref _post, 1, variables, codeContext | CodeContext.Conditional | CodeContext.InLoop | CodeContext.InExpression, message, stats, opts);
                if (_post == null && message != null)
                {
                    message(MessageLevel.Warning, new CodeCoordinates(0, Position, Length), "Last expression of for-loop was removed. Maybe, it's a mistake.");
                }
            }

            Parser.Build(ref _body, System.Math.Max(1, expressionDepth), variables, codeContext | CodeContext.Conditional | CodeContext.InLoop, message, stats, opts);

            if (initAsVds != null && initAsVds.Kind != VariableKind.FunctionScope && initAsVds._variables.Any(x => x.captured))
            {
                var bodyAsCodeBlock = _body as CodeBlock;
                if (bodyAsCodeBlock != null)
                {
                    var newLines = new CodeNode[bodyAsCodeBlock._lines.Length + 1];
                    System.Array.Copy(bodyAsCodeBlock._lines, newLines, bodyAsCodeBlock._lines.Length);
                    newLines[newLines.Length - 1] = new PerIterationScopeInitializer(initAsVds._variables);
                    bodyAsCodeBlock._lines        = newLines;
                }
                else
                {
                    _body = bodyAsCodeBlock = new CodeBlock(new[] { _body, new PerIterationScopeInitializer(initAsVds._variables) });
                }

                bodyAsCodeBlock._suppressScopeIsolation = SuppressScopeIsolationMode.DoNotSuppress;

                for (var i = 0; i < initAsVds._variables.Length; i++)
                {
                    if (initAsVds._variables[i].captured)
                    {
                        initAsVds._variables[i].definitionScopeLevel = -1;
                    }
                }
            }

            if (_condition == null)
            {
                _condition = new Constant(BaseLibrary.Boolean.True);
            }
            else if ((_condition is Expression) &&
                     (_condition as Expression).ContextIndependent &&
                     !(bool)_condition.Evaluate(null))
            {
                _this = _initializer;
                return(false);
            }
            else if (_body == null || _body is Empty)
            {
                VariableReference variable = null;
                Constant          limit    = null;
                if (_condition is Less)
                {
                    variable = (_condition as Less).LeftOperand as VariableReference;
                    limit    = (_condition as Less).RightOperand as Constant;
                }
                else if (_condition is More)
                {
                    variable = (_condition as More).RightOperand as VariableReference;
                    limit    = (_condition as More).LeftOperand as Constant;
                }
                else if (_condition is NotEqual)
                {
                    variable = (_condition as Less).RightOperand as VariableReference;
                    limit    = (_condition as Less).LeftOperand as Constant;
                    if (variable == null && limit == null)
                    {
                        variable = (_condition as Less).LeftOperand as VariableReference;
                        limit    = (_condition as Less).RightOperand as Constant;
                    }
                }
                if (variable != null &&
                    limit != null &&
                    _post is Increment &&
                    ((_post as Increment).LeftOperand as VariableReference)._descriptor == variable._descriptor)
                {
                    if (variable.ScopeLevel >= 0 && variable._descriptor.definitionScopeLevel >= 0)
                    {
                        if (_initializer is Assignment &&
                            (_initializer as Assignment).LeftOperand is Variable &&
                            ((_initializer as Assignment).LeftOperand as Variable)._descriptor == variable._descriptor)
                        {
                            var value = (_initializer as Assignment).RightOperand;
                            if (value is Constant)
                            {
                                var vvalue = value.Evaluate(null);
                                var lvalue = limit.Evaluate(null);
                                if ((vvalue._valueType == JSValueType.Integer ||
                                     vvalue._valueType == JSValueType.Boolean ||
                                     vvalue._valueType == JSValueType.Double) &&
                                    (lvalue._valueType == JSValueType.Integer ||
                                     lvalue._valueType == JSValueType.Boolean ||
                                     lvalue._valueType == JSValueType.Double))
                                {
                                    _post.Eliminated      = true;
                                    _condition.Eliminated = true;

                                    if (!Less.Check(vvalue, lvalue))
                                    {
                                        _this = _initializer;
                                        return(false);
                                    }

                                    _this = new CodeBlock(new[] { _initializer, new Assignment(variable, limit) });
                                    return(true);
                                }
                            }
                        }
                    }
                }
            }
            return(false);
        }
Beispiel #4
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 ForIn()
            {
                _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, "in", 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-in 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
            });
        }
Beispiel #5
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, 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
            });
        }
Beispiel #6
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, 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, 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
            });
        }
Beispiel #7
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
            });
        }
Beispiel #8
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]));

            var combinedBody = state.Code[i] == '{';

            CodeNode 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 }); // для того, чтобы не дублировать код по декларации функции,
                // она оборачивается в блок, который сделает самовыпил на втором этапе, но перед этим корректно объявит функцию.
            }

            CodeNode elseBody = null;

            var pos = i;

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

            if (i < state.Code.Length && !combinedBody && 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.message != null)
                    {
                        state.message(MessageLevel.CriticalWarning, elseBody.Position, elseBody.Length, Strings.DoNotDeclareFunctionInNestedBlocks);
                    }

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