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);
}
}
};
};
}