diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexElementLabel.cs b/StgSharp.RegularAnalysis/TextRegex/RegexElementLabel.cs
index 67ee3515..dec57691 100644
--- a/StgSharp.RegularAnalysis/TextRegex/RegexElementLabel.cs
+++ b/StgSharp.RegularAnalysis/TextRegex/RegexElementLabel.cs
@@ -49,6 +49,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
SEQUENCE = UNIT | UNIT_SPAN | UNIT_SET,
SINGLE = UNIT | UNIT_SET,
OPERATOR = COUNT | ALT | CONCAT,
+ VAST_OPERATOR = OPERATOR | GROUP_BEGIN,
ATOM_BEGIN = SEQUENCE | GROUP_BEGIN ,
ATOM_END = SEQUENCE | GROUP_END | COUNT,
diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexIR.cs b/StgSharp.RegularAnalysis/TextRegex/RegexIR.cs
index bd10f273..e1aa0871 100644
--- a/StgSharp.RegularAnalysis/TextRegex/RegexIR.cs
+++ b/StgSharp.RegularAnalysis/TextRegex/RegexIR.cs
@@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
@@ -36,12 +37,16 @@ namespace StgSharp.RegularAnalysis.TextRegex
internal enum RegexIRCommand
{
- Search = 0,
- Jump = 1,
- Condition = 2,
- Count = 3,
- Try = 4,
- Pop = 5,
+ Search_Seq = 0,
+ Search_Set = 1,
+ SearchChar = 2,
+ Jump = 3,
+ Condition = 4,
+ Try = 5,
+ Pop = 6,
+ Count = 7,
+ Count_Seq = 8,
+ Count_Set = 9
}
@@ -50,28 +55,6 @@ namespace StgSharp.RegularAnalysis.TextRegex
internal abstract RegexIRCommand Command { get; }
- public static RegexIR Condition(
- int success,
- int fail
- )
- {
- return new RegexConditionIR(success, fail);
- }
-
- public static RegexIR PopLevel(
- bool isSuccess
- )
- {
- return new RegexPopIR(isSuccess);
- }
-
- public static RegexIR Try(
- int count
- )
- {
- return new RegexTryIR(count);
- }
-
internal abstract void Execute();
}
@@ -95,14 +78,14 @@ namespace StgSharp.RegularAnalysis.TextRegex
///
/// Searches for a certain string pattern or charset from current position.
///
- internal sealed class RegexSearchStringIR(
+ internal sealed class RegexSearchSeqIR(
string pattern
) : RegexIR
{
public string Pattern { get; } = pattern;
- internal override RegexIRCommand Command => RegexIRCommand.Search;
+ internal override RegexIRCommand Command => RegexIRCommand.Search_Seq;
internal override void Execute()
{
@@ -111,30 +94,14 @@ namespace StgSharp.RegularAnalysis.TextRegex
}
- internal sealed class RegexSearchCharsetIR(
+ internal sealed class RegexMatchSetIR(
string charset
) : RegexIR
{
public string Charset { get; } = charset;
- internal override RegexIRCommand Command => RegexIRCommand.Search;
-
- internal override void Execute()
- {
- throw new NotImplementedException();
- }
-
- }
-
- internal sealed class RegexSearchCharSetIR(
- string c
- ) : RegexIR
- {
-
- public string Target { get; } = c;
-
- internal override RegexIRCommand Command => RegexIRCommand.Search;
+ internal override RegexIRCommand Command => RegexIRCommand.Search_Set;
internal override void Execute()
{
@@ -200,7 +167,57 @@ namespace StgSharp.RegularAnalysis.TextRegex
public int OperationIndex { get; } = operation;
- internal override RegexIRCommand Command => throw new NotImplementedException();
+ internal override RegexIRCommand Command { get; } = RegexIRCommand.Count;
+
+ internal override void Execute()
+ {
+ throw new NotImplementedException();
+ }
+
+ }
+
+ internal sealed class RegexCountSeqIR(
+ int min,
+ int max,
+ bool isGreedy,
+ string seq
+ ) : RegexIR
+ {
+
+ public bool IsGreedy { get; } = isGreedy;
+
+ public int Min { get; } = min;
+
+ public int Max { get; } = max;
+
+ public string Sequence { get; } = seq;
+
+ internal override RegexIRCommand Command { get; } = RegexIRCommand.Count_Seq;
+
+ internal override void Execute()
+ {
+ throw new NotImplementedException();
+ }
+
+ }
+
+ internal sealed class RegexCountSetIR(
+ int min,
+ int max,
+ bool isGreedy,
+ string set
+ ) : RegexIR
+ {
+
+ public bool IsGreedy { get; } = isGreedy;
+
+ public int Min { get; } = min;
+
+ public int Max { get; } = max;
+
+ public string CharSet { get; } = set;
+
+ internal override RegexIRCommand Command => RegexIRCommand.Count_Set;
internal override void Execute()
{
diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexIRGenerator.cs b/StgSharp.RegularAnalysis/TextRegex/RegexIRGenerator.cs
new file mode 100644
index 00000000..e4268348
--- /dev/null
+++ b/StgSharp.RegularAnalysis/TextRegex/RegexIRGenerator.cs
@@ -0,0 +1,168 @@
+//-----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+// file="RegexIRGenerator"
+// Project: StgSharp
+// AuthorGroup: Nitload
+// Copyright (c) Nitload. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace StgSharp.RegularAnalysis.TextRegex
+{
+ internal class RegexIRGenerator
+ {
+
+ private Node _head = new();
+ private Node _tail;
+
+ public RegexIRGenerator()
+ {
+ _tail = _head;
+ }
+
+ public int Count { get; private set; }
+
+ public void EmitCondition(
+ int success,
+ int fail
+ )
+ {
+ _tail.Add(new RegexConditionIR(success, fail));
+ Count++;
+ }
+
+ public void EmitCount(
+ int min,
+ int max,
+ bool isGreedy,
+ int operation
+ )
+ {
+ _tail.Add(new RegexCountIR(min, max, isGreedy, operation));
+ Count++;
+ }
+
+ public void EmitCountSeq(
+ int min,
+ int max,
+ bool isGreedy,
+ string seq
+ )
+ {
+ _tail.Add(new RegexCountSeqIR(min, max, isGreedy, seq));
+ Count++;
+ }
+
+ public void EmitCountSet(
+ int min,
+ int max,
+ bool isGreedy,
+ string set
+ )
+ {
+ _tail.Add(new RegexCountSetIR(min, max, isGreedy, set));
+ Count++;
+ }
+
+ public void EmitIRStream(
+ RegexIRGenerator stream
+ )
+ {
+ if (stream is null || stream.Count == 0) {
+ return;
+ }
+ _tail.Next = stream._head;
+ _tail = stream._tail;
+ Count += stream.Count;
+ }
+
+ public void EmitMatchSet(
+ string unit
+ )
+ {
+ _tail.Add(new RegexMatchSetIR(unit));
+ Count++;
+ }
+
+ public void EmitMatchSeq(
+ string unit
+ )
+ {
+ _tail.Add(new RegexMatchSeqIR(unit));
+ Count++;
+ }
+
+ public void EmitPopLevel(
+ bool isSuccess
+ )
+ {
+ _tail.Add(new RegexPopIR(isSuccess));
+ Count++;
+ }
+
+ public void EmitTry(
+ int count
+ )
+ {
+ _tail.Add(new RegexTryIR(count));
+ Count++;
+ }
+
+ public List ToList()
+ {
+ List result = new(Count);
+ Node current = _head;
+ while (current != null)
+ {
+ result.AddRange(current.IRList);
+ current = current.Next!;
+ }
+ return result;
+ }
+
+ private class Node
+ {
+
+ public Node? Next { get; set; }
+
+ public int Count => IRList.Count;
+
+ public List IRList { get; } = [];
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Add(
+ RegexIR ir
+ )
+ {
+ IRList.Add(ir);
+ }
+
+ }
+
+ }
+}
diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.IRGenerate.cs b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.IRGenerate.cs
index b07bbe1a..04f06670 100644
--- a/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.IRGenerate.cs
+++ b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.IRGenerate.cs
@@ -28,8 +28,12 @@
using StgSharp.RegularAnalysis.Abstraction;
using System;
using System.Collections.Generic;
+using System.ComponentModel.Design;
using System.Data;
+using System.Diagnostics.Metrics;
using System.Linq;
+using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
@@ -45,27 +49,68 @@ namespace StgSharp.RegularAnalysis.TextRegex
AbstractSyntaxTree tree
)
{
- return GenerateIRRecursion(tree.Root, 0);
+ return GenerateIRRecursion(tree.Root, 0).ToList();
}
- private List GenerateIRRecursion(
- RegexAstNode node,
- int depth
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void EmitCount(
+ int curDepth,
+ RegexIRGenerator ir,
+ int min,
+ int max,
+ bool isGreedy,
+ RegexAstNode right
)
{
- if (depth > 1024) {
+ bool isRightOperator = !RegexAstNode.IsNullOrEmpty(right) &&
+ (right.Source.Flag & RegexElementLabel.OPERATOR) != 0;
+
+ if (isRightOperator) // seq to be count is complex
+ {
+ ir.EmitCount(min, max, isGreedy, 1);
+ RegexIRGenerator rightIR = GenerateIRRecursion(right, curDepth + 1);
+ ir.EmitTry(rightIR.Count);
+ ir.EmitIRStream(rightIR);
+ } else
+ {
+ RegexElementLabel count_source_mask = right.Source.Flag;
+ switch (count_source_mask)
+ {
+ case RegexElementLabel.UNIT:
+ ir.EmitCountSeq(min, max, isGreedy, right.Source.Value);
+ break;
+ case RegexElementLabel.UNIT_SET:
+ ir.EmitCountSet(min, max, isGreedy, right.Source.Value);
+ break;
+ case RegexElementLabel.UNIT_SPAN:
+ ir.EmitCountSet(min, max, isGreedy, right.Source.Value);
+ break;
+ default:
+ throw new InvalidOperationException($"Unexpected regex element type for count operator: {count_source_mask}");
+ }
+ }
+ }
+
+ private RegexIRGenerator GenerateIRRecursion(
+ RegexAstNode node,
+ int depth
+ )
+ {
+#pragma warning disable IDE0010
+ if (depth > 1024)
+ {
throw new OverflowException("Regex parse exceeds maximum recursion depth");
}
int curDepth = depth;
RegexAstNode left = node.Left;
RegexAstNode right = node.Right;
- List leftIR = EmptyIR;
- List rightIR = EmptyIR;
+ RegexIRGenerator leftIR;
+ RegexIRGenerator rightIR;
bool isLeftOperator = !RegexAstNode.IsNullOrEmpty(left) &&
- (left.Source.Flag & RegexElementLabel.OPERATOR) != 0;
+ (left.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0;
bool isRightOperator = !RegexAstNode.IsNullOrEmpty(right) &&
- (right.Source.Flag & RegexElementLabel.OPERATOR) != 0;
+ (right.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0;
Token token = node.Source;
@@ -73,30 +118,127 @@ namespace StgSharp.RegularAnalysis.TextRegex
{
case RegexElementLabel.GROUP_BEGIN:
string group_source = token.Value;
- bool is_group = group_source.Length == 1;
- string group_name = group_source.StartsWith(@"(?<", StringComparison.Ordinal) ?
- group_source[3..^2] :
- string.Empty;
- List groupIR = [];
+ // process group type
+ bool is_group = group_source.Length == 1; // simple group: (pattern)
+ string group_name =
+ group_source.StartsWith(@"(?<", StringComparison.Ordinal) ?
+ group_source[3..^2] : /* named group (?) */
+ string.Empty; /* unnamed group (?:) */
+
+ RegexIRGenerator groupIR = new();
rightIR = GenerateIRRecursion(right, curDepth + 1);
- groupIR.Add(RegexIR.Try(rightIR.Count));
- groupIR.AddRange(rightIR);
- groupIR.Add(RegexIR.Condition(2, 1));
- groupIR.Add(RegexIR.PopLevel(false));
- groupIR.Add(RegexIR.PopLevel(true));
- break;
- case RegexElementLabel.COUNT:
- break;
- case RegexElementLabel.CONCAT:
- break;
- case RegexElementLabel.ALT:
- break;
- default:
- break;
- }
+ groupIR.EmitTry(rightIR.Count);
+ groupIR.EmitIRStream(rightIR);
+ groupIR.EmitCondition(2, 1);
+ groupIR.EmitPopLevel(false);
- return [];
+ // a grouping op needed here, before popping
+ groupIR.EmitPopLevel(true);
+ return groupIR;
+ case RegexElementLabel.COUNT:
+ string count_source = token.Value;
+ bool isGreedy = !(count_source.Length > 1 && !count_source.EndsWith('?'));
+ ReadOnlySpan count_source_span = count_source;
+ RegexIRGenerator countIR = new();
+
+ if (count_source_span[0] == '*') // infinite count
+ {
+ EmitCount(curDepth, countIR, 0, int.MaxValue, isGreedy, right);
+ } else if (count_source_span[0] == '+') // at least one
+ {
+ EmitCount(curDepth, countIR, 1, int.MaxValue, isGreedy, right);
+ } else if (count_source_span[0] == '?') // zero or one
+ {
+ EmitCount(curDepth, countIR, 0, 1, isGreedy, right);
+ } else if (count_source_span[0] == '{') // zero or one, non-greedy
+ {
+ int comma_pos = count_source_span.IndexOf(',');
+ if (comma_pos == -1)
+ {
+ if (int.TryParse(count_source[1..(isGreedy ? ^3 : ^2)], out int count))
+ {
+ EmitCount(curDepth, countIR, count, count, isGreedy, right);
+ } else
+ {
+ throw new InvalidCastException($"Invalid count format: {count_source}");
+ }
+ } else
+ {
+ if (int.TryParse(count_source[1..comma_pos], out int min) &&
+ int.TryParse(count_source[(comma_pos + 1)..(isGreedy ? ^3 : ^2)], out int max))
+ {
+ EmitCount(curDepth, countIR, min, max, isGreedy, right);
+ } else
+ {
+ throw new InvalidCastException($"Invalid count format: {count_source}");
+ }
+ }
+ } else
+ {
+ throw new InvalidOperationException();
+ } // unknown count format
+
+ return countIR;
+ case RegexElementLabel.CONCAT:
+ RegexIRGenerator concat = new();
+
+ // process left node
+ if (RegexAstNode.IsNullOrEmpty(left))
+ {
+ // do nothing
+ } else if ((left.Source.Flag & RegexElementLabel.SEQUENCE) != 0)
+ {
+ switch (left.Source.Flag)
+ {
+ case RegexElementLabel.UNIT_SPAN:
+ goto case RegexElementLabel.UNIT_SPAN;
+ case RegexElementLabel.UNIT:
+ concat.EmitMatchSeq(left.Source.Value);
+ break;
+ case RegexElementLabel.UNIT_SET:
+ concat.EmitMatchSet(left.Source.Value);
+ break;
+ default:
+ break;
+ }
+ } else if ((left.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0)
+ {
+ leftIR = GenerateIRRecursion(left, curDepth + 1);
+ concat.EmitIRStream(leftIR);
+ }
+
+ // process right node
+ if (RegexAstNode.IsNullOrEmpty(right))
+ {
+ // do nothing
+ } else if ((right.Source.Flag & RegexElementLabel.SEQUENCE) != 0)
+ {
+ switch (right.Source.Flag)
+ {
+ case RegexElementLabel.UNIT_SPAN:
+ goto case RegexElementLabel.UNIT;
+ case RegexElementLabel.UNIT:
+ concat.EmitMatchSeq(right.Source.Value);
+ break;
+ case RegexElementLabel.UNIT_SET:
+ concat.EmitMatchSet(right.Source.Value);
+ break;
+ default:
+ break;
+ }
+ } else if ((right.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0)
+ {
+ rightIR = GenerateIRRecursion(right, curDepth + 1);
+ concat.EmitIRStream(rightIR);
+ }
+ return concat;
+ case RegexElementLabel.ALT:
+ return null!;
+ default:
+ return null!;
+ }
+#pragma warning restore IDE0010
}
}
diff --git a/future/ngra-regex-ir.md b/future/ngra-regex-ir.md
index 7de080ee..5e563832 100644
--- a/future/ngra-regex-ir.md
+++ b/future/ngra-regex-ir.md
@@ -22,3 +22,5 @@
4. 条件指令(CONDITION %cmd_true %cmd_fail),比较前一条SEARCH指令是否成功,并指定跳转到指定的位置,如果某种条件不需要跳转,请使用0进行填充
5. 跳转执行指令(TRY %begin %end),尝试idx指向的IR块,并记住执行结果数据
6. 计数指令(COUNT %min %max %is_greedy %cmd),重复执行指令cmd,直到满足参数配置的数量为止
+7. 快速序列计数指令(COUNT_SEQ %min %max %is_greedy %seq),快速搜索一个确定性序列,直到满足参数配置的数量为止
+8. 快速字符集计数指令(COUNT_SET %min %max %is_greedy %set),快速搜索一个字符集,直到满足参数配置的数量为止
\ No newline at end of file
diff --git a/future/sample.cs b/future/sample.cs
deleted file mode 100644
index 0250f0d5..00000000
--- a/future/sample.cs
+++ /dev/null
@@ -1,501 +0,0 @@
-//
-#nullable enable
-#pragma warning disable
-
-namespace StgSharp
-{
- partial class TestRegexAnalyse
- {
- ///
- /// Pattern:
- /// a*.[abc]*(abcd|a(bc)c)+(?<name>abc)
- /// Explanation:
- ///
- /// ○ Match 'a' greedily any number of times.
- /// ○ Match any character other than '\n'.
- /// ○ Match a character in the set [a-c] greedily any number of times.
- /// ○ Loop greedily at least once.
- /// ○ 1st capture group.
- /// ○ Match 'a'.
- /// ○ Match with 2 alternative expressions.
- /// ○ Match the string "bcd".
- /// ○ Match a sequence of expressions.
- /// ○ 2nd capture group.
- /// ○ Match the string "bc".
- /// ○ Match 'c'.
- /// ○ "name" capture group.
- /// ○ Match the string "abc".
- ///
- ///
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "10.0.14.27113")]
- internal static partial global::System.Text.RegularExpressions.Regex GetRegex() => global::System.Text.RegularExpressions.Generated.GetRegex_0.Instance;
- }
-}
-
-namespace System.Text.RegularExpressions.Generated
-{
- using System;
- using System.Buffers;
- using System.CodeDom.Compiler;
- using System.Collections;
- using System.ComponentModel;
- using System.Globalization;
- using System.Runtime.CompilerServices;
- using System.Text.RegularExpressions;
- using System.Threading;
-
- /// Custom -derived type for the GetRegex method.
- [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "10.0.14.27113")]
- file sealed class GetRegex_0 : Regex
- {
- /// Cached, thread-safe singleton instance.
- internal static readonly GetRegex_0 Instance = new();
-
- /// Initializes the instance.
- private GetRegex_0()
- {
- base.pattern = "a*.[abc]*(abcd|a(bc)c)+(?abc)";
- base.roptions = RegexOptions.None;
- ValidateMatchTimeout(Utilities.s_defaultTimeout);
- base.internalMatchTimeout = Utilities.s_defaultTimeout;
- base.factory = new RunnerFactory();
- base.CapNames = new Hashtable { { "0", 0 } , { "1", 1 } , { "2", 2 } , { "name", 3 } };
- base.capslist = new string[] {"0", "1", "2", "name" };
- base.capsize = 4;
- }
-
- /// Provides a factory for creating instances to be used by methods on .
- private sealed class RunnerFactory : RegexRunnerFactory
- {
- /// Creates an instance of a used by methods on .
- protected override RegexRunner CreateInstance() => new Runner();
-
- /// Provides the runner that contains the custom logic implementing the specified regular expression.
- private sealed class Runner : RegexRunner
- {
- /// Scan the starting from base.runtextstart for the next match.
- /// The text being scanned by the regular expression.
- protected override void Scan(ReadOnlySpan inputSpan)
- {
- // Search until we can't find a valid starting position, we find a match, or we reach the end of the input.
- while (TryFindNextPossibleStartingPosition(inputSpan) &&
- !TryMatchAtCurrentPosition(inputSpan) &&
- base.runtextpos != inputSpan.Length)
- {
- base.runtextpos++;
- if (Utilities.s_hasTimeout)
- {
- base.CheckTimeout();
- }
- }
- }
-
- /// Search starting from base.runtextpos for the next location a match could possibly start.
- /// The text being scanned by the regular expression.
- /// true if a possible match was found; false if no more matches are possible.
- private bool TryFindNextPossibleStartingPosition(ReadOnlySpan inputSpan)
- {
- int pos = base.runtextpos;
-
- // Any possible match is at least 8 characters.
- if (pos <= inputSpan.Length - 8)
- {
- // The pattern begins with a character in the set [^\n].
- // Find the next occurrence. If it can't be found, there's no match.
- ReadOnlySpan span = inputSpan.Slice(pos);
- for (int i = 0; i < span.Length; i++)
- {
- if ((span[i] != '\n'))
- {
- base.runtextpos = pos + i;
- return true;
- }
- }
- }
-
- // No match found.
- base.runtextpos = inputSpan.Length;
- return false;
- }
-
- /// Determine whether at base.runtextpos is a match for the regular expression.
- /// The text being scanned by the regular expression.
- /// true if the regular expression matches at the current position; otherwise, false.
- private bool TryMatchAtCurrentPosition(ReadOnlySpan inputSpan)
- {
- int pos = base.runtextpos;
- int matchStart = pos;
- int capture_starting_pos2 = 0;
- int charloop_capture_pos = 0;
- int charloop_capture_pos1 = 0;
- int charloop_starting_pos = 0, charloop_ending_pos = 0;
- int charloop_starting_pos1 = 0, charloop_ending_pos1 = 0;
- int loop_iteration = 0;
- int stackpos = 0;
- ReadOnlySpan slice = inputSpan.Slice(pos);
-
- // Match 'a' greedily any number of times.
- //{
- charloop_starting_pos = pos;
-
- int iteration = slice.IndexOfAnyExcept('a');
- if (iteration < 0)
- {
- iteration = slice.Length;
- }
-
- slice = slice.Slice(iteration);
- pos += iteration;
-
- charloop_ending_pos = pos;
- goto CharLoopEnd;
-
- CharLoopBacktrack:
- UncaptureUntil(charloop_capture_pos);
-
- if (Utilities.s_hasTimeout)
- {
- base.CheckTimeout();
- }
-
- if (charloop_starting_pos >= charloop_ending_pos ||
- (charloop_ending_pos = inputSpan.Slice(charloop_starting_pos, charloop_ending_pos - charloop_starting_pos).LastIndexOfAnyExcept('\n')) < 0)
- {
- UncaptureUntil(0);
- return false; // The input didn't match.
- }
- charloop_ending_pos += charloop_starting_pos;
- pos = charloop_ending_pos;
- slice = inputSpan.Slice(pos);
-
- CharLoopEnd:
- charloop_capture_pos = base.Crawlpos();
- //}
-
- // Advance the next matching position.
- if (base.runtextpos < pos)
- {
- base.runtextpos = pos;
- }
-
- // Match any character other than '\n'.
- if (slice.IsEmpty || slice[0] == '\n')
- {
- goto CharLoopBacktrack;
- }
-
- // Match a character in the set [a-c] greedily any number of times.
- //{
- pos++;
- slice = inputSpan.Slice(pos);
- charloop_starting_pos1 = pos;
-
- int iteration1 = slice.IndexOfAnyExceptInRange('a', 'c');
- if (iteration1 < 0)
- {
- iteration1 = slice.Length;
- }
-
- slice = slice.Slice(iteration1);
- pos += iteration1;
-
- charloop_ending_pos1 = pos;
- goto CharLoopEnd1;
-
- CharLoopBacktrack1:
- UncaptureUntil(charloop_capture_pos1);
-
- if (Utilities.s_hasTimeout)
- {
- base.CheckTimeout();
- }
-
- if (charloop_starting_pos1 >= charloop_ending_pos1 ||
- (charloop_ending_pos1 = inputSpan.Slice(charloop_starting_pos1, charloop_ending_pos1 - charloop_starting_pos1).LastIndexOf('a')) < 0)
- {
- goto CharLoopBacktrack;
- }
- charloop_ending_pos1 += charloop_starting_pos1;
- pos = charloop_ending_pos1;
- slice = inputSpan.Slice(pos);
-
- CharLoopEnd1:
- charloop_capture_pos1 = base.Crawlpos();
- //}
-
- // Loop greedily at least once.
- //{
- loop_iteration = 0;
-
- LoopBody:
- Utilities.StackPush(ref base.runstack!, ref stackpos, base.Crawlpos(), pos);
-
- loop_iteration++;
-
- // 1st capture group.
- //{
- int capture_starting_pos = pos;
-
- // Match 'a'.
- if (slice.IsEmpty || slice[0] != 'a')
- {
- goto LoopIterationNoMatch;
- }
-
- // Match with 2 alternative expressions.
- //{
- int alternation_starting_pos = pos;
- int alternation_starting_capturepos = base.Crawlpos();
-
- // Branch 0
- //{
- // Match the string "bcd".
- if (!slice.Slice(1).StartsWith("bcd"))
- {
- goto AlternationBranch;
- }
-
- Utilities.StackPush(ref base.runstack!, ref stackpos, 0, alternation_starting_pos, alternation_starting_capturepos);
- pos += 4;
- slice = inputSpan.Slice(pos);
- goto AlternationMatch;
-
- AlternationBranch:
- pos = alternation_starting_pos;
- slice = inputSpan.Slice(pos);
- UncaptureUntil(alternation_starting_capturepos);
- //}
-
- // Branch 1
- //{
- // 2nd capture group.
- {
- pos++;
- slice = inputSpan.Slice(pos);
- int capture_starting_pos1 = pos;
-
- // Match the string "bc".
- if (!slice.StartsWith("bc"))
- {
- goto LoopIterationNoMatch;
- }
-
- pos += 2;
- slice = inputSpan.Slice(pos);
- base.Capture(2, capture_starting_pos1, pos);
- }
-
- // Match 'c'.
- if (slice.IsEmpty || slice[0] != 'c')
- {
- goto LoopIterationNoMatch;
- }
-
- Utilities.StackPush(ref base.runstack!, ref stackpos, 1, alternation_starting_pos, alternation_starting_capturepos);
- pos++;
- slice = inputSpan.Slice(pos);
- goto AlternationMatch;
- //}
-
- AlternationBacktrack:
- if (Utilities.s_hasTimeout)
- {
- base.CheckTimeout();
- }
-
- Utilities.StackPop(base.runstack!, ref stackpos, out alternation_starting_capturepos, out alternation_starting_pos);
- switch (base.runstack![--stackpos])
- {
- case 0:
- goto AlternationBranch;
- case 1:
- goto LoopIterationNoMatch;
- }
-
- AlternationMatch:;
- //}
-
- base.Capture(1, capture_starting_pos, pos);
-
- Utilities.StackPush(ref base.runstack!, ref stackpos, capture_starting_pos);
- goto CaptureSkipBacktrack;
-
- CaptureBacktrack:
- capture_starting_pos = base.runstack![--stackpos];
- goto AlternationBacktrack;
-
- CaptureSkipBacktrack:;
- //}
-
-
- // The loop has no upper bound. Continue iterating greedily.
- goto LoopBody;
-
- // The loop iteration failed. Put state back to the way it was before the iteration.
- LoopIterationNoMatch:
- if (--loop_iteration < 0)
- {
- // Unable to match the remainder of the expression after exhausting the loop.
- goto CharLoopBacktrack1;
- }
- pos = base.runstack![--stackpos];
- UncaptureUntil(base.runstack![--stackpos]);
- slice = inputSpan.Slice(pos);
- if (loop_iteration == 0)
- {
- // No iterations have been matched to backtrack into. Fail the loop.
- goto CharLoopBacktrack1;
- }
-
- goto LoopEnd;
-
- LoopBacktrack:
- if (Utilities.s_hasTimeout)
- {
- base.CheckTimeout();
- }
-
- if (loop_iteration == 0)
- {
- // No iterations of the loop remain to backtrack into. Fail the loop.
- goto CharLoopBacktrack1;
- }
- goto CaptureBacktrack;
- LoopEnd:;
- //}
-
- // "name" capture group.
- {
- capture_starting_pos2 = pos;
-
- // Match the string "abc".
- if (!slice.StartsWith("abc"))
- {
- goto LoopBacktrack;
- }
-
- pos += 3;
- slice = inputSpan.Slice(pos);
- base.Capture(3, capture_starting_pos2, pos);
- }
-
- // The input matched.
- base.runtextpos = pos;
- base.Capture(0, matchStart, pos);
- return true;
-
- // Undo captures until it reaches the specified capture position.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- void UncaptureUntil(int capturePosition)
- {
- while (base.Crawlpos() > capturePosition)
- {
- base.Uncapture();
- }
- }
- }
- }
- }
-
- }
-
- /// Helper methods used by generated -derived implementations.
- [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "10.0.14.27113")]
- file static class Utilities
- {
- /// Default timeout value set in , or if none was set.
- internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout;
-
- /// Whether is non-infinite.
- internal static readonly bool s_hasTimeout = s_defaultTimeout != Regex.InfiniteMatchTimeout;
-
- /// Pops 2 values from the backtracking stack.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void StackPop(int[] stack, ref int pos, out int arg0, out int arg1)
- {
- arg0 = stack[--pos];
- arg1 = stack[--pos];
- }
-
- /// Pushes 1 value onto the backtracking stack.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void StackPush(ref int[] stack, ref int pos, int arg0)
- {
- // If there's space available for the value, store it.
- int[] s = stack;
- int p = pos;
- if ((uint)p < (uint)s.Length)
- {
- s[p] = arg0;
- pos++;
- return;
- }
-
- // Otherwise, resize the stack to make room and try again.
- WithResize(ref stack, ref pos, arg0);
-
- // Resize the backtracking stack array and push 1 value onto the stack.
- [MethodImpl(MethodImplOptions.NoInlining)]
- static void WithResize(ref int[] stack, ref int pos, int arg0)
- {
- Array.Resize(ref stack, (pos + 0) * 2);
- StackPush(ref stack, ref pos, arg0);
- }
- }
-
- /// Pushes 2 values onto the backtracking stack.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1)
- {
- // If there's space available for all 2 values, store them.
- int[] s = stack;
- int p = pos;
- if ((uint)(p + 1) < (uint)s.Length)
- {
- s[p] = arg0;
- s[p + 1] = arg1;
- pos += 2;
- return;
- }
-
- // Otherwise, resize the stack to make room and try again.
- WithResize(ref stack, ref pos, arg0, arg1);
-
- // Resize the backtracking stack array and push 2 values onto the stack.
- [MethodImpl(MethodImplOptions.NoInlining)]
- static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1)
- {
- Array.Resize(ref stack, (pos + 1) * 2);
- StackPush(ref stack, ref pos, arg0, arg1);
- }
- }
-
- /// Pushes 3 values onto the backtracking stack.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1, int arg2)
- {
- // If there's space available for all 3 values, store them.
- int[] s = stack;
- int p = pos;
- if ((uint)(p + 2) < (uint)s.Length)
- {
- s[p] = arg0;
- s[p + 1] = arg1;
- s[p + 2] = arg2;
- pos += 3;
- return;
- }
-
- // Otherwise, resize the stack to make room and try again.
- WithResize(ref stack, ref pos, arg0, arg1, arg2);
-
- // Resize the backtracking stack array and push 3 values onto the stack.
- [MethodImpl(MethodImplOptions.NoInlining)]
- static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1, int arg2)
- {
- Array.Resize(ref stack, (pos + 2) * 2);
- StackPush(ref stack, ref pos, arg0, arg1, arg2);
- }
- }
- }
-}