in ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Parsing/FSharpPreprocessedLexer.cs [226:315]
private void LocateToken() =>
myCurrTokenType ??= LocateTokenImpl();
private class PreprocessorState
{
private enum PreprocessorElseState
{
BeforeElse,
AfterElse,
InactiveBeforeElse,
InactiveAfterElse,
Error
}
private struct PreprocessorBlockState
{
private PreprocessorElseState myElseState;
private readonly bool myCondition;
public PreprocessorBlockState(bool condition, bool hasActiveBranch)
{
myCondition = condition;
myElseState = hasActiveBranch ? PreprocessorElseState.BeforeElse : PreprocessorElseState.InactiveBeforeElse;
}
public bool Condition
{
get
{
switch (myElseState)
{
case PreprocessorElseState.BeforeElse: return myCondition;
case PreprocessorElseState.AfterElse: return !myCondition;
case PreprocessorElseState.Error: return true;
default: return false;
}
}
}
public PreprocessorElseState SwitchBranch()
{
switch (myElseState)
{
case PreprocessorElseState.BeforeElse:
myElseState = PreprocessorElseState.AfterElse;
break;
case PreprocessorElseState.InactiveBeforeElse:
myElseState = PreprocessorElseState.InactiveAfterElse;
break;
default:
myElseState = PreprocessorElseState.Error;
break;
}
return myElseState;
}
}
private readonly Stack<PreprocessorBlockState> myStack = new();
private readonly Queue<LexerState> myQueue = new();
public IEnumerable<LexerState> LexerStates() => myQueue;
public void EnqueueLexerState(LexerState state) =>
myQueue.Enqueue(state);
public LexerState DequeueLexerState() =>
myQueue.Dequeue();
public void InIfBlock(bool condition, bool hasActiveBranch) =>
myStack.Push(new PreprocessorBlockState(condition, hasActiveBranch));
public void FromIfBlock()
{
if (!myStack.IsEmpty())
myStack.Pop();
}
public void SwitchBranch()
{
if (myStack.IsEmpty())
return;
var state = myStack.Pop();
if (state.SwitchBranch() == PreprocessorElseState.Error)
myStack.Clear();
else
myStack.Push(state);
}
public bool Condition => myStack.IsEmpty() || myStack.Peek().Condition;
}