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; using glue.Debugging; namespace agree.Parse { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract class UnificationParseChart : SubscriptionChart { public UnificationParseChart( ParserConfiguration config, ISysObj so_owner, String source_text, IEnumerable<ISysObj> 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<ISysObj> start_symbols; public abstract bool CanUnify(ISysObj t1, TfsEdge t2); public abstract bool UnifyPartial(IParseChartRule mother, TfsEdge daughter, TfsEdge candidate, out TfsEdge result, bool f_last); public abstract Task<TfsEdge> UnifyPartialAsync(IParseChartRule mother, TfsEdge daughter, TfsEdge candidate, bool f_last); public abstract IGrammarRule IncorporatePart(IGrammarRule mother, TfsEdge result); public virtual bool QuickCheck(TfsEdge t1, TfsEdge t2) { return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int FinishMatchedEdge(ISysObj license, TfsEdge result, Span span, IParseChartEdge[] rgce_new) { //if (new System.Text.RegularExpressions.Regex("FinishMatchedEdge").Matches(new StackTrace().ToString()).Count > 20) //{ // m_chart.DumpChart(@"d:\chart_dump.html"); // Environment.Exit(0); // throw new ParseException("cyclic"); //} int cu = 0; DerivedPassiveEdge nce = null; // try to match the start symbol if (span == EntireSpan) { foreach (ISysObj start_sym in start_symbols) { cu++; if (CanUnify(start_sym, result)) { nce = new CompletedParse(this, span, license, result, rgce_new, start_sym); if (debug_output != null) debug_output.WriteLineColor("$darkgreen {0}$ matched start symbol $magenta {1}", nce, start_sym); break; } } } nce = nce ?? new DerivedPassiveEdge(this, span, license, result, rgce_new); StartAttachedChildTask(AddEdgeInner, nce); return cu; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <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 => { SetComplete(); ClearSubscribers(); if (t.Exception != null) { CancelParse(); m_status |= TaskCancellationChart.Status.Faulted; 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() { foreach (IParseChartEdge tok in initial_tokens) StartAttachedChildTask(AddEdgeInner, tok); } }; }