feat: Parser Combinator库和词法分析器 (#2)
All checks were successful
Run unit test / Unit-Test (push) Successful in 41s

Reviewed-on: https://git.bupt-hpc.cn/jackfiled/CanonSharp/pulls/2
Co-authored-by: jackfiled <xcrenchangjun@outlook.com>
Co-committed-by: jackfiled <xcrenchangjun@outlook.com>
This commit is contained in:
2024-08-13 14:46:11 +08:00
committed by 任昌骏
parent 57c31ec435
commit 3ed8bf5d36
68 changed files with 3133 additions and 1068 deletions

View File

@@ -0,0 +1,49 @@
namespace CanonSharp.Combinator.Abstractions;
/// <summary>
/// 失败解析结果基类
/// </summary>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果类型</typeparam>
public abstract class FailedResult<TToken, T> : ParseResult<TToken, T>
{
public override T Value => throw Exception;
/// <summary>
/// 当前读取到的状态
/// </summary>
public abstract IReadState<TToken> State { get; }
/// <summary>
/// 解析失败的消息
/// </summary>
public abstract string Message { get; }
/// <summary>
/// 解析失败的异常
/// </summary>
public virtual ParseException Exception => new(ToString());
/// <summary>
/// 转换该失败结果的类型
/// </summary>
/// <typeparam name="TNext">转换之后的结果类型</typeparam>
/// <returns>转换之后的失败解析类型</returns>
public abstract FailedResult<TToken, TNext> Convert<TNext>();
internal override ParseResult<TToken, TResult> Next<TNext, TResult>(Func<T, Parser<TToken, TNext>> nextParser,
Func<ParseResult<TToken, TNext>, ParseResult<TToken, TResult>> continuation)
=> continuation(Convert<TNext>());
public override ParseResult<TToken, TResult> Map<TResult>(Func<T, TResult> map)
=> Convert<TResult>();
public override TResult CaseOf<TResult>(Func<SuccessfulResult<TToken, T>, TResult> successfulHandler,
Func<FailedResult<TToken, T>, TResult> failedHandler)
=> failedHandler(this);
public override string ToString()
{
return $"Parse Failed: {Message}.";
}
}

View File

@@ -0,0 +1,26 @@
namespace CanonSharp.Combinator.Abstractions;
/// <summary>
/// 输入流的读取状态
/// </summary>
/// <typeparam name="TToken">输入流元素类型</typeparam>
public interface IReadState<out TToken>
{
public TToken Current { get; }
public bool HasValue { get; }
}
/// <summary>
/// 输入流的读取状态
/// </summary>
/// <typeparam name="TToken">输入流元素类型</typeparam>
/// <typeparam name="TState">下一个读取状态的类型</typeparam>
public interface IReadState<out TToken, TState> : IReadState<TToken>, IEquatable<TState>
where TState : IReadState<TToken, TState>
{
/// <summary>
/// 下一个读取状态
/// </summary>
TState Next { get; }
}

View File

@@ -0,0 +1,48 @@
namespace CanonSharp.Combinator.Abstractions;
/// <summary>
/// 解析器结果
/// </summary>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">实际结果类型</typeparam>
public abstract class ParseResult<TToken, T>
{
/// <summary>
/// 实际结果对象
/// </summary>
public abstract T Value { get; }
protected ParseResult()
{
}
/// <summary>
/// 在当前结果上应用下一个解析器
/// </summary>
/// <param name="nextParser">下一个解析器的函数</param>
/// <param name="continuation">处理解析结果的后继函数</param>
/// <typeparam name="TNext">下一个解析器函数返回的解析结果类型</typeparam>
/// <typeparam name="TResult">最终的解析结果类型</typeparam>
/// <returns></returns>
internal abstract ParseResult<TToken, TResult> Next<TNext, TResult>(Func<T, Parser<TToken, TNext>> nextParser,
Func<ParseResult<TToken, TNext>, ParseResult<TToken, TResult>> continuation);
/// <summary>
/// 映射结果
/// </summary>
/// <param name="map">映射结果的函数</param>
/// <typeparam name="TResult">映射结果函数返回解析结果的类型</typeparam>
/// <returns>最终的解析结果</returns>
public abstract ParseResult<TToken, TResult> Map<TResult>(Func<T, TResult> map);
/// <summary>
/// 在成功或者失败解析结果上应用不同的后继函数
/// </summary>
/// <param name="successfulHandler">在成功解析结果上应用的函数</param>
/// <param name="failedHandler">在失败解析结构上应用的函数</param>
/// <typeparam name="TResult">最后返回解析结果的类型</typeparam>
/// <returns>最后的解析结果</returns>
public abstract TResult CaseOf<TResult>(Func<SuccessfulResult<TToken, T>, TResult> successfulHandler,
Func<FailedResult<TToken, T>, TResult> failedHandler);
}

View File

@@ -0,0 +1,43 @@
using CanonSharp.Combinator.Extensions;
namespace CanonSharp.Combinator.Abstractions;
/// <summary>
/// 解析器抽象基类
/// </summary>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果类型</typeparam>
public abstract class Parser<TToken, T>
{
/// <summary>
/// 解析器运行函数
/// </summary>
/// <param name="state">解析的输入流状态</param>
/// <param name="continuation">运行之后的后继函数</param>
/// <typeparam name="TState">输入流状态类型</typeparam>
/// <typeparam name="TResult">后继函数运行之后的解析结果类型</typeparam>
/// <returns></returns>
internal abstract ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
where TState : IReadState<TToken, TState>;
public ParseResult<TToken, T> Parse<TState>(TState state) where TState : IReadState<TToken, TState>
{
return Run(state);
}
private ParseResult<TToken, T> Run<TState>(TState state) where TState : IReadState<TToken, TState>
{
try
{
return Run(state, result => result);
}
catch (Exception e)
{
return ParseResultBuilder.Fail<TToken, TState, T>(e, state);
}
}
public static Parser<TToken, T> operator |(Parser<TToken, T> a, Parser<TToken, T> b)
=> a.Alternative(b);
}

View File

@@ -0,0 +1,33 @@
namespace CanonSharp.Combinator.Abstractions;
/// <summary>
/// 成功解析结果基类
/// </summary>
/// <param name="value">实际的解析结果</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">实际的解析结果类型</typeparam>
public abstract class SuccessfulResult<TToken, T>(T value) : ParseResult<TToken, T>
{
public override T Value => value;
/// <summary>
/// 运行下一个解析器
/// </summary>
/// <param name="parser">下一个解析器</param>
/// <param name="continuation">处理解析结果的后继函数</param>
/// <typeparam name="TNext">下一个解析器返回的结果类型</typeparam>
/// <typeparam name="TResult">最终的结果类型</typeparam>
/// <returns>最终的结果</returns>
protected abstract ParseResult<TToken, TResult> RunNext<TNext, TResult>(Parser<TToken, TNext> parser,
Func<ParseResult<TToken, TNext>, ParseResult<TToken, TResult>> continuation);
internal override ParseResult<TToken, TResult> Next<TNext, TResult>(Func<T, Parser<TToken, TNext>> nextParser,
Func<ParseResult<TToken, TNext>, ParseResult<TToken, TResult>> continuation)
=> RunNext(nextParser(Value), continuation);
public override TResult CaseOf<TResult>(Func<SuccessfulResult<TToken, T>, TResult> successfulHandler,
Func<FailedResult<TToken, T>, TResult> failedHandler)
=> successfulHandler(this);
public override string ToString() => Value?.ToString() ?? string.Empty;
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,572 @@
using System.Runtime.CompilerServices;
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Parsers.Bases;
using CanonSharp.Combinator.Parsers.Modifiers;
using static CanonSharp.Combinator.ParserBuilder;
namespace CanonSharp.Combinator.Extensions;
public static class ParserExtensions
{
#region BasesParser
/// <summary>
/// 选择组合子
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Alternative<TToken, T>(this Parser<TToken, T> first, Parser<TToken, T> second)
=> new AlternativeParser<TToken, T>(first, second);
/// <summary>
/// 选择组合子
/// 按照失败的解析结果选择第二个解析器
/// </summary>
/// <param name="parser"></param>
/// <param name="resume"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Alternative<TToken, T>(this Parser<TToken, T> parser,
Func<FailedResult<TToken, T>, Parser<TToken, T>> resume)
=> new ResumeParser<TToken, T>(parser, resume);
/// <summary>
/// 单子解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="next">按照输出指定下一个解析器的函数</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Bind<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, Parser<TToken, TResult>> next)
=> new BindParser<TToken, T, TResult>(parser, next);
/// <summary>
/// 映射解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="map">按照输出指定结果的函数</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Map<TToken, T, TResult>(this Parser<TToken, T> parser, Func<T, TResult> map)
=> new MapParser<TToken, T, TResult>(parser, map);
/// <summary>
/// 映射解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="result">最后的输出结果</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Map<TToken, T, TResult>(this Parser<TToken, T> parser, TResult result)
=> parser.Map(_ => result);
/// <summary>
/// 下一个解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="next">输入成功结果输出下一个解析器的函数</param>
/// <param name="failedNext">输入失败结果输出下一个解析器的函数</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Next<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, Parser<TToken, TResult>> next,
Func<FailedResult<TToken, T>, Parser<TToken, TResult>> failedNext)
=> new NextParser<TToken, T, TResult>(parser, next, failedNext);
/// <summary>
/// 下一个解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="next">输入成功结果输出下一个解析器的函数</param>
/// <param name="failedHandler">输出失败结果输出后续结果的函数</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Next<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, Parser<TToken, TResult>> next, Func<FailedResult<TToken, T>, TResult> failedHandler)
=> parser.Next(next, failedResult => Pure<TToken, TResult>(failedHandler(failedResult)));
/// <summary>
/// 下一个解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="next">输出成功结果输出下一个解析器的函数</param>
/// <param name="failedResult">如果失败之后返回该结果</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Next<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, Parser<TToken, TResult>> next, TResult failedResult)
=> parser.Next(next, _ => Pure<TToken, TResult>(failedResult));
/// <summary>
/// 下一个解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="nextResult">输入成功结果返回新的结果</param>
/// <param name="failedResume">输入失败结果返回下一个解析器的函数</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Next<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, TResult> nextResult, Func<FailedResult<TToken, T>, Parser<TToken, TResult>> failedResume)
=> parser.Next(x => Pure<TToken, TResult>(nextResult(x)), failedResume);
/// <summary>
/// 下一个解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="nextResult">输入成功结果返回新的结果</param>
/// <param name="failedResult">输入失败结果返回新的结果</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Next<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, TResult> nextResult, Func<FailedResult<TToken, T>, TResult> failedResult)
=> new SuccessfulMapParser<TToken, T, TResult>(parser, nextResult, failedResult);
/// <summary>
/// 下一个解析器组合子
/// </summary>
/// <param name="parser"></param>
/// <param name="successfulHandler">输入成功结果返回新结果的函数</param>
/// <param name="failedResult">返回的失败结果</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Next<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, TResult> successfulHandler, TResult failedResult)
=> parser.Next(successfulHandler, _ => failedResult);
#endregion
#region ModifiedParser
/// <summary>
/// 在解析结果上执行指定操作
/// </summary>
/// <param name="parser"></param>
/// <param name="successfulAction">成功结果上执行的操作</param>
/// <param name="failedAction">失败结果上执行的操作</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Do<TToken, T>(this Parser<TToken, T> parser, Action<T> successfulAction,
Action<FailedResult<TToken, T>> failedAction)
=> new DoParser<TToken, T>(parser, successfulAction, failedAction);
/// <summary>
/// 在解析结果上执行指定的操作
/// </summary>
/// <param name="parser"></param>
/// <param name="successfulAction">成功结果上执行的操作</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Do<TToken, T>(this Parser<TToken, T> parser, Action<T> successfulAction)
=> parser.Do(successfulAction, _ => { });
/// <summary>
/// 向前看解析器
/// 执行解析器的同时不消耗输入流
/// </summary>
/// <param name="parser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> LookAhead<TToken, T>(this Parser<TToken, T> parser)
=> new LookAheadParser<TToken, T>(parser);
/// <summary>
/// 翻转上游解析器的输出结果
/// </summary>
/// <param name="parser"></param>
/// <param name="result">翻转之后的输出结果</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Not<TToken, TIgnore, T>(this Parser<TToken, TIgnore> parser, T result)
=> new ReverseParser<TToken, TIgnore, T>(parser, result);
/// <summary>
/// 翻转上游解析器的输出结果
/// 输出结果默认为Unit
/// </summary>
/// <param name="parser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, Unit> Not<TToken, TIgnore>(this Parser<TToken, TIgnore> parser)
=> parser.Not(Unit.Instance);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Try<TToken, T>(this Parser<TToken, T> parser,
Func<FailedResult<TToken, T>, T> resume)
=> new TryParser<TToken, T>(parser, resume);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Try<TToken, T>(this Parser<TToken, T> parser, T result)
=> parser.Try(_ => result);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, bool> Try<TToken, T>(this Parser<TToken, T> parser)
=> parser.Next(_ => true, false).Try(false);
#endregion
#region Combinators
/// <summary>
/// 连接两个解析器,返回左边解析器的结果
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TLeft"></typeparam>
/// <typeparam name="TRight"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TLeft> Left<TToken, TLeft, TRight>(this Parser<TToken, TLeft> left,
Parser<TToken, TRight> right)
=> left.Bind(right.Map);
/// <summary>
/// 连接两个解析器,返回右边解析器的结果
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TLeft"></typeparam>
/// <typeparam name="TRight"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TRight> Right<TToken, TLeft, TRight>(this Parser<TToken, TLeft> left,
Parser<TToken, TRight> right)
=> left.Bind(_ => right);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Parser<TToken, IEnumerable<T>> ManyRecursively<TToken, T>(this Parser<TToken, T> parser,
IEnumerable<T> result)
=> parser.Next(x => parser.ManyRecursively(result.Append(x)), result);
/// <summary>
/// 将上游解析器运行零或若干次
/// </summary>
/// <param name="parser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> Many<TToken, T>(this Parser<TToken, T> parser)
=> parser.ManyRecursively([]);
/// <summary>
/// 将上游解析器运行若干次
/// </summary>
/// <param name="parser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> Many1<TToken, T>(this Parser<TToken, T> parser)
=> parser.Bind(x => parser.ManyRecursively([x]));
/// <summary>
/// 跳过执行上游解析器运行零或若干次
/// 跳过执行不是不执行
/// 而是不返回结果
/// </summary>
/// <param name="parser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, Unit> SkipMany<TToken, TIgnore>(this Parser<TToken, TIgnore> parser)
=> Fix<TToken, Unit>(self => parser.Next(_ => self, Unit.Instance));
/// <summary>
/// 跳过执行上游解析器运行若干次
/// 跳过执行不是不执行
/// 而是不返回结果
/// </summary>
/// <param name="parser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, Unit> SkipMany1<TToken, TIgnore>(this Parser<TToken, TIgnore> parser)
=> parser.Right(parser.SkipMany());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Parser<TToken, T> ChainRecursively<TToken, T>(Func<T, Parser<TToken, T>> chain, T value)
=> chain(value).Next(x => ChainRecursively(chain, x), value);
/// <summary>
/// 链式解析器组合子
/// 按照解析结果决定下一个解析器
/// </summary>
/// <param name="parser"></param>
/// <param name="chain"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Chain<TToken, T>(this Parser<TToken, T> parser, Func<T, Parser<TToken, T>> chain)
=> parser.Bind(x => ChainRecursively(chain, x));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Parser<TToken, IEnumerable<T>> ManyTillRecursively<TToken, T, TIgnore>(this Parser<TToken, T> parser,
Parser<TToken, TIgnore> terminator, IEnumerable<T> result)
=> terminator.Next(_ => Pure<TToken, IEnumerable<T>>(result),
_ => parser.Bind(x => parser.ManyTillRecursively(terminator, result.Append(x))));
/// <summary>
/// 执行指定解析器直到终结解析器执行成功的组合子
/// 指定解析器可以执行零次或者多次
/// </summary>
/// <param name="parser">指定重复执行的解析器</param>
/// <param name="terminator">判断是否终结的解析器</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> ManyTill<TToken, T, TIgnore>(this Parser<TToken, T> parser,
Parser<TToken, TIgnore> terminator)
=> parser.ManyTillRecursively(terminator, []);
/// <summary>
/// 执行指定解析器直到终结解析器执行成功的组合子
/// 指定解析器至少执行一次
/// </summary>
/// <param name="parser">指定重复执行的解析器</param>
/// <param name="terminator">判断是否终结的解析器</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> Many1Till<TToken, T, TIgnore>(this Parser<TToken, T> parser,
Parser<TToken, TIgnore> terminator)
=> parser.Bind(x => parser.ManyTillRecursively(terminator, [x]));
/// <summary>
/// 跳过指定解析器直到终结解析器执行成功的组合子
/// 指定解析器可以执行零次或者若干次
/// </summary>
/// <param name="parser"></param>
/// <param name="terminator"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> SkipTill<TToken, TIgnore, T>(this Parser<TToken, TIgnore> parser,
Parser<TToken, T> terminator)
=> Fix<TToken, T>(self => terminator | parser.Right(self));
/// <summary>
/// 跳过指定解析器直到终结解析器执行成功的组合子
/// 指定解析器至少要执行一次
/// </summary>
/// <param name="parser"></param>
/// <param name="terminator"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Skip1Till<TToken, TIgnore, T>(this Parser<TToken, TIgnore> parser,
Parser<TToken, T> terminator)
=> parser.Right(parser.SkipTill(terminator));
/// <summary>
/// 解析直到指定的解析器识别成功
/// </summary>
/// <param name="parser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Match<TToken, T>(this Parser<TToken, T> parser)
=> SkipTill(Any<TToken>(), parser);
/// <summary>
/// 在左右两个解析器指定的范围内进行解析
/// 解析类似于左右括号和左右引号类似的句式
/// </summary>
/// <param name="parser"></param>
/// <param name="left"></param>
/// <param name="right"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TLeft"></typeparam>
/// <typeparam name="TRight"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> Quote<TToken, T, TLeft, TRight>(this Parser<TToken, T> parser,
Parser<TToken, TLeft> left, Parser<TToken, TRight> right)
=> left.Right(parser.ManyTill(right));
/// <summary>
/// 在同一个解析器指定的范围内进行解析
/// </summary>
/// <param name="parser"></param>
/// <param name="quotedParser"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TQuote"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> Quote<TToken, T, TQuote>(this Parser<TToken, T> parser,
Parser<TToken, TQuote> quotedParser)
=> parser.Quote(quotedParser, quotedParser);
/// <summary>
/// 解析由分隔符解析器分割的多个符号
/// 例如a,b,c
/// 实际的解析器可以运行零次或者多次
/// </summary>
/// <param name="parser">实际的解析器</param>
/// <param name="separator">分隔符解析器</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TSeparator"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> SeparatedBy1<TToken, T, TSeparator>(this Parser<TToken, T> parser,
Parser<TToken, TSeparator> separator)
=> parser.Bind(x => separator.Right(parser).ManyRecursively([x]));
/// <summary>
/// 解析由分隔符解析器分割的多个符号
/// 例如a,b,c
/// 实际的解析器可以运行多次
/// </summary>
/// <param name="parser">实际的解析器</param>
/// <param name="separator">分隔符解析器</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TSeparator"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> SeparatedBy<TToken, T, TSeparator>(this Parser<TToken, T> parser,
Parser<TToken, TSeparator> separator)
=> parser.SeparatedBy1(separator).Try([]);
/// <summary>
/// 解析直到使用分隔符解析器结束
/// 例如abc.
/// 实际的解析器可以运行零次或者多次
/// </summary>
/// <param name="parser"></param>
/// <param name="separator"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TSeparator"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> EndBy<TToken, T, TSeparator>(this Parser<TToken, T> parser,
Parser<TToken, TSeparator> separator)
=> parser.Many().Left(separator);
/// <summary>
/// 解析直到使用分隔符解析器结束
/// 例如abc.
/// 实际的解析器至少运行一次
/// </summary>
/// <param name="parser"></param>
/// <param name="separator"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TSeparator"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> EndBy1<TToken, T, TSeparator>(this Parser<TToken, T> parser,
Parser<TToken, TSeparator> separator)
=> parser.Many1().Left(separator);
/// <summary>
/// Separated和End的综合体
/// 形如a,b,c,
/// 实际的解析器至少运行一次
/// </summary>
/// <param name="parser"></param>
/// <param name="separator"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TSeparator"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> SeparatedOrEndBy1<TToken, T, TSeparator>(this Parser<TToken, T> parser,
Parser<TToken, TSeparator> separator)
=> parser.SeparatedBy1(separator).Left(separator.Try());
/// <summary>
/// Separated和End的综合体
/// 形如a,b,c,
/// 实际的解析器可以运行零次或者多次
/// </summary>
/// <param name="parser"></param>
/// <param name="separator"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TSeparator"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> SeparatedOrEndBy<TToken, T, TSeparator>(this Parser<TToken, T> parser,
Parser<TToken, TSeparator> separator)
=> parser.SeparatedOrEndBy1(separator).Try([]);
#endregion
#region LINQ
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> Select<TToken, T, TResult>(this Parser<TToken, T> parser,
Func<T, TResult> selector)
=> parser.Map(selector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TResult> SelectMany<TToken, T, TIntermediate, TResult>(this Parser<TToken, T> parser,
Func<T, Parser<TToken, TIntermediate>> selector, Func<T, TIntermediate, TResult> projector)
=> parser.Bind(x => selector(x).Map(y => projector(x, y)));
#endregion
}

