using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using glue.Collections.XSpinLock; using glue.Debugging; using glue.Extensions.Enumerable; using glue.Tokenization; namespace agree.Parse { abstract public partial class ChartBase : ISysObj { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public interface ISelf : IDisposable { TfsEdge Contents { get; } bool SpinCompare(TfsEdge other); }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// for (e.g.) TfsEdge -- doesn't know it's license /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public interface IMotherDaughter : ISelf { IEnumerable<TfsEdge> RuleDaughters { get; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public interface ILicense : ISelf { ISysObj License { get; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public interface IParseChartRule : IMotherDaughter, ILicense { new IList<TfsEdge> RuleDaughters { get; } int KeyDaughterIndex { get; } bool IsSpanOnly { get; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public interface IGrammarRule : IParseChartRule { bool CheckDaughterCompatibility(ISysObj daughter, int i_arg); }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public interface IParseChartEdge : ILicense, IAtomicallySequenceable { Span ChartSpan { get; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public interface IParseChartToken : IParseChartEdge { String Text { get; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// DEBUG CODE FOLLOWS /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void ChartEdgeReport(IParseChartEdge ce) { if (debug_output != null) { String span_color = ce.ChartSpan == EntireSpan ? "$yellow" : "$darkyellow"; String sis = ce.SequenceId == ast.InertValue ? "--" : ce.SequenceId.ToString(); DerivedPassiveEdge dce = ce as DerivedPassiveEdge; 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.ChartSpan, ce.Contents); } else { String fedge = dce.Contents.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.ChartSpan, medge.PadRight(35 + (medge.Length - fedge.Length)), dce.Daughters.Select(de => String.Format("{0}", de.ToString())).StringJoin("$ + $darkgreen ").PadLeft(9 + (dce.Daughters.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.AllEdges() ._GroupBy(e => e.ChartSpan.Length) .ToDictionary(g => g.Key, g => g.ToLookup(e => e.ChartSpan.StartIndex)); for (int span = c; span > 0; span--) { sb.Append("<tr>\r\n"); ILookup<int, IParseChartEdge> 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<IParseChartEdge> edges = length_starts_map[k]; String s_cont; if (edges != null && edges.Any()) { StringBuilder contents = new StringBuilder(); foreach (IParseChartEdge pe in edges) { String kk = edge_lookup[pe].Select(a => String.Format("dv{0}", a.ix)).StringJoin(" "); String b = pe is CompletedParse ? "style='font-weight:bold;' " : String.Empty; contents.AppendFormat("\t<span {0}class='{1}'>{2}</span><br />\r\n", b, kk, pe.ToString().Replace("-", "‑")); } s_cont = contents.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()); } public TextWriter debug_output = null; public void SetDebugOutput(TextWriter tw) { debug_output = tw; } }; }