using System; using System.Diagnostics; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using glue.Extensions.String; using glue.Extensions.Enumerable; using glue.Tasks; using glue.Tokenization; namespace agree.Parse { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract class UnificationParseChart<T> : SubscriptionChart<T> where T : ChartBase<T>.IMotherDaughter, IEquatable<T> { public UnificationParseChart( ParserConfiguration config, ISysObj so_owner, String source_text, IEnumerable<ISelf> start_symbols, int chart_span, IEnumerable<IParseChartEdge> initial_tokens) : base(config, so_owner, source_text, chart_span) { this.initial_tokens = initial_tokens; this.start_symbols = start_symbols; } readonly IEnumerable<IParseChartEdge> initial_tokens; readonly internal IEnumerable<ISelf> start_symbols; public abstract bool CanUnify(T t1, T t2); public abstract bool UnifyPartial(IGrammarRule mother, T daughter, T candidate, out T result, bool f_last); public abstract Task<T> UnifyPartialAsync(IGrammarRule mother, T daughter, T candidate, bool f_last); public abstract IGrammarRule IncorporatePart(IGrammarRule mother, T result); public virtual QuickCheckResult QuickCheck(T t1, T t2) { return QuickCheckResult.ProceedToUnify; } public enum QuickCheckResult { Failed = 0, ProceedToUnify = 1, } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Guarantee a parent task context so that nested tasks will be attached as child tasks. /// Do not specify AttachedToParent (or rethrown exception will propagate into the parent task, which is not /// accessible to this function) and do not specify the chart's CancelTok (or this task's act of cancelling the /// parse will put a task-canceled exception into the continuation, and trump/erase the actual exception) /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Task ParseAsync() { var hs = initial_tokens.UnionMany(tok => tok.ChartSpan.Range); if (hs.Count != ColumnCount) { String m2 = Enumerable.Range(0, ColumnCount).Except(hs).StringJoin(", "); throw new ParseException("No tokens were submitted to the parser for the following chart column positions: {0}.", m2); } timer.Start(); return StartAttachedChildTask(ParseInner).ContinueWith( t => { timer.Stop(); ClearSubscribers(); if (t.Exception != null) { CancelParse(); AggregateException aex = t.Exception.Flatten(); var rgex = aex.InnerExceptions.OfType<ParseException>().Distinct(e => e.Id).ToArray(); if (rgex.Length == 1) throw rgex[0]; throw aex; } }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } void ParseInner() { //return //return TaskFactory.ContinueWhenAll(initial_tokens.Select(tok => StartAttachedChildTask(AddEdgeInner, tok)).ToArray(), rgt => // { // if (rgt.Any(t => t.Exception != null)) // { // glue.Debugging.Nop.X(); // } // return Tasks.CompletedTask; // }); //return TaskEx.WhenAll(initial_tokens.Select(tok => //)); foreach (IParseChartEdge tok in initial_tokens) StartAttachedChildTask(AddEdgeInner, tok); } }; }