using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using miew.Enumerable;
namespace agree
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public abstract partial class Entry : Instance
{
public Entry(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t.tm, name, bfc)
{
this.t = t;
this.m_flags = (t.m_flags & Flags.HasAnyFeatures);
}
readonly Type t;
public override Type InstanceType { get { return t; } }
protected TargetTfs PreExpand()
{
TargetTfs tt = Unification.UnifyForceExpand(Definition, InstanceType.Expanded);
if (tt == null)
throw new TfsException("Error expanding entry '{0}': could not unify with its instance type(s).", this.Name);
tt.Name = Name + " - Expanded";
return tt;
}
/// to avoid expanding lexical a dynamic expanding entry if all you need is the hash
long _exp_tfs_hash = -1;
public long ExpandedTfsHash
{
get
{
if (_exp_tfs_hash == -1)
{
if (this is StaticExpandEntry)
_exp_tfs_hash = ((StaticExpandEntry)this).Expanded.TfsHash();
else
_exp_tfs_hash = ((DemandExpandEntry)this).GetExpanded().TfsHash();
}
return _exp_tfs_hash;
}
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public abstract partial class StaticExpandEntry : Entry
{
public StaticExpandEntry(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
}
public override Tfs EnsureExpanded(out bool f_did)
{
f_did = false;
Tfs _tmp;
if ((_tmp = _expanded) != null)
return _tmp;
Stopwatch stopw = Stopwatch.StartNew();
TargetTfs tt = PreExpand();
if ((_tmp = _expanded) != null)
return _tmp;
Tfs _new;
if (tt.EdgeCount == 0)
_new = new BareTfs(tt.Type);
else
_new = tt.ToArrayTfs();
Interlocked.Add(ref tm.ms_expand, (int)stopw.ElapsedMilliseconds);
if ((_tmp = Interlocked.CompareExchange(ref _expanded, _new, null)) != null)
return _tmp;
f_did = true;
return _new;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Expand-on-demand support
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public abstract partial class DemandExpandEntry : Entry
{
public DemandExpandEntry(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
/// an ID for the expanded TFS that will remain the same after weak resurrection
exp_tfs_id = Interlocked.Increment(ref Tfs.next_tfs_id);
}
public override Tfs EnsureExpanded(out bool f_did)
{
f_did = true;
return GetExpanded();
//throw new NotImplementedException("use GetExpanded() for DynamicExpandEntry");
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Hook the expansion of lexical entries and keep a weak reference. The published reference to a lexical entry or
/// entries can be released but a weak reference will remain in the object for possible future recovery.
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakReference wr = null;
int exp_tfs_id;
public Tfs GetExpanded()
{
/// we have to count weak reference recoveries as unifications (and pay the penalty of re-installing
/// them atomically) or else the regression test results for number of unifications won't exactly match
Tfs _exp;
if (wr != null && (_exp = (Tfs)wr.Target) != null)
return _exp;
_exp = PreExpand().ToArrayTfs();
_exp.id = exp_tfs_id;
if (wr == null)
wr = new WeakReference(_exp, false);
else
wr.Target = _exp;
return _exp;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[DebuggerDisplay("{ToString(),nq} ({t._feature_info(),nq})")]
public abstract class Rule : StaticExpandEntry
{
public Rule(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
}
public Rule(Type t, BinaryReader br)
: base(t, br)
{
}
HashSet<Rule> _key_mothers = null;
public bool IsSpanOnly = false;
private MotherDaughterTfs _mdtfs;
public override Tfs EnsureExpanded(out bool f_did)
{
f_did = false;
Tfs _tmp;
if ((_tmp = _expanded) != null)
return _tmp;
Stopwatch stopw = Stopwatch.StartNew();
TargetTfs tt = PreExpand();
if ((_tmp = _expanded) != null)
return _tmp;
_mdtfs = tt.ToMotherDaughterTfs(null);
Interlocked.Add(ref tm.ms_expand, (int)stopw.ElapsedMilliseconds);
if ((_tmp = Interlocked.CompareExchange(ref _expanded, _mdtfs, null)) != null)
return _tmp;
f_did = true;
return _mdtfs;
}
public MotherDaughterTfs RuleTfs
{
get
{
bool f_dont_care;
return _mdtfs ?? (MotherDaughterTfs)EnsureExpanded(out f_dont_care);
}
}
public TfsSection[] RuleDaughters
{
get
{
bool f_dont_care;
return (_mdtfs ?? (MotherDaughterTfs)EnsureExpanded(out f_dont_care)).RuleDaughters;
}
}
public int KeyDaughterIndex
{
get
{
bool f_dont_care;
return (_mdtfs ?? (MotherDaughterTfs)EnsureExpanded(out f_dont_care)).KeyDaughterIndex;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Check rule compatibility. There are two cache directions: first, each rule pre-checks and caches the mother
/// rules for which this rule is compatible with that mother's KEY daughter. This cache is used by both grammar
/// rules--which build both upwards and downwards--and lexical rules--which build upwards only. GrammarRule
/// subclasses this function to add the down cache for non-key-daughters.
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public virtual void AnalyzeRuleCompatibility(IEnumerable<Rule> key_mother_check, IEnumerable<Rule> daughter_check)
{
/// find the mother rules for which this rule is compatible with its KEY daughter
_key_mothers = new HashSet<Rule>();
foreach (Rule mother in key_mother_check)
if (tm.da.UnifyCheck(Expanded, mother.RuleDaughters[mother.KeyDaughterIndex]))
_key_mothers.Add(mother);
}
public HashSet<Rule> CompatibleKeyMothers { get { return _key_mothers; } }
public override string ToString()
{
return String.Format("{0}", Name);
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public partial class GrammarRule : Rule
{
public GrammarRule(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
}
public GrammarRule(Type t, BinaryReader br)
: base(t, br)
{
}
HashSet<Rule>[] _non_key_daughters = null;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public override void AnalyzeRuleCompatibility(IEnumerable<Rule> key_mother_check, IEnumerable<Rule> daughter_check)
{
base.AnalyzeRuleCompatibility(key_mother_check, daughter_check);
/// find the rules which are compatible with each non-KEY daughter position of this rule
_non_key_daughters = new HashSet<Rule>[RuleDaughters.Length];
for (int i = 0; i < RuleDaughters.Length; i++)
{
if (i != KeyDaughterIndex)
{
_non_key_daughters[i] = new HashSet<Rule>();
TfsSection rd = RuleDaughters[i];
foreach (Rule candidate in daughter_check)
if (tm.da.UnifyCheck(candidate.Expanded, rd))
_non_key_daughters[i].Add(candidate);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool CheckDaughterCompatibility(Rule rule, int i_arg)
{
return _non_key_daughters[i_arg].Contains(rule);
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public partial class LexicalRule : Rule
{
public LexicalRule(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[DebuggerDisplay("{ToString(),nq}")]
public partial class MorphologicalRule : LexicalRule
{
MorphologySubrule[] morph_subrules = null;
public MorphologicalRule(Type t, String name, List<BaseFeatConstraint> bfc, List<MorphologySubrule> morph_subrules)
: base(t, name, bfc)
{
if (morph_subrules != null)
this.morph_subrules = morph_subrules.ToArray();
}
public IList<MorphologySubrule> Subrules { get { return morph_subrules; } }
public override string ToString()
{
return base.ToString() + String.Format(" subrules: {0}", morph_subrules.Length);
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class StartSymbol : StaticExpandEntry
{
public StartSymbol(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
}
public StartSymbol(Type t, BinaryReader br)
: base(t, br)
{
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
abstract public class NodeLabel : StaticExpandEntry
{
public NodeLabel(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
}
public NodeLabel(Type t, BinaryReader br)
: base(t, br)
{
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[DebuggerDisplay("{Name}")]
public class NodeLabelTemplate : NodeLabel
{
String label;
public Tfs effective;
public TfsSection effective_local;
public NodeLabelTemplate(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
TypeMgr tm = t.tm;
Tfs exp = this.Definition;// this.Expanded;
ConstraintRef cr_label;
if (!exp.GetEdgeAtPath(exp.Edge, tm.config.nodeLabels.LabelPath, out cr_label))
throw new Exception(String.Format("Node label template '{0}' has no label at '{1}'",
Name,
tm.config.nodeLabels.LabelPath.StringJoin(".")));
label = tm.GetStringValue(cr_label.Constraint.FlagsId);
/// Sharing the Mark of 'Expanded' but with a more derived type (computed here) causes
/// the 'label' feature to be ignored when unifying for node labels
Type t_new = tm.GlbOfMany(exp.AllPools.Exclude(cr_label.i_feat));
effective = exp.GetSection(exp.tm.CreateEdge(t_new, exp.Edge.Mark, false), 0);
//if (!
effective_local = exp.GetSection(tm.config.nodeLabels.LocalPath);
//effective_local = default(TfsEdge);
}
public NodeLabelTemplate(Type t, BinaryReader br)
: base(t, br)
{
}
public String Label { get { return label; } }
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[DebuggerDisplay("{Name}")]
public class NodeMetaTemplate : NodeLabel
{
String meta_prefix;
String meta_suffix;
public TfsSection effective;
public NodeMetaTemplate(Type t, String name, List<BaseFeatConstraint> bfc)
: base(t, name, bfc)
{
TypeMgr tm = t.tm;
Tfs exp = this.Definition;//.Expanded;
ConstraintRef cref;
if (!exp.GetEdgeAtPath(exp.Edge, tm.config.nodeLabels.PrefixPath, out cref))
throw new Exception(String.Format("Node meta template '{0}' has no prefix at '{1}'",
Name,
tm.config.nodeLabels.PrefixPath.StringJoin(".")));
meta_prefix = tm.GetStringValue(cref.Constraint.FlagsId);
if (!exp.GetEdgeAtPath(exp.Edge, tm.config.nodeLabels.SuffixPath, out cref))
throw new Exception(String.Format("Node meta template '{0}' has no suffix at '{1}'",
Name,
tm.config.nodeLabels.SuffixPath.StringJoin(".")));
meta_suffix = tm.GetStringValue(cref.Constraint.FlagsId);
/// Sharing the Mark of 'Expanded' but with a more derived type (computed here) causes
/// the 'prefix' and 'suffix' features to be ignored when unifying
/// for now, assuming that the prefix and suffix features are introduced by meta
Type t_new = tm.GlbOfMany(exp.AllPools.Where(fix => tm.feat_arr[fix].maximal_type != tm.tt_meta));
effective = exp.GetSection(tm.config.nodeLabels.RecursivePath);
if (effective == null)
throw new Exception();
}
public NodeMetaTemplate(Type t, BinaryReader br)
: base(t, br)
{
}
public String Prefix { get { return meta_prefix; } }
public String Suffix { get { return meta_suffix; } }
};
}