View File

@@ -0,0 +1,18 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Extensions;
public static class ReadStateExtensions
{
public static IEnumerable<TState> AsEnumerable<TToken, TState>(this TState source)
where TState : IReadState<TToken, TState>
{
TState current = source;
while (current.HasValue)
{
yield return current;
current = current.Next;
}
}
}

View File

@@ -0,0 +1,15 @@
namespace CanonSharp.Combinator;
/// <summary>
/// 解析过程中的异常
/// </summary>
public class ParseException : Exception
{
public ParseException(string message) : base(message)
{
}
public ParseException(string message, Exception innerException) : base(message, innerException)
{
}
}

View File

@@ -0,0 +1,67 @@
using System.Runtime.CompilerServices;
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Results;
namespace CanonSharp.Combinator;
/// <summary>
/// <see cref="T:CanonSharp.Combinator.Abstractions.ParseResult"/> 相关的扩展方法
/// </summary>
public static class ParseResultBuilder
{
/// <summary>
/// 生成解析成功的结果
/// </summary>
/// <param name="value">解析成功的对象</param>
/// <param name="state">下一个输入流状态</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TState">输入流状态类型</typeparam>
/// <typeparam name="T">解析成功的对象类型</typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ParseResult<TToken, T> Succeed<TToken, TState, T>(T value, TState state)
where TState : IReadState<TToken, TState>
=> new InternalSuccessfulResult<TToken, TState, T>(value, state);
/// <summary>
/// 生成错误类型的解析失败结果
/// </summary>
/// <param name="state">解析的输入流状态</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TState">输入流状态类型</typeparam>
/// <typeparam name="T">解析成功的对象类型</typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ParseResult<TToken, T> Fail<TToken, TState, T>(TState state)
where TState : IReadState<TToken, TState>
=> new FailedResultWithError<TToken, TState, T>(state);
/// <summary>
/// 生成消息类型的解析失败结果
/// </summary>
/// <param name="message">错误消息</param>
/// <param name="state">输入流状态</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TState">输入流状态类型</typeparam>
/// <typeparam name="T">解析成功的对象类型</typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ParseResult<TToken, T> Fail<TToken, TState, T>(string message, TState state)
where TState : IReadState<TToken, TState>
=> new FailedResultWithMessage<TToken, TState, T>(message, state);
/// <summary>
/// 生成异常类型的解析失败结果
/// </summary>
/// <param name="exception">解析异常</param>
/// <param name="state">输入流状态</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TState">输入流状态类型</typeparam>
/// <typeparam name="T">解析成功的对象类型</typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ParseResult<TToken, T> Fail<TToken, TState, T>(Exception exception, TState state)
where TState : IReadState<TToken, TState>
=> new FailedResultWithException<TToken, TState, T>(exception, state);
}

