feat: Grammar Parser (#3)

Reviewed-on: https://git.bupt-hpc.cn/jackfiled/CanonSharp/pulls/3
Co-authored-by: jackfiled <xcrenchangjun@outlook.com>
Co-committed-by: jackfiled <xcrenchangjun@outlook.com>
This commit is contained in:
2024-08-18 12:01:27 +08:00
committed by 任昌骏
parent 3ed8bf5d36
commit cf19f8197e
85 changed files with 2340 additions and 413 deletions

View File

@@ -11,7 +11,7 @@ public class BasicParsersTests : ParserTestsBase
[Fact]
public void AlternativeTest()
{
Parser<char, char> parser = Token('a') | Token('b');
IParser<char, char> parser = Token('a') | Token('b');
ValidateSuccessfulResult(parser, 'a', "abc");
ValidateSuccessfulResult(parser, 'b', "bcd");
@@ -26,7 +26,7 @@ public class BasicParsersTests : ParserTestsBase
[Fact]
public void BindTest()
{
Parser<char, char> parser = Token('a').Bind(_ => Token('b')).Bind(_ => Token('c'));
IParser<char, char> parser = Token('a').Bind(_ => Token('b')).Bind(_ => Token('c'));
ValidateSuccessfulResult(parser, 'c', "abc");
ValidateFailedResult(parser, "acd");
@@ -36,7 +36,7 @@ public class BasicParsersTests : ParserTestsBase
[Fact]
public void MapTest()
{
Parser<char, string> parser = Token('a').Map(c => $"{c}");
IParser<char, string> parser = Token('a').Map(c => $"{c}");
ValidateSuccessfulResult(parser, "a", "abc");
parser = Token('a').Map("test");
@@ -46,7 +46,7 @@ public class BasicParsersTests : ParserTestsBase
[Fact]
public void NextTest()
{
Parser<char, char> parser = Token('a').Next(_ => Token('a'), _ => Token('b'));
IParser<char, char> parser = Token('a').Next(_ => Token('a'), _ => Token('b'));
ValidateSuccessfulResult(parser, 'a', "aaa");
ValidateSuccessfulResult(parser, 'b', "bbb");
@@ -61,7 +61,7 @@ public class BasicParsersTests : ParserTestsBase
[Fact]
public void NextTest2()
{
Parser<char, string> parser = Token('a').Next(_ => "123", _ => Pure<char, string>("456"));
IParser<char, string> parser = Token('a').Next(_ => "123", _ => Pure<char, string>("456"));
ValidateSuccessfulResult(parser, "123", "aaa");
ValidateSuccessfulResult(parser, "456", "bbb");
@@ -77,7 +77,7 @@ public class BasicParsersTests : ParserTestsBase
[Fact]
public void FixTest()
{
Parser<char, char> parser = Fix<char, Unit>(self => Token('a').Next(_ => self, Unit.Instance))
IParser<char, char> parser = Fix<char, Unit>(self => Token('a').Next(_ => self, Unit.Instance))
.Bind(_ => Token('b'));
ValidateSuccessfulResult(parser, 'b', "aaaaab");
}

View File

@@ -11,7 +11,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void ChoiceTest()
{
Parser<char, char> parser = Choice(Token('a'), Token('b'), Token('c'));
IParser<char, char> parser = Choice(Token('a'), Token('b'), Token('c'));
ValidateSuccessfulResult(parser, 'a', "abc");
ValidateSuccessfulResult(parser, 'b', "bcd");
ValidateSuccessfulResult(parser, 'c', "cde");
@@ -25,17 +25,18 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void SequenceTest()
{
Parser<char, IEnumerable<char>> parser = Sequence(Token('a'), Token('b'), Token('c'));
IParser<char, IEnumerable<char>> parser = Sequence(Token('a'), Token('b'), Token('c'));
ValidateSuccessfulResult(parser, ['a', 'b', 'c'], "abc");
parser = Sequence([Token('a'), Token('b'), Token('c')]);
IEnumerable<IParser<char, char>> parsers = [Token('a'), Token('b'), Token('c')];
parser = Sequence(parsers);
ValidateSuccessfulResult(parser, ['a', 'b', 'c'], "abc");
}
[Fact]
public void LeftRightTest()
{
Parser<char, char> parser = Token('a').Left(Token('b'));
IParser<char, char> parser = Token('a').Left(Token('b'));
ValidateSuccessfulResult(parser, 'a', "ab");
parser = Token('a').Right(Token('b'));
@@ -45,7 +46,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void ManyTest()
{
Parser<char, IEnumerable<char>> parser = Token('a').Many();
IParser<char, IEnumerable<char>> parser = Token('a').Many();
ValidateSuccessfulResult(parser, [], "bbb");
ValidateSuccessfulResult(parser, ['a', 'a', 'a'], "aaa");
@@ -57,7 +58,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void SkipManyTest()
{
Parser<char, char> parser = Token('a').SkipMany().Right(Token('b'));
IParser<char, char> parser = Token('a').SkipMany().Right(Token('b'));
ValidateSuccessfulResult(parser, 'b', "aaaab");
ValidateSuccessfulResult(parser, 'b', "bbbb");
@@ -71,7 +72,7 @@ public class CombinatorParserTests : ParserTestsBase
{
// 等效于Many1
// 但是不返回中间结果
Parser<char, char> parser = Token('a').Chain(Token);
IParser<char, char> parser = Token('a').Chain(Token);
ValidateSuccessfulResult(parser, 'a', "aa");
ValidateFailedResult(parser, "bb");
@@ -83,7 +84,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void ManyTillTest()
{
Parser<char, IEnumerable<char>> parser = Token('a').ManyTill(Token('b').LookAhead());
IParser<char, IEnumerable<char>> parser = Token('a').ManyTill(Token('b').LookAhead());
ValidateSuccessfulResult(parser, ['a', 'a', 'a'], "aaab");
ValidateSuccessfulResult(parser, [], "b");
@@ -95,19 +96,33 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void SkipTillTest()
{
Parser<char, char> parser = Token('a').SkipTill(Token('b'));
IParser<char, char> parser = Token('a').SkipTill(Token('b'));
ValidateSuccessfulResult(parser, 'b', "aaab");
ValidateSuccessfulResult(parser, 'b', "b");
parser = Token('a').Skip1Till(Token('b'));
ValidateSuccessfulResult(parser, 'b', "aaab");
ValidateFailedResult(parser, "b");
parser = Token('a').SkipTill(Choice(
Token('b'), Token('c')));
ValidateSuccessfulResult(parser, 'b', "aaab");
ValidateSuccessfulResult(parser, 'c', "ac");
}
[Fact]
public void SkipTillManyTest()
{
IParser<char, IEnumerable<char>> parser = Token('a').SkipTill(Token('b')).Many();
ValidateSuccessfulResult(parser, ['b', 'b'], "aaabaab");
}
[Fact]
public void TakeTillTest()
{
Parser<char, IEnumerable<char>> parser = TakeTill(Token('b').LookAhead());
IParser<char, IEnumerable<char>> parser = TakeTill(Token('b').LookAhead());
ValidateSuccessfulResult(parser, ['a', 'a'], "aab");
ValidateSuccessfulResult(parser, [], "b");
@@ -119,7 +134,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void MatchTest()
{
Parser<char, char> parser = Token('b').Match();
IParser<char, char> parser = Token('b').Match();
ValidateSuccessfulResult(parser, 'b', "asdfasdfasdfasdfb");
ValidateSuccessfulResult(parser, 'b', "b");
}
@@ -127,7 +142,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void QuoteTest()
{
Parser<char, IEnumerable<char>> parser = Any<char>().Quote(Token('['), Token(']'));
IParser<char, IEnumerable<char>> parser = Any<char>().Quote(Token('['), Token(']'));
ValidateSuccessfulResult(parser, ['1', '2', '3'], "[123]");
parser = Any<char>().Quote(Token('\''));
@@ -137,7 +152,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void SeparatedByTest()
{
Parser<char, IEnumerable<char>> parser = Token('a').SeparatedBy(Token(','));
IParser<char, IEnumerable<char>> parser = Token('a').SeparatedBy(Token(','));
ValidateSuccessfulResult(parser, ['a', 'a', 'a'], "a,a,a");
ValidateSuccessfulResult(parser, ['a'], "a");
ValidateSuccessfulResult(parser, [], "");
@@ -151,7 +166,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void EndByTest()
{
Parser<char, IEnumerable<char>> parser = Satisfy<char>(char.IsLetter).EndBy(Token('.'));
IParser<char, IEnumerable<char>> parser = Satisfy<char>(char.IsLetter).EndBy(Token('.'));
ValidateSuccessfulResult(parser, ['a', 'b', 'c'], "abc.");
ValidateSuccessfulResult(parser, [], ".");
@@ -163,7 +178,7 @@ public class CombinatorParserTests : ParserTestsBase
[Fact]
public void SeparatedOrEndByTest()
{
Parser<char, IEnumerable<char>> parser = Satisfy<char>(char.IsLetter).SeparatedOrEndBy1(Token(','));
IParser<char, IEnumerable<char>> parser = Satisfy<char>(char.IsLetter).SeparatedOrEndBy1(Token(','));
ValidateSuccessfulResult(parser, ['a', 'b', 'c'], "a,b,c,");
ValidateSuccessfulResult(parser, ['a', 'b', 'c'], "a,b,c");
ValidateFailedResult(parser, "");

View File

@@ -10,7 +10,7 @@ public class LinqTests : ParserTestsBase
[Fact]
public void SelectTest1()
{
Parser<char, string> parser = from token in Char('a')
IParser<char, string> parser = from token in Char('a')
select token.ToString();
ValidateSuccessfulResult(parser, "a", "a");
ValidateFailedResult(parser, "b");
@@ -19,7 +19,7 @@ public class LinqTests : ParserTestsBase
[Fact]
public void SelectManyTest1()
{
Parser<char, int> parser = from _1 in Char('a')
IParser<char, int> parser = from _1 in Char('a')
from _2 in Char('b')
from _3 in Char('c')
select 123;

View File

@@ -12,7 +12,7 @@ public class ModifierParserTests : ParserTestsBase
[Fact]
public void DoTest()
{
Parser<char, char> parser = Token('a').Do(x => Assert.Equal('a', x)).Do(x => Assert.Equal('a', x),
IParser<char, char> parser = Token('a').Do(x => Assert.Equal('a', x)).Do(x => Assert.Equal('a', x),
failedResult => Assert.ThrowsAny<ParseException>(() => failedResult.Value));
ValidateSuccessfulResult(parser, 'a', "abc");
@@ -22,7 +22,7 @@ public class ModifierParserTests : ParserTestsBase
[Fact]
public void LookAheadTest()
{
Parser<char, char> parser = Token('a').LookAhead().Next(_ => Token('a'), _ => Token('b'));
IParser<char, char> parser = Token('a').LookAhead().Next(_ => Token('a'), _ => Token('b'));
ValidateSuccessfulResult(parser, 'a', "abc");
ValidateSuccessfulResult(parser, 'b', "bcd");
}
@@ -30,7 +30,7 @@ public class ModifierParserTests : ParserTestsBase
[Fact]
public void NotTest()
{
Parser<char, char> parser = Token('a').Not('b');
IParser<char, char> parser = Token('a').Not('b');
ValidateSuccessfulResult(parser, 'b', "bcd");
parser = Token('a').Not().Bind(_ => Token('b'));
@@ -40,7 +40,7 @@ public class ModifierParserTests : ParserTestsBase
[Fact]
public void TryTest()
{
Parser<char, string> parser = String("abc").Try("cde");
IParser<char, string> parser = String("abc").Try("cde");
ValidateSuccessfulResult(parser, "abc", "abc");
ValidateSuccessfulResult(parser, "cde", "cde");

View File

@@ -11,7 +11,7 @@ public class PrimitiveParserTests : ParserTestsBase
[Fact]
public void PureTest()
{
Parser<char, char> parser = Pure<char, char>('a');
IParser<char, char> parser = Pure<char, char>('a');
ValidateSuccessfulResult(parser, 'a', "abc");
parser = Pure<char, char>(_ => 'a');
@@ -21,18 +21,18 @@ public class PrimitiveParserTests : ParserTestsBase
[Fact]
public void NullTest()
{
Parser<char, Unit> parser = Null<char>();
IParser<char, Unit> parser = Null<char>();
ValidateSuccessfulResult(parser, Unit.Instance, "abc");
}
[Fact]
public void FailTest()
{
Parser<char, char> parser = Fail<char, char>();
IParser<char, char> parser = Fail<char, char>();
ValidateFailedResult(parser, "abc");
parser = Fail<char, char>("Failed message");
FailedResult<char, char> result = ValidateFailedResult(parser, "abc");
IFailedResult<char, char> result = ValidateFailedResult(parser, "abc");
Assert.Equal("Failed message", result.Message);
parser = Fail<char, char>(x => $"{x}");
@@ -47,29 +47,36 @@ public class PrimitiveParserTests : ParserTestsBase
[Fact]
public void SatisfyTest()
{
Parser<char, char> parser = Satisfy<char>(char.IsLetter);
IParser<char, char> parser = Satisfy<char>(char.IsLetter);
ValidateSuccessfulResult(parser, 'a', "abc");
ValidateFailedResult(parser, "123");
}
[Fact]
public void SatisfyFailedTest()
{
IParser<char, char> parser = Satisfy<char>(char.IsLetter);
ValidateFailedResult(parser, "");
}
[Fact]
public void AnyTest()
{
Parser<char, char> parser = Any<char>();
IParser<char, char> parser = Any<char>();
ValidateSuccessfulResult(parser, '1', "123");
}
[Fact]
public void TokenTest()
{
Parser<char, char> parser = Token('a');
IParser<char, char> parser = Token('a');
ValidateSuccessfulResult(parser, 'a', "abc");
}
[Fact]
public void TakeTest()
{
Parser<char, IEnumerable<char>> parser = Take<char>(5);
IParser<char, IEnumerable<char>> parser = Take<char>(5);
ValidateSuccessfulResult(parser, ['h', 'e', 'l', 'l', 'o'], "hello");
ValidateFailedResult(parser, "abc");
}
@@ -77,7 +84,7 @@ public class PrimitiveParserTests : ParserTestsBase
[Fact]
public void SkipTest()
{
Parser<char, char> parser = Skip<char>(5).Bind(_ => Token(','));
IParser<char, char> parser = Skip<char>(5).Bind(_ => Token(','));
ValidateSuccessfulResult(parser, ',', "hello,world.");
ValidateFailedResult(parser, "abc");
}