Skip to content

Commit

Permalink
Track in ParserState if suspending the tokenizer is supported.
Browse files Browse the repository at this point in the history
I thought that suspending the tokenizer without being in a chain would have no effect, but it actually has the effect of prohibiting subsequent suspensions.
With this change, suspending is a real no-op if the tokenizer is not wrapped in a chain.
  • Loading branch information
teo-tsirpanis committed Aug 28, 2023
1 parent dd69b7b commit e193f17
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/FarkleNeo/Parser/ParserState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ public struct ParserState
/// <seealso cref="ParserExtensions.ParseFileAsync"/>
public string? InputName { get; set; }

/// <summary>
/// Whether suspending the tokenizer will have any effect.
/// </summary>
/// <remarks>
/// We must have this property because if the tokenizer is not wrapped in a chain
/// and suspends to itself (which is still supported), there is no chain to "unsuspend"
/// the tokenizer, and when the tokenizer returns and wants to suspend again, it will
/// throw with a message that it is already suspended.
/// </remarks>
internal bool TokenizerSupportsSuspending { get; set; }

internal void Consume<T>(ReadOnlySpan<T> characters)
{
_positionTracker.Advance(characters);
Expand Down
4 changes: 4 additions & 0 deletions src/FarkleNeo/Parser/Tokenizers/ChainedTokenizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ internal static Tokenizer<TChar> Create(ImmutableArray<Tokenizer<TChar>> compone

public override bool TryGetNextToken(ref ParserInputReader<TChar> input, ITokenSemanticProvider<TChar> semanticProvider, out TokenizerResult result)
{
// We mark this parser operation as supporting suspending.
// It might cause some issues if the tokenizer changes in the middle of the
// operation but this is not a supported scenario.
input.State.TokenizerSupportsSuspending = true;
// Get the state of the chained tokenizer. If we have not suspended before,
// it will be null.
var tokenizerState = input.GetChainedTokenizerStateOrNull();
Expand Down
10 changes: 10 additions & 0 deletions src/FarkleNeo/Parser/Tokenizers/TokenizerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ private static void SuspendTokenizerCore<TChar>(this ref ParserInputReader<TChar
public static void SuspendTokenizer<TChar>(this ref ParserInputReader<TChar> input, Tokenizer<TChar> tokenizer)
{
ArgumentNullExceptionCompat.ThrowIfNull(tokenizer);

if (!input.State.TokenizerSupportsSuspending)
{
return;
}
input.SuspendTokenizerCore(tokenizer);
}

Expand Down Expand Up @@ -119,6 +124,11 @@ public static void SuspendTokenizer<TChar, TArg>(this ref ParserInputReader<TCha
ITokenizerResumptionPoint<TChar, TArg> resumptionPoint, TArg arg)
{
ArgumentNullExceptionCompat.ThrowIfNull(resumptionPoint);

if (!input.State.TokenizerSupportsSuspending)
{
return;
}
input.SuspendTokenizerCore(new TokenizerResumptionPoint<TChar, TArg>(resumptionPoint, arg));
}

Expand Down

0 comments on commit e193f17

Please sign in to comment.