/// <summary> /// This is the "trampoline" function /// </summary> /// <param name="workList"></param> /// <param name="input"></param> /// <param name="log"></param> /// <typeparam name="TInput"></typeparam> /// <returns></returns> private static WorkList <TInput> Apply <TInput>(WorkList <TInput> workList, TInput input, Action <string> log) { log($"Input: '{input}'"); var(matchers, initialParsers) = workList; var parsers = new Queue <RegisterParser <TInput> >(initialParsers); var registrar = new ParserRegistrar <TInput>(); log("Creating new work"); while (parsers.Count > 0) { foreach (var registration in parsers.Dequeue()(registrar)) { parsers.Enqueue(registration); } } matchers = matchers.AddRange(registrar.GetWork()); log("Apply input to work"); return(matchers.Select(matcher => matcher(input)).Aggregate((a, b) => a.Add(b))); }
/// <summary> /// Determines if a work list is empty (has no matchers or parser registrations). /// </summary> /// <param name="this">This work list</param> /// <typeparam name="TInput">Input element type</typeparam> /// <returns><code>true</code> if the work list has no matchers or parser registrations</returns> public static bool IsEmpty <TInput>(this WorkList <TInput> @this) => @this.Matchers.IsEmpty && @this.Parsers.IsEmpty;
/// <summary> /// Creates a new <see cref="WorkList{T}"/> with the work from this list and an additional parser to start. /// </summary> /// <param name="this">This work list</param> /// <param name="parser">Parser to be started</param> /// <param name="resolver">Resolver to invoke when the parser matches</param> /// <typeparam name="TInput">Input element type</typeparam> /// <typeparam name="TMatch">Parse result type</typeparam> /// <returns>The new work list</returns> public static WorkList <TInput> Add <TInput, TMatch>(this WorkList <TInput> @this, IParser <TInput, TMatch> parser, Resolver <TInput, TMatch> resolver) => new WorkList <TInput>(@this.Matchers, @this.Parsers.Add(r => r.Register(parser, resolver)));
/// <summary> /// Creates a new <see cref="WorkList{T}"/> with the work from this list and additional matchers. /// </summary> /// <param name="this">This work list</param> /// <param name="matchers">Matchers to add</param> /// <typeparam name="TInput">Input element type</typeparam> /// <returns>The new work list</returns> public static WorkList <TInput> Add <TInput>(this WorkList <TInput> @this, params Matcher <TInput>[] matchers) => new WorkList <TInput>(@this.Matchers.AddRange(matchers), @this.Parsers);
/// <summary> /// Creates a new <see cref="WorkList{T}"/> with the combined work of this list and another. /// </summary> /// <param name="this">This work list</param> /// <param name="other">Work list to add</param> /// <typeparam name="TInput">Input element type</typeparam> /// <returns>The new work list</returns> public static WorkList <TInput> Add <TInput>(this WorkList <TInput> @this, WorkList <TInput> other) => new WorkList <TInput>(@this.Matchers.AddRange(other.Matchers), @this.Parsers.AddRange(other.Parsers));