1231 references to RegexNodeKind
System.Text.RegularExpressions.Generator (1231)
parent\src\System\Text\RegularExpressions\RegexFindOptimizations.cs (18)
56if (rightToLeft && LeadingAnchor == RegexNodeKind.Bol) 59LeadingAnchor = RegexNodeKind.Unknown; 61if (LeadingAnchor is RegexNodeKind.Beginning or RegexNodeKind.Start or RegexNodeKind.EndZ or RegexNodeKind.End) 65(RegexNodeKind.Beginning, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Beginning, 66(RegexNodeKind.Beginning, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_Beginning, 67(RegexNodeKind.Start, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Start, 68(RegexNodeKind.Start, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_Start, 69(RegexNodeKind.End, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_End, 70(RegexNodeKind.End, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_End, 83if (TrailingAnchor is RegexNodeKind.End or RegexNodeKind.EndZ && 90FindMode = TrailingAnchor == RegexNodeKind.End ? 280LeadingAnchor == RegexNodeKind.Bol; // there's a leading BOL anchor we can otherwise search for 286public RegexNodeKind LeadingAnchor { get; private set; } 289public RegexNodeKind TrailingAnchor { get; }
parent\src\System\Text\RegularExpressions\RegexNode.cs (675)
23public RegexNodeKind Kind { get; private set; } 51public RegexNode(RegexNodeKind kind, RegexOptions options) 57public RegexNode(RegexNodeKind kind, RegexOptions options, char ch) 64public RegexNode(RegexNodeKind kind, RegexOptions options, string str) 71public RegexNode(RegexNodeKind kind, RegexOptions options, int m) 78public RegexNode(RegexNodeKind kind, RegexOptions options, int m, int n) 89Debug.Assert(Kind is RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or 90RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or 91RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic); 121return new RegexNode(RegexNodeKind.One, options & ~RegexOptions.IgnoreCase, ch); 127return new RegexNode(RegexNodeKind.Set, options & ~RegexOptions.IgnoreCase, stringSet); 131return new RegexNode(RegexNodeKind.One, options, ch); 138Kind == RegexNodeKind.Concatenate && 150private void MakeRep(RegexNodeKind kind, int min, int max) 152Kind += kind - RegexNodeKind.One; 169case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop: 172Kind += RegexNodeKind.Oneloopatomic - RegexNodeKind.Oneloop; 175case RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy: 179Kind += RegexNodeKind.Oneloopatomic - RegexNodeKind.Onelazy; 189Kind = RegexNodeKind.Empty; 193else if (Kind == RegexNodeKind.Oneloopatomic && N is >= 2 and <= MultiVsRepeaterLimit) 197Kind = RegexNodeKind.Multi; 204case RegexNodeKind.Loop: 205if (Parent is not { Kind: RegexNodeKind.Atomic }) 207RegexNode loopAsChild = new(RegexNodeKind.Loop, Options, M, N); 208Kind = RegexNodeKind.Atomic; 215case RegexNodeKind.Lazyloop: 225goto case RegexNodeKind.Loop; 228Kind = RegexNodeKind.Empty; 372Debug.Assert(rootNode.Kind == RegexNodeKind.Capture); 429case RegexNodeKind.Atomic: 433case RegexNodeKind.Concatenate: 438case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when node.N == int.MaxValue: 439case RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy when node.N == int.MaxValue && !atomicByAncestry: 440if (node.Parent is { Kind: RegexNodeKind.Concatenate } parent) 442parent.InsertChild(1, new RegexNode(RegexNodeKind.UpdateBumpalong, node.Options)); 523case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop: 524case RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy: 530case RegexNodeKind.Atomic: 531case RegexNodeKind.PositiveLookaround: 532case RegexNodeKind.NegativeLookaround: 542case RegexNodeKind.Capture: 543case RegexNodeKind.Concatenate when !rtl: 545if ((existingChild.Kind is RegexNodeKind.Alternate or RegexNodeKind.BackreferenceConditional or RegexNodeKind.ExpressionConditional or RegexNodeKind.Loop or RegexNodeKind.Lazyloop) && 546node.Parent is not { Kind: RegexNodeKind.Atomic }) // validate grandparent isn't atomic 548var atomic = new RegexNode(RegexNodeKind.Atomic, existingChild.Options); 558case RegexNodeKind.Alternate: 559case RegexNodeKind.BackreferenceConditional: 560case RegexNodeKind.ExpressionConditional: 568if (node.Kind != RegexNodeKind.ExpressionConditional) // ReduceExpressionConditional will have already applied ending backtracking removal 583case RegexNodeKind.Lazyloop: 584case RegexNodeKind.Loop: 589Debug.Assert(node.Kind is RegexNodeKind.Atomic or RegexNodeKind.Empty or RegexNodeKind.Loop or RegexNodeKind.Lazyloop); 591if (node.Kind is RegexNodeKind.Atomic) 594Debug.Assert(node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop); 597if (node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop) 631case RegexNodeKind.Backreference: 638RegexNodeKind.Alternate => ReduceAlternation(), 639RegexNodeKind.Atomic => ReduceAtomic(), 640RegexNodeKind.Concatenate => ReduceConcatenation(), 641RegexNodeKind.Group => ReduceGroup(), 642RegexNodeKind.Loop or RegexNodeKind.Lazyloop => ReduceLoops(), 643RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround => ReduceLookaround(), 644RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy => ReduceSet(), 645RegexNodeKind.ExpressionConditional => ReduceExpressionConditional(), 646RegexNodeKind.BackreferenceConditional => ReduceBackreferenceConditional(), 659Debug.Assert(Kind is RegexNodeKind.Alternate or RegexNodeKind.Concatenate); 6620 => new RegexNode(Kind == RegexNodeKind.Alternate ? RegexNodeKind.Nothing : RegexNodeKind.Empty, Options), 676Debug.Assert(Kind == RegexNodeKind.Group); 679while (u.Kind == RegexNodeKind.Group) 704Debug.Assert(Kind == RegexNodeKind.Atomic); 709while (child.Kind == RegexNodeKind.Atomic) 719case RegexNodeKind.Empty: 720case RegexNodeKind.Nothing: 725case RegexNodeKind.One: 726case RegexNodeKind.Notone: 727case RegexNodeKind.Set: 728case RegexNodeKind.Multi: 732case RegexNodeKind.Oneloopatomic: 733case RegexNodeKind.Notoneloopatomic: 734case RegexNodeKind.Setloopatomic: 739case RegexNodeKind.Oneloop: 740case RegexNodeKind.Notoneloop: 741case RegexNodeKind.Setloop: 742case RegexNodeKind.Onelazy: 743case RegexNodeKind.Notonelazy: 744case RegexNodeKind.Setlazy: 750case RegexNodeKind.Alternate: 759if (branches[0].Kind == RegexNodeKind.Empty) 761return new RegexNode(RegexNodeKind.Empty, child.Options); 770if (branches[i].Kind == RegexNodeKind.Empty) 851(child.Child(0).Kind is RegexNodeKind.Empty || child.Child(1).Kind is RegexNodeKind.Empty); // can be transformed into a ? or ?? 866return child.Kind == RegexNodeKind.Empty ? 881Debug.Assert(Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop); 884RegexNodeKind kind = Kind; 897if (kind == RegexNodeKind.Loop) 901case RegexNodeKind.Oneloop: 902case RegexNodeKind.Oneloopatomic: 903case RegexNodeKind.Notoneloop: 904case RegexNodeKind.Notoneloopatomic: 905case RegexNodeKind.Setloop: 906case RegexNodeKind.Setloopatomic: 915case RegexNodeKind.Onelazy: 916case RegexNodeKind.Notonelazy: 917case RegexNodeKind.Setlazy: 951return new RegexNode(RegexNodeKind.Nothing, Options); 962case RegexNodeKind.One: 963case RegexNodeKind.Notone: 964case RegexNodeKind.Set: 965child.MakeRep(u.Kind == RegexNodeKind.Lazyloop ? RegexNodeKind.Onelazy : RegexNodeKind.Oneloop, u.M, u.N); 969case RegexNodeKind.Empty: 974case RegexNodeKind.PositiveLookaround when ContainsKind(child, [RegexNodeKind.Capture]) is false: 975case RegexNodeKind.NegativeLookaround or 976RegexNodeKind.Beginning or RegexNodeKind.Start or 977RegexNodeKind.Bol or RegexNodeKind.Eol or 978RegexNodeKind.End or RegexNodeKind.EndZ or 979RegexNodeKind.Boundary or RegexNodeKind.ECMABoundary or 980RegexNodeKind.NonBoundary or RegexNodeKind.NonECMABoundary: 990u = u.M == 0 ? new RegexNode(RegexNodeKind.Empty, Options) : child; 1013Debug.Assert(Kind is RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy); 1018Kind = RegexNodeKind.Nothing; 1026Kind == RegexNodeKind.Set ? RegexNodeKind.One : 1027Kind == RegexNodeKind.Setloop ? RegexNodeKind.Oneloop : 1028Kind == RegexNodeKind.Setloopatomic ? RegexNodeKind.Oneloopatomic : 1029RegexNodeKind.Onelazy; 1036Kind == RegexNodeKind.Set ? RegexNodeKind.Notone : 1037Kind == RegexNodeKind.Setloop ? RegexNodeKind.Notoneloop : 1038Kind == RegexNodeKind.Setloopatomic ? RegexNodeKind.Notoneloopatomic : 1039RegexNodeKind.Notonelazy; 1073Debug.Assert(Kind == RegexNodeKind.Alternate); 1078return new RegexNode(RegexNodeKind.Nothing, Options); 1086if (node.Kind == RegexNodeKind.Alternate) 1089if (node.Kind == RegexNodeKind.Alternate) 1092if (node.Kind == RegexNodeKind.Alternate) 1100if (node.Kind is RegexNodeKind.Alternate && node.ChildCount() == 2) 1102if (node.Child(1).Kind is RegexNodeKind.Empty) 1106else if (node.Child(0).Kind is RegexNodeKind.Empty) 1143if (at.Kind == RegexNodeKind.Alternate) 1161else if (at.Kind is RegexNodeKind.Set or RegexNodeKind.One) 1166if (at.Kind == RegexNodeKind.Set) 1190if (prev.Kind == RegexNodeKind.One) 1200if (at.Kind == RegexNodeKind.One) 1210prev.Kind = RegexNodeKind.Set; 1217else if (at.Kind == RegexNodeKind.Nothing) 1241Debug.Assert(alternation.Kind == RegexNodeKind.Alternate); 1260RegexNode required = startingNode.Kind == RegexNodeKind.Concatenate ? startingNode.Child(0) : startingNode; 1263case RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set: 1264case RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloopatomic: 1265case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop or RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy when required.M == required.N: 1266case RegexNodeKind.Beginning or RegexNodeKind.Start or RegexNodeKind.Bol 1267or RegexNodeKind.End or RegexNodeKind.EndZ or RegexNodeKind.Eol 1268or RegexNodeKind.Boundary or RegexNodeKind.ECMABoundary 1269or RegexNodeKind.NonBoundary or RegexNodeKind.NonECMABoundary: 1281RegexNode other = endingNode.Kind == RegexNodeKind.Concatenate ? endingNode.Child(0) : endingNode; 1300var newAlternate = new RegexNode(RegexNodeKind.Alternate, alternation.Options); 1303if (children[i].Kind == RegexNodeKind.Concatenate) 1311newAlternate.AddChild(new RegexNode(RegexNodeKind.Empty, children[i].Options)); 1316if (alternation.Parent is RegexNode { Kind: RegexNodeKind.Atomic }) 1318var atomic = new RegexNode(RegexNodeKind.Atomic, alternation.Options); 1325var newConcat = new RegexNode(RegexNodeKind.Concatenate, alternation.Options); 1341Debug.Assert(node.Kind == RegexNodeKind.Alternate); 1352case RegexNodeKind.Empty when !seenEmpty: 1356case RegexNodeKind.Empty: 1357case RegexNodeKind.Nothing: 1384Debug.Assert(alternation.Kind == RegexNodeKind.Alternate); 1414if (startingNode.Kind == RegexNodeKind.One) 1434if (startingNode.Kind == RegexNodeKind.One) 1448Debug.Assert(startingNode.Kind == RegexNodeKind.Multi); 1479new RegexNode(RegexNodeKind.One, startingNodeOptions, startingSpan[0]) : 1480new RegexNode(RegexNodeKind.Multi, startingNodeOptions, startingSpan.ToString()); 1481var newAlternate = new RegexNode(RegexNodeKind.Alternate, startingNodeOptions); 1485ProcessOneOrMulti(branch.Kind == RegexNodeKind.Concatenate ? branch.Child(0) : branch, startingSpan); 1493if (node.Kind == RegexNodeKind.One) 1497node.Kind = RegexNodeKind.Empty; 1502Debug.Assert(node.Kind == RegexNodeKind.Multi); 1506node.Kind = RegexNodeKind.Empty; 1511node.Kind = RegexNodeKind.One; 1523if (alternation.Parent is RegexNode parent && parent.Kind == RegexNodeKind.Atomic) 1525var atomic = new RegexNode(RegexNodeKind.Atomic, startingNodeOptions); 1530var newConcat = new RegexNode(RegexNodeKind.Concatenate, startingNodeOptions); 1550RegexNode branch = Kind == RegexNodeKind.Concatenate ? Child(0) : this; 1551return branch.Kind is RegexNodeKind.One or RegexNodeKind.Multi ? branch : null; 1557Debug.Assert(Kind is RegexNodeKind.One or RegexNodeKind.Multi || (IsOneFamily && M > 0)); 1572Debug.Assert(Kind is RegexNodeKind.Alternate); 1596if (startingLiteralNode.IsOneFamily || startingLiteralNode.Kind is RegexNodeKind.Multi) 1642case RegexNodeKind.One: 1643case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy when node.M > 0: 1644case RegexNodeKind.Notone: 1645case RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy when node.M > 0: 1646case RegexNodeKind.Set: 1647case RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy when node.M > 0: 1648case RegexNodeKind.Multi: 1651case RegexNodeKind.Atomic: 1652case RegexNodeKind.Concatenate: 1653case RegexNodeKind.Capture: 1654case RegexNodeKind.Group: 1655case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.M > 0: 1656case RegexNodeKind.PositiveLookaround when allowZeroWidth: 1677case RegexNodeKind.One or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy: 1680case RegexNodeKind.Notone or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy: 1683case RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy: 1699case RegexNodeKind.Multi: 1742Debug.Assert(Kind == RegexNodeKind.Concatenate); 1748return new RegexNode(RegexNodeKind.Empty, Options); 1758if (child.Kind == RegexNodeKind.Nothing) 1784Debug.Assert(Kind == RegexNodeKind.Concatenate); 1801if (at.Kind == RegexNodeKind.Concatenate && 1820else if (at.Kind is RegexNodeKind.Multi or RegexNodeKind.One) 1834if (prev.Kind == RegexNodeKind.One) 1836prev.Kind = RegexNodeKind.Multi; 1841((at.Kind == RegexNodeKind.One) ? $"{prev.Str}{at.Ch}" : prev.Str + at.Str) : 1842((at.Kind == RegexNodeKind.One) ? $"{at.Ch}{prev.Str}" : at.Str + prev.Str); 1844else if (at.Kind == RegexNodeKind.Empty) 1867Debug.Assert(Kind == RegexNodeKind.Concatenate); 1905case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy when nextNode.Kind == currentNode.Kind && currentNode.Ch == nextNode.Ch: 1906case RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy when nextNode.Kind == currentNode.Kind && currentNode.Str == nextNode.Str: 1908currentNode.Kind is RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloopatomic) 1931case RegexNodeKind.Oneloop or RegexNodeKind.Onelazy when nextNode.Kind == RegexNodeKind.One && currentNode.Ch == nextNode.Ch: 1932case RegexNodeKind.Notoneloop or RegexNodeKind.Notonelazy when nextNode.Kind == RegexNodeKind.Notone && currentNode.Ch == nextNode.Ch: 1933case RegexNodeKind.Setloop or RegexNodeKind.Setlazy when nextNode.Kind == RegexNodeKind.Set && currentNode.Str == nextNode.Str: 1947case RegexNodeKind.Oneloop or RegexNodeKind.Onelazy when 1948nextNode.Kind == RegexNodeKind.Multi && 1981nextNode.Kind = RegexNodeKind.One; 1999case RegexNodeKind.One when (nextNode.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy) && currentNode.Ch == nextNode.Ch: 2000case RegexNodeKind.Notone when (nextNode.Kind is RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy) && currentNode.Ch == nextNode.Ch: 2001case RegexNodeKind.Set when (nextNode.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy) && currentNode.Str == nextNode.Str: 2014case RegexNodeKind.Notone when nextNode.Kind == currentNode.Kind && currentNode.Ch == nextNode.Ch: 2015case RegexNodeKind.Set when nextNode.Kind == RegexNodeKind.Set && currentNode.Str == nextNode.Str: 2016currentNode.MakeRep(RegexNodeKind.Oneloop, 2, 2); 2021case RegexNodeKind.Beginning or RegexNodeKind.Start or 2022RegexNodeKind.End or RegexNodeKind.EndZ or 2023RegexNodeKind.Bol or RegexNodeKind.Eol or 2024RegexNodeKind.Boundary or RegexNodeKind.NonBoundary or 2025RegexNodeKind.ECMABoundary or RegexNodeKind.NonECMABoundary 2069if (Kind is not RegexNodeKind.Concatenate) 2093while (node.Kind is RegexNodeKind.Capture or RegexNodeKind.Concatenate) 2101case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop when CanBeMadeAtomic(node, subsequent, iterateNullableSubsequent: true, allowLazy: false): 2110case RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy when CanBeMadeAtomic(node, subsequent, iterateNullableSubsequent: false, allowLazy: true): 2126node.Kind -= RegexNodeKind.Onelazy - RegexNodeKind.Oneloop; // lazy to greedy 2130case RegexNodeKind.Loop when CanBeMadeAtomic(node, subsequent, iterateNullableSubsequent: true, allowLazy: false): 2131case RegexNodeKind.Lazyloop when CanBeMadeAtomic(node, subsequent, iterateNullableSubsequent: false, allowLazy: true): 2145while (loopChild.Kind is RegexNodeKind.Capture or RegexNodeKind.Concatenate) 2157RegexNodeKind.Boundary or RegexNodeKind.ECMABoundary or 2158RegexNodeKind.Multi or 2159RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set && 2164else if (node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop) 2168goto case RegexNodeKind.Loop; 2176case RegexNodeKind.Loop: 2186case RegexNodeKind.Lazyloop: 2196case RegexNodeKind.Alternate or RegexNodeKind.BackreferenceConditional or RegexNodeKind.ExpressionConditional: 2207for (int b = node.Kind == RegexNodeKind.ExpressionConditional ? 1 : 0; b < alternateBranches; b++) 2221Debug.Assert(Kind is RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround); 2229if (Kind is RegexNodeKind.NegativeLookaround && ContainsKind(Child(0), [RegexNodeKind.Backreference, RegexNodeKind.BackreferenceConditional]) is false) 2244if (node is { Kind: RegexNodeKind.Capture, N: -1 }) 2275if (Kind is RegexNodeKind.PositiveLookaround) 2278child.Kind is RegexNodeKind.Empty) 2283else if (Kind is RegexNodeKind.NegativeLookaround) 2288if (child.Kind is RegexNodeKind.Empty) 2290Kind = RegexNodeKind.Nothing; 2298private static bool IsZeroWidthAssertion(RegexNodeKind kind) => kind is 2299RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround or 2300RegexNodeKind.Beginning or RegexNodeKind.Start or 2301RegexNodeKind.Bol or RegexNodeKind.Eol or 2302RegexNodeKind.End or RegexNodeKind.EndZ or 2303RegexNodeKind.Boundary or RegexNodeKind.ECMABoundary or 2304RegexNodeKind.NonBoundary or RegexNodeKind.NonECMABoundary or 2305RegexNodeKind.UpdateBumpalong; 2309private static bool? ContainsKind(RegexNode node, ReadOnlySpan<RegexNodeKind> kinds) 2311foreach (RegexNodeKind kind in kinds) 2341Debug.Assert(Kind == RegexNodeKind.BackreferenceConditional); 2350AddChild(new RegexNode(RegexNodeKind.Empty, Options)); 2359Debug.Assert(Kind == RegexNodeKind.ExpressionConditional); 2368AddChild(new RegexNode(RegexNodeKind.Empty, Options)); 2377if (condition.Kind == RegexNodeKind.PositiveLookaround && (condition.Options & RegexOptions.RightToLeft) == 0) 2402Debug.Assert(loopNode.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop); 2413case RegexNodeKind.One when CharInLoopSet(loopNode, literal.Ch): // e.g. \w+a\s : 'a' is in \w, check \s is disjoint 2414case RegexNodeKind.Set when loopNode.Kind is RegexNodeKind.Setloop && RegexCharClass.IsSubsetOf(literal.Str!, loopNode.Str!): // e.g. \d+[0-9]\s 2426case RegexNodeKind.Multi when CharInLoopSet(loopNode, literal.Str![0]) && !CharInLoopSet(loopNode, literal.Str[1]): 2438RegexNodeKind.Oneloop => loopNode.Ch == ch, 2439RegexNodeKind.Notoneloop => loopNode.Ch != ch, 2440RegexNodeKind.Setloop => RegexCharClass.CharInClass(ch, loopNode.Str!), 2462while (node.Kind is RegexNodeKind.Capture or RegexNodeKind.Concatenate) 2480case RegexNodeKind.Concatenate: 2481case RegexNodeKind.Capture: 2482case RegexNodeKind.Atomic: 2486case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when subsequent.M > 0: 2494case RegexNodeKind.PositiveLookaround when (subsequent.Options & RegexOptions.RightToLeft) == 0: 2518case RegexNodeKind.Alternate: 2519case RegexNodeKind.ExpressionConditional when childCount is 3: // condition, yes, and no branch 2534case RegexNodeKind.Oneloop: 2535case RegexNodeKind.Onelazy when allowLazy: 2538case RegexNodeKind.One when node.Ch != subsequent.Ch: 2539case RegexNodeKind.Notone when node.Ch == subsequent.Ch: 2540case RegexNodeKind.Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): 2541case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: 2542case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: 2543case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): 2544case RegexNodeKind.Multi when node.Ch != subsequent.Str![0]: 2545case RegexNodeKind.End: 2546case RegexNodeKind.EndZ or RegexNodeKind.Eol when node.Ch != '\n': 2547case RegexNodeKind.Boundary when node.M > 0 && RegexCharClass.IsBoundaryWordChar(node.Ch): 2548case RegexNodeKind.NonBoundary when node.M > 0 && !RegexCharClass.IsBoundaryWordChar(node.Ch): 2549case RegexNodeKind.ECMABoundary when node.M > 0 && RegexCharClass.IsECMAWordChar(node.Ch): 2550case RegexNodeKind.NonECMABoundary when node.M > 0 && !RegexCharClass.IsECMAWordChar(node.Ch): 2553case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M == 0 && node.Ch != subsequent.Ch: 2554case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: 2555case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): 2564case RegexNodeKind.Notoneloop: 2565case RegexNodeKind.Notonelazy when allowLazy: 2568case RegexNodeKind.One when node.Ch == subsequent.Ch: 2569case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: 2570case RegexNodeKind.Multi when node.Ch == subsequent.Str![0]: 2571case RegexNodeKind.End: 2574case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: 2583case RegexNodeKind.Setloop: 2584case RegexNodeKind.Setlazy when allowLazy: 2587case RegexNodeKind.One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): 2588case RegexNodeKind.Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): 2589case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): 2590case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): 2591case RegexNodeKind.Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): 2592case RegexNodeKind.End: 2593case RegexNodeKind.EndZ or RegexNodeKind.Eol when !RegexCharClass.CharInClass('\n', node.Str!): 2594case RegexNodeKind.Boundary when node.M > 0 && RegexCharClass.IsSubsetOf(node.Str!, RegexCharClass.WordClass): 2595case RegexNodeKind.NonBoundary when node.M > 0 && node.Str is RegexCharClass.NotWordClass or RegexCharClass.NotDigitClass: 2596case RegexNodeKind.ECMABoundary when node.M > 0 && node.Str is RegexCharClass.ECMAWordClass or RegexCharClass.ECMADigitClass: 2597case RegexNodeKind.NonECMABoundary when node.M > 0 && node.Str is RegexCharClass.NotECMAWordClass or RegexCharClass.NotDigitClass: 2600case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): 2601case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M == 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): 2610case RegexNodeKind.Loop: 2611case RegexNodeKind.Lazyloop when allowLazy: 2634case RegexNodeKind.One when !CharInStartingOrEndingSet(subsequent.Ch): 2635case RegexNodeKind.Set when !MayOverlapStartingOrEndingSet(subsequent.Str!): 2636case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M > 0 && !CharInStartingOrEndingSet(subsequent.Ch): 2637case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M > 0 && !MayOverlapStartingOrEndingSet(subsequent.Str!): 2638case RegexNodeKind.Multi when !CharInStartingOrEndingSet(subsequent.Str![0]): 2639case RegexNodeKind.End: 2640case RegexNodeKind.EndZ or RegexNodeKind.Eol when !CharInStartingOrEndingSet('\n'): 2641case RegexNodeKind.Boundary when node.M > 0 && RegexCharClass.IsSubsetOf(loopStartingSet, RegexCharClass.WordClass) && RegexCharClass.IsSubsetOf(loopEndingSet, RegexCharClass.WordClass): 2642case RegexNodeKind.NonBoundary when node.M > 0 && (loopStartingSet is RegexCharClass.NotWordClass or RegexCharClass.NotDigitClass) && (loopEndingSet is RegexCharClass.NotWordClass or RegexCharClass.NotDigitClass): 2643case RegexNodeKind.ECMABoundary when node.M > 0 && (loopStartingSet is RegexCharClass.ECMAWordClass or RegexCharClass.ECMADigitClass) && (loopEndingSet is RegexCharClass.ECMAWordClass or RegexCharClass.ECMADigitClass): 2644case RegexNodeKind.NonECMABoundary when node.M > 0 && (loopStartingSet is RegexCharClass.NotECMAWordClass or RegexCharClass.NotDigitClass) && (loopEndingSet is RegexCharClass.NotECMAWordClass or RegexCharClass.NotDigitClass): 2647case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M == 0 && !CharInStartingOrEndingSet(subsequent.Ch): 2648case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M == 0 && !MayOverlapStartingOrEndingSet(subsequent.Str!): 2703case RegexNodeKind.Atomic: 2704case RegexNodeKind.Alternate: 2705case RegexNodeKind.Capture: 2709case RegexNodeKind.Concatenate: 2740RegexNodeKind.Alternate => true, 2741RegexNodeKind.Loop or RegexNodeKind.Lazyloop when M != N => true, 2742RegexNodeKind.Oneloop or RegexNodeKind.Onelazy or 2743RegexNodeKind.Notoneloop or RegexNodeKind.Notonelazy or 2744RegexNodeKind.Setloop or RegexNodeKind.Setlazy when M != N => true, 2788Debug.Assert(node.Kind is not RegexNodeKind.Concatenate, "The existing logic assumes that the node itself isn't a concatenation."); 2801case RegexNodeKind.Atomic: 2802case RegexNodeKind.Alternate: 2803case RegexNodeKind.Capture: 2807case RegexNodeKind.Concatenate: 2843case RegexNodeKind.One: 2844case RegexNodeKind.Notone: 2845case RegexNodeKind.Set: 2849case RegexNodeKind.Multi: 2853case RegexNodeKind.Notonelazy: 2854case RegexNodeKind.Notoneloop: 2855case RegexNodeKind.Notoneloopatomic: 2856case RegexNodeKind.Onelazy: 2857case RegexNodeKind.Oneloop: 2858case RegexNodeKind.Oneloopatomic: 2859case RegexNodeKind.Setlazy: 2860case RegexNodeKind.Setloop: 2861case RegexNodeKind.Setloopatomic: 2865case RegexNodeKind.Lazyloop: 2866case RegexNodeKind.Loop: 2870case RegexNodeKind.Alternate: 2883case RegexNodeKind.BackreferenceConditional: 2887case RegexNodeKind.ExpressionConditional: 2891case RegexNodeKind.Concatenate: 2903case RegexNodeKind.Atomic: 2904case RegexNodeKind.Capture: 2905case RegexNodeKind.Group: 2910case RegexNodeKind.Empty: 2911case RegexNodeKind.Nothing: 2912case RegexNodeKind.UpdateBumpalong: 2916case RegexNodeKind.Beginning: 2917case RegexNodeKind.Bol: 2918case RegexNodeKind.Boundary: 2919case RegexNodeKind.ECMABoundary: 2920case RegexNodeKind.End: 2921case RegexNodeKind.EndZ: 2922case RegexNodeKind.Eol: 2923case RegexNodeKind.NonBoundary: 2924case RegexNodeKind.NonECMABoundary: 2925case RegexNodeKind.Start: 2926case RegexNodeKind.NegativeLookaround: 2927case RegexNodeKind.PositiveLookaround: 2929case RegexNodeKind.Backreference: 2937goto case RegexNodeKind.Empty; 2956case RegexNodeKind.One: 2957case RegexNodeKind.Notone: 2958case RegexNodeKind.Set: 2962case RegexNodeKind.Multi: 2966case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or 2967RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or 2968RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic: 2972case RegexNodeKind.Loop or RegexNodeKind.Lazyloop: 2987case RegexNodeKind.Alternate: 3010case RegexNodeKind.BackreferenceConditional: 3011case RegexNodeKind.ExpressionConditional: 3014int i = Kind == RegexNodeKind.BackreferenceConditional ? 0 : 1; 3020case RegexNodeKind.Concatenate: 3042case RegexNodeKind.Atomic: 3043case RegexNodeKind.Capture: 3048case RegexNodeKind.Empty: 3049case RegexNodeKind.Nothing: 3050case RegexNodeKind.UpdateBumpalong: 3051case RegexNodeKind.Beginning: 3052case RegexNodeKind.Bol: 3053case RegexNodeKind.Boundary: 3054case RegexNodeKind.ECMABoundary: 3055case RegexNodeKind.End: 3056case RegexNodeKind.EndZ: 3057case RegexNodeKind.Eol: 3058case RegexNodeKind.NonBoundary: 3059case RegexNodeKind.NonECMABoundary: 3060case RegexNodeKind.Start: 3061case RegexNodeKind.PositiveLookaround: 3062case RegexNodeKind.NegativeLookaround: 3066case RegexNodeKind.Backreference: 3074goto case RegexNodeKind.Empty; 3105Debug.Assert(Kind == RegexNodeKind.Concatenate, $"Expected Concatenate, got {Kind}"); 3127while (child.Kind is RegexNodeKind.Capture or RegexNodeKind.Atomic) 3133if (child.Kind is RegexNodeKind.One) 3146else if (child.Kind is RegexNodeKind.Multi) 3158else if (child.Kind is RegexNodeKind.Set || 3159(child.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic && child.M == child.N)) 3168vsb.Append((char)(twoChars[0] | 0x20), child.Kind is RegexNodeKind.Set ? 1 : child.M); 3170else if (child.Kind is RegexNodeKind.Concatenate) 3190else if (child.Kind is RegexNodeKind.Empty) 3241Debug.Assert(Kind == RegexNodeKind.Concatenate, $"Expected Concatenate, got {Kind}"); 3245RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set => true, 3246RegexNodeKind.Multi => true, 3247RegexNodeKind.Oneloop or RegexNodeKind.Onelazy or RegexNodeKind.Oneloopatomic or 3248RegexNodeKind.Notoneloop or RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloopatomic or 3249RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic 3291return new RegexNode(RegexNodeKind.Empty, Options); 3297case <= MultiVsRepeaterLimit when Kind == RegexNodeKind.One: 3303Kind = RegexNodeKind.Multi; 3312case RegexNodeKind.One: 3313case RegexNodeKind.Notone: 3314case RegexNodeKind.Set: 3315MakeRep(lazy ? RegexNodeKind.Onelazy : RegexNodeKind.Oneloop, min, max); 3319var result = new RegexNode(lazy ? RegexNodeKind.Lazyloop : RegexNodeKind.Loop, Options, min, max); 3450public bool IsSetFamily => Kind is RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy; 3453public bool IsOneFamily => Kind is RegexNodeKind.One or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy; 3456public bool IsNotoneFamily => Kind is RegexNodeKind.Notone or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy;
parent\src\System\Text\RegularExpressions\RegexParser.cs (87)
277StartGroup(new RegexNode(RegexNodeKind.Capture, (_options & ~RegexOptions.IgnoreCase), 0, -1)); 347_unit = new RegexNode(RegexNodeKind.Set, _options & ~RegexOptions.IgnoreCase, setString); 400_unit = new RegexNode((_options & RegexOptions.Multiline) != 0 ? RegexNodeKind.Bol : RegexNodeKind.Beginning, _options); 411_unit = new RegexNode((_options & RegexOptions.Multiline) != 0 ? RegexNodeKind.Eol : RegexNodeKind.EndZ, _options); 418_unit = new RegexNode(RegexNodeKind.Set, _options & ~RegexOptions.IgnoreCase, RegexCharClass.AnyClass); 422_unit = new RegexNode(RegexNodeKind.Set, _options & ~RegexOptions.IgnoreCase, RegexCharClass.NotAnyNewLineClass); 426_unit = new RegexNode(RegexNodeKind.Notone, _options & ~RegexOptions.IgnoreCase, '\n'); 544_concatenation = new RegexNode(RegexNodeKind.Concatenate, _options); 829return new RegexNode(RegexNodeKind.Group, _options); 833return new RegexNode(RegexNodeKind.Capture, _options, _autocap++, -1); 846RegexNodeKind nodeType; 853nodeType = RegexNodeKind.Group; 859nodeType = RegexNodeKind.PositiveLookaround; 865nodeType = RegexNodeKind.NegativeLookaround; 870nodeType = RegexNodeKind.Atomic; 893nodeType = RegexNodeKind.PositiveLookaround; 904nodeType = RegexNodeKind.NegativeLookaround; 1007return new RegexNode(RegexNodeKind.Capture, _options, capnum, uncapnum); 1029return new RegexNode(RegexNodeKind.BackreferenceConditional, _options, capnum); 1043return new RegexNode(RegexNodeKind.BackreferenceConditional, _options, tmpCapnum); 1048nodeType = RegexNodeKind.ExpressionConditional; 1072nodeType = RegexNodeKind.Group; 1075if (_group!.Kind != RegexNodeKind.ExpressionConditional || _group.ChildCount() > 0) 1166(_options & RegexOptions.AnyNewLine) != 0 ? AnyNewLineEndZNode() : new RegexNode(RegexNodeKind.EndZ, _options); 1171new RegexNode(RegexNodeKind.Set, (_options & ~RegexOptions.IgnoreCase), (_options & RegexOptions.ECMAScript) != 0 ? RegexCharClass.ECMAWordClass : RegexCharClass.WordClass); 1176new RegexNode(RegexNodeKind.Set, (_options & ~RegexOptions.IgnoreCase), (_options & RegexOptions.ECMAScript) != 0 ? RegexCharClass.NotECMAWordClass : RegexCharClass.NotWordClass); 1181new RegexNode(RegexNodeKind.Set, (_options & ~RegexOptions.IgnoreCase), (_options & RegexOptions.ECMAScript) != 0 ? RegexCharClass.ECMASpaceClass : RegexCharClass.SpaceClass); 1186new RegexNode(RegexNodeKind.Set, (_options & ~RegexOptions.IgnoreCase), (_options & RegexOptions.ECMAScript) != 0 ? RegexCharClass.NotECMASpaceClass : RegexCharClass.NotSpaceClass); 1191new RegexNode(RegexNodeKind.Set, (_options & ~RegexOptions.IgnoreCase), (_options & RegexOptions.ECMAScript) != 0 ? RegexCharClass.ECMADigitClass : RegexCharClass.DigitClass); 1196new RegexNode(RegexNodeKind.Set, (_options & ~RegexOptions.IgnoreCase), (_options & RegexOptions.ECMAScript) != 0 ? RegexCharClass.NotECMADigitClass : RegexCharClass.NotDigitClass); 1213return new RegexNode(RegexNodeKind.Set, (_options & ~RegexOptions.IgnoreCase), cc.ToStringClass()); 1217if (result != null && result.Kind == RegexNodeKind.Backreference && (result.Options & RegexOptions.IgnoreCase) != 0) 1278IsCaptureSlot(capnum) ? new RegexNode(RegexNodeKind.Backreference, _options, capnum) : 1310return scanOnly ? null : new RegexNode(RegexNodeKind.Backreference, _options, capnum); 1324return new RegexNode(RegexNodeKind.Backreference, _options, capnum); 1344_capnames?[capname] is int tmpCapnum ? new RegexNode(RegexNodeKind.Backreference, _options, tmpCapnum) : 1420return new RegexNode(RegexNodeKind.Backreference, _options, capnum); 1430return new RegexNode(RegexNodeKind.Backreference, _options, capnum); 1442return new RegexNode(RegexNodeKind.Backreference, _options, tmpCapnum); 1480return new RegexNode(RegexNodeKind.Backreference, _options, capnum); 1741var lookbehindCr = new RegexNode(RegexNodeKind.PositiveLookaround, lookbehindOpts); 1742lookbehindCr.AddChild(new RegexNode(RegexNodeKind.One, lookbehindOptsNoCase, '\r')); 1745var crThenLf = new RegexNode(RegexNodeKind.Concatenate, lookaheadOpts); 1747crThenLf.AddChild(new RegexNode(RegexNodeKind.One, lookaheadOptsNoCase, '\n')); 1750var guard = new RegexNode(RegexNodeKind.NegativeLookaround, lookaheadOpts); 1769var crlfEnd = new RegexNode(RegexNodeKind.Concatenate, lookaheadOpts); 1770crlfEnd.AddChild(new RegexNode(RegexNodeKind.One, lookaheadOptsNoCase, '\r')); 1771crlfEnd.AddChild(new RegexNode(RegexNodeKind.One, lookaheadOptsNoCase, '\n')); 1772crlfEnd.AddChild(new RegexNode(RegexNodeKind.End, lookaheadOpts)); 1775var anyNewLineOptEnd = new RegexNode(RegexNodeKind.Concatenate, lookaheadOpts); 1776anyNewLineOptEnd.AddChild(new RegexNode(RegexNodeKind.Set, lookaheadOptsNoCase, RegexCharClass.AnyNewLineClass).MakeQuantifier(false, 0, 1)); 1777anyNewLineOptEnd.AddChild(new RegexNode(RegexNodeKind.End, lookaheadOpts)); 1780var innerAlt = new RegexNode(RegexNodeKind.Alternate, lookaheadOpts); 1783var lookahead = new RegexNode(RegexNodeKind.PositiveLookaround, lookaheadOpts); 1787var result = new RegexNode(RegexNodeKind.Concatenate, opts); 1806var innerAlt = new RegexNode(RegexNodeKind.Alternate, lookaheadOpts); 1807innerAlt.AddChild(new RegexNode(RegexNodeKind.Set, lookaheadOptsNoCase, RegexCharClass.AnyNewLineClass)); 1808innerAlt.AddChild(new RegexNode(RegexNodeKind.End, lookaheadOpts)); 1809var lookahead = new RegexNode(RegexNodeKind.PositiveLookaround, lookaheadOpts); 1813var result = new RegexNode(RegexNodeKind.Concatenate, opts); 1832var innerAlt = new RegexNode(RegexNodeKind.Alternate, lookbehindOpts); 1833innerAlt.AddChild(new RegexNode(RegexNodeKind.Set, lookbehindOptsNoCase, RegexCharClass.AnyNewLineClass)); 1834innerAlt.AddChild(new RegexNode(RegexNodeKind.Beginning, lookbehindOpts)); 1835var lookbehind = new RegexNode(RegexNodeKind.PositiveLookaround, lookbehindOpts); 1839var result = new RegexNode(RegexNodeKind.Concatenate, opts); 1847private readonly RegexNodeKind TypeFromCode(char ch) => 1850'b' => (_options & RegexOptions.ECMAScript) != 0 ? RegexNodeKind.ECMABoundary : RegexNodeKind.Boundary, 1851'B' => (_options & RegexOptions.ECMAScript) != 0 ? RegexNodeKind.NonECMABoundary : RegexNodeKind.NonBoundary, 1852'A' => RegexNodeKind.Beginning, 1853'G' => RegexNodeKind.Start, 1854'Z' => RegexNodeKind.EndZ, 1855'z' => RegexNodeKind.End, 1856_ => RegexNodeKind.Nothing, 2198_concatenation!.AddChild(new RegexNode(RegexNodeKind.Multi, _options & ~RegexOptions.IgnoreCase, _pattern.Substring(pos, cch))); 2228if (_group.Kind == RegexNodeKind.ExpressionConditional && _group.ChildCount() == 0) 2244_alternation = new RegexNode(RegexNodeKind.Alternate, _options); 2245_concatenation = new RegexNode(RegexNodeKind.Concatenate, _options); 2253if (_group!.Kind is RegexNodeKind.ExpressionConditional or RegexNodeKind.BackreferenceConditional) 2262_concatenation = new RegexNode(RegexNodeKind.Concatenate, _options); 2268if (_group!.Kind is RegexNodeKind.ExpressionConditional or RegexNodeKind.BackreferenceConditional) 2272if (_group.Kind == RegexNodeKind.BackreferenceConditional && _group.ChildCount() > 2 || _group.ChildCount() > 3)
parent\src\System\Text\RegularExpressions\RegexPrefixAnalyzer.cs (224)
84case RegexNodeKind.Atomic: 85case RegexNodeKind.Capture: 90case RegexNodeKind.Bol: 91case RegexNodeKind.Eol: 92case RegexNodeKind.Boundary: 93case RegexNodeKind.ECMABoundary: 94case RegexNodeKind.NonBoundary: 95case RegexNodeKind.NonECMABoundary: 96case RegexNodeKind.Beginning: 97case RegexNodeKind.Start: 98case RegexNodeKind.EndZ: 99case RegexNodeKind.End: 100case RegexNodeKind.Empty: 101case RegexNodeKind.UpdateBumpalong: 102case RegexNodeKind.PositiveLookaround: 103case RegexNodeKind.NegativeLookaround: 112case RegexNodeKind.One or RegexNodeKind.Oneloop or RegexNodeKind.Onelazy or RegexNodeKind.Oneloopatomic when !ignoreCase || !RegexCharClass.ParticipatesInCaseConversion(node.Ch): 114int reps = node.Kind is RegexNodeKind.One ? 1 : Math.Min(node.M, MaxPrefixLength); 119return node.Kind is RegexNodeKind.One || reps == node.N; 124case RegexNodeKind.Multi: 156case RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic when !RegexCharClass.IsNegated(node.Str!): // negated sets are too complex to analyze 164int reps = node.Kind is RegexNodeKind.Set ? 1 : Math.Min(node.M, MaxPrefixLength); 209return node.Kind is RegexNodeKind.Set || reps == node.N; 212case RegexNodeKind.Concatenate: 226case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.M > 0: 242case RegexNodeKind.Alternate: 363case RegexNodeKind.Concatenate: 377case RegexNodeKind.Alternate when !rtl: // for RTL we'd need to be matching the suffixes of the alternation cases 422case RegexNodeKind.One: 427case RegexNodeKind.Multi: 432case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy when node.M > 0: 439case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.M > 0: 454case RegexNodeKind.Atomic: 455case RegexNodeKind.Capture: 459case RegexNodeKind.Bol: 460case RegexNodeKind.Eol: 461case RegexNodeKind.Boundary: 462case RegexNodeKind.ECMABoundary: 463case RegexNodeKind.NonBoundary: 464case RegexNodeKind.NonECMABoundary: 465case RegexNodeKind.Beginning: 466case RegexNodeKind.Start: 467case RegexNodeKind.EndZ: 468case RegexNodeKind.End: 469case RegexNodeKind.Empty: 470case RegexNodeKind.UpdateBumpalong: 471case RegexNodeKind.PositiveLookaround: 472case RegexNodeKind.NegativeLookaround: 491case RegexNodeKind.Atomic: 492case RegexNodeKind.Capture: 493case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.M > 0: 497case RegexNodeKind.Concatenate: 600case RegexNodeKind.One: 609case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when node.M > 0: 621case RegexNodeKind.Multi: 633case RegexNodeKind.Set: 641case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when node.M > 0: 652case RegexNodeKind.Notone: 658case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic when node.M == node.N: 662case RegexNodeKind.Beginning: 663case RegexNodeKind.Bol: 664case RegexNodeKind.Boundary: 665case RegexNodeKind.ECMABoundary: 666case RegexNodeKind.Empty: 667case RegexNodeKind.End: 668case RegexNodeKind.EndZ: 669case RegexNodeKind.Eol: 670case RegexNodeKind.NonBoundary: 671case RegexNodeKind.NonECMABoundary: 672case RegexNodeKind.UpdateBumpalong: 673case RegexNodeKind.Start: 674case RegexNodeKind.NegativeLookaround: 675case RegexNodeKind.PositiveLookaround: 681case RegexNodeKind.Atomic: 682case RegexNodeKind.Group: 683case RegexNodeKind.Capture: 686case RegexNodeKind.Lazyloop or RegexNodeKind.Loop when node.M > 0: 696case RegexNodeKind.Concatenate: 709case RegexNodeKind.Alternate when thorough: 954case RegexNodeKind.One or RegexNodeKind.Oneloop or RegexNodeKind.Onelazy or RegexNodeKind.Oneloopatomic: 959return node.Kind is RegexNodeKind.One || node.M > 0 ? true : null; 963case RegexNodeKind.Notone or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy: 977return node.Kind is RegexNodeKind.Notone || node.M > 0 ? true : null; 981case RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic: 996node.Kind is RegexNodeKind.Set || node.M > 0 ? true : 1000case RegexNodeKind.Multi: 1012case RegexNodeKind.Empty: 1013case RegexNodeKind.Nothing: 1014case RegexNodeKind.Bol: 1015case RegexNodeKind.Eol: 1016case RegexNodeKind.Boundary: 1017case RegexNodeKind.NonBoundary: 1018case RegexNodeKind.ECMABoundary: 1019case RegexNodeKind.NonECMABoundary: 1020case RegexNodeKind.Beginning: 1021case RegexNodeKind.Start: 1022case RegexNodeKind.EndZ: 1023case RegexNodeKind.End: 1024case RegexNodeKind.UpdateBumpalong: 1025case RegexNodeKind.PositiveLookaround: 1026case RegexNodeKind.NegativeLookaround: 1030case RegexNodeKind.Atomic: 1031case RegexNodeKind.Capture: 1037case RegexNodeKind.Loop: 1038case RegexNodeKind.Lazyloop: 1050case RegexNodeKind.Concatenate: 1081case RegexNodeKind.Alternate: 1102case RegexNodeKind.BackreferenceConditional: 1103case RegexNodeKind.ExpressionConditional: 1104int branchStart = node.Kind is RegexNodeKind.BackreferenceConditional ? 0 : 1; 1113case RegexNodeKind.Backreference: 1138while (node.Kind is RegexNodeKind.Atomic or RegexNodeKind.Capture) 1142if (node.Kind != RegexNodeKind.Concatenate) 1155while (firstChild.Kind is RegexNodeKind.Atomic or RegexNodeKind.Capture) 1159if (firstChild.Kind is not (RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy) || firstChild.N != int.MaxValue) 1167if (nextChild.Kind == RegexNodeKind.UpdateBumpalong) 1224while ((nextChild.Kind is RegexNodeKind.Atomic or RegexNodeKind.Capture or RegexNodeKind.Concatenate) || 1225(nextChild.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop && nextChild.M >= 1)) 1233(nextChild.Kind is RegexNodeKind.Set || nextChild.M >= 1)) 1279case RegexNodeKind.PositiveLookaround: 1284case RegexNodeKind.Bol: 1285case RegexNodeKind.Eol: 1286case RegexNodeKind.Beginning: 1287case RegexNodeKind.Start: 1288case RegexNodeKind.EndZ: 1289case RegexNodeKind.End: 1290case RegexNodeKind.Boundary: 1291case RegexNodeKind.ECMABoundary: 1292case RegexNodeKind.NegativeLookaround: 1293case RegexNodeKind.Empty: 1297case RegexNodeKind.Atomic: 1298case RegexNodeKind.Capture: 1303case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.M >= 1: 1309case RegexNodeKind.Concatenate: 1330public static RegexNodeKind FindLeadingAnchor(RegexNode node) => 1334public static RegexNodeKind FindTrailingAnchor(RegexNode node) => 1338private static RegexNodeKind FindLeadingOrTrailingAnchor(RegexNode node, bool leading) 1344return RegexNodeKind.Unknown; 1351case RegexNodeKind.Bol: 1352case RegexNodeKind.Eol: 1353case RegexNodeKind.Beginning: 1354case RegexNodeKind.Start: 1355case RegexNodeKind.EndZ: 1356case RegexNodeKind.End: 1360case RegexNodeKind.Atomic: 1361case RegexNodeKind.Capture: 1362case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when leading && node.M >= 1: 1363case RegexNodeKind.PositiveLookaround when leading && (node.Options & RegexOptions.RightToLeft) == 0: 1373case RegexNodeKind.Concatenate: 1380RegexNodeKind bestAnchorFound = RegexNodeKind.Unknown; 1388case RegexNodeKind.Empty or RegexNodeKind.NegativeLookaround: 1389case RegexNodeKind.PositiveLookaround when ((node.Options | tmpChild.Options) & RegexOptions.RightToLeft) != 0: 1390case RegexNodeKind.Boundary or RegexNodeKind.ECMABoundary or RegexNodeKind.NonBoundary or RegexNodeKind.NonECMABoundary: 1394case RegexNodeKind.PositiveLookaround: 1416if (node.Child(i).Kind is not (RegexNodeKind.Empty or RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround)) 1424if (bestAnchorFound is not RegexNodeKind.Unknown) 1446static RegexNodeKind ChooseBetterAnchor(RegexNodeKind anchor1, RegexNodeKind anchor2) 1449anchor1 == RegexNodeKind.Unknown ? anchor2 : 1450anchor2 == RegexNodeKind.Unknown ? anchor1 : 1454static int RankAnchorQuality(RegexNodeKind node) => 1457RegexNodeKind.Beginning => 3, 1458RegexNodeKind.Start => 3, 1459RegexNodeKind.End => 3, 1460RegexNodeKind.EndZ => 3, 1462RegexNodeKind.Bol => 2, 1463RegexNodeKind.Eol => 2, 1465RegexNodeKind.Boundary => 1, 1466RegexNodeKind.ECMABoundary => 1, 1472static bool IsBestAnchor(RegexNodeKind anchor) => 1474anchor is RegexNodeKind.Beginning or RegexNodeKind.Start or RegexNodeKind.End or RegexNodeKind.EndZ; 1477case RegexNodeKind.Alternate: 1481RegexNodeKind anchor = FindLeadingOrTrailingAnchor(node.Child(0), leading); 1482if (anchor == RegexNodeKind.Unknown) 1484return RegexNodeKind.Unknown; 1494return RegexNodeKind.Unknown; 1504return RegexNodeKind.Unknown;
parent\src\System\Text\RegularExpressions\RegexTreeAnalyzer.cs (16)
59case RegexNodeKind.Atomic: 60case RegexNodeKind.NegativeLookaround: 61case RegexNodeKind.PositiveLookaround: 66case RegexNodeKind.Capture: 71case RegexNodeKind.Loop: 72case RegexNodeKind.Lazyloop: 90RegexNodeKind.Atomic or RegexNodeKind.NegativeLookaround or RegexNodeKind.PositiveLookaround => true, 94RegexNodeKind.Alternate or RegexNodeKind.BackreferenceConditional or RegexNodeKind.ExpressionConditional => true, 97RegexNodeKind.Capture => true, 101RegexNodeKind.Concatenate => i == childCount - 1, 107RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.N == 1 => true,
RegexGenerator.cs (1)
373if (node.Kind is RegexNodeKind.Backreference && (node.Options & RegexOptions.IgnoreCase) != 0)
RegexGenerator.Emitter.cs (210)
760if (root.Kind is RegexNodeKind.Empty) 769else if (root.Kind is RegexNodeKind.Nothing) 775else if (root.Kind is RegexNodeKind.Multi or RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set) 784writer.WriteLine($"int end = base.runtextpos = start {(!rtl ? "+" : "-")} {(root.Kind == RegexNodeKind.Multi ? root.Str!.Length : 1)};"); 812rm.Tree.FindOptimizations.LeadingAnchor != RegexNodeKind.Unknown || 813rm.Tree.FindOptimizations.TrailingAnchor != RegexNodeKind.Unknown; 960if (RegexPrefixAnalyzer.FindTrailingAnchor(regexTree.Root) == RegexNodeKind.End && 1082case RegexNodeKind.Bol: 1118case RegexNodeKind.End when regexTree.FindOptimizations.MaxPossibleLength is int maxLength: 1127case RegexNodeKind.EndZ when regexTree.FindOptimizations.MaxPossibleLength is int maxLength: 1503Debug.Assert(target.LoopNode.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic); 1625Debug.Assert(node.Kind == RegexNodeKind.Capture, "Every generated tree should begin with a capture node"); 1807Debug.Assert(node.Kind is RegexNodeKind.Alternate, $"Unexpected type: {node.Kind}"); 1909case RegexNodeKind.One: 1910case RegexNodeKind.Set: 1915case RegexNodeKind.Multi: 1922case RegexNodeKind.Concatenate when child.Child(0) == startingLiteralNode && (startingLiteralNode.Kind is RegexNodeKind.One or RegexNodeKind.Set or RegexNodeKind.Multi): 1932child.Child(0).Kind is RegexNodeKind.Multi ? 1934new RegexNode(RegexNodeKind.Empty, child.Options)); // single, so removing it yields empty 1978Debug.Assert(multi.Kind is RegexNodeKind.Multi, $"Expected a Multi node, got {multi.Kind}"); 1980new(RegexNodeKind.One, multi.Options, multi.Str[1]) : 1981new(RegexNodeKind.Multi, multi.Options, multi.Str.Substring(1)); 2205Debug.Assert(node.Kind is RegexNodeKind.Backreference, $"Unexpected type: {node.Kind}"); 2274Debug.Assert(node.Kind is RegexNodeKind.BackreferenceConditional, $"Unexpected type: {node.Kind}"); 2287RegexNode? noBranch = node.Child(1) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null; 2447Debug.Assert(node.Kind is RegexNodeKind.ExpressionConditional, $"Unexpected type: {node.Kind}"); 2463RegexNode? noBranch = node.Child(2) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null; 2627Debug.Assert(node.Kind is RegexNodeKind.Capture, $"Unexpected type: {node.Kind}"); 2720Debug.Assert(node.Kind is RegexNodeKind.PositiveLookaround, $"Unexpected type: {node.Kind}"); 2761Debug.Assert(node.Kind is RegexNodeKind.NegativeLookaround, $"Unexpected type: {node.Kind}"); 2894case RegexNodeKind.Empty: 2898case RegexNodeKind.Nothing: 2903case RegexNodeKind.Atomic when !rm.Analysis.MayBacktrack(node.Child(0)): 2909case RegexNodeKind.Concatenate: 2921case RegexNodeKind.Beginning: 2922case RegexNodeKind.Start: 2923case RegexNodeKind.Bol: 2924case RegexNodeKind.Eol: 2925case RegexNodeKind.End: 2926case RegexNodeKind.EndZ: 2930case RegexNodeKind.Boundary: 2931case RegexNodeKind.NonBoundary: 2932case RegexNodeKind.ECMABoundary: 2933case RegexNodeKind.NonECMABoundary: 2937case RegexNodeKind.One: 2938case RegexNodeKind.Notone: 2939case RegexNodeKind.Set: 2943case RegexNodeKind.Multi when (node.Options & RegexOptions.RightToLeft) == 0: 2947case RegexNodeKind.UpdateBumpalong: 2958case RegexNodeKind.Multi: 2962case RegexNodeKind.Oneloop: 2963case RegexNodeKind.Notoneloop: 2964case RegexNodeKind.Setloop: 2968case RegexNodeKind.Onelazy: 2969case RegexNodeKind.Notonelazy: 2970case RegexNodeKind.Setlazy: 2974case RegexNodeKind.Oneloopatomic: 2975case RegexNodeKind.Notoneloopatomic: 2976case RegexNodeKind.Setloopatomic: 2980case RegexNodeKind.Loop: 2984case RegexNodeKind.Lazyloop: 2988case RegexNodeKind.Alternate: 2992case RegexNodeKind.Backreference: 2996case RegexNodeKind.BackreferenceConditional: 3000case RegexNodeKind.ExpressionConditional: 3004case RegexNodeKind.Atomic: 3009case RegexNodeKind.Capture: 3013case RegexNodeKind.PositiveLookaround: 3017case RegexNodeKind.NegativeLookaround: 3030Debug.Assert(node.Kind is RegexNodeKind.Atomic or RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround or RegexNodeKind.ExpressionConditional, $"Unexpected type: {node.Kind}"); 3031Debug.Assert(node.Kind is RegexNodeKind.ExpressionConditional ? node.ChildCount() >= 1 : node.ChildCount() == 1, $"Unexpected number of children: {node.ChildCount()}"); 3033Debug.Assert(node.Kind is RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround or RegexNodeKind.ExpressionConditional || rm.Analysis.MayBacktrack(node.Child(0)), "Expected lookaround/conditional or a child that may backtrack"); 3060Debug.Assert(node.Kind is RegexNodeKind.UpdateBumpalong, $"Unexpected type: {node.Kind}"); 3072Debug.Assert(node.Kind is RegexNodeKind.Concatenate, $"Unexpected type: {node.Kind}"); 3120else if (child.Kind is RegexNodeKind.Multi) 3131int repeatCount = child.Kind is RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set ? 1 : child.M; 3189if (next.Kind is not RegexNodeKind.UpdateBumpalong) // skip node types that don't have a semantic impact 3246Debug.Assert(node.Kind is RegexNodeKind.Boundary or RegexNodeKind.NonBoundary or RegexNodeKind.ECMABoundary or RegexNodeKind.NonECMABoundary, $"Unexpected kind: {node.Kind}"); 3248string negation = node.Kind is RegexNodeKind.Boundary or RegexNodeKind.ECMABoundary ? "!" : ""; 3253case RegexNodeKind.Boundary or RegexNodeKind.NonBoundary: 3286Debug.Assert(node.Kind is RegexNodeKind.Beginning or RegexNodeKind.Start or RegexNodeKind.Bol or RegexNodeKind.End or RegexNodeKind.EndZ or RegexNodeKind.Eol, $"Unexpected type: {node.Kind}"); 3292case RegexNodeKind.Beginning: 3293case RegexNodeKind.Start: 3302using (EmitBlock(writer, node.Kind == RegexNodeKind.Beginning ? 3311case RegexNodeKind.Bol: 3320case RegexNodeKind.End: 3329case RegexNodeKind.EndZ: 3338case RegexNodeKind.Eol: 3352Debug.Assert(node.Kind is RegexNodeKind.Multi, $"Unexpected type: {node.Kind}"); 3401Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop, $"Unexpected type: {node.Kind}"); 3500RegexNodeKind.One or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy => 3502RegexNodeKind.Notone or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy => 3504RegexNodeKind.Multi => 3579Debug.Assert(node.Kind is RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy, $"Unexpected type: {node.Kind}"); 3680node.Kind is RegexNodeKind.Notonelazy && 3747node.Kind is RegexNodeKind.Setlazy && 3826Debug.Assert(node.Kind is RegexNodeKind.Lazyloop, $"Unexpected type: {node.Kind}"); 4252Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic, $"Unexpected type: {node.Kind}"); 4384Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic, $"Unexpected type: {node.Kind}"); 4422Debug.Assert(node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop, $"Unexpected type: {node.Kind}"); 4442Debug.Assert(node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop, $"Unexpected type: {node.Kind}"); 5064if (node.Kind == RegexNodeKind.Multi) 5589RegexNodeKind.Alternate => $"Match with {node.ChildCount()} alternative expressions{(rm.Analysis.IsAtomicByAncestor(node) ? ", atomically" : "")}.", 5590RegexNodeKind.Atomic => $"Atomic group.", 5591RegexNodeKind.Beginning => "Match if at the beginning of the string.", 5592RegexNodeKind.Bol => "Match if at the beginning of a line.", 5593RegexNodeKind.Boundary => $"Match if at a word boundary.", 5594RegexNodeKind.Capture when node.M == -1 && node.N != -1 => $"Non-capturing balancing group. Uncaptures the {DescribeCapture(node.N, rm)}.", 5595RegexNodeKind.Capture when node.N != -1 => $"Balancing group. Captures the {DescribeCapture(node.M, rm)} and uncaptures the {DescribeCapture(node.N, rm)}.", 5596RegexNodeKind.Capture when node.N == -1 => $"{DescribeCapture(node.M, rm)}.", 5597RegexNodeKind.Concatenate => "Match a sequence of expressions.", 5598RegexNodeKind.ECMABoundary => $"Match if at a word boundary (according to ECMAScript rules).", 5599RegexNodeKind.Empty => $"Match an empty string.", 5600RegexNodeKind.End => "Match if at the end of the string.", 5601RegexNodeKind.EndZ => "Match if at the end of the string or if before an ending newline.", 5602RegexNodeKind.Eol => "Match if at the end of a line.", 5603RegexNodeKind.Loop or RegexNodeKind.Lazyloop => node.M == 0 && node.N == 1 ? $"Optional ({(node.Kind is RegexNodeKind.Loop ? "greedy" : "lazy")})." : $"Loop {DescribeLoop(node, rm)}{direction}.", 5604RegexNodeKind.Multi => $"Match the string {Literal(node.Str!)}{direction}.", 5605RegexNodeKind.NonBoundary => $"Match if at anything other than a word boundary.", 5606RegexNodeKind.NonECMABoundary => $"Match if at anything other than a word boundary (according to ECMAScript rules).", 5607RegexNodeKind.Nothing => $"Fail to match.", 5608RegexNodeKind.Notone => $"Match any character other than {Literal(node.Ch)}{direction}.", 5609RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy => $"Match a character other than {Literal(node.Ch)} {DescribeLoop(node, rm)}{direction}.", 5610RegexNodeKind.One => $"Match {Literal(node.Ch)}{direction}.", 5611RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy => $"Match {Literal(node.Ch)} {DescribeLoop(node, rm)}{direction}.", 5612RegexNodeKind.NegativeLookaround => $"Zero-width negative {(rtl ? "lookbehind" : "lookahead")}.", 5613RegexNodeKind.Backreference => $"Match the same text as matched by the {DescribeCapture(node.M, rm)}{direction}.", 5614RegexNodeKind.PositiveLookaround => $"Zero-width positive {(rtl ? "lookbehind" : "lookahead")}.", 5615RegexNodeKind.Set => $"Match {DescribeSet(node.Str!)}{direction}.", 5616RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy => $"Match {DescribeSet(node.Str!)} {DescribeLoop(node, rm)}{direction}.", 5617RegexNodeKind.Start => "Match if at the start position.", 5618RegexNodeKind.ExpressionConditional => $"Conditionally match one of two expressions depending on whether an initial expression matches.", 5619RegexNodeKind.BackreferenceConditional => $"Conditionally match one of two expressions depending on whether the {DescribeCapture(node.M, rm)} matched.", 5620RegexNodeKind.UpdateBumpalong => $"Advance the next matching position.", 5771RegexNodeKind.Concatenate when node.Parent is not { Kind: RegexNodeKind.Alternate or RegexNodeKind.BackreferenceConditional or RegexNodeKind.ExpressionConditional } => true, 5774RegexNodeKind.Atomic when node.Child(0).Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop or RegexNodeKind.Alternate => true, 5777RegexNodeKind.UpdateBumpalong => true, 5787RegexNodeKind.ExpressionConditional when node.Parent.Child(0) == node => "Condition: ", 5788RegexNodeKind.ExpressionConditional when node.Parent.Child(1) == node => "Matched: ", 5789RegexNodeKind.ExpressionConditional when node.Parent.Child(2) == node => "Not Matched: ", 5791RegexNodeKind.BackreferenceConditional when node.Parent.Child(0) == node => "Matched: ", 5792RegexNodeKind.BackreferenceConditional when node.Parent.Child(1) == node => "Not Matched: ", 5832RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloopatomic => "atomically", 5833RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop => "greedily", 5834RegexNodeKind.Loop => rm.Analysis.IsAtomicByAncestor(node) ? "atomically" : "greedily",