using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using miew.Enumerable; using miew.String; using miew.Debugging; using miew.Concurrency; namespace agree { public abstract partial class PassiveEdge : ArrayTfs, IParseObj { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if !DEBUG sealed #endif public partial class ParseTree : IDerivation, IList<IDerivation> { [DebuggerBrowsable(DebuggerBrowsableState.Never)] static readonly ParseTree[] _leaf = new ParseTree[0]; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public ParseTree(ParseControl ctrl, IParseObj po, IEnumerable<IDerivation> q) { if (po.IsRemove()) throw new Exception(); this.ctrl = ctrl; this.mother = po; this.daughters = q == null ? _leaf : q as IDerivation[] ?? q.ToArray(); #if DEBUG this.id = next_id++; #endif } [DebuggerBrowsable(DebuggerBrowsableState.Never)] ParseControl ctrl; [DebuggerBrowsable(DebuggerBrowsableState.Never)] IParseObj mother; public IParseObj Source { get { return mother; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly IDerivation[] daughters; [DebuggerBrowsable(DebuggerBrowsableState.Never)] Task<Tfs> unpack_task; Tfs _tfs; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MotherDaughterTfs Unpack() { Derived dpe = mother as Derived; Debug.Assert(dpe != null); GrammarRule r = (GrammarRule)dpe.License; int c = daughters.Length; Debug.Assert(r.RuleDaughters.Length == c); if (c > 1 && ctrl.TryEnterMultithread()) { for (int i = 0; i < c; i++) if (daughters[i] is ParseTree) ((ParseTree)daughters[i]).UnpackTask(); ctrl.LeaveMultithread(); } MotherDaughterTfs mdtfs; if (c > 1)// && ctrl.parser_config.f_variadic_unpack) { var rgd = new Tfs[c]; for (int i = 0; i < c; i++) if ((rgd[i] = daughters[i].UnpackedTfs) == null) return null; mdtfs = ctrl.UnifySections(r.RuleTfs, 0, rgd, true, false, ref ctrl.stats.Parsing.Unpacking.Unification); if (mdtfs == null) return null; } else { mdtfs = r.RuleTfs; for (int i = 0; i < c; i++) { Tfs candidate = daughters[i].UnpackedTfs; if (candidate == null) return null; mdtfs = ctrl.UnifySection(mdtfs.RuleDaughters[i], candidate, i == c - 1, false, ref ctrl.stats.Parsing.Unpacking.Unification); if (mdtfs == null) return null; } } /// done if the mother wasn't tagged as Completed Completed cp = mother as Completed; if (cp == null) return mdtfs; #if CHECK_ALL_SS foreach (StartSymbol ss in ctrl.g.StartSymbols) if (ctrl.UnifyCheck((ss.Expanded, mdtfs)) return mdtfs; #else /// only need to validate against start symbols that the mother unified with. bool[] rgss_map = cp.MatchedStartSymbolsMap; for (int i = 0; i < rgss_map.Length; i++) if (rgss_map[i]) if (ctrl.UnifyCheck(ctrl.g.StartSymbols[i].Expanded, mdtfs)) return mdtfs; #endif /// didn't match any of the eligible start symbols return null; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// the pervasive 'avoiding double work' task pattern: having captured the necessary work /// for the as-yet unstarted task in the above closure, now only start it if we are the /// thread that wins a race to publish the Task (closure). Otherwise, our version is /// discarded and we'll return the (result of) the victor's task. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Task<Tfs> UnpackTask() { if (unpack_task == null) { Task<Tfs> _tmp = new Task<Tfs>(Unpack); if (Interlocked.CompareExchange(ref unpack_task, _tmp, null) == null) _tmp.Start(); } return unpack_task; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [DebuggerBrowsable(DebuggerBrowsableState.Never)] public Tfs UnpackedTfs { get { if (_tfs == null) { if (ctrl.TryEnterMultithread()) { _tfs = (unpack_task ?? UnpackTask()).Result; ctrl.LeaveMultithread(); } else _tfs = Unpack(); } return _tfs; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Turns out it's not so trivial to get a reliable hash that is fixed for a given subtree, but maintains /// positional distinctness of sub-derivations when nested recursively in any/all arbitrary future /// (unforeseen) contexts. The solution here is progressively change the rotation of the daughter /// hashes (i.e. by argument position) while stamping the hash of the mother rule ('z') into a fixed /// position (relative to the daughter) every time. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [DebuggerBrowsable(DebuggerBrowsableState.Never)] ulong _dh; [DebuggerBrowsable(DebuggerBrowsableState.Never)] public ulong DerivationHash { get { if (_dh == 0) { ulong z, ul = z = (ulong)mother.License.Name.GetHashCode() << 16; for (int i = 0; i < daughters.Length; i++) { int rot = i + 23; ul = (ul << rot) | (ul >> (64 - rot)); ul += daughters[i].DerivationHash ^ z; } _dh = ul; } return _dh; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public String TreeDisplay() { Debug.Assert(daughters.Length > 0); int id = 0; var uptfs = UnpackedTfs == null ? "**NULL**" : UnpackedTfs.id.ToString("X"); String s = String.Format("{0} {{{1}}} {{{2}}}{3} {4} {{{5}}}",// {6:X}", mother.TokenSpan, id.ToString("X"), mother.Tfs.id.ToString("X"), mother.Tfs.IsRestricted ? " R" : "", mother.Tfs.Type.Name, uptfs /*, DerivationHash*/) + Environment.NewLine; foreach (var pt in daughters) s += pt.TreeDisplay().Indent(4) + Environment.NewLine; return s; } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public IEnumerable<IDerivation> Descendants { get { ParseTree dpe; foreach (IDerivation ipce in this) { yield return ipce; if ((dpe = ipce as ParseTree) != null) foreach (IDerivation ipce_d in dpe.Descendants) yield return ipce_d; } } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public IEnumerable<IDerivation> DescendantsAndSelf { get { yield return this; foreach (IDerivation ipce in Descendants) yield return ipce; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public IDerivation this[int index] { get { if (index >= daughters.Length) throw new ArgumentException(); return daughters[index]; } set { throw new InvalidOperationException(); } } public int IndexOf(IDerivation item) { return Array.IndexOf<IDerivation>(daughters, item); } public bool Contains(IDerivation item) { return Array.IndexOf<IDerivation>(daughters, item) != -1; } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public int Count { get { return daughters.Length; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsReadOnly { get { return true; } } public void CopyTo(IDerivation[] array, int arrayIndex) { foreach (var idrv in daughters) array[arrayIndex++] = idrv; } public void Insert(int index, IDerivation item) { throw new InvalidOperationException(); } public void RemoveAt(int index) { throw new InvalidOperationException(); } public bool Remove(IDerivation item) { throw new InvalidOperationException(); } public void Add(IDerivation item) { throw new InvalidOperationException(); } public void Clear() { throw new InvalidOperationException(); } public IEnumerator<IDerivation> GetEnumerator() { return daughters.AsEnumerable<IDerivation>().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return daughters.GetEnumerator(); } }; }; }