@@ -754,7 +754,7 @@ void UncaptureUntil(int capturePosition)
754
754
}
755
755
756
756
/// <summary>Helper methods used by generated <see cref="Regex"/>-derived implementations.</summary>
757
- [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "42.42.42.42 ")]
757
+ [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION% ")]
758
758
file static class Utilities
759
759
{
760
760
/// <summary>Supports searching for the string "href".</summary>
@@ -930,6 +930,206 @@ file static class Utilities
930
930
}
931
931
"""
932
932
} ;
933
+
934
+ yield return new object [ ]
935
+ {
936
+ """
937
+ using System.Text.RegularExpressions;
938
+ partial class C
939
+ {
940
+ [GeneratedRegex(@"abcd*e|f")]
941
+ public static partial Regex Valid();
942
+ }
943
+ """ ,
944
+
945
+ """
946
+ // <auto-generated/>
947
+ #nullable enable
948
+ #pragma warning disable CS0162 // Unreachable code
949
+ #pragma warning disable CS0164 // Unreferenced label
950
+ #pragma warning disable CS0219 // Variable assigned but never used
951
+
952
+ partial class C
953
+ {
954
+ /// <remarks>
955
+ /// Pattern:<br/>
956
+ /// <code>abcd*e|f</code><br/>
957
+ /// Explanation:<br/>
958
+ /// <code>
959
+ /// ○ Match with 2 alternative expressions, atomically.<br/>
960
+ /// ○ Match a sequence of expressions.<br/>
961
+ /// ○ Match the string "abc".<br/>
962
+ /// ○ Match 'd' atomically any number of times.<br/>
963
+ /// ○ Match 'e'.<br/>
964
+ /// ○ Match 'f'.<br/>
965
+ /// </code>
966
+ /// </remarks>
967
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION%")]
968
+ public static partial global::System.Text.RegularExpressions.Regex Valid() => global::System.Text.RegularExpressions.Generated.Valid_0.Instance;
969
+ }
970
+
971
+ namespace System.Text.RegularExpressions.Generated
972
+ {
973
+ using System;
974
+ using System.Buffers;
975
+ using System.CodeDom.Compiler;
976
+ using System.Collections;
977
+ using System.ComponentModel;
978
+ using System.Globalization;
979
+ using System.Runtime.CompilerServices;
980
+ using System.Text.RegularExpressions;
981
+ using System.Threading;
982
+
983
+ /// <summary>Custom <see cref="Regex"/>-derived type for the Valid method.</summary>
984
+ [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION%")]
985
+ [SkipLocalsInit]
986
+ file sealed class Valid_0 : Regex
987
+ {
988
+ /// <summary>Cached, thread-safe singleton instance.</summary>
989
+ internal static readonly Valid_0 Instance = new();
990
+
991
+ /// <summary>Initializes the instance.</summary>
992
+ private Valid_0()
993
+ {
994
+ base.pattern = "abcd*e|f";
995
+ base.roptions = RegexOptions.None;
996
+ ValidateMatchTimeout(Utilities.s_defaultTimeout);
997
+ base.internalMatchTimeout = Utilities.s_defaultTimeout;
998
+ base.factory = new RunnerFactory();
999
+ base.capsize = 1;
1000
+ }
1001
+
1002
+ /// <summary>Provides a factory for creating <see cref="RegexRunner"/> instances to be used by methods on <see cref="Regex"/>.</summary>
1003
+ private sealed class RunnerFactory : RegexRunnerFactory
1004
+ {
1005
+ /// <summary>Creates an instance of a <see cref="RegexRunner"/> used by methods on <see cref="Regex"/>.</summary>
1006
+ protected override RegexRunner CreateInstance() => new Runner();
1007
+
1008
+ /// <summary>Provides the runner that contains the custom logic implementing the specified regular expression.</summary>
1009
+ private sealed class Runner : RegexRunner
1010
+ {
1011
+ /// <summary>Scan the <paramref name="inputSpan"/> starting from base.runtextstart for the next match.</summary>
1012
+ /// <param name="inputSpan">The text being scanned by the regular expression.</param>
1013
+ protected override void Scan(ReadOnlySpan<char> inputSpan)
1014
+ {
1015
+ // Search until we can't find a valid starting position, we find a match, or we reach the end of the input.
1016
+ while (TryFindNextPossibleStartingPosition(inputSpan) &&
1017
+ !TryMatchAtCurrentPosition(inputSpan) &&
1018
+ base.runtextpos != inputSpan.Length)
1019
+ {
1020
+ base.runtextpos++;
1021
+ if (Utilities.s_hasTimeout)
1022
+ {
1023
+ base.CheckTimeout();
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ /// <summary>Search <paramref name="inputSpan"/> starting from base.runtextpos for the next location a match could possibly start.</summary>
1029
+ /// <param name="inputSpan">The text being scanned by the regular expression.</param>
1030
+ /// <returns>true if a possible match was found; false if no more matches are possible.</returns>
1031
+ private bool TryFindNextPossibleStartingPosition(ReadOnlySpan<char> inputSpan)
1032
+ {
1033
+ int pos = base.runtextpos;
1034
+
1035
+ // Empty matches aren't possible.
1036
+ if ((uint)pos < (uint)inputSpan.Length)
1037
+ {
1038
+ // The pattern begins with a character in the set [af].
1039
+ // Find the next occurrence. If it can't be found, there's no match.
1040
+ int i = inputSpan.Slice(pos).IndexOfAny('a', 'f');
1041
+ if (i >= 0)
1042
+ {
1043
+ base.runtextpos = pos + i;
1044
+ return true;
1045
+ }
1046
+ }
1047
+
1048
+ // No match found.
1049
+ base.runtextpos = inputSpan.Length;
1050
+ return false;
1051
+ }
1052
+
1053
+ /// <summary>Determine whether <paramref name="inputSpan"/> at base.runtextpos is a match for the regular expression.</summary>
1054
+ /// <param name="inputSpan">The text being scanned by the regular expression.</param>
1055
+ /// <returns>true if the regular expression matches at the current position; otherwise, false.</returns>
1056
+ private bool TryMatchAtCurrentPosition(ReadOnlySpan<char> inputSpan)
1057
+ {
1058
+ int pos = base.runtextpos;
1059
+ int matchStart = pos;
1060
+ ReadOnlySpan<char> slice = inputSpan.Slice(pos);
1061
+
1062
+ // Match with 2 alternative expressions, atomically.
1063
+ {
1064
+ if (slice.IsEmpty)
1065
+ {
1066
+ return false; // The input didn't match.
1067
+ }
1068
+
1069
+ switch (slice[0])
1070
+ {
1071
+ case 'a':
1072
+ // Match the string "bc".
1073
+ if (!slice.Slice(1).StartsWith("bc"))
1074
+ {
1075
+ return false; // The input didn't match.
1076
+ }
1077
+
1078
+ // Match 'd' atomically any number of times.
1079
+ {
1080
+ int iteration = slice.Slice(3).IndexOfAnyExcept('d');
1081
+ if (iteration < 0)
1082
+ {
1083
+ iteration = slice.Length - 3;
1084
+ }
1085
+
1086
+ slice = slice.Slice(iteration);
1087
+ pos += iteration;
1088
+ }
1089
+
1090
+ // Match 'e'.
1091
+ if ((uint)slice.Length < 4 || slice[3] != 'e')
1092
+ {
1093
+ return false; // The input didn't match.
1094
+ }
1095
+
1096
+ pos += 4;
1097
+ slice = inputSpan.Slice(pos);
1098
+ break;
1099
+
1100
+ case 'f':
1101
+ pos++;
1102
+ slice = inputSpan.Slice(pos);
1103
+ break;
1104
+
1105
+ default:
1106
+ return false; // The input didn't match.
1107
+ }
1108
+ }
1109
+
1110
+ // The input matched.
1111
+ base.runtextpos = pos;
1112
+ base.Capture(0, matchStart, pos);
1113
+ return true;
1114
+ }
1115
+ }
1116
+ }
1117
+
1118
+ }
1119
+
1120
+ /// <summary>Helper methods used by generated <see cref="Regex"/>-derived implementations.</summary>
1121
+ [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION%")]
1122
+ file static class Utilities
1123
+ {
1124
+ /// <summary>Default timeout value set in <see cref="AppContext"/>, or <see cref="Regex.InfiniteMatchTimeout"/> if none was set.</summary>
1125
+ internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout;
1126
+
1127
+ /// <summary>Whether <see cref="s_defaultTimeout"/> is non-infinite.</summary>
1128
+ internal static readonly bool s_hasTimeout = s_defaultTimeout != Regex.InfiniteMatchTimeout;
1129
+ }
1130
+ }
1131
+ """
1132
+ } ;
933
1133
}
934
1134
}
935
1135
}
0 commit comments