diff --git a/src/Parlot/Fluent/OneOf.cs b/src/Parlot/Fluent/OneOf.cs
index 5fa7edb..8e61ed2 100644
--- a/src/Parlot/Fluent/OneOf.cs
+++ b/src/Parlot/Fluent/OneOf.cs
@@ -13,16 +13,21 @@ namespace Parlot.Fluent
/// We then return the actual result of each parser.
///
///
- public sealed class OneOf : Parser, ICompilable
+ public sealed class OneOf : Parser, ICompilable, ISeekable
{
internal readonly Parser[] _parsers;
internal readonly FrozenDictionary>> _lookupTable;
- internal readonly bool _skipWhiteSpace;
public OneOf(Parser[] parsers)
{
_parsers = parsers ?? throw new ArgumentNullException(nameof(parsers));
+ // We can't build a lookup table if there is only one parser
+ if (_parsers.Length <= 1)
+ {
+ return;
+ }
+
// If all parsers are seekable we can build a lookup table
if (_parsers.All(x => x is ISeekable seekable && seekable.CanSeek))
{
@@ -53,7 +58,7 @@ public OneOf(Parser[] parsers)
else if (_parsers.All(x => x is ISeekable seekable && seekable.SkipWhitespace))
{
// All parsers can start with white spaces
- _skipWhiteSpace = true;
+ SkipWhitespace = true;
}
else if (_parsers.Any(x => x is ISeekable seekable && seekable.SkipWhitespace))
{
@@ -65,10 +70,19 @@ public OneOf(Parser[] parsers)
if (lookupTable != null)
{
_lookupTable = lookupTable.ToFrozenDictionary();
+
+ CanSeek = true;
+ ExpectedChars = _lookupTable.Keys.ToArray();
}
}
}
+ public bool CanSeek { get; }
+
+ public char[] ExpectedChars { get; } = [];
+
+ public bool SkipWhitespace { get; }
+
public Parser[] Parsers => _parsers;
public override bool Parse(ParseContext context, ref ParseResult result)
@@ -79,7 +93,7 @@ public override bool Parse(ParseContext context, ref ParseResult result)
if (_lookupTable != null)
{
- if (_skipWhiteSpace)
+ if (SkipWhitespace)
{
var start = context.Scanner.Cursor.Position;
@@ -201,7 +215,7 @@ public CompilationResult Compile(CompilationContext context)
cases
);
- if (_skipWhiteSpace)
+ if (SkipWhitespace)
{
var start = context.DeclarePositionVariable(result);
diff --git a/src/Parlot/Fluent/Parsers.And.cs b/src/Parlot/Fluent/Parsers.And.cs
index 7bc98b2..5b162d4 100644
--- a/src/Parlot/Fluent/Parsers.And.cs
+++ b/src/Parlot/Fluent/Parsers.And.cs
@@ -1,37 +1,45 @@
-using System;
-
-namespace Parlot.Fluent
+namespace Parlot.Fluent
{
public static partial class Parsers
{
///
/// Builds a parser that ensure the specified parsers match consecutively.
///
- public static Parser> And(this Parser parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this Parser parser, Parser and) => new Sequence(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively.
///
- public static Parser> And(this Parser> parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this Sequence parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceAndSkip parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceSkipAnd parser, Parser and) => new Sequence(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively.
///
- public static Parser> And(this Parser> parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this Sequence parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceAndSkip parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceSkipAnd parser, Parser and) => new Sequence(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively.
///
- public static Parser> And(this Parser> parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this Sequence parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceAndSkip parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceSkipAnd parser, Parser and) => new Sequence(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively.
///
- public static Parser> And(this Parser> parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this Sequence parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceAndSkip parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceSkipAnd parser, Parser and) => new Sequence(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively.
///
- public static Parser> And(this Parser> parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this Sequence parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceAndSkip parser, Parser and) => new Sequence(parser, and);
+ public static Sequence And(this SequenceSkipAnd parser, Parser and) => new Sequence(parser, and);
}
}
diff --git a/src/Parlot/Fluent/Parsers.AndSkip.cs b/src/Parlot/Fluent/Parsers.AndSkip.cs
index e35f2b4..4543e25 100644
--- a/src/Parlot/Fluent/Parsers.AndSkip.cs
+++ b/src/Parlot/Fluent/Parsers.AndSkip.cs
@@ -7,36 +7,48 @@ public static partial class Parsers
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser AndSkip(this Parser parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this Parser parser, Parser and) => new SequenceAndSkip(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser> AndSkip(this Parser> parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this Sequence parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceAndSkip parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceSkipAnd parser, Parser and) => new SequenceAndSkip(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser> AndSkip(this Parser> parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this Sequence parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceAndSkip parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceSkipAnd parser, Parser and) => new SequenceAndSkip(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser> AndSkip(this Parser> parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this Sequence parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceAndSkip parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceSkipAnd parser, Parser and) => new SequenceAndSkip(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser> AndSkip(this Parser> parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this Sequence parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceAndSkip parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceSkipAnd parser, Parser and) => new SequenceAndSkip(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser> AndSkip(this Parser> parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this Sequence parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceAndSkip parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceSkipAnd parser, Parser and) => new SequenceAndSkip(parser, and);
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser> AndSkip(this Parser> parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this Sequence parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceAndSkip parser, Parser and) => new SequenceAndSkip(parser, and);
+ public static SequenceAndSkip AndSkip(this SequenceSkipAnd parser, Parser and) => new SequenceAndSkip(parser, and);
}
}
diff --git a/src/Parlot/Fluent/Parsers.SkipAnd.cs b/src/Parlot/Fluent/Parsers.SkipAnd.cs
index e5358bb..071e52b 100644
--- a/src/Parlot/Fluent/Parsers.SkipAnd.cs
+++ b/src/Parlot/Fluent/Parsers.SkipAnd.cs
@@ -1,6 +1,4 @@
-using System;
-
-namespace Parlot.Fluent
+namespace Parlot.Fluent
{
public static partial class Parsers
{
@@ -8,36 +6,46 @@ public static partial class Parsers
///
/// Builds a parser that ensure the specified parsers match consecutively. The last parser's result is then ignored.
///
- public static Parser SkipAnd(this Parser