parent\src\System\Text\RegularExpressions\RegexFindOptimizations.cs (5)
18public static RegexFindOptimizations Create(RegexNode root, RegexOptions options)
24RegexPrefixAnalyzer.FindLeadingPositiveLookahead(root) is RegexNode positiveLookahead)
46private unsafe RegexFindOptimizations(RegexNode root, RegexOptions options, bool isLeadingPartial)
202(RegexNode LoopNode, (char Char, string? String, StringComparison StringComparison, char[]? Chars) Literal)? literalAfterLoop = RegexPrefixAnalyzer.FindLiteralFollowingLeadingLoop(root);
336public (RegexNode LoopNode, (char Char, string? String, StringComparison StringComparison, char[]? Chars) Literal)? LiteralAfterLoop { get; }
parent\src\System\Text\RegularExpressions\RegexNode.cs (143)
49public RegexNode? Parent;
87public RegexNode CloneCharLoopWithOneLessIteration()
94RegexNode newNode = IsSetFamily ?
110public static RegexNode CreateOneWithCaseConversion(char ch, RegexOptions options, CultureInfo? culture, ref RegexCaseBehavior caseBehavior)
135public RegexNode ReverseConcatenationIfRightToLeft()
141((List<RegexNode>)Children!).Reverse();
207RegexNode loopAsChild = new(RegexNodeKind.Loop, Options, M, N);
369internal RegexNode FinalOptimize()
371RegexNode rootNode = this;
423RegexNode node = rootNode.Child(0); // skip implicit root capture node
480RegexNode child = Child(i);
483RegexNode reduced = child.Reduce();
509RegexNode node = this;
544RegexNode existingChild = node.Child(node.ChildCount() - 1);
548var atomic = new RegexNode(RegexNodeKind.Atomic, existingChild.Options);
621internal RegexNode Reduce()
657private RegexNode ReplaceNodeIfUnnecessary()
674private RegexNode ReduceGroup()
678RegexNode u = this;
695private RegexNode ReduceAtomic()
707RegexNode atomic = this;
708RegexNode child = Child(0);
753List<RegexNode>? branches = child.Children as List<RegexNode>;
794RegexNode startNode = branches[start];
830RegexNode nextChild = branches[next];
879private RegexNode ReduceLoops()
883RegexNode u = this;
891RegexNode child = u.Child(0);
959RegexNode child = u.Child(0);
1010private RegexNode ReduceSet()
1071private RegexNode ReduceAlternation()
1085RegexNode node = ReplaceNodeIfUnnecessary();
1130RegexNode at;
1131RegexNode prev;
1133List<RegexNode> children = (List<RegexNode>)Children!;
1145if (at.Children is List<RegexNode> atChildren)
1155RegexNode atChild = (RegexNode)at.Children!;
1239static RegexNode ExtractCommonPrefixNode(RegexNode alternation)
1242Debug.Assert(alternation.Children is List<RegexNode> { Count: >= 2 });
1243var children = (List<RegexNode>)alternation.Children;
1259RegexNode startingNode = children[startingIndex];
1260RegexNode required = startingNode.Kind == RegexNodeKind.Concatenate ? startingNode.Child(0) : startingNode;
1280RegexNode endingNode = children[endingIndex];
1281RegexNode other = endingNode.Kind == RegexNodeKind.Concatenate ? endingNode.Child(0) : endingNode;
1300var newAlternate = new RegexNode(RegexNodeKind.Alternate, alternation.Options);
1305((List<RegexNode>)children[i].Children!).RemoveAt(0);
1316if (alternation.Parent is RegexNode { Kind: RegexNodeKind.Atomic })
1318var atomic = new RegexNode(RegexNodeKind.Atomic, alternation.Options);
1325var newConcat = new RegexNode(RegexNodeKind.Concatenate, alternation.Options);
1339static RegexNode RemoveRedundantEmptiesAndNothings(RegexNode node)
1343var children = (List<RegexNode>)node.Children!;
1349RegexNode child = children[i];
1382static RegexNode ExtractCommonPrefixText(RegexNode alternation)
1385Debug.Assert(alternation.Children is List<RegexNode> { Count: >= 2 });
1386var children = (List<RegexNode>)alternation.Children;
1405RegexNode? startingNode = children[startingIndex].FindBranchOneOrMultiStart();
1478var prefix = startingSpan.Length == 1 ?
1481var newAlternate = new RegexNode(RegexNodeKind.Alternate, startingNodeOptions);
1484RegexNode branch = children[i];
1491static void ProcessOneOrMulti(RegexNode node, ReadOnlySpan<char> startingSpan)
1523if (alternation.Parent is RegexNode parent && parent.Kind == RegexNodeKind.Atomic)
1525var atomic = new RegexNode(RegexNodeKind.Atomic, startingNodeOptions);
1530var newConcat = new RegexNode(RegexNodeKind.Concatenate, startingNodeOptions);
1548public RegexNode? FindBranchOneOrMultiStart()
1550RegexNode branch = Kind == RegexNodeKind.Concatenate ? Child(0) : this;
1587if (Child(i).FindStartingLiteralNode(allowZeroWidth: false) is not RegexNode startingLiteralNode ||
1633public RegexNode? FindStartingLiteralNode(bool allowZeroWidth = true)
1635RegexNode? node = this;
1673if (FindStartingLiteralNode() is RegexNode node)
1740private RegexNode ReduceConcatenation()
1757RegexNode child = Child(i);
1785Debug.Assert(Children is List<RegexNode>);
1791List<RegexNode> children = (List<RegexNode>)Children!;
1794RegexNode at = children[i];
1804if (at.Children is List<RegexNode> atChildren)
1814RegexNode atChild = (RegexNode)at.Children!;
1832RegexNode prev = children[--j];
1868Debug.Assert(Children is List<RegexNode>);
1870var children = (List<RegexNode>)Children!;
1875RegexNode currentNode = children[current];
1876RegexNode nextNode = children[next];
2076Debug.Assert(Children is List<RegexNode>);
2077var children = (List<RegexNode>)Children;
2082static void ProcessNode(RegexNode node, RegexNode subsequent)
2144RegexNode loopChild = node.Child(0);
2178RegexNode child = node.Child(0);
2188RegexNode child = node.Child(0);
2219private RegexNode ReduceLookaround()
2238static bool RemoveCaptures(RegexNode parent, int nodeIndex)
2240RegexNode node = parent.Child(nodeIndex);
2270RegexNode child = Child(0);
2309private static bool? ContainsKind(RegexNode node, ReadOnlySpan<RegexNodeKind> kinds)
2339private RegexNode ReduceBackreferenceConditional()
2357private RegexNode ReduceExpressionConditional()
2376RegexNode condition = Child(0);
2400internal static bool CanReduceLoopBacktrackingToSinglePosition(RegexNode loopNode, RegexNode subsequent)
2406if (subsequent.FindStartingLiteralNode() is RegexNode literal)
2423FindNextNodeInSequence(literal, out _) is RegexNode afterLiteral &&
2436static bool CharInLoopSet(RegexNode loopNode, char ch) => loopNode.Kind switch
2453private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool iterateNullableSubsequent, bool allowLazy)
2618RegexNode loopChild = node.Child(0);
2669RegexNode? nextSubsequent = FindNextNodeInSequence(subsequent, out bool reachedEnd);
2691private static RegexNode? FindNextNodeInSequence(RegexNode node, out bool reachedEnd)
2700RegexNode? parent = node.Parent;
2710var peers = (List<RegexNode>)parent.Children!;
2751private static bool MayContainBacktracking(RegexNode node)
2787RegexNode node = this;
2794node.Parent is not RegexNode parent)
2808var peers = (List<RegexNode>)parent.Children!;
3116RegexNode child = Child(i);
3243static bool CanJoinLengthCheck(RegexNode node) => node.Kind switch
3254RegexNode child = Child(childIndex);
3282public RegexNode MakeQuantifier(bool lazy, int min, int max)
3319var result = new RegexNode(lazy ? RegexNodeKind.Lazyloop : RegexNodeKind.Loop, Options, min, max);
3325public void AddChild(RegexNode newChild)
3335else if (Children is RegexNode currentChild)
3337Children = new List<RegexNode>() { currentChild, newChild };
3341((List<RegexNode>)Children).Add(newChild);
3345public void InsertChild(int index, RegexNode newChild)
3347Debug.Assert(Children is List<RegexNode>);
3353((List<RegexNode>)Children).Insert(index, newChild);
3356public void ReplaceChild(int index, RegexNode newChild)
3369private void UnsafeReplaceChild(int index, RegexNode newChild)
3373if (Children is RegexNode)
3379((List<RegexNode>)Children)[index] = newChild;
3383public RegexNode Child(int i) => Children is RegexNode child ? child : ((List<RegexNode>)Children!)[i];
3392if (Children is List<RegexNode> children)
3397Debug.Assert(Children is RegexNode);
3428static bool ExceedsMaxDepthAllowedDepth(RegexNode node, int allowedDepth)
parent\src\System\Text\RegularExpressions\RegexParser.cs (41)
24private RegexNode? _stack;
25private RegexNode? _group;
26private RegexNode? _alternation;
27private RegexNode? _concatenation;
28private RegexNode? _unit;
109RegexNode root = parser.ScanRegex();
144RegexNode root = parser.ScanReplacement();
270private RegexNode ScanRegex()
332_unit = RegexNode.CreateOneWithCaseConversion(_pattern[endpos - 1], _options, _culture, ref _caseBehavior);
353if (ScanGroupOpen() is RegexNode grouper)
542private RegexNode ScanReplacement()
818private RegexNode? ScanGroupOpen()
1147private RegexNode? ScanBackslash(bool scanOnly)
1216RegexNode? result = ScanBasicBackslash(scanOnly);
1226private RegexNode? ScanBasicBackslash(bool scanOnly)
1355RegexNode.CreateOneWithCaseConversion(ch, _options, _culture, ref _caseBehavior) :
1360private RegexNode ScanDollar()
1364return RegexNode.CreateOneWithCaseConversion('$', _options, _culture, ref _caseBehavior);
1454return RegexNode.CreateOneWithCaseConversion('$', _options, _culture, ref _caseBehavior);
1487return RegexNode.CreateOneWithCaseConversion('$', _options, _culture, ref _caseBehavior);
1733private RegexNode AnyNewLineCrLfGuardNode()
1741var lookbehindCr = new RegexNode(RegexNodeKind.PositiveLookaround, lookbehindOpts);
1745var crThenLf = new RegexNode(RegexNodeKind.Concatenate, lookaheadOpts);
1750var guard = new RegexNode(RegexNodeKind.NegativeLookaround, lookaheadOpts);
1762private RegexNode AnyNewLineEndZNode()
1769var crlfEnd = new RegexNode(RegexNodeKind.Concatenate, lookaheadOpts);
1775var anyNewLineOptEnd = new RegexNode(RegexNodeKind.Concatenate, lookaheadOpts);
1780var innerAlt = new RegexNode(RegexNodeKind.Alternate, lookaheadOpts);
1783var lookahead = new RegexNode(RegexNodeKind.PositiveLookaround, lookaheadOpts);
1787var result = new RegexNode(RegexNodeKind.Concatenate, opts);
1799private RegexNode AnyNewLineEolNode()
1806var innerAlt = new RegexNode(RegexNodeKind.Alternate, lookaheadOpts);
1809var lookahead = new RegexNode(RegexNodeKind.PositiveLookaround, lookaheadOpts);
1813var result = new RegexNode(RegexNodeKind.Concatenate, opts);
1825private RegexNode AnyNewLineBolNode()
1832var innerAlt = new RegexNode(RegexNodeKind.Alternate, lookbehindOpts);
1835var lookbehind = new RegexNode(RegexNodeKind.PositiveLookaround, lookbehindOpts);
1839var result = new RegexNode(RegexNodeKind.Concatenate, opts);
2194_concatenation!.AddChild(RegexNode.CreateOneWithCaseConversion(_pattern[pos], isReplacement ? _options & ~RegexOptions.IgnoreCase : _options, _culture, ref _caseBehavior));
2204_concatenation!.AddChild(RegexNode.CreateOneWithCaseConversion(c, _options, _culture, ref _caseBehavior));
2241private void StartGroup(RegexNode openGroup)
parent\src\System\Text\RegularExpressions\RegexPrefixAnalyzer.cs (25)
21public static string[]? FindPrefixes(RegexNode node, bool ignoreCase)
57static unsafe bool FindPrefixesCore(RegexNode node, List<StringBuilder> results, bool ignoreCase)
340public static unsafe string FindPrefix(RegexNode node)
348static bool Process(RegexNode node, ref ValueStringBuilder vsb)
483public static string? FindPrefixOrdinalCaseInsensitive(RegexNode node)
511public static unsafe List<RegexFindOptimizations.FixedDistanceSet>? FindFixedDistanceSets(RegexNode root, bool thorough)
586static bool TryFindRawFixedSets(RegexNode node, List<RegexFindOptimizations.FixedDistanceSet> results, ref int distance, bool thorough)
906public static string? FindFirstCharClass(RegexNode root) => FindFirstOrLastCharClass(root, findFirst: true);
911public static string? FindLastCharClass(RegexNode root) => FindFirstOrLastCharClass(root, findFirst: false);
913public static string? FindFirstOrLastCharClass(RegexNode root, bool findFirst)
942static bool? TryFindFirstOrLastCharClass(RegexNode node, bool findFirst, ref RegexCharClass? cc)
1127public static unsafe (RegexNode LoopNode, (char Char, string? String, StringComparison StringComparison, char[]? Chars) Literal)? FindLiteralFollowingLeadingLoop(RegexNode node)
1154RegexNode firstChild = node.Child(0);
1166RegexNode nextChild = node.Child(1);
1256public static RegexNode? FindLeadingPositiveLookahead(RegexNode node)
1258RegexNode? positiveLookahead = null;
1263static bool FindLeadingPositiveLookahead(RegexNode node, ref RegexNode? positiveLookahead)
1330public static RegexNodeKind FindLeadingAnchor(RegexNode node) =>
1334public static RegexNodeKind FindTrailingAnchor(RegexNode node) =>
1338private static RegexNodeKind FindLeadingOrTrailingAnchor(RegexNode node, bool leading)
1379RegexNode? child = null;
1385RegexNode tmpChild = node.Child(i);
RegexGenerator.Emitter.cs (60)
756RegexNode root = rm.Tree.Root.Child(0);
1501(RegexNode LoopNode, (char Char, string? String, StringComparison StringComparison, char[]? Chars) Literal) target = regexTree.FindOptimizations.LiteralAfterLoop.Value;
1624RegexNode node = regexTree.Root;
1805void EmitAlternation(RegexNode node)
1889RegexNode child = node.Child(i);
1890RegexNode? startingLiteralNode = child.FindStartingLiteralNode(allowZeroWidth: false);
1930RegexNode originalFirst = child.Child(0);
1976static RegexNode SliceOffMultiFirstChar(RegexNode multi)
2203void EmitBackreference(RegexNode node)
2272void EmitBackreferenceConditional(RegexNode node)
2286RegexNode yesBranch = node.Child(0);
2287RegexNode? noBranch = node.Child(1) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null;
2445void EmitExpressionConditional(RegexNode node)
2458RegexNode condition = node.Child(0);
2462RegexNode yesBranch = node.Child(1);
2463RegexNode? noBranch = node.Child(2) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null;
2625void EmitCapture(RegexNode node, RegexNode? subsequent = null)
2649RegexNode child = node.Child(0);
2718void EmitPositiveLookaroundAssertion(RegexNode node)
2759void EmitNegativeLookaroundAssertion(RegexNode node)
2790RegexNode child = node.Child(0);
2857void EmitNode(RegexNode node, RegexNode? subsequent = null, bool emitLengthChecksIfRequired = true)
3028void EmitAtomic(RegexNode node, RegexNode? subsequent)
3058void EmitUpdateBumpalong(RegexNode node)
3070void EmitConcatenation(RegexNode node, RegexNode? subsequent, bool emitLengthChecksIfRequired)
3108RegexNode child = node.Child(i);
3183static RegexNode? GetSubsequentOrDefault(int index, RegexNode node, RegexNode? defaultNode)
3188RegexNode next = node.Child(i);
3200void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, string? offset = null, bool clauseOnly = false)
3244void EmitBoundary(RegexNode node)
3284void EmitAnchors(RegexNode node)
3350void EmitMultiChar(RegexNode node, bool emitLengthCheck)
3399void EmitSingleCharLoop(RegexNode node, RegexNode? subsequent = null, bool emitLengthChecksIfRequired = true)
3484subsequent?.FindStartingLiteralNode() is RegexNode literalNode &&
3489if (subsequent is not null && RegexNode.CanReduceLoopBacktrackingToSinglePosition(node, subsequent))
3577void EmitSingleCharLazy(RegexNode node, RegexNode? subsequent = null, bool emitLengthChecksIfRequired = true)
3681subsequent?.FindStartingLiteral() is RegexNode.StartingLiteralData literal &&
3749subsequent?.FindStartingLiteralNode() is RegexNode literal2 &&
3824void EmitLazy(RegexNode node)
3831RegexNode child = node.Child(0);
4130void EmitSingleCharRepeater(RegexNode node, bool emitLengthCheck = true)
4148case <= RegexNode.MultiVsRepeaterLimit when node.IsOneFamily:
4250void EmitSingleCharAtomicLoop(RegexNode node, bool emitLengthChecksIfRequired = true)
4382void EmitAtomicSingleCharZeroOrOne(RegexNode node)
4420void EmitNonBacktrackingRepeater(RegexNode node)
4440void EmitLoop(RegexNode node)
4446RegexNode child = node.Child(0);
5058RegexNode node,
5583private static string DescribeNode(RegexNode node, RegexMethod rm)
5757private static void DescribeExpressionAsXmlComment(TextWriter writer, RegexNode node, RegexMethod rm, int depth = 0)
5827private static string DescribeLoop(RegexNode node, RegexMethod rm)