/// <summary> /// Refer to another parser indirectly. This allows circular compile-time dependency between parsers. /// </summary> /// <typeparam name="TToken"></typeparam> /// <typeparam name="T"></typeparam> /// <param name="reference"></param> /// <returns></returns> public static Parser <TToken, T> Ref <TToken, T>(Func <Parser <TToken, T> > reference) { if (reference == null) { throw new ArgumentNullException(nameof(reference)); } Parser <TToken, T> p = null; return(i => { if (p == null) { p = reference(); } if (i.Memos.ContainsKey(p)) { throw new ParsingException(i.Memos[p].ToString()); } i.Memos[p] = ParserResult <TToken, T> .Failure(i, new string[0], "Left recursion in the grammar." ); var result = p(i); i.Memos[p] = result; return result; }); }
public ParserResult <TToken, U> IfSuccess <U>(Func <ParserResult <TToken, TValue>, ParserResult <TToken, U> > next) { if (next == null) { throw new ArgumentNullException(nameof(next)); } if (this.IsSuccess) { return(next(this)); } return(ParserResult <TToken, U> .Failure(this.Rest, this.Expected, this.Description)); }
public static Parser <TToken, T> End <TToken, T>(this Parser <TToken, T> parser) { if (parser == null) { throw new ArgumentNullException(nameof(parser)); } return(i => parser(i).IfSuccess(s => s.Rest.AtEnd ? s : ParserResult <TToken, T> .Failure( s.Rest, new[] { "end of input" }, string.Format("unexpected '{0}'", s.Rest.GetCurrent()) ) )); }
public static Parser <ScriptToken, ScriptToken> ScriptToken(Func <int, bool> predicate, string expected) { return(i => { if (i.AtEnd) { return ParserResult <ScriptToken, ScriptToken> .Failure(i, new [] { expected }, "Unexpected end of input"); } if (predicate(i.GetCurrent().Tag)) { return ParserResult <ScriptToken, ScriptToken> .Success(i.Advance(), i.GetCurrent()); } return ParserResult <ScriptToken, ScriptToken> .Failure(i, $"Unexpected {i.GetCurrent()}"); }); }
/// <summary> /// Succeed if the parsed value matches predicate. /// </summary> /// <typeparam name="TToken"></typeparam> /// <typeparam name="T"></typeparam> /// <param name="parser"></param> /// <param name="predicate"></param> /// <returns></returns> public static Parser <TToken, T> Where <TToken, T>(this Parser <TToken, T> parser, Func <T, bool> predicate) { if (parser == null) { throw new ArgumentNullException(nameof(parser)); } if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); } return(i => parser(i).IfSuccess(s => predicate(s.Value) ? s : ParserResult <TToken, T> .Failure(i, new string[0], string.Format("Unexpected {0}.", s.Value) ) )); }
public static ParserResult <TToken, T> DetermineBestError <TToken, T>( ParserResult <TToken, T> firstF, ParserResult <TToken, T> secondF ) { if (secondF.Rest.Position > firstF.Rest.Position) { return(secondF); } if (secondF.Rest.Position == firstF.Rest.Position) { return(ParserResult <TToken, T> .Failure( firstF.Rest, firstF.Expected.Union(secondF.Expected), firstF.Description )); } return(firstF); }
public static Parser <char, char> Char(Func <char, bool> predicate, string expected) { if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); } return(i => { if (i.AtEnd) { return ParserResult <char, char> .Failure(i, new [] { expected }, "Unexpected end of input"); } if (predicate(i.GetCurrent())) { return ParserResult <char, char> .Success(i.Advance(), i.GetCurrent()); } return ParserResult <char, char> .Failure(i, new [] { expected }, $"Unexpected '{i.GetCurrent()}'"); }); }
/// <summary> /// Attempt parsing only if the <paramref name="except"/> parser fails. /// </summary> /// <typeparam name="TToken"></typeparam> /// <typeparam name="T"></typeparam> /// <typeparam name="U"></typeparam> /// <param name="parser"></param> /// <param name="except"></param> /// <returns></returns> public static Parser <TToken, T> Except <TToken, T, U>(this Parser <TToken, T> parser, Parser <TToken, U> except) { if (parser == null) { throw new ArgumentNullException(nameof(parser)); } if (except == null) { throw new ArgumentNullException(nameof(except)); } // Could be more like: except.Then(s => s.Fail("..")).XOr(parser) return(i => { var r = except(i); if (r.IsSuccess) { return ParserResult <TToken, T> .Failure(i, new[] { "other than the excepted input" }, "Excepted parser succeeded."); } return parser(i); }); }
internal static ParserResult <ScriptToken, T> TryParse <T>(this Parser <ScriptToken, T> parser, Script input) { if (parser == null) { throw new System.ArgumentNullException(nameof(parser)); } if (input == null) { throw new System.ArgumentNullException(nameof(input)); } try { return(parser(new ScriptInput(input))); } // Catching exception here is bit ugly, but converting `Script` to `ScriptToken` is itself unsafe // so this is good for assuring purity of this method. catch (ParsingException e) { return(ParserResult <ScriptToken, T> .Failure(new ScriptInput(new ScriptToken[] {}), e.Message)); } }