Ejemplo n.º 1
0
 /// <summary>
 /// Folds a character terminal node.
 /// </summary>
 /// <param name="characterTerminal"></param>
 /// <param name="argument">The argument to be passed to the visitor method.</param>
 /// <returns>
 /// <list type="number">
 /// <item>The original node if it's to be kept</item>
 /// <item>A different node to replace the original node with</item>
 /// <item>Null if the node is to be removed</item>
 /// </list>
 /// </returns>
 protected override GrammarNode <Char>?VisitCharacterTerminal(CharacterTerminal characterTerminal, TArgument argument) => characterTerminal;
Ejemplo n.º 2
0
            /// <inheritdoc />
            protected override GrammarNode <Char>?VisitAlternation(Alternation <Char> alternation, OptimizeArgs argument)
            {
                var nodes = alternation.GrammarNodes.Select(node => this.Visit(node, argument))
                            .Where(node => node is not null)
                            .ToList();

                var matchedCharTerminals     = new HashSet <Char>();
                var matchedStringTerminals   = new HashSet <String>();
                var matchedCharRanges        = new HashSet <Range <Char> >();
                var matchedUnicodeCategories = new HashSet <UnicodeCategory>();
                var matchedNodes             = new HashSet <GrammarNode <Char> >(GrammarTreeStructuralComparer.Instance);

                for (var nodeIdx = 0; nodeIdx < nodes.Count; nodeIdx++)
                {
loopStart:
                    GrammarNode <Char> currentNode = nodes[nodeIdx] !;

                    if (matchedNodes.Contains(currentNode))
                    {
                        nodes.RemoveAt(nodeIdx);
                        goto loopStart;
                    }

                    switch (currentNode.Kind)
                    {
                    case GrammarNodeKind.CharacterStringTerminal:
                    {
                        var strTerminal = (StringTerminal)currentNode;
                        if (matchedStringTerminals.Contains(strTerminal.Value))
                        {
                            nodes.RemoveAt(nodeIdx);
                            goto loopStart;
                        }
                        matchedStringTerminals.Add(strTerminal.Value);
                        break;
                    }

                    case GrammarNodeKind.CharacterTerminal:
                    {
                        var ch = ((CharacterTerminal)currentNode).Value;
                        if (isCharMatched(ch))
                        {
                            nodes.RemoveAt(nodeIdx);
                            goto loopStart;
                        }
                        matchedCharTerminals.Add(ch);
                        break;
                    }

                    case GrammarNodeKind.CharacterRange:
                    {
                        var characterRange = (CharacterRange)currentNode;
                        var newStart       = characterRange.Range.Start;
                        while (isCharMatched(newStart) &&
                               newStart <= characterRange.Range.End)
                        {
                            newStart++;
                        }

                        var newEnd = characterRange.Range.End;
                        while (isCharMatched(newEnd) &&
                               newEnd >= newStart)
                        {
                            newEnd--;
                        }

                        // The new start will be greater than the new end if all characters in the
                        // range are already being matched.
                        if (newStart > newEnd)
                        {
                            nodes.RemoveAt(nodeIdx);
                            goto loopStart;
                        }
                        else if (newStart == newEnd)
                        {
                            nodes[nodeIdx] = new CharacterTerminal(newStart);
                            goto loopStart;
                        }
                        else if (characterRange.Range.Start != newStart || characterRange.Range.End != newEnd)
                        {
                            nodes[nodeIdx]         =
                                currentNode        =
                                    characterRange = new CharacterRange(newStart, newEnd);
                        }
                        break;
                    }
                    }

                    matchedNodes.Add(currentNode);
                }

                if (nodes.Count == 0)
                {
                    return(null);
                }
                else if (nodes.Count == 1)
                {
                    return(nodes[0]);
                }
                else if (nodes.SequenceEqual(alternation.GrammarNodes))
                {
                    return(alternation);
                }
                else
                {
                    return(new Alternation <Char>(nodes !));
                }

                Boolean isCharMatched(Char ch) =>
                matchedCharTerminals !.Contains(ch) ||
                matchedCharRanges !.Any(range => CharUtils.IsInRange(range.Start, ch, range.End)) ||
                matchedUnicodeCategories !.Contains(Char.GetUnicodeCategory(ch));
            }
Ejemplo n.º 3
0
 protected override String?VisitCharacterTerminal(CharacterTerminal characterTerminal, Unit argument) =>
 Char.ToString(characterTerminal.Value);
Ejemplo n.º 4
0
 /// <summary>
 /// Visits a character terminal.
 /// </summary>
 /// <param name="characterTerminal"></param>
 /// <param name="argument">The argument data passed by the caller.</param>
 /// <returns>The result of visiting this node.</returns>
 protected abstract TReturn VisitCharacterTerminal(CharacterTerminal characterTerminal, TArgument argument);