using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using glue.Extensions.Enumerable; namespace agree { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract partial class Entry : Instance { public Entry(Type t, String name, List<BaseFeatConstraint> bfc) : base(t.mgr, name, bfc) { this.t = t; this.m_flags = (t.m_flags & Flags.HasAnyFeatures); } readonly Type t; public override Type InstanceType { get { return t; } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract partial class StaticExpandEntry : Entry { public StaticExpandEntry(Type t, String name, List<BaseFeatConstraint> bfc) : base(t, name, bfc) { } TfsEdge _expanded; [DebuggerBrowsable(DebuggerBrowsableState.Never)] public override TfsEdge Expanded { get { if (_expanded.IsNull) { Tray tr = mgr.g.loadtray; Stopwatch stopw = Stopwatch.StartNew(); TfsEdge _tmp; if (!new Unification.Expander(tr).ExpandEntry(_definition, InstanceType.Expanded, out _tmp)) throw new TfsException("Error expanding entry '{0}': could not unify with its instance type(s).", this.Name); if (!_tmp.PseudoAtomicStoreTo(ref _expanded)) _tmp.Dispose(); else { _expanded.RegisterName(Name); m_flags |= Flags.Expanded; // fix fix } Interlocked.Add(ref mgr.ms_expand, (int)stopw.ElapsedMilliseconds); } return _expanded; } } public virtual bool ReleaseExpanded() { TfsEdge _tmp = _expanded; if (default(TfsEdge).PseudoAtomicStoreTo(ref _expanded)) { m_flags &= ~Flags.Expanded; // fix fix _tmp.Dispose(); return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract partial class DemandExpandEntry : Entry { public DemandExpandEntry(Type t, String name, List<BaseFeatConstraint> bfc) : base(t, name, bfc) { } Task<TfsEdge> _expand_task = null; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [DebuggerBrowsable(DebuggerBrowsableState.Never)] // side effects public override TfsEdge Expanded { get { bool _dont_care; return CheckExpand(out _dont_care); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public virtual void ReleaseExpanded() { Task<TfsEdge> tk = _expand_task; if (tk != null) { if (Interlocked.CompareExchange(ref _expand_task, null, tk) == tk) tk.Result.Dispose(); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public TfsEdge CheckExpand(out bool f_did) { f_did = false; if (_expand_task == null) { // If we're in a task already, do the job synchronously. In either case, only the race winner proceeds with the job. if (glue.Debugging.Nop.single_threaded || Task.CurrentId.HasValue) { TaskCompletionSource<TfsEdge> tcs = new TaskCompletionSource<TfsEdge>(); if (Interlocked.CompareExchange(ref _expand_task, tcs.Task, null) == null) { tcs.SetResult(_do_expand()); f_did = true; } } else { Task<TfsEdge> t = new Task<TfsEdge>(_do_expand); if (Interlocked.CompareExchange(ref _expand_task, t, null) == null) { t.Start(TaskScheduler.Default); f_did = true; } } } return _expand_task.Result; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TfsEdge _do_expand() { Tray tr = mgr.g.loadtray; Stopwatch stopw = Stopwatch.StartNew(); TfsEdge _tmp; if (!new Unification.Expander(tr).ExpandEntry(_definition, InstanceType.Expanded, out _tmp)) throw new TfsException("Error expanding entry '{0}': could not unify with its instance type(s).", this.Name); _tmp.RegisterName(Name); Interlocked.Add(ref mgr.ms_expand, (int)stopw.ElapsedMilliseconds); return _tmp; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [DebuggerDisplay("{ToString(),nq} ({t._feature_info(),nq})")] public abstract class Rule : StaticExpandEntry, ParseChart.IParseChartRule { public Rule(Type t, String name, List<BaseFeatConstraint> bfc) : base(t, name, bfc) { } public Rule(Type t, BinaryReader br, Dictionary<int, Tray> tray_map) : base(t, br, tray_map) { } TfsEdge[] daughters = null; int i_key_daughter = 0; HashSet<Rule> _key_mothers = null; bool f_span_only = false; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// locate the positions of this rule's daughters in the instance Type's expanded TFS, and cache them /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void InitializeDaughters() { daughters = Expanded.RuleDaughters.ToArray(); if (daughters.Length == 0) throw new Exception(); /// locate the daughter entry points in the expanded contents i_key_daughter = 0; Type t_key = mgr.tt_key_daughter; if (t_key.IsTop) t_key = null; /// find the first KEY daughter, i.e. the first daughter where the type at the KEY daughter path (if /// specified) matches the KEY daughter type (if specified). In the absence of such a match, the /// parser will default to active rightwards expansion starting at daughter index 0. /// As noted in a comment elsewhere, the KEY daughter index remains constant for active edges derived /// from this rule, so we don't need to redo this during parsing; instead we can just copy this value /// over. for (int i = 0; i < daughters.Length; i++) { TfsEdge rd = daughters[i]; if (i_key_daughter == 0 && t_key != null) { if (rd.Tray.KeyDaughterPath.GetType(rd.Edge.Mark) == t_key) i_key_daughter = i; } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <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) { Tray tr = this.Expanded.Tray; /// 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) { var up = new Unification.Partial(tr); TfsEdge full; if (up.UnifyAndComplete(mother.Expanded, mother.RuleDaughters[mother.KeyDaughterIndex], this.Expanded.Clone(), out full)) { _key_mothers.Add(mother); full.Dispose(); } } } public TfsEdge Contents { get { return Expanded; } } public ISysObj License { get { return this; } } public IList<TfsEdge> RuleDaughters { get { return daughters; } } public HashSet<Rule> CompatibleKeyMothers { get { return _key_mothers; } } public int KeyDaughterIndex { get { return i_key_daughter; } } IEnumerable<TfsEdge> ParseChart.IMotherDaughter.RuleDaughters { get { throw new InvalidOperationException("IList access via IGrammarRule is preferable"); } } public override bool ReleaseExpanded() { if (!base.ReleaseExpanded()) return false; daughters = null; return true; } public bool IsSpanOnly { get { return f_span_only; } set { f_span_only = value; } } public bool SpinCompare(TfsEdge other) { throw new NotImplementedException(); } public override string ToString() { return String.Format("{0}", Name); } public void Dispose() { throw new InvalidOperationException("Cannot release an object which is a permanent part of the grammar in this way."); } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public partial class GrammarRule : Rule, ParseChart.IGrammarRule { public GrammarRule(Type t, String name, List<BaseFeatConstraint> bfc) : base(t, name, bfc) { } public GrammarRule(Type t, BinaryReader br, Dictionary<int, Tray> tray_map) : base(t, br, tray_map) { } 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); Tray tr = this.Expanded.Tray; /// find the rules which are compatible with each non-KEY daughter position of this rule _non_key_daughters = new HashSet<Rule>[RuleDaughters.Count]; for (int i = 0; i < RuleDaughters.Count; i++) { if (i != KeyDaughterIndex) { _non_key_daughters[i] = new HashSet<Rule>(); TfsEdge rd = RuleDaughters[i]; foreach (Rule candidate in daughter_check) { var up = new Unification.Partial(tr); TfsEdge full; if (up.UnifyAndComplete(this.Expanded, rd, candidate.Expanded.Clone(), out full)) { _non_key_daughters[i].Add(candidate); full.Dispose(); } } } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public bool CheckDaughterCompatibility(ISysObj rule, int i_arg) { return rule is Rule && _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, Dictionary<int, Tray> tray_map) : base(t, br, tray_map) { } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <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, Dictionary<int, Tray> tray_map) : base(t, br, tray_map) { } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [DebuggerDisplay("{Name}")] public class NodeLabelTemplate : NodeLabel { String label; public TfsEdge effective; public TfsEdge effective_local; public NodeLabelTemplate(Tray tr, Type t, String name, List<BaseFeatConstraint> bfc) : base(t, name, bfc) { LoadDefinition(tr); TypeMgr tm = t.mgr; TfsEdge exp = this.Definition;// this.Expanded; ConstraintRef cr_label; if (!tr.GetEdgeAtPath(exp.Edge, tm.config.NodeLabelConfiguration.LabelPath, out cr_label)) throw new Exception(String.Format("Node label template '{0}' has no label at '{1}'", Name, tm.config.NodeLabelConfiguration.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.Pool)); effective = tr.CreateTfs(tr.CreateRecycledEdge(t_new, exp.Edge.Mark, false)); //if (! tr.GetTfsEdgeAtPath(exp.Edge, tm.config.NodeLabelConfiguration.LocalPath, out effective_local); //effective_local = default(TfsEdge); } public NodeLabelTemplate(Type t, BinaryReader br, Dictionary<int, Tray> tray_map) : base(t, br, tray_map) { } public String Label { get { return label; } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [DebuggerDisplay("{Name}")] public class NodeMetaTemplate : NodeLabel { String meta_prefix; String meta_suffix; public TfsEdge effective; public NodeMetaTemplate(Tray tr, Type t, String name, List<BaseFeatConstraint> bfc) : base(t, name, bfc) { LoadDefinition(tr); TypeMgr tm = t.mgr; TfsEdge exp = this.Definition;//.Expanded; ConstraintRef cref; if (!tr.GetEdgeAtPath(exp.Edge, tm.config.NodeLabelConfiguration.PrefixPath, out cref)) throw new Exception(String.Format("Node meta template '{0}' has no prefix at '{1}'", Name, tm.config.NodeLabelConfiguration.PrefixPath.StringJoin("."))); meta_prefix = tm.GetStringValue(cref.Constraint.FlagsId); if (!tr.GetEdgeAtPath(exp.Edge, tm.config.NodeLabelConfiguration.SuffixPath, out cref)) throw new Exception(String.Format("Node meta template '{0}' has no suffix at '{1}'", Name, tm.config.NodeLabelConfiguration.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(cp => cp.IntroducedBy != tm.tt_meta)); if (!tr.GetTfsEdgeAtPath(exp.Edge, tm.config.NodeLabelConfiguration.RecursivePath, out effective)) throw new Exception(); //effective = tr.CreateTfs(tr.CreateRecycledEdge(t_new.m_id, exp.Mark, false)); } public NodeMetaTemplate(Type t, BinaryReader br, Dictionary<int, Tray> tray_map) : base(t, br, tray_map) { } public String Prefix { get { return meta_prefix; } } public String Suffix { get { return meta_suffix; } } }; }