Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Ramstack.Parsing/Literal.Char.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using static Ramstack.Parsing.Parser;

namespace Ramstack.Parsing;

partial class Literal
{
private static Parser<char>? _quotedCharacter;

/// <summary>
/// Gets a parser that matches a character enclosed in single quotes.
/// </summary>
public static Parser<char> QuotedCharacter => _quotedCharacter ??=
Choice(
EscapeSequence,
UnicodeEscapeSequence,
Not(
Choice(
L('\''),
L('\n'),
L('\r'))
).Then(Any))
.Between(L('\''), L('\''))
.As("quoted-character");
}
16 changes: 8 additions & 8 deletions src/Ramstack.Parsing/Parser.ThenIgnore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@ partial class Parser
/// <typeparam name="TResult">The type of the value produced by the first parser.</typeparam>
/// <typeparam name="T">The type of the value produced by the second parser, which is ignored.</typeparam>
/// <param name="parser">The initial parser whose result is returned.</param>
/// <param name="before">The subsequent parser.</param>
/// <param name="ignore">The subsequent parser, applied after the initial parser.</param>
/// <returns>
/// A parser that sequentially applies the current parser and a specified second parser,
/// returning the result of the first parser with ignoring the result of the second.
/// </returns>
public static Parser<TResult> ThenIgnore<TResult, T>(this Parser<TResult> parser, Parser<T> before) =>
new ThenIgnoreParser<TResult>(parser, before.Void());
public static Parser<TResult> ThenIgnore<TResult, T>(this Parser<TResult> parser, Parser<T> ignore) =>
new ThenIgnoreParser<TResult>(parser, ignore.Void());

#region Inner type: BeforeParser
#region Inner type: ThenIgnoreParser

/// <summary>
/// Represents a parser that sequentially applies an initial parser and a specified second parser,
/// returning the result of the first parser with ignoring the result of the second.
/// </summary>
/// <typeparam name="T">The type of the value produced by the first parser.</typeparam>
/// <param name="parser">The initial parser whose result is returned.</param>
/// <param name="before">The subsequent parser, applied after the initial parser.</param>
private sealed class ThenIgnoreParser<T>(Parser<T> parser, Parser<Unit> before) : Parser<T>
/// <param name="ignore">The subsequent parser, applied after the initial parser.</param>
private sealed class ThenIgnoreParser<T>(Parser<T> parser, Parser<Unit> ignore) : Parser<T>
{
/// <inheritdoc />
public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out T? value)
Expand All @@ -37,7 +37,7 @@ public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out
{
var (index, length) = context.MatchedSegment;

if (before.TryParse(ref context, out _))
if (ignore.TryParse(ref context, out _))
{
context.SetMatched(index, length);
return true;
Expand All @@ -50,7 +50,7 @@ public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out

/// <inheritdoc />
protected internal override Parser<Unit> ToVoidParser() =>
new ThenIgnoreParser<Unit>(parser.Void(), before);
new ThenIgnoreParser<Unit>(parser.Void(), ignore);
}

#endregion
Expand Down
31 changes: 31 additions & 0 deletions tests/Ramstack.Parsing.Tests/LiteralTests.Char.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Ramstack.Parsing;

partial class LiteralTests
{
[TestCase("'1'", '1')]
[TestCase("'\\u0045'", '\u0045')]
[TestCase("'\\r'", '\r')]
[TestCase("'\\n'", '\n')]
[TestCase("'\\t'", '\t')]
public void QuotedCharacterTest(string input, char expected)
{
Assert.That(
Literal.QuotedCharacter.Parse(input).Value,
Is.EqualTo(expected));
}

[TestCase("'1")]
[TestCase("'\\uabcw'")]
[TestCase("'\\u123q'")]
[TestCase("'\\z'")]
[TestCase("'\r'")]
[TestCase("'\n'")]
[TestCase("'\''")]
[TestCase("'a")]
[TestCase("'ab'")]
public void QuotedCharacter_Error(string input)
{
var parser = Literal.QuotedCharacter;
Assert.That(parser.Parse(input).Success, Is.False);
}
}