private void PopAndSetResult(InvocationAndState result) { _invocationStack.Pop(); var prevFrame = _invocationStack.Peek(); prevFrame.Invocations.AddLast(result); }
protected override Expression VisitInvocation(InvocationExpression node) { if (_state == RecursionState.Check) { Push(); var rewritten = (InvocationExpression)base.VisitInvocation(node); var frame = _invocationStack.Peek(); var freeCount = 0; var dqCount = 0; var candidateCount = 0; foreach (var invocation in frame.Invocations) { if (invocation.State == InvocationSubtreeState.Disqualified) { dqCount++; } else if (invocation.State == InvocationSubtreeState.Free) { freeCount++; } else { candidateCount++; } } if (frame.DelegationTargets.Count == 0) { if (frame.Invocations.Count == freeCount) { PopAndSetResult(InvocationAndState.CreateFree()); return(rewritten); } else if (candidateCount == 1 && dqCount == 0) { var candidate = frame.Invocations.Single(i => i.State == InvocationSubtreeState.Candidate).DelegationTarget; var target = _delegatableTargets[candidate]; if (target.CanDelegate(candidate, rewritten)) { PopAndSetResult(InvocationAndState.CreateCandidate(candidate)); return(rewritten); } else { var delegated = RewriteInvocations(rewritten); PopAndSetResult(InvocationAndState.CreateDisqualified()); return(delegated); } } else { var delegated = RewriteInvocations(rewritten); PopAndSetResult(InvocationAndState.CreateDisqualified()); return(delegated); } } else if (frame.DelegationTargets.Count > 1) { var delegated = RewriteInvocations(rewritten); PopAndSetResult(InvocationAndState.CreateDisqualified()); return(delegated); } else { if (frame.Invocations.Count == freeCount) { var candidate = frame.DelegationTargets.Single(); var target = _delegatableTargets[candidate]; if (target.CanDelegate(candidate, rewritten)) { PopAndSetResult(InvocationAndState.CreateCandidate(candidate)); return(rewritten); } else { var delegated = RewriteInvocations(rewritten); PopAndSetResult(InvocationAndState.CreateDisqualified()); return(delegated); } } else { var delegated = RewriteInvocations(rewritten); PopAndSetResult(InvocationAndState.CreateDisqualified()); return(delegated); } } } else { var currFrame = _invocationStack.Peek(); var currInvocation = currFrame.Invocations.First(); currFrame.Invocations.RemoveFirst(); if (currInvocation.State == InvocationSubtreeState.Candidate) { var candidate = currInvocation.DelegationTarget; var target = _delegatableTargets[candidate]; return(target.Delegate(candidate, node)); } else { return(node); } } }