using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using miew.Debugging; using miew.Enumerable; using miew.Tokenization; using miew.String; using miew.String.Builder; using miew.Concurrency; namespace agree { public abstract partial class PassiveEdge : ArrayTfs, IParseObj { #if DEBUG public partial class Derived : PassiveEdge { public void DumpDerivations(TextWriter tw = null) { tw = tw ?? Console.Out; System.Text.StringBuilder sb = null; if (_packed_edges == null) return; sb = new System.Text.StringBuilder(); sb.AppendFormatLine("================== {0} ================", this.ToString()); sb.AppendFormatLine("daughters:"); IDerivation[][] rgrg = new IDerivation[rgo.Count][]; for (int j = 0; j < rgo.Count; j++) { rgrg[j] = rgo[j].Derivations.ToArray(); sb.AppendFormatLine(" #{0} derivations: {1}", j, rgrg[j].Length); for (int k = 0; k < rgrg[j].Length; k++) { sb.AppendFormatLine(" {0}", rgrg[j][k].ToString()); } } sb.AppendLine(); sb.AppendFormatLine("packed: {0} edges", _packed_edges.Count); int i = 0; foreach (Derived dpe in _packed_edges) { sb.AppendFormatLine(" packed edge #{0} {1} derivations: {2}", i++, dpe.ToString(), dpe.Derivations.Count); foreach (IDerivation dv in dpe.Derivations) { sb.AppendFormatLine(" === dv #{0} {1} ===", i++, dv.Source.ToString()); //sb.AppendFormatLine("{0}", dv.TreeDisplay().ToString()); if (dv is ParseTree) sb.AppendLine(((ParseTree)dv).Select(d => d.ToString()).StringJoin(Environment.NewLine).Indent(8)); else sb.AppendLine(" " + ((LexicalAnalysis.AnalysisStack)dv).ToString()); sb.AppendLine(); //sb.AppendFormatLine(" {0}", dpe.rgo[j].ToString()); //for (int j = 0; j < rgo.Count; j++) //{ // sb.AppendFormatLine(" {0}", dpe.rgo[j].ToString()); //} } } sb.AppendLine(); sb.AppendFormatLine("cross-product: {0}", _parse_trees.Length); i = 0; foreach (var dv in _parse_trees) { sb.AppendFormatLine(" === dv #{0} {1} ===", i++, dv.Source.ToString()); //sb.AppendFormatLine("{0}", dv.TreeDisplay().ToString()); if (dv is ParseTree) sb.AppendLine(((ParseTree)dv).Select(d => d.ToString()).StringJoin(Environment.NewLine).Indent(8)); else sb.AppendLine(" " + ((LexicalAnalysis.AnalysisStack)dv).ToString()); sb.AppendLine(); } sb.AppendLine(); tw.WriteLine(sb.ToString()); } }; [DebuggerDisplay("{ToString(),nq}")] public partial class ParseTree : IDerivation, IList<IDerivation> { static int next_id = 0; [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly int id; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public ParseTree[] _TREE { get { ParseTree[] rg = new ParseTree[daughters.Length]; for (int i = 0; i < daughters.Length; i++) rg[i] = daughters[i] as ParseTree ?? new LexEntryPlaceholder(ctrl, (LexicalAnalysis.AnalysisStack)daughters[i]); return rg; } } [DebuggerDisplay("{ToString(),nq}")] public class LexEntryPlaceholder : ParseTree { LexicalAnalysis.AnalysisStack stk; public LexEntryPlaceholder(ParseControl ctrl, LexicalAnalysis.AnalysisStack stk) : base(ctrl, stk, null) { this.stk = stk; } public override string ToString() { return stk.ToString(); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override string ToString() { int p = 0; String pp = ""; if (mother is PassiveEdge) { PassiveEdge pt = (PassiveEdge)mother; if (pt._packed_edges != null) { p = pt._packed_edges.Count; pp = " [" + pt._packed_edges.Select(po => String.Format("#{0:X}", po.Tfs.id)).StringJoin(", ") + "]"; } } String md = ""; if (mother is Derived) { Derived dpe = (Derived)mother; md = dpe.ChartDaughters.Select(po => String.Format("#{0:X}", po.Tfs.id)).StringJoin(", "); } return String.Format("{0:X} #{1:X} [{2}] peers: {3}{4} dtrs: {5} [{6}]", GetHashCode() & 0xFFFF, mother.Tfs.id, md, p, pp, daughters.Length, daughters.Select(d => String.Format("{0:X}", d.GetHashCode() & 0xFFFF)).StringJoin(", ")); } }; #endif }; abstract public unsafe partial class ChartBase : ISysObj, IEnumerable<IParseObj> { #if DEBUG public void CheckDuplicateDerivations() { ConcurrentHashSet<ulong> d_hashes = new ConcurrentHashSet<ulong>(); int c_derivations = 0; foreach (var drv in ((ParseChart)this).AllDerivations) { d_hashes.Add(drv.DerivationHash); c_derivations++; } if (c_derivations != d_hashes.Count) { //throw new Exception(String.Format("{0} duplicate derivations", c_derivations - d_hashes.Count)); var grps = ((ParseChart)this).AllDerivations.GroupBy(drv => drv.DerivationHash).Where(grp => grp.Count() > 1); Console.WriteLine(String.Format("{0} duplicate derivations in {1} groups", c_derivations - d_hashes.Count, grps.Count())); List<String> l0 = new List<String>(), l1 = new List<String>(); foreach (var grp in grps) { l0.Add(grp.ElementAt(0).TreeDisplay()); l1.Add(grp.ElementAt(1).TreeDisplay()); System.IO.File.WriteAllLines(String.Format("000.tfs-dump"), l0); System.IO.File.WriteAllLines(String.Format("001.tfs-dump"), l1); Console.WriteLine("========================="); foreach (var drv in grp) { Console.WriteLine("{0}", drv.TreeDisplay()); Console.WriteLine(); } } } //if (rgdrv != null) //{ // if (rgdrv.Count != hsdrv.Count) // report.AppendLine(String.Format("derivations: {0} --- distinct: {1} (extra {2})", rgdrv.Count, hsdrv.Count, rgdrv.Count - hsdrv.Count)); //} } public IEnumerable<PassiveEdge.Derived> AllDerivedEdges() { var e = new ChartCell._enum_all_edges(this); while (e.MoveNext()) { PassiveEdge.Derived dpe = e.Current as PassiveEdge.Derived; if (dpe != null) yield return dpe; } } internal IEnumerable<PassiveEdge.Derived> OrphanEdges() { var ade = AllDerivedEdges(); return ade.Except(ade.SelectMany(dce => dce.ChartDaughters.OfType<PassiveEdge.Derived>())); } public IEnumerable<PassiveEdge.Derived> DerivationTopEdges() { return OrphanEdges().OfType<PassiveEdge.Derived>(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// DEBUG CODE FOLLOWS /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void ChartEdgeReport(IParseObj ce) { String span_color = ce.TokenSpan == EntireSpan ? "$yellow" : "$darkyellow"; String sis = SequenceControl.ToString(ce); PassiveEdge.Derived dce = ce as PassiveEdge.Derived; TextWriter debug_output = dce.ctrl.config.system.tw_debug; if (dce == null) { debug_output.WriteLineColor("$darkcyan {0,-18} $green E{2,-4} " + span_color + " {3,-7} $green {4}", ce.GetType().Name, null, sis, ce.TokenSpan, ce.Tfs); } else { String fedge = dce.Tfs.ToString(); String medge = fedge.Replace("@", "$green @").Replace("…", "…$darkgreen "); debug_output.WriteLineColor(new String(' ', 25) + span_color + " {0,-7} $darkgreen {1}$ added by $darkgreen {2}$ is now $darkcyan {3}$ $green E{4,-4}", dce.TokenSpan, medge.PadRight(35 + (medge.Length - fedge.Length)), dce.ChartDaughters.Select(de => String.Format("{0}", de.ToString())).StringJoin("$ + $darkgreen ").PadLeft(9 + (dce.ChartDaughters.Count() - 1) * 12), dce.GetType().Name, sis); } } public void DumpChart(String html_out_file) { var derivations = DerivationTopEdges() .Select((de, ix) => new { top = de, ix, de.DescendantsAndSelf }); var edge_lookup = derivations .SelectMany(dv => dv.DescendantsAndSelf.Select(e => new { top = dv, dv.ix, e })) .ToLookup(de => de.e, de => new { de.ix, de.top }); StringBuilder sb1 = new StringBuilder(); foreach (var derivation in derivations) { sb1.AppendFormat(@" .dv{0} {{ }}", derivation.ix); } StringBuilder sb = new StringBuilder(); sb.AppendFormat(@" <html> <head> <style> body {{ font-family:Arial; }} span {{ cursor: pointer; }} .fill {{ background-color:#f0f0f0; }} table tr td {{ vertical-align:top; font-size:smaller; }} {0} </style> </head> <body> ", sb1.ToString()); int c = ColumnCount; double grid_cells_x = 120;// Enumerable.Range(1, c - 1).LeastCommonMultiple(); sb.Append("<table border=1><tr>"); int cx_total = 0; for (int j = 0; j < c; j++) { int cx = (int)Math.Round(grid_cells_x * (j + 1) / c) - cx_total; cx_total += cx; sb.AppendFormat("<th colspan={0}>{1}</th>\r\n", cx, j); } sb.Append("</tr>\r\n\r\n"); var dict = this._GroupBy(e => e.TokenSpan.Length) .ToDictionary(g => g.Key, g => g.ToLookup(e => e.TokenSpan.StartIndex)); for (int span = c; span > 0; span--) { sb.Append("<tr>\r\n"); ILookup<int, IParseObj> length_starts_map; if (dict.TryGetValue(span, out length_starts_map)) { cx_total = 0; int items = c - span + 1; for (int k = 0; k < items; k++) { int cx = (int)Math.Round(grid_cells_x * (k + 1) / items) - cx_total; cx_total += cx; IEnumerable<IParseObj> edges = length_starts_map[k]; String s_cont; if (edges != null && edges.Any()) { StringBuilder content = new StringBuilder(); foreach (IParseObj pe in edges) { String kk = edge_lookup[pe].Select(a => String.Format("dv{0}", a.ix)).StringJoin(" "); String b = pe is PassiveEdge.Completed ? "style='font-weight:bold;' " : String.Empty; content.AppendFormat("\t<span {0}class='{1}'>{2}</span><br />\r\n", b, kk, pe.ToString().Replace("-", "‑")); } s_cont = content.ToString(); } else s_cont = " "; sb.AppendFormat("\t<td colspan='{0}'>\r\n{1}</td>\r\n", cx, s_cont); } } sb.Append("</tr>\r\n"); } sb.AppendFormat("</table>"); sb.Append(@" <script type='text/javascript'> function getCSSRule(ruleName) { ruleName = ruleName.toLowerCase(); if (document.styleSheets) { for (var i = 0; i < document.styleSheets.length; i++) { var styleSheet = document.styleSheets[i]; var ii = 0; var cssRule = null; do { if (styleSheet.cssRules) { cssRule = styleSheet.cssRules[ii]; } else { cssRule = styleSheet.rules[ii]; } if (cssRule) { if (cssRule.selectorText.toLowerCase() == ruleName) { return cssRule; } } ii++; } while (cssRule) } } return null; } function ms_in(e) { var x = e.className.split(' '); for (var z = 0; z < x.length; z++) { var r = getCSSRule('.' + x[z]); if (r != null) r.style.color = 'red'; } } function ms_out(e) { var x = e.className.split(' '); for (var z = 0; z < x.length; z++) { var r = getCSSRule('.' + x[z]); if (r != null) r.style.color = 'black'; } } var obj = document.getElementsByTagName('span'), o, i = 0; while (o = obj[i++]) { o.onmouseover = function() { ms_in(this); }; o.onmouseout = function() { ms_out(this); }; } </script> "); sb.AppendFormat("</body></html>"); File.WriteAllText(html_out_file, sb.ToString()); } #else public void ChartEdgeReport(IParseObj ce) { } public void DumpChart(String html_out_file) { } #endif }; }