View File

@@ -0,0 +1,223 @@
using System.Runtime.CompilerServices;
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Extensions;
using CanonSharp.Combinator.Parsers.Bases;
using CanonSharp.Combinator.Parsers.Primitives;
namespace CanonSharp.Combinator;
public static class ParserBuilder
{
#region PrimitiveParser
// 对应Parsers.Primitives命名空间下的Parser实现
/// <summary>
/// 直接成功的解析器
/// </summary>
/// <param name="value"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Pure<TToken, T>(T value)
=> new PureParser<TToken, T>(value);
/// <summary>
/// 直接成功的解析器
/// </summary>
/// <param name="valueFunc">生成结果的函数</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Pure<TToken, T>(Func<IReadState<TToken>, T> valueFunc)
=> new DelayedPureParser<TToken, T>(valueFunc);
/// <summary>
/// 生成空结果的解析器
/// </summary>
/// <typeparam name="TToken"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, Unit> Null<TToken>() => Pure<TToken, Unit>(Unit.Instance);
/// <summary>
/// 失败的解析器
/// </summary>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Fail<TToken, T>() => new FailedParser<TToken, T>();
/// <summary>
/// 失败的解析器
/// </summary>
/// <param name="message">失败的原因</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Fail<TToken, T>(string message) => new FailedParserWithMessage<TToken, T>(message);
/// <summary>
/// 失败的解析器
/// </summary>
/// <param name="messageFunc">产生失败原因的函数</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Fail<TToken, T>(Func<IReadState<TToken>, string> messageFunc) =>
new FailedParserWithDelayedMessage<TToken, T>(messageFunc);
/// <summary>
/// 失败的解析器
/// </summary>
/// <param name="exception">失败的异常</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Fail<TToken, T>(Exception exception) =>
new FailedParserWithException<TToken, T>(exception);
/// <summary>
/// 满足指定条件的解析器
/// </summary>
/// <param name="predicate"></param>
/// <typeparam name="TToken"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TToken> Satisfy<TToken>(Func<TToken, bool> predicate)
=> new SatisfyParser<TToken>(predicate);
/// <summary>
/// 识别任何输入的解析器
/// </summary>
/// <typeparam name="TToken"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TToken> Any<TToken>() => Satisfy<TToken>(_ => true);
/// <summary>
/// 识别指定输入元素的解析器
/// </summary>
/// <param name="token">识别的指定元素</param>
/// <typeparam name="TToken"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, TToken> Token<TToken>(TToken token)
=> Satisfy<TToken>(t => EqualityComparer<TToken>.Default.Equals(t, token));
/// <summary>
/// 跳过指定数量输入元素的解析器
/// </summary>
/// <param name="count"></param>
/// <typeparam name="TToken"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, Unit> Skip<TToken>(int count) => new SkipParser<TToken>(count);
/// <summary>
/// 识别指定数量输入元素的解析器
/// </summary>
/// <param name="count"></param>
/// <typeparam name="TToken"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<TToken>> Take<TToken>(int count) => new TakeParser<TToken>(count);
#endregion
#region Bases
/// <summary>
/// 按照给定的函数修改解析器的解析器
/// </summary>
/// <param name="parserFix"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Fix<TToken, T>(Func<Parser<TToken, T>, Parser<TToken, T>> parserFix)
=> new FixParser<TToken, T>(parserFix);
#endregion
#region Combinators
/// <summary>
/// 按照给定的解析器组依次尝试
/// </summary>
/// <param name="parsers"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Choice<TToken, T>(IEnumerable<Parser<TToken, T>> parsers)
=> parsers.Reverse().Aggregate((next, parser) => parser.Alternative(next));
/// <summary>
/// 按照给定的解析器组依次尝试
/// </summary>
/// <param name="parsers"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, T> Choice<TToken, T>(params Parser<TToken, T>[] parsers)
=> Choice(parsers.AsEnumerable());
/// <summary>
/// 顺序应用所有输入的解析器
/// </summary>
/// <param name="parsers"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> Sequence<TToken, T>(IEnumerable<Parser<TToken, T>> parsers)
=> parsers.Reverse().Aggregate(Pure<TToken, IEnumerable<T>>([]),
(next, parser) => parser.Bind(
x => next.Map(result => result.Prepend(x))));
/// <summary>
/// 顺序应用输入输入的解析器
/// </summary>
/// <param name="parsers"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<T>> Sequence<TToken, T>(params Parser<TToken, T>[] parsers)
=> Sequence(parsers.AsEnumerable());
/// <summary>
/// 识别输入令牌直到终止解析器运行成功
/// 在终止解析器之前可以存在零个或者多个输入令牌
/// </summary>
/// <param name="terminator"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<TToken>> TakeTill<TToken, TIgnore>(Parser<TToken, TIgnore> terminator)
=> Any<TToken>().ManyTill(terminator);
/// <summary>
/// 识别输入令牌直到终止解析器运行成功
/// 在终止解析器之前至少存在一个输入令牌
/// </summary>
/// <param name="termintor"></param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIgnore"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<TToken, IEnumerable<TToken>> Take1Till<TToken, TIgnore>(Parser<TToken, TIgnore> termintor)
=> Any<TToken>().Many1Till(termintor);
#endregion
}

