Skip to content

Commit

Permalink
Fix Seekable (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienros authored Dec 14, 2024
1 parent 45d671e commit 4951f01
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/Parlot/Fluent/OneOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ public OneOf(Parser<T>[] parsers)
}
else if (Parsers.Any(x => x is ISeekable seekable && seekable.SkipWhitespace))
{
// There is a mix of parsers that can skip whitespaces.
// If the ones that can skip don't have a custom WS parser then
// we can group them in a special OneOf and add them to a lookup
// with space chars.

// But there are still cases where this can't be done, like if the
// parsers have a space in their lookup table, or if non-seekable
// accept a space. So we can't always redirect spaces automatically.

lookupTable = null;
}

Expand Down
5 changes: 3 additions & 2 deletions src/Parlot/Fluent/Seekable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ namespace Parlot.Fluent;
/// </summary>
internal sealed class Seekable<T> : Parser<T>, ISeekable
{
public bool CanSeek { get; }
public bool CanSeek { get; set; }

public char[] ExpectedChars { get; set; }

public bool SkipWhitespace { get; }
public bool SkipWhitespace { get; set; }

public Parser<T> Parser { get; }

Expand All @@ -24,6 +24,7 @@ public Seekable(Parser<T> parser, bool skipWhiteSpace, params ReadOnlySpan<char>
Parser = parser ?? throw new ArgumentNullException(nameof(parser));
ExpectedChars = expectedChars.ToArray().Distinct().ToArray();
SkipWhitespace = skipWhiteSpace;
CanSeek = true;

Name = $"{parser.Name} (Seekable)";
}
Expand Down
44 changes: 44 additions & 0 deletions test/Parlot.Tests/RewriteTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,48 @@ public void OneOfCompiled()

Assert.Null(p1.Parse("c"));
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void OneOfShouldHandleWhiteSpace(bool compiled)
{
var pa = Literals.Text("a");
var pb = Literals.Text("b");
var pc = Terms.Text("b").Then("c");

var p = OneOf(pa, pb, pc);

if (compiled) p = p.Compile();

Assert.Equal("a", p.Parse("a"));
Assert.Equal("b", p.Parse("b"));

Assert.Null(p.Parse(" a"));
Assert.Equal("c", p.Parse(" b"));
}

[Theory]
[InlineData(true, true)]
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(false, false)]
public void OneOfShouldFindNonSeekableWithSpace(bool compiled, bool skipWhiteSpace)
{
var pa = Literals.Text("a");
var pb = Literals.Text("b");
var pc = new FakeParser<string> { CanSeek = false, Success = true, SkipWhitespace = skipWhiteSpace, Result = "c" };

var p = OneOf(pa, pb, pc);

if (compiled) p = p.Compile();

Assert.Equal("a", p.Parse("a"));
Assert.Equal("b", p.Parse("b"));
Assert.Equal("c", p.Parse("c"));

Assert.Equal("c", p.Parse(" a"));
Assert.Equal("c", p.Parse(" b"));
Assert.Equal("c", p.Parse(" c"));
}
}

0 comments on commit 4951f01

Please sign in to comment.