Exemple #1
0
 public override string ToString() =>
 PrevCharKind == 0 ? Node.ToString() :
 $"({CharKind.DescribePrev(PrevCharKind)},{Node})";
        public override void SaveDGML(TextWriter writer, int maxLabelLength)
        {
            lock (this)
            {
                if (maxLabelLength < 0)
                {
                    maxLabelLength = int.MaxValue;
                }

                Dictionary <(int Source, int Target), (TSet Rule, List <int> NfaTargets)> transitions = GatherTransitions(this);

                writer.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
                writer.WriteLine("<DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\" ZoomLevel=\"1.5\" GraphDirection=\"TopToBottom\" >");
                writer.WriteLine("    <Nodes>");
                writer.WriteLine("        <Node Id=\"dfa\" Label=\" \" Group=\"Collapsed\" Category=\"DFA\" DFAInfo=\"{0}\" />", FormatInfo(this, transitions.Count));
                writer.WriteLine("        <Node Id=\"dfainfo\" Category=\"DFAInfo\" Label=\"{0}\"/>", FormatInfo(this, transitions.Count));
                foreach (MatchingState <TSet> state in _stateCache.Values)
                {
                    string info         = CharKind.DescribePrev(state.PrevCharKind);
                    string deriv        = WebUtility.HtmlEncode(state.Node.ToString());
                    string nodeDgmlView = $"{(info == string.Empty ? info : $"Previous: {info}&#13;")}{(deriv == string.Empty ? "()" : deriv)}";

                    writer.WriteLine("        <Node Id=\"{0}\" Label=\"{0}\" Category=\"State\" Group=\"Collapsed\" StateInfo=\"{1}\">", state.Id, nodeDgmlView);
                    if (_stateFlagsArray[state.Id].IsInitial())
                    {
                        writer.WriteLine("            <Category Ref=\"InitialState\" />");
                    }
                    if (state.Node.CanBeNullable)
                    {
                        writer.WriteLine("            <Category Ref=\"FinalState\" />");
                    }
                    writer.WriteLine("        </Node>");
                    writer.WriteLine("        <Node Id=\"{0}info\" Label=\"{1}\" Category=\"StateInfo\"/>", state.Id, nodeDgmlView);
                }
                writer.WriteLine("    </Nodes>");
                writer.WriteLine("    <Links>");
                foreach (MatchingState <TSet> initialState in GetInitialStates(this))
                {
                    writer.WriteLine("        <Link Source=\"dfa\" Target=\"{0}\" Label=\"\" Category=\"StartTransition\" />", initialState.Id);
                }
                writer.WriteLine("        <Link Source=\"dfa\" Target=\"dfainfo\" Label=\"\" Category=\"Contains\" />");

                foreach (KeyValuePair <(int Source, int Target), (TSet Rule, List <int> NfaTargets)> transition in transitions)
                {
                    string label = DescribeLabel(transition.Value.Rule, _builder);
                    string info  = "";
                    if (label.Length > maxLabelLength)
                    {
                        info  = $"FullLabel = \"{label}\" ";
                        label = string.Concat(label.AsSpan(0, maxLabelLength), "..");
                    }

                    writer.WriteLine($"        <Link Source=\"{transition.Key.Source}\" Target=\"{transition.Key.Target}\" Label=\"{label}\" Category=\"NonEpsilonTransition\" {info}/>");
                    // Render NFA transitions as labelless "epsilon" transitions (i.e. ones that don't consume a character)
                    // from the target of the DFA transition.
                    foreach (int nfaTarget in transition.Value.NfaTargets)
                    {
                        writer.WriteLine($"        <Link Source=\"{transition.Key.Target}\" Target=\"{nfaTarget}\" Category=\"EpsilonTransition\"/>");
                    }
                }

                foreach (MatchingState <TSet> state in _stateCache.Values)
                {
                    writer.WriteLine("        <Link Source=\"{0}\" Target=\"{0}info\" Category=\"Contains\" />", state.Id);
                }

                writer.WriteLine("    </Links>");
                writer.WriteLine("    <Categories>");
                writer.WriteLine("        <Category Id=\"DFA\" Label=\"DFA\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"EpsilonTransition\" Label=\"Epsilon transition\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"StartTransition\" Label=\"Initial transition\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"FinalLabel\" Label=\"Final transition\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"FinalState\" Label=\"Final\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"SinkState\" Label=\"Sink state\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"EpsilonState\" Label=\"Epsilon state\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"InitialState\" Label=\"Initial\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"NonEpsilonTransition\" Label=\"Nonepsilon transition\" IsTag=\"True\" />");
                writer.WriteLine("        <Category Id=\"State\" Label=\"State\" IsTag=\"True\" />");
                writer.WriteLine("    </Categories>");
                writer.WriteLine("    <Styles>");
                writer.WriteLine("        <Style TargetType=\"Node\" GroupLabel=\"InitialState\" ValueLabel=\"True\">");
                writer.WriteLine("            <Condition Expression=\"HasCategory('InitialState')\" />");
                writer.WriteLine("            <Setter Property=\"Background\" Value=\"lightblue\" />");
                writer.WriteLine("            <Setter Property=\"MinWidth\" Value=\"0\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Node\" GroupLabel=\"FinalState\" ValueLabel=\"True\">");
                writer.WriteLine("            <Condition Expression=\"HasCategory('FinalState')\" />");
                writer.WriteLine("            <Setter Property=\"Background\" Value=\"lightgreen\" />");
                writer.WriteLine("            <Setter Property=\"StrokeThickness\" Value=\"4\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Node\" GroupLabel=\"State\" ValueLabel=\"True\">");
                writer.WriteLine("            <Condition Expression=\"HasCategory('State')\" />");
                writer.WriteLine("            <Setter Property=\"Stroke\" Value=\"black\" />");
                writer.WriteLine("            <Setter Property=\"Background\" Value=\"white\" />");
                writer.WriteLine("            <Setter Property=\"MinWidth\" Value=\"0\" />");
                writer.WriteLine("            <Setter Property=\"FontSize\" Value=\"12\" />");
                writer.WriteLine("            <Setter Property=\"FontFamily\" Value=\"Arial\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Link\" GroupLabel=\"NonEpsilonTransition\" ValueLabel=\"True\">");
                writer.WriteLine("            <Condition Expression=\"HasCategory('NonEpsilonTransition')\" />");
                writer.WriteLine("            <Setter Property=\"FontSize\" Value=\"18\" />");
                writer.WriteLine("            <Setter Property=\"FontFamily\" Value=\"Arial\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Link\" GroupLabel=\"StartTransition\" ValueLabel=\"True\">");
                writer.WriteLine("            <Condition Expression=\"HasCategory('StartTransition')\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Link\" GroupLabel=\"EpsilonTransition\" ValueLabel=\"True\">");
                writer.WriteLine("            <Condition Expression=\"HasCategory('EpsilonTransition')\" />");
                writer.WriteLine("            <Setter Property=\"StrokeDashArray\" Value=\"8 8\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Link\" GroupLabel=\"FinalLabel\" ValueLabel=\"False\">");
                writer.WriteLine("            <Condition Expression=\"HasCategory('FinalLabel')\" />");
                writer.WriteLine("            <Setter Property=\"StrokeDashArray\" Value=\"8 8\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Node\" GroupLabel=\"StateInfo\" ValueLabel=\"True\">");
                writer.WriteLine("            <Setter Property=\"Stroke\" Value=\"white\" />");
                writer.WriteLine("            <Setter Property=\"FontSize\" Value=\"18\" />");
                writer.WriteLine("            <Setter Property=\"FontFamily\" Value=\"Arial\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("        <Style TargetType=\"Node\" GroupLabel=\"DFAInfo\" ValueLabel=\"True\">");
                writer.WriteLine("            <Setter Property=\"Stroke\" Value=\"white\" />");
                writer.WriteLine("            <Setter Property=\"FontSize\" Value=\"18\" />");
                writer.WriteLine("            <Setter Property=\"FontFamily\" Value=\"Arial\" />");
                writer.WriteLine("        </Style>");
                writer.WriteLine("    </Styles>");
                writer.WriteLine("</DirectedGraph>");
            }