View File

@@ -0,0 +1,21 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Bases;
/// <summary>
/// 选择解析器
/// 如果第一个不成功则调用第二个
/// </summary>
/// <param name="first">第一个解析器</param>
/// <param name="second">第二个解析器</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析器结果类型</typeparam>
internal sealed class AlternativeParser<TToken, T>(Parser<TToken, T> first, Parser<TToken, T> second)
: Parser<TToken, T>
{
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
{
return first.Run(state, result => result.CaseOf(continuation, _ => second.Run(state, continuation)));
}
}

View File

@@ -0,0 +1,20 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Bases;
/// <summary>
/// 单子解析器
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="next">下游解析器生成函数</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TIntermediate">上游解析器结果类型</typeparam>
/// <typeparam name="T">下游解析器结果类型</typeparam>
internal sealed class BindParser<TToken, TIntermediate, T>(
Parser<TToken, TIntermediate> parser,
Func<TIntermediate, Parser<TToken, T>> next) : Parser<TToken, T>
{
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
=> parser.Run(state, result => result.Next(next, continuation));
}

View File

@@ -0,0 +1,33 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Bases;
/// <summary>
/// 修正?解析器
/// 感觉是一种递归的高级实现?
///
/// </summary>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="T"></typeparam>
internal sealed class FixParser<TToken, T> : Parser<TToken, T>
{
private readonly Parser<TToken, T> _parser;
public FixParser(Func<Parser<TToken, T>, Parser<TToken, T>> func)
{
_parser = func(this);
}
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
=> _parser.Run(state, continuation);
}
internal sealed class FixParser<TToken, TParameter, T>(
Func<Func<TParameter, Parser<TToken, T>>, TParameter, Parser<TToken, T>> func,
TParameter parameter) : Parser<TToken, T>
{
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
=> func(p => new FixParser<TToken, TParameter, T>(func, p), parameter).Run(state, continuation);
}

