Beispiel #1
0
        public static void CopyStatement(ILSLCodeStatement to, ILSLCodeStatement from)
        {
            to.IsLastStatementInScope     = from.IsLastStatementInScope;
            to.InsideSingleStatementScope = from.InsideSingleStatementScope;

            to.IsDeadCode     = from.IsDeadCode;
            to.DeadCodeType   = from.DeadCodeType;
            to.StatementIndex = from.StatementIndex;
            to.ParentScopeId  = from.ParentScopeId;
        }
Beispiel #2
0
        /// <summary>
        ///     Add a code statement to the code scope, the dead code detection algorithm is encapsulated inside
        ///     of this object, the algorithm is on-line and most of its logic occurs in this function
        /// </summary>
        /// <remarks>
        ///     if JumpStatementAnalysis is enabled, this function expects the JumpTarget of every
        ///     <see cref="LSLJumpStatementNode" /> object (the <see cref="LSLLabelStatementNode" /> reference) to have a correct
        ///     StatementIndex and ScopeId already. this includes JumpTarget's that are jumps forward in code
        ///     and have not been added to the code scope yet.  this prerequisite should be accomplished
        ///     with a pre-pass that creates the jump graph ahead of time. so that all Jump statement objects
        ///     have a reference to where they jump to exactly, and all label statements have references to
        ///     the jump statements that jump to to them.
        /// </remarks>
        /// <param name="statement">The statement to add to the code scope</param>
        /// <exception cref="ArgumentNullException"><paramref name="statement" /> is <c>null</c>.</exception>
        /// <exception cref="InvalidOperationException"><see cref="EndScope"/> has already been called.</exception>
        /// <seealso cref="EndScope" />
        public void AddStatement(ILSLCodeStatement statement)
        {
            if (statement == null)
            {
                throw new ArgumentNullException("statement");
            }

            if (_endScope)
            {
                throw new InvalidOperationException(
                          "EndScope has already been called, cannot add any more statements.");
            }


            var asCodeScope = statement as LSLCodeScopeNode;

            if (asCodeScope != null)
            {
                asCodeScope.CodeScopeType = LSLCodeScopeType.AnonymousBlock;
            }

            var asLabel = statement as LSLLabelStatementNode;

            if (_preDefinedLabels.Contains(asLabel))
            {
                _preDefinedLabels.Remove(asLabel);
            }
            else
            {
                statement.Parent = this;
            }


            statement.InsideSingleStatementScope = IsSingleStatementScope;

            statement.StatementIndex         = _codeStatements.Count;
            statement.IsLastStatementInScope = true;
            statement.ParentScopeId          = ScopeId;

            if (_lastStatementAdded != null)
            {
                _lastStatementAdded.IsLastStatementInScope = false;
            }

            _lastStatementAdded = statement;
            _codeStatements.Add(statement);


            if (!_insideDeadCode)
            {
                //inspect all constant jumps that have been added prior to the current statement
                foreach (var constantJump in ConstantJumps)
                {
                    if (constantJump.JumpTarget.ParentScopeId != ScopeId)
                    {
                        //we jumped out of the scope, into the outer scope. this is the only possible scenario
                        //because we can't jump into a nested scope (like into an if statement, or scope block).
                        //everything after the jump out is dead, like a return statement

                        _insideDeadCode = true;


                        if (FirstDeadStatementNode == null)
                        {
                            FirstDeadStatementNode = statement;
                        }

                        _deadCodeSegmentsStack.Push(
                            new LSLDeadCodeSegment(LSLDeadCodeType.AfterJumpOutOfScope));
                    }
                    else if ((constantJump.EffectiveJumpStatement.StatementIndex < statement.StatementIndex) &&
                             (constantJump.JumpTarget.StatementIndex > statement.StatementIndex))
                    {
                        //this is a jump over code scenario
                        //when _deadCodeJumpOverEnding statement index is reached, we are no longer inside
                        //dead code
                        _inDeadJumpedOverCode   = true;
                        _deadCodeJumpOverEnding = constantJump.JumpTarget.StatementIndex;
                        _insideDeadCode         = true;

                        if (FirstDeadStatementNode == null)
                        {
                            FirstDeadStatementNode = statement;
                        }

                        _deadCodeSegmentsStack.Push(
                            new LSLDeadCodeSegment(LSLDeadCodeType.JumpOverCode));
                    }
                    else if ((constantJump.EffectiveJumpStatement.StatementIndex < statement.StatementIndex) &&
                             (constantJump.JumpTarget.StatementIndex <
                              constantJump.EffectiveJumpStatement.StatementIndex))
                    {
                        //we are below a forever loop that jumps upward into the same scope
                        //so everything else after is dead, like a return statement

                        _insideDeadCode = true;

                        if (FirstDeadStatementNode == null)
                        {
                            FirstDeadStatementNode = statement;
                        }

                        _deadCodeSegmentsStack.Push(
                            new LSLDeadCodeSegment(LSLDeadCodeType.AfterJumpLoopForever));
                    }
                }


                var control = statement as LSLControlStatementNode;
                if (control != null)
                {
                    var cJump = control.GetConstantJump();
                    if (cJump != null && !_insideDeadCode)
                    {
                        _constantJumps.Add(cJump);
                    }
                }

                var jump = statement as LSLJumpStatementNode;

                //don't add the jump if its an error, because the only
                //reason for it to be an error would be for it to have
                //referenced a non existent label. the recursive nature
                //of how a constant jump is derived from a control chain
                //keeps GetConstantJump() from ever returning an erroneous node
                //since its child scopes won't add them either
                if (jump != null && !_insideDeadCode && !jump.HasErrors)
                {
                    jump.ConstantJump = true;
                    _constantJumps.Add(new LSLConstantJumpDescription(jump));
                }
            }


            if (!_inDeadJumpedOverCode && !IsSingleStatementScope)
            {
                if (!HasReturnPath && statement.HasReturnPath)
                {
                    HasReturnPath = true;
                    ReturnPath    = statement;
                    //if the return path was a top level return statement
                    //save it, otherwise null
                    ReturnStatementNode = statement as LSLReturnStatementNode;

                    _afterLabelJumpDownOverReturn = false;
                }
                else if (HasReturnPath)
                {
                    //this code is after a return path, everything after is dead

                    var label = statement as LSLLabelStatementNode;

                    var dead = !_afterLabelJumpDownOverReturn;

                    if (label != null)
                    {
                        if (
                            label.JumpsToHere.Any(
                                x => (x.SourceRange.StartIndex < label.SourceRange.StartIndex) && !IsJumpDead(x)))
                        {
                            dead = false;
                            _afterLabelJumpDownOverReturn = true;
                            HasReturnPath = false;
                        }
                    }


                    if (dead)
                    {
                        if (FirstDeadStatementNode == null)
                        {
                            FirstDeadStatementNode = statement;
                        }

                        if (!_insideDeadCode)
                        {
                            _deadCodeSegmentsStack.Push(
                                new LSLDeadCodeSegment(LSLDeadCodeType.AfterReturnPath));
                        }


                        _insideDeadCode = true;
                        _insideDeadCodeAfterReturnPath = true;
                    }
                }
            }
            else
            {
                HasReturnPath       = statement.HasReturnPath;
                ReturnStatementNode = statement as LSLReturnStatementNode;
            }


            if (!_insideDeadCode)
            {
                return;
            }

            if (_insideDeadCodeAfterReturnPath)
            {
                var label = statement as LSLLabelStatementNode;

                var dead = true;

                if (label != null)
                {
                    if (
                        label.JumpsToHere.Any(
                            x => (x.SourceRange.StartIndex < label.SourceRange.StartIndex) && !IsJumpDead(x)))
                    {
                        dead = false;
                        _afterLabelJumpDownOverReturn = true;
                        HasReturnPath = false;
                    }
                }

                if (dead)
                {
                    statement.IsDeadCode   = true;
                    statement.DeadCodeType = _deadCodeSegmentsStack.Peek().DeadCodeType;
                    _deadCodeSegmentsStack.Peek().AddStatement(statement);
                }
                else
                {
                    _insideDeadCode = false;
                    _insideDeadCodeAfterReturnPath = false;
                }
            }
            else if (_inDeadJumpedOverCode && statement.StatementIndex < _deadCodeJumpOverEnding)
            {
                statement.IsDeadCode   = true;
                statement.DeadCodeType = _deadCodeSegmentsStack.Peek().DeadCodeType;
                _deadCodeSegmentsStack.Peek().AddStatement(statement);
            }
            else if (_inDeadJumpedOverCode && statement.StatementIndex == _deadCodeJumpOverEnding)
            {
                _deadCodeSegments.Add(_deadCodeSegmentsStack.Pop());
                _insideDeadCode       = false;
                _inDeadJumpedOverCode = false;
            }
            else if (!_inDeadJumpedOverCode)
            {
                statement.IsDeadCode   = true;
                statement.DeadCodeType = _deadCodeSegmentsStack.Peek().DeadCodeType;
                _deadCodeSegmentsStack.Peek().AddStatement(statement);
            }
        }
Beispiel #3
0
        /// <exception cref="ArgumentNullException"><paramref name="context" /> or <paramref name="statement" /> is <c>null</c>.</exception>
        internal LSLCodeScopeNode(LSLParser.CodeStatementContext context, int scopeId, ILSLCodeStatement statement)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (statement == null)
            {
                throw new ArgumentNullException("statement");
            }

            AddStatement(statement);
            EndScope();

            ScopeId = scopeId;
            _isSingleStatementScope = true;

            SourceRange = new LSLSourceCodeRange(context);

            SourceRangesAvailable = true;
        }