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