View File

@@ -0,0 +1,21 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Bases;
/// <summary>
/// 映射解析器
/// 提供一个函数修改上游解析器返回的结果
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="func">修改上游解析器返回结果的</param>
/// <typeparam name="TToken"></typeparam>
/// <typeparam name="TIntermediate"></typeparam>
/// <typeparam name="T"></typeparam>
internal sealed class MapParser<TToken, TIntermediate, T>(
Parser<TToken, TIntermediate> parser,
Func<TIntermediate, T> func) : Parser<TToken, T>
{
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
=> parser.Run(state, result => continuation(result.Map(func)));
}

View File

@@ -0,0 +1,26 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Bases;
/// <summary>
/// 下一步解析器
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="successfulParser">成功情况下的解析器函数</param>
/// <param name="failedParser">失败情况下的解析器函数</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TIntermediate">上游解析器结果类型</typeparam>
/// <typeparam name="T">最终解析结果类型</typeparam>
internal sealed class NextParser<TToken, TIntermediate, T>(
Parser<TToken, TIntermediate> parser,
Func<TIntermediate, Parser<TToken, T>> successfulParser,
Func<FailedResult<TToken, TIntermediate>, Parser<TToken, T>> failedParser) : Parser<TToken, T>
{
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
{
return parser.Run(state, result => result.CaseOf(
successfulResult => successfulResult.Next(successfulParser, continuation),
failedResult => failedParser(failedResult).Run(state, continuation)));
}
}

View File

@@ -0,0 +1,24 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Bases;
/// <summary>
/// 恢复解析器
/// 在上游解析器失败的情况下调用指定恢复函数返回的解析器
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="failedHandler">返回新解析器的恢复函数</param>
/// <typeparam name="TToken">输入令牌类型</typeparam>
/// <typeparam name="T">解析结果类型</typeparam>
internal sealed class ResumeParser<TToken, T>(
Parser<TToken, T> parser,
Func<FailedResult<TToken, T>, Parser<TToken, T>> failedHandler) : Parser<TToken, T>
{
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
{
return parser.Run(state,
result => result.CaseOf(continuation,
failedResult => failedHandler(failedResult).Run(state, continuation)));
}
}

