using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using miew.Tokenization; namespace agree { using unif_stats = ParseControl.Stats._unification; abstract public partial class SubscriptionChart : ChartBase { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Active chart edge: binds a sequence interlock to a passive edge notification closure /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract class ActiveEdge : IAtomicSequence { public ActiveEdge(ParseChart c, GrammarRule r, MotherDaughterTfs m, ref PassiveEdge.ParseObjs rgo) { this.chart = c; this.ctrl = c.ctrl; this.r = r; this.rgo = rgo; this.f_restrict = c.ctrl.AnyPacking; c.ctrl.stats.Parsing.Chart.ActiveEdge(); } internal ActiveEdge m_next; /// linked list managed by 'NotificationSource' readonly protected ParseChart chart; readonly protected ParseControl ctrl; readonly protected GrammarRule r; protected PassiveEdge.ParseObjs rgo; internal TfsSection daughter; protected int i_arg; protected bool f_restrict; public abstract void TryMatchEdge(IParseObj ce, ref unif_stats u_stats); public Span CompletedSpan { get { return rgo.Span; } } protected int i_seq; public void SetSequenceId(int id) { i_seq = id; } public int SequenceId { get { return i_seq; } } protected int s_state; public int State { get { return s_state; } } public void SetStateRaw(int s) { s_state = s; } public bool BeginTransact() { throw new NotImplementedException(); } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Active right edge: a partial left edge. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class ActiveRightEdge : ActiveEdge { readonly int i_chart_limit; readonly bool f_last; public ActiveRightEdge(ParseChart c, GrammarRule r, MotherDaughterTfs m, ref PassiveEdge.ParseObjs rgo) : base(c, r, m, ref rgo) { this.i_arg = rgo.Count; TfsSection[] rd = m.RuleDaughters; this.i_chart_limit = chart.ColumnCount - (rd.Length - i_arg); this.daughter = rd[i_arg]; this.f_last = i_arg == rd.Length - 1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// The active edge tries to match the given PassiveChart edge. Three cases are possible: /// 1.) the specified edge does not extend this active edge; or /// 2.) the rule is complete, create a new passive edge and insert it into the chart; or /// 3.) the rule is still not complete: create a new active edge which incorporates the new partial result. /// In any of these three cases, this rule continues to accept future edges as before. /// This function preserves the thread-safety of the user-supplied Unification callback, if any. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override void TryMatchEdge(IParseObj ce, ref unif_stats u_stats) { if (this.IsRemove()) return; if (rgo.AnyInactive) { /// by setting this, we request to be opportunistically removed from the chart-edge subscription we /// have been subscribed as interested in, during the next subscription posting pass s_state = SequenceControl.REMOVE; return; } // if the candidate edge doesn't fit, don't bother unifying if (ce.TokenSpan.EndIndex > i_chart_limit) return; if (f_last && r.IsSpanOnly && ce.TokenSpan.EndIndex < chart.ColumnCount - 1) return; Rule d_rule = ce.License as Rule; if (d_rule != null && !r.CheckDaughterCompatibility(d_rule, i_arg)) return; //var pe = ce as PassiveEdge.Derived; //if (pe != null && pe.IsHold()) // pe.DirectCancel(); if (!ce.IsActive()) return; if (ctrl.QuickCheckParse(ce.Tfs, daughter)) return; MotherDaughterTfs mdtfs = ctrl.UnifySection( daughter, ce.Tfs, f_last, f_restrict, ref u_stats); if (mdtfs != null) { PassiveEdge.ParseObjs npo = new PassiveEdge.ParseObjs(rgo, ce); if (f_last) chart.FinishMatchedEdge(r, mdtfs, ref npo, ref u_stats); else chart.Subscribe(RIGHT, new ActiveRightEdge(chart, r, mdtfs, ref npo), ref u_stats); } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Active left edge: a partial right edge. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class ActiveLeftEdge : ActiveEdge { public ActiveLeftEdge(ParseChart c, GrammarRule r, MotherDaughterTfs m, ref PassiveEdge.ParseObjs rgo) : base(c, r, m, ref rgo) { this.i_arg = (byte)(m.RuleDaughters.Length - 1 - rgo.Count); this.daughter = m.RuleDaughters[i_arg]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// The active edge tries to match the given PassiveChart edge. Three cases are possible: /// 1.) the specified edge does not extend this active edge; or /// 2.) the rule is complete, create a new passive edge and insert it into the chart; or /// 3.) the rule is still not complete: create a new active edge which incorporates the new partial result. /// In any of these three cases, this rule continues to accept future edges as before. /// This function preserves the thread-safety of the user-supplied Unification callback, if any. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override void TryMatchEdge(IParseObj ce, ref unif_stats u_stats) { if (this.IsRemove()) return; if (rgo.AnyInactive) { /// by setting this, we request to be opportunistically removed from the chart-edge subscription we /// have been subscribed as interested in, during the next subscription posting pass s_state = SequenceControl.REMOVE; return; } // if the candidate edge doesn't fit, don't bother unifying if (ce.TokenSpan.StartIndex < i_arg) return; if (i_arg == 0 && r.IsSpanOnly && ce.TokenSpan.StartIndex > 0) return; Rule d_rule = ce.License as Rule; if (d_rule != null && !r.CheckDaughterCompatibility(d_rule, i_arg)) return; //var pe = ce as PassiveEdge.Derived; //if (pe != null && pe.IsHold()) // pe.DirectCancel(); if (!ce.IsActive()) return; if (ctrl.QuickCheckParse(ce.Tfs, daughter)) return; MotherDaughterTfs mdtfs = ctrl.UnifySection( daughter, ce.Tfs, i_arg == 0, f_restrict, ref u_stats); if (mdtfs != null) { PassiveEdge.ParseObjs npo = new PassiveEdge.ParseObjs(ce, rgo); if (i_arg == 0) chart.FinishMatchedEdge(r, mdtfs, ref npo, ref u_stats); else chart.Subscribe(LEFT, new ActiveLeftEdge(chart, r, mdtfs, ref npo), ref u_stats); } } }; }; }