View File

@@ -0,0 +1,27 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers;
/// <summary>
/// 修改解析器返回结果的解析器基类
/// </summary>
/// <param name="parser">需要修改结果的解析器</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TIntermediate">需要修改结果的解析器</typeparam>
/// <typeparam name="T">最终返回的解析结果</typeparam>
public abstract class ModifiedParser<TToken, TIntermediate, T>(Parser<TToken, TIntermediate> parser) : Parser<TToken, T>
{
protected abstract ParseResult<TToken, T> Fail<TState>(TState state,
FailedResult<TToken, TIntermediate> failedResult)
where TState : IReadState<TToken, TState>;
protected abstract ParseResult<TToken, T> Succeed<TState>(TState state,
SuccessfulResult<TToken, TIntermediate> successfulResult)
where TState : IReadState<TToken, TState>;
internal override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
=> parser.Run(state, result => result.CaseOf(
success => continuation(Succeed(state, success)),
failure => continuation(Fail(state, failure))));
}

View File

@@ -0,0 +1,30 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Modifiers;
/// <summary>
/// 对结果运行指定操作,但是不做修改操作的解析器
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="succeed">对成功结果的操作</param>
/// <param name="fail">对失败结果的操作</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果类型</typeparam>
internal sealed class DoParser<TToken, T>(
Parser<TToken, T> parser,
Action<T> succeed,
Action<FailedResult<TToken, T>> fail) : ModifiedParser<TToken, T, T>(parser)
{
protected override ParseResult<TToken, T> Succeed<TState>(TState state,
SuccessfulResult<TToken, T> successfulResult)
{
succeed(successfulResult.Value);
return successfulResult;
}
protected override ParseResult<TToken, T> Fail<TState>(TState state, FailedResult<TToken, T> failedResult)
{
fail(failedResult);
return failedResult;
}
}

View File

@@ -0,0 +1,21 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Modifiers;
/// <summary>
/// 向前看解析器
/// 使用传入的解析器向前解析
/// 但是返回的结果中输入流读取状态不前移
/// </summary>
/// <param name="parser">需要向前看的解析器</param>
/// <typeparam name="TToken">输入流令牌</typeparam>
/// <typeparam name="T">返回的解析结果类型</typeparam>
internal sealed class LookAheadParser<TToken, T>(Parser<TToken, T> parser) : ModifiedParser<TToken, T, T>(parser)
{
protected override ParseResult<TToken, T> Succeed<TState>(TState state,
SuccessfulResult<TToken, T> successfulResult)
=> ParseResultBuilder.Succeed<TToken, TState, T>(successfulResult.Value, state);
protected override ParseResult<TToken, T> Fail<TState>(TState state, FailedResult<TToken, T> failedResult)
=> ParseResultBuilder.Fail<TToken, TState, T>($"Failed when looking ahead: {failedResult}", state);
}

View File

@@ -0,0 +1,26 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Modifiers;
/// <summary>
/// 翻转结果的解析器
/// 当成功时失败
/// 当失败时返回指定的成功结果
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="result">期望中的结果</param>
/// <typeparam name="TToken">输入流的类型</typeparam>
/// <typeparam name="TIntermediate">上游解析器结果类型</typeparam>
/// <typeparam name="T">最终的返回结果</typeparam>
internal sealed class ReverseParser<TToken, TIntermediate, T>(Parser<TToken, TIntermediate> parser, T result)
: ModifiedParser<TToken, TIntermediate, T>(parser)
{
protected override ParseResult<TToken, T> Succeed<TState>(TState state,
SuccessfulResult<TToken, TIntermediate> successfulResult)
=> ParseResultBuilder.Fail<TToken, TState, T>($"Unexpected successful result: {successfulResult.Value}",
state);
protected override ParseResult<TToken, T> Fail<TState>(TState state,
FailedResult<TToken, TIntermediate> failedResult)
=> ParseResultBuilder.Succeed<TToken, TState, T>(result, state);
}

View File

@@ -0,0 +1,26 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Modifiers;
/// <summary>
/// 成功映射的解析器
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="successfulHandler">当上游成功时的处理函数</param>
/// <param name="failedHandler">当上游失败时的处理函数</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TIntermediate">上游解析器解析结果类型</typeparam>
/// <typeparam name="T">最终的解析结果类型</typeparam>
internal sealed class SuccessfulMapParser<TToken, TIntermediate, T>(
Parser<TToken, TIntermediate> parser,
Func<TIntermediate, T> successfulHandler,
Func<FailedResult<TToken, TIntermediate>, T> failedHandler) : ModifiedParser<TToken, TIntermediate, T>(parser)
{
protected override ParseResult<TToken, T> Succeed<TState>(TState state,
SuccessfulResult<TToken, TIntermediate> successfulResult)
=> successfulResult.Map(successfulHandler);
protected override ParseResult<TToken, T> Fail<TState>(TState state,
FailedResult<TToken, TIntermediate> failedResult)
=> ParseResultBuilder.Succeed<TToken, TState, T>(failedHandler(failedResult), state);
}

View File

@@ -0,0 +1,23 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Modifiers;
/// <summary>
/// 尝试的解析器
/// 当成功时直接返回原结果
/// 当失败时调用resume函数处理失败结果并返回成功结果
/// </summary>
/// <param name="parser">上游解析器</param>
/// <param name="resume">处理失败结果的恢复函数</param>
/// <typeparam name="TToken">输入流令牌</typeparam>
/// <typeparam name="T">解析器返回结果类型</typeparam>
internal sealed class TryParser<TToken, T>(Parser<TToken, T> parser, Func<FailedResult<TToken, T>, T> resume)
: ModifiedParser<TToken, T, T>(parser)
{
protected override ParseResult<TToken, T> Succeed<TState>(TState state,
SuccessfulResult<TToken, T> successfulResult)
=> successfulResult;
protected override ParseResult<TToken, T> Fail<TState>(TState state, FailedResult<TToken, T> failedResult)
=> ParseResultBuilder.Succeed<TToken, TState, T>(resume(failedResult), state);
}

View File

@@ -0,0 +1,25 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers;
/// <summary>
/// 解析器原型基类
/// 实际上就是处理了一个后继调用
/// </summary>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
public abstract class PrimitiveParser<TToken, T> : Parser<TToken, T>
{
/// <summary>
/// 运行解析器 返回解析结果
/// </summary>
/// <param name="state">当前输入流的状态</param>
/// <typeparam name="TState">输入流状态的类型</typeparam>
/// <returns>解析结果</returns>
protected abstract ParseResult<TToken, T> Run<TState>(TState state)
where TState : IReadState<TToken, TState>;
internal sealed override ParseResult<TToken, TResult> Run<TState, TResult>(TState state,
Func<ParseResult<TToken, T>, ParseResult<TToken, TResult>> continuation)
=> continuation(Run(state));
}

View File

@@ -0,0 +1,51 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Primitives;
/// <summary>
/// 直接失败的解析器
/// </summary>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
internal sealed class FailedParser<TToken, T> : PrimitiveParser<TToken, T>
{
protected override ParseResult<TToken, T> Run<TState>(TState state)
=> ParseResultBuilder.Fail<TToken, TState, T>(state);
}
/// <summary>
/// 含有失败信息的失败解析器
/// </summary>
/// <param name="message">失败信息</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
internal sealed class FailedParserWithMessage<TToken, T>(string message) : PrimitiveParser<TToken, T>
{
protected override ParseResult<TToken, T> Run<TState>(TState state)
=> ParseResultBuilder.Fail<TToken, TState, T>(message, state);
}
/// <summary>
/// 按照输入状态产生失败信息的失败解析器
/// </summary>
/// <param name="messageFunc">产生失败信息的函数</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
internal sealed class FailedParserWithDelayedMessage<TToken, T>(Func<IReadState<TToken>, string> messageFunc)
: PrimitiveParser<TToken, T>
{
protected override ParseResult<TToken, T> Run<TState>(TState state)
=> ParseResultBuilder.Fail<TToken, TState, T>(messageFunc(state), state);
}
/// <summary>
/// 含有失败异常的失败解析器
/// </summary>
/// <param name="e">异常</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
internal sealed class FailedParserWithException<TToken, T>(Exception e) : PrimitiveParser<TToken, T>
{
protected override ParseResult<TToken, T> Run<TState>(TState state)
=> ParseResultBuilder.Fail<TToken, TState, T>(e, state);
}

View File

@@ -0,0 +1,27 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Primitives;
/// <summary>
/// 直接成功的解析器
/// </summary>
/// <param name="value">解析成功返回的值</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析成功返回值的类型</typeparam>
internal sealed class PureParser<TToken, T>(T value) : PrimitiveParser<TToken, T>
{
protected override ParseResult<TToken, T> Run<TState>(TState state)
=> ParseResultBuilder.Succeed<TToken, TState, T>(value, state);
}
/// <summary>
/// 按照输入状态返回结果的始终成功解析器
/// </summary>
/// <param name="valueFunc">按照输入状态返回解析结果的函数</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="T">解析成功返回值的类型</typeparam>
internal sealed class DelayedPureParser<TToken, T>(Func<IReadState<TToken>, T> valueFunc) : PrimitiveParser<TToken, T>
{
protected override ParseResult<TToken, T> Run<TState>(TState state)
=> ParseResultBuilder.Succeed<TToken, TState, T>(valueFunc(state), state);
}

View File

@@ -0,0 +1,18 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Parsers.Primitives;
/// <summary>
/// 满足指定条件即成功的解析器
/// </summary>
/// <param name="predicate">满足的条件谓词</param>
/// <typeparam name="TToken">输入流类型</typeparam>
internal sealed class SatisfyParser<TToken>(Func<TToken, bool> predicate) : PrimitiveParser<TToken, TToken>
{
protected override ParseResult<TToken, TToken> Run<TState>(TState state)
{
return state.HasValue && predicate(state.Current)
? ParseResultBuilder.Succeed<TToken, TState, TToken>(state.Current, state.Next)
: ParseResultBuilder.Fail<TToken, TState, TToken>(state);
}
}

View File

@@ -0,0 +1,22 @@
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Extensions;
namespace CanonSharp.Combinator.Parsers.Primitives;
/// <summary>
/// 跳过指定数量的输入令牌
/// </summary>
/// <param name="count">需要跳过的令牌数量</param>
/// <typeparam name="TToken">输入流类型</typeparam>
internal sealed class SkipParser<TToken>(int count) : PrimitiveParser<TToken, Unit>
{
protected override ParseResult<TToken, Unit> Run<TState>(TState state)
{
List<TState> result = state.AsEnumerable<TToken, TState>().Take(count).ToList();
return result.Count == count
? ParseResultBuilder.Succeed<TToken, TState, Unit>(Unit.Instance,
result.Count == 0 ? state : result.Last().Next)
: ParseResultBuilder.Fail<TToken, TState, Unit>("An input does not have required length.", state);
}
}

View File

@@ -0,0 +1,23 @@
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Extensions;
namespace CanonSharp.Combinator.Parsers.Primitives;
/// <summary>
/// 解析指定数量的解析器
/// </summary>
/// <param name="count">需要解析的数量</param>
/// <typeparam name="TToken">输入流类型</typeparam>
internal sealed class TakeParser<TToken>(int count) : PrimitiveParser<TToken, IEnumerable<TToken>>
{
protected override ParseResult<TToken, IEnumerable<TToken>> Run<TState>(TState state)
{
List<TState> result = state.AsEnumerable<TToken, TState>().Take(count).ToList();
return result.Count == count
? ParseResultBuilder.Succeed<TToken, TState, IEnumerable<TToken>>(result.Select(s => s.Current),
result.Count == 0 ? state : result.Last().Next)
: ParseResultBuilder.Fail<TToken, TState, IEnumerable<TToken>>("An input does not have required length.",
state);
}
}

View File

@@ -0,0 +1,22 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Results;
/// <summary>
/// 错误类型的失败解析结果
/// </summary>
/// <typeparam name="TToken">输入流的类型</typeparam>
/// <typeparam name="TState">输入流的读取类型</typeparam>
/// <typeparam name="T">实际的结果类型</typeparam>
internal sealed class FailedResultWithError<TToken, TState, T>(TState state) : FailedResult<TToken, T>
where TState : IReadState<TToken, TState>
{
public override IReadState<TToken> State => state;
public override string Message => $"Unexpected state: {state}.";
public override FailedResult<TToken, TNext> Convert<TNext>()
{
return new FailedResultWithError<TToken, TState, TNext>(state);
}
}

View File

@@ -0,0 +1,24 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Results;
/// <summary>
/// 异常类型的失败解析结果
/// </summary>
/// <param name="exception">解析中发生的异常</param>
/// <param name="state">当前输入流的状态</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TState">当前输入流状态的类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
public class FailedResultWithException<TToken, TState, T>(Exception exception, TState state) : FailedResult<TToken, T>
where TState : IReadState<TToken, TState>
{
public override IReadState<TToken> State => state;
public override ParseException Exception => new(ToString(), exception);
public override string Message => $"Exception occured: {exception}.";
public override FailedResult<TToken, TNext> Convert<TNext>()
=> new FailedResultWithException<TToken, TState, TNext>(exception, state);
}

View File

@@ -0,0 +1,24 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Results;
/// <summary>
/// 消息类型的失败解析结果
/// </summary>
/// <param name="message">解析失败的消息</param>
/// <param name="state">当前读取的状态</param>
/// <typeparam name="TToken">输入流的类型</typeparam>
/// <typeparam name="TState">读取状态类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
internal sealed class FailedResultWithMessage<TToken, TState, T>(string message, TState state) : FailedResult<TToken, T>
where TState : IReadState<TToken, TState>
{
public override IReadState<TToken> State => state;
public override string Message => message;
public override FailedResult<TToken, TNext> Convert<TNext>()
{
return new FailedResultWithMessage<TToken, TState, TNext>(message, state);
}
}

View File

@@ -0,0 +1,23 @@
using CanonSharp.Combinator.Abstractions;
namespace CanonSharp.Combinator.Results;
/// <summary>
/// 实际实现的解析成功结果
/// </summary>
/// <param name="result">解析结果</param>
/// <param name="state">解析成功之后的下一个输入流状态</param>
/// <typeparam name="TToken">输入流类型</typeparam>
/// <typeparam name="TState">输入流的状态类型</typeparam>
/// <typeparam name="T">解析结果的类型</typeparam>
internal sealed class InternalSuccessfulResult<TToken, TState, T>(T result, TState state)
: SuccessfulResult<TToken, T>(result)
where TState : IReadState<TToken, TState>
{
protected override ParseResult<TToken, TResult> RunNext<TNext, TResult>(Parser<TToken, TNext> parser,
Func<ParseResult<TToken, TNext>, ParseResult<TToken, TResult>> continuation)
=> parser.Run(state, continuation);
public override ParseResult<TToken, TResult> Map<TResult>(Func<T, TResult> map)
=> new InternalSuccessfulResult<TToken, TState, TResult>(map(Value), state);
}

View File

@@ -0,0 +1,22 @@
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Extensions;
using CanonSharp.Combinator.Parsers;
namespace CanonSharp.Combinator.Text;
/// <summary>
/// 字符串解析器
/// </summary>
/// <param name="except">期望的字符串</param>
/// <param name="comparison">字符串比较模式</param>
public class StringParser(string except, StringComparison comparison) : PrimitiveParser<char, string>
{
protected override ParseResult<char, string> Run<TState>(TState state)
{
TState[] states = state.AsEnumerable<char, TState>().Take(except.Length).ToArray();
string actual = new(states.Select(x => x.Current).ToArray());
return string.Equals(except, actual, comparison)
? ParseResultBuilder.Succeed<char, TState, string>(actual, states.Length == 0 ? state : states.Last().Next)
: ParseResultBuilder.Fail<char, TState, string>($"Except '{except}' but found '{actual}.", state);
}
}

View File

@@ -0,0 +1,123 @@
using System.Runtime.CompilerServices;
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Extensions;
using static CanonSharp.Combinator.ParserBuilder;
namespace CanonSharp.Combinator.Text;
public static class TextParserBuilder
{
/// <summary>
/// 识别单个字符
/// </summary>
/// <param name="token">识别的单个字符</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> Char(char token) => Satisfy<char>(x => x == token);
/// <summary>
/// 忽略大小写识别单个字符
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> CharIgnoreCase(char token) =>
Satisfy<char>(x => char.ToUpperInvariant(x) == char.ToUpperInvariant(token));
/// <summary>
/// 识别提供字符串中的一个字符
/// </summary>
/// <param name="candidate"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> OneOf(string candidate) => Satisfy<char>(candidate.Contains);
/// <summary>
/// 忽略大小写识别字符串中的一个字符
/// </summary>
/// <param name="candidate"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> OneOfIgnoreCase(string candidate) =>
Satisfy<char>(x => candidate.Contains(x, StringComparison.OrdinalIgnoreCase));
/// <summary>
/// 识别一个字符串
/// </summary>
/// <param name="except">识别的字符串</param>
/// <param name="comparison">字符串比较方法</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, string> String(string except, StringComparison comparison) =>
new StringParser(except, comparison);
/// <summary>
/// 识别一个字符串
/// </summary>
/// <param name="except"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, string> String(string except) => String(except, StringComparison.Ordinal);
/// <summary>
/// 忽略大小写识别一个字符串
/// </summary>
/// <param name="except"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, string> StringIgnoreCase(string except) =>
String(except, StringComparison.OrdinalIgnoreCase);
/// <summary>
/// 识别范围内的所有字符
/// </summary>
/// <param name="start">包括的起始字符</param>
/// <param name="end">包括的终止字符</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> Range(char start, char end) => Satisfy<char>(x => x >= start && x <= end);
/// <summary>
/// 识别Unicode字符类别的解析器
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> Letter() => Satisfy<char>(char.IsLetter);
/// <summary>
/// 识别Unicode数字类别的解析器
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> Digit() => Satisfy<char>(char.IsDigit);
/// <summary>
/// 识别ASCII字符类别的解析器
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> AsciiLetter() =>
Satisfy<char>(x => x is >= 'a' and <= 'z' or >= 'A' and <= 'Z');
/// <summary>
/// 识别ASCII数字类别的解析器
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> AsciiDigit() => Satisfy<char>(x => x is >= '0' and <= '9');
/// <summary>
/// 识别Unicode空白类型的字符
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, char> Space() => Satisfy<char>(char.IsWhiteSpace);
/// <summary>
/// 识别所有的换行符
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Parser<char, string> LineBreak() =>
OneOf("\u000D\u000A\u0085\u2028\u2029\n").Map(x => x.ToString()) | String("\r\n");
}

View File

@@ -0,0 +1,14 @@
using CanonSharp.Combinator.Abstractions;
using CanonSharp.Combinator.Extensions;
using static CanonSharp.Combinator.Text.TextParserBuilder;
namespace CanonSharp.Combinator.Text;
public static class TextParserExtensions
{
public static Parser<char, T> SkipSpaces<T>(this Parser<char, T> parser)
=> Space().SkipTill(parser);
public static Parser<char, T> SkipSpaceAndLineBreak<T>(this Parser<char, T> parser)
=> (Space().Map(x => x.ToString()) | LineBreak()).SkipTill(parser);
}

View File

@@ -0,0 +1,23 @@
namespace CanonSharp.Combinator;
/// <summary>
/// 单元类型Unit
/// </summary>
public readonly struct Unit : IComparable<Unit>, IEquatable<Unit>
{
public static Unit Instance => default;
public bool Equals(Unit other) => true;
public int CompareTo(Unit other) => 0;
public override bool Equals(object? obj) => obj is Unit;
public override int GetHashCode() => 0;
public override string ToString() => $"<{nameof(Unit)}>";
public static bool operator ==(Unit _0, Unit _1) => true;
public static bool operator !=(Unit _0, Unit _1) => false;
}