2 // Based upon interpreter.cs, written by Dan Lewis (dlewis@gmx.co.uk)
4 // There are a couple of bits flagged with DEAD_CODE which are bits that do
5 // not seem to have been completed
8 using System.Collections;
9 using System.Globalization;
10 using System.Diagnostics;
12 namespace System.Text.RegularExpressions {
14 internal delegate bool EvalDelegate (RxInterpreter interp, int strpos, ref int strpos_result);
16 sealed class RxInterpreter: BaseMachine {
24 EvalDelegate eval_del; // optimized EvalByteCode method created by the CILCompiler
26 Mark[] marks = null; // mark stack
27 int mark_start; // start of current checkpoint
28 int mark_end; // end of checkpoint/next free mark
30 IntStack stack; // utility stack
32 RepeatContext repeat; // current repeat context
33 RepeatContext deep; // points to the most-nested repeat context
35 /* The readonly ensures the JIT can optimize out if (trace_rx) statements */
36 public static readonly bool trace_rx =
38 Environment.GetEnvironmentVariable ("MONO_TRACE_RX") != null;
45 internal struct IntStack {
50 return values [--count];
52 public void Push (int value)
56 } else if (count == values.Length) {
57 int new_size = values.Length;
58 new_size += new_size >> 1;
59 int [] new_values = new int [new_size];
60 for (int i = 0; i < count; ++i)
61 new_values [i] = values [i];
64 values [count++] = value;
67 get { return values [count - 1]; }
73 throw new SystemException ("can only truncate the stack");
79 private class RepeatContext {
80 public RepeatContext (RepeatContext previous, int min, int max, bool lazy, int expr_pc) {
81 this.previous = previous;
85 this.expr_pc = expr_pc;
93 set { count = value; }
98 set { start = value; }
101 public bool IsMinimum {
102 get { return min <= count; }
105 public bool IsMaximum {
106 get { return max <= count; }
113 public int Expression {
114 get { return expr_pc; }
117 public RepeatContext Previous {
118 get { return previous; }
122 private int min, max;
125 private RepeatContext previous;
130 static int ReadInt (byte[] code, int pc)
133 val |= (int)code [pc + 1] << 8;
134 val |= (int)code [pc + 2] << 16;
135 val |= (int)code [pc + 3] << 24;
139 public RxInterpreter (byte[] program, EvalDelegate eval_del)
141 this.program = program;
142 this.eval_del = eval_del;
143 group_count = 1 + (program [1] | ((int)program [2] << 8));
144 groups = new int [group_count];
145 stack = new IntStack ();
150 public override Match Scan (Regex regex, string text, int start, int end) {
152 string_start = start;
157 if (eval_del != null) {
158 match = eval_del (this, start, ref res);
160 match = EvalByteCode (11, start, ref res);
162 marks [groups [0]].End = res;
164 return GenerateMatch (regex);
165 //Match m = new Match (regex, this, text, end, 0, match_start, res - match_start);
171 // capture management
172 private void Open (int gid, int ptr) {
173 int m = groups [gid];
174 if (m < mark_start || marks [m].IsDefined) {
179 marks [m].Start = ptr;
182 private void Close (int gid, int ptr) {
183 marks [groups [gid]].End = ptr;
186 private bool Balance (int gid, int balance_gid, bool capture, int ptr) {
187 int b = groups [balance_gid];
189 if(b == -1 || marks[b].Index < 0) {
190 //Group not previously matched
193 Debug.Assert (marks [b].IsDefined, "Regex", "Balancng group not closed");
194 if (gid > 0 && capture){
195 Open (gid, marks [b].Index + marks [b].Length);
199 groups [balance_gid] = marks[b].Previous;
204 private int Checkpoint () {
205 mark_start = mark_end;
209 private void Backtrack (int cp) {
210 for (int i = 0; i < groups.Length; ++ i) {
213 m = marks [m].Previous;
218 private void ResetGroups () {
219 int n = groups.Length;
221 marks = new Mark [n];
223 for (int i = 0; i < n; ++ i) {
226 marks [i].Start = -1;
228 marks [i].Previous = -1;
234 private int GetLastDefined (int gid) {
235 int m = groups [gid];
236 while (m >= 0 && !marks [m].IsDefined)
237 m = marks [m].Previous;
242 private int CreateMark (int previous) {
243 if (mark_end == marks.Length) {
244 Mark [] dest = new Mark [marks.Length * 2];
245 marks.CopyTo (dest, 0);
250 marks [m].Start = marks [m].End = -1;
251 marks [m].Previous = previous;
256 private void GetGroupInfo (int gid, out int first_mark_index, out int n_caps)
258 first_mark_index = -1;
260 for (int m = groups [gid]; m >= 0; m = marks [m].Previous) {
261 if (!marks [m].IsDefined)
263 if (first_mark_index < 0)
264 first_mark_index = m;
269 private void PopulateGroup (Group g, int first_mark_index, int n_caps)
272 for (int m = marks [first_mark_index].Previous; m >= 0; m = marks [m].Previous) {
273 if (!marks [m].IsDefined)
275 Capture cap = new Capture (str, marks [m].Index, marks [m].Length);
276 g.Captures.SetValue (cap, n_caps - 1 - i);
281 private Match GenerateMatch (Regex regex)
283 int n_caps, first_mark_index;
285 GetGroupInfo (0, out first_mark_index, out n_caps);
287 // Avoid fully populating the Match instance if not needed
288 if (!needs_groups_or_captures)
289 return new Match (regex, this, str, string_end, 0, marks [first_mark_index].Index, marks [first_mark_index].Length);
291 Match retval = new Match (regex, this, str, string_end, groups.Length,
292 marks [first_mark_index].Index, marks [first_mark_index].Length, n_caps);
293 PopulateGroup (retval, first_mark_index, n_caps);
295 for (int gid = 1; gid < groups.Length; ++ gid) {
296 GetGroupInfo (gid, out first_mark_index, out n_caps);
297 if (first_mark_index < 0) {
300 g = new Group (str, marks [first_mark_index].Index, marks [first_mark_index].Length, n_caps);
301 PopulateGroup (g, first_mark_index, n_caps);
303 retval.Groups.SetValue (g, gid);
308 // used by the IL backend
309 internal void SetStartOfMatch (int pos)
311 marks [groups [0]].Start = pos;
314 static bool IsWordChar (char c)
316 return Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
319 bool EvalByteCode (int pc, int strpos, ref int strpos_result)
321 // luckily the IL engine can deal with char_group_end at compile time
322 // this code offset needs to be checked only in opcodes that handle
323 // a single char and that are included in a TestCharGroup expression:
324 // the engine is supposed to jump to this offset as soons as the
325 // first opcode in the expression matches
326 // The code pattern becomes:
327 // on successfull match: check if char_group_end is nonzero and jump to
328 // test_char_group_passed after adjusting strpos
329 // on failure: try the next expression by simply advancing pc
330 int char_group_end = 0;
331 int length, start, end;
334 Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}, cge: {3}", (RxOp)program [pc], pc, strpos, char_group_end);
335 //Console.WriteLine ("deep: " + (deep == null ? 0 : deep.GetHashCode ()) + " repeat: " + (this.repeat == null ? 0 : this.repeat.GetHashCode ()));
337 switch ((RxOp)program [pc]) {
339 if (char_group_end != 0) {
344 strpos_result = strpos;
348 case RxOp.AnyPosition:
351 case RxOp.StartOfString:
356 case RxOp.StartOfLine:
357 if (strpos == 0 || str [strpos - 1] == '\n') {
362 case RxOp.StartOfScan:
363 if (strpos != string_start)
368 if (strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')) {
373 case RxOp.EndOfString:
374 if (strpos != string_end)
379 if (strpos == string_end || str [strpos] == '\n') {
384 case RxOp.WordBoundary:
388 if (IsWordChar (str [strpos])) {
392 } else if (strpos == string_end) {
393 if (IsWordChar (str [strpos - 1])) {
398 if (IsWordChar (str [strpos]) != IsWordChar (str [strpos - 1])) {
404 case RxOp.NoWordBoundary:
408 if (!IsWordChar (str [strpos])) {
412 } else if (strpos == string_end) {
413 if (!IsWordChar (str [strpos - 1])) {
418 if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
425 int skip = program [pc + 1] | ((int)program [pc + 2] << 8);
426 int anch_offset = program [pc + 3] | ((int)program [pc + 4] << 8);
429 * In the general case, we have to evaluate the bytecode
430 * starting at pc + skip, however the optimizer emits some
431 * special cases, whose bytecode begins at pc + 5.
433 int anch_pc = pc + 5;
434 RxOp anch_op = (RxOp)(program[anch_pc] & 0x00ff);
436 bool spec_anch = false;
438 // FIXME: Add more special cases from interpreter.cs
439 if (anch_op == RxOp.String || anch_op == RxOp.StringIgnoreCase) {
440 if (pc + skip == anch_pc + 2 + program [anch_pc + 1] + 1) {
446 Console.WriteLine (" string anchor at {0}, offset {1}", anch_pc, anch_offset);
452 if ((RxOp)program [pc] == RxOp.StartOfString) {
455 if (groups.Length > 1) {
457 marks [groups [0]].Start = strpos;
459 if (EvalByteCode (pc + 1, strpos, ref res)) {
460 marks [groups [0]].Start = strpos;
461 if (groups.Length > 1)
462 marks [groups [0]].End = res;
470 // it's important to test also the end of the string
471 // position for things like: "" =~ /$/
472 end = string_end + 1;
473 while (strpos < end) {
475 if (anch_op == RxOp.String || anch_op == RxOp.StringIgnoreCase) {
477 * This means the match must contain a given
478 * string at a constant position, so we can skip
479 * forward until the string matches. This is a win if
480 * the rest of the regex
481 * has a complex positive lookbehind for example.
483 int tmp_res = strpos;
484 if (!EvalByteCode (anch_pc, strpos + anch_offset, ref tmp_res)) {
491 if (groups.Length > 1) {
493 marks [groups [0]].Start = strpos;
495 if (EvalByteCode (pc, strpos, ref res)) {
496 // match_start = strpos;
497 marks [groups [0]].Start = strpos;
498 if (groups.Length > 1)
499 marks [groups [0]].End = res;
506 case RxOp.AnchorReverse:
507 length = program [pc + 3] | ((int)program [pc + 4] << 8);
508 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
509 // it's important to test also the end of the string
510 // position for things like: "" =~ /$/
512 while (strpos >= 0) {
514 if (groups.Length > 1) {
516 marks [groups [0]].Start = strpos;
518 if (EvalByteCode (pc, strpos, ref res)) {
519 // match_start = strpos;
520 marks [groups [0]].Start = strpos;
521 if (groups.Length > 1)
522 marks [groups [0]].End = res;
530 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
533 start = marks [length].Index;
534 length = marks [length].Length;
535 if (strpos + length > string_end)
537 for (end = start + length; start < end; ++start) {
538 if (str [strpos] != str [start])
544 case RxOp.ReferenceIgnoreCase:
545 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
548 start = marks [length].Index;
549 length = marks [length].Length;
550 if (strpos + length > string_end)
552 for (end = start + length; start < end; ++start) {
553 if (str [strpos] != str [start] && Char.ToLower (str [strpos]) != Char.ToLower (str [start]))
559 case RxOp.ReferenceReverse: {
560 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
563 start = marks [length].Index;
564 length = marks [length].Length;
565 if (strpos - length < 0)
567 int p = strpos - length;
568 for (end = start + length; start < end; ++start, ++p) {
569 if (str [p] != str [start])
577 if (GetLastDefined (program [pc + 3] | ((int)program [pc + 4] << 8)) >= 0)
580 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
582 case RxOp.SubExpression: {
584 if (EvalByteCode (pc + 3, strpos, ref res)) {
585 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
594 if (EvalByteCode (pc + 5, strpos, ref res)) {
595 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
597 pc += program [pc + 3] | ((int)program [pc + 4] << 8);
602 Open (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
605 case RxOp.CloseGroup:
606 Close (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
609 case RxOp.BalanceStart: {
612 if (!EvalByteCode (pc + 8, strpos, ref res))
615 int gid = program [pc + 1] | ((int)program [pc + 2] << 8);
616 int balance_gid = program [pc + 3] | ((int)program [pc + 4] << 8);
617 bool capture = program [pc + 5] > 0;
618 if (!Balance (gid, balance_gid, capture, strpos))
622 pc += program[pc + 6] | ((int)program [pc + 7] << 8);
630 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
632 case RxOp.TestCharGroup:
633 char_group_end = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
638 length = program [pc + 1];
639 if (strpos + length > string_end)
641 end = start + length;
642 for (; start < end; ++start) {
643 if (str [strpos] != program [start])
649 case RxOp.StringIgnoreCase:
651 length = program [pc + 1];
652 if (strpos + length > string_end)
654 end = start + length;
655 for (; start < end; ++start) {
656 if (str [strpos] != program [start] && Char.ToLower (str [strpos]) != program [start])
662 case RxOp.StringReverse: {
664 length = program [pc + 1];
667 int p = strpos - length;
668 end = start + length;
669 for (; start < end; ++start, ++p) {
670 if (str [p] != program [start])
677 case RxOp.StringIgnoreCaseReverse: {
679 length = program [pc + 1];
682 int p = strpos - length;
683 end = start + length;
684 for (; start < end; ++start, ++p) {
685 if (str [p] != program [start] && Char.ToLower (str [p]) != program [start])
692 case RxOp.UnicodeString: {
694 length = program [pc + 1] | ((int)program [pc + 2] << 8);
695 if (strpos + length > string_end)
697 end = start + length * 2;
698 for (; start < end; start += 2) {
699 int c = program [start] | ((int)program [start + 1] << 8);
700 if (str [strpos] != c)
707 case RxOp.UnicodeStringIgnoreCase: {
709 length = program [pc + 1] | ((int)program [pc + 2] << 8);
710 if (strpos + length > string_end)
712 end = start + length * 2;
713 for (; start < end; start += 2) {
714 int c = program [start] | ((int)program [start + 1] << 8);
715 if (str [strpos] != c && Char.ToLower (str [strpos]) != c)
722 case RxOp.UnicodeStringReverse: {
724 length = program [pc + 1] | ((int)program [pc + 2] << 8);
727 int p = strpos - length;
728 end = start + length * 2;
729 for (; start < end; start += 2, p += 2) {
730 int c = program [start] | ((int)program [start + 1] << 8);
738 case RxOp.UnicodeStringIgnoreCaseReverse: {
740 length = program [pc + 1] | ((int)program [pc + 2] << 8);
743 int p = strpos - length;
744 end = start + length * 2;
745 for (; start < end; start += 2, p += 2) {
746 int c = program [start] | ((int)program [start + 1] << 8);
747 if (str [p] != c && Char.ToLower (str [p]) != c)
756 * The opcodes below are basically specialized versions of one
757 * generic opcode, which has three parameters:
758 * - reverse (Reverse), revert (No), ignore-case (IgnoreCase)
759 * Thus each opcode has 8 variants.
760 * FIXME: Maybe move all unusual variations
761 * (Reverse+IgnoreCase+Unicode) into a generic GenericChar opcode
762 * like in the old interpreter.
763 * FIXME: Move all the Reverse opcodes to a separate method.
767 if (strpos < string_end && (COND (str [strpos]))) {
770 if (char_group_end != 0)
771 goto test_char_group_passed;
776 * If we are inside a char group, the cases are ANDed
777 * together, so we have to continue checking the
778 * other cases, and we need to increase strpos after
780 * The char group is termined by a True, hence the
782 * FIXME: Optimize this.
785 if (char_group_end == 0 || (pc + 1 == char_group_end))
787 if (pc + 1 == char_group_end)
788 goto test_char_group_passed;
793 if (char_group_end == 0)
798 /* Fail both inside and outside a char group */
803 // Same as above, but use:
804 // - strpos > 0 instead of strpos < string_len
805 // - COND (str [strpos - 1]) instead of COND (str [strpos])
806 // - strpos -- instead of strpos ++
809 // GENERATED BY gen-interp.cs, DO NOT MODIFY
814 if (strpos < string_end) {
815 char c = str [strpos];
816 if (((c == program [pc + 1]))) {
818 if (char_group_end != 0)
819 goto test_char_group_passed;
824 if (char_group_end == 0)
832 if (strpos < string_end) {
833 char c = str [strpos];
834 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
836 if (char_group_end != 0)
837 goto test_char_group_passed;
842 if (char_group_end == 0)
849 case RxOp.UnicodeRange:
850 if (strpos < string_end) {
851 char c = str [strpos];
852 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
854 if (char_group_end != 0)
855 goto test_char_group_passed;
860 if (char_group_end == 0)
867 case RxOp.UnicodeChar:
868 if (strpos < string_end) {
869 char c = str [strpos];
870 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
872 if (char_group_end != 0)
873 goto test_char_group_passed;
878 if (char_group_end == 0)
885 case RxOp.CategoryAny:
886 if (strpos < string_end) {
887 char c = str [strpos];
890 if (char_group_end != 0)
891 goto test_char_group_passed;
896 if (char_group_end == 0)
901 /* CategoryAnySingleline */
903 case RxOp.CategoryAnySingleline:
904 if (strpos < string_end) {
905 // char c = str [strpos];
908 if (char_group_end != 0)
909 goto test_char_group_passed;
914 if (char_group_end == 0)
921 case RxOp.CategoryWord:
922 if (strpos < string_end) {
923 char c = str [strpos];
924 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
926 if (char_group_end != 0)
927 goto test_char_group_passed;
932 if (char_group_end == 0)
939 case RxOp.CategoryDigit:
940 if (strpos < string_end) {
941 char c = str [strpos];
942 if (((Char.IsDigit (c)))) {
944 if (char_group_end != 0)
945 goto test_char_group_passed;
950 if (char_group_end == 0)
955 /* CategoryWhiteSpace */
957 case RxOp.CategoryWhiteSpace:
958 if (strpos < string_end) {
959 char c = str [strpos];
960 if (((Char.IsWhiteSpace (c)))) {
962 if (char_group_end != 0)
963 goto test_char_group_passed;
968 if (char_group_end == 0)
973 /* CategoryEcmaWord */
975 case RxOp.CategoryEcmaWord:
976 if (strpos < string_end) {
977 char c = str [strpos];
978 if ((('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
980 if (char_group_end != 0)
981 goto test_char_group_passed;
986 if (char_group_end == 0)
991 /* CategoryEcmaWhiteSpace */
993 case RxOp.CategoryEcmaWhiteSpace:
994 if (strpos < string_end) {
995 char c = str [strpos];
996 if (((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
998 if (char_group_end != 0)
999 goto test_char_group_passed;
1004 if (char_group_end == 0)
1009 /* CategoryUnicodeSpecials */
1011 case RxOp.CategoryUnicodeSpecials:
1012 if (strpos < string_end) {
1013 char c = str [strpos];
1014 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1016 if (char_group_end != 0)
1017 goto test_char_group_passed;
1022 if (char_group_end == 0)
1027 /* CategoryUnicode */
1029 case RxOp.CategoryUnicode:
1030 if (strpos < string_end) {
1031 char c = str [strpos];
1032 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1034 if (char_group_end != 0)
1035 goto test_char_group_passed;
1040 if (char_group_end == 0)
1045 /* CategoryGeneral */
1047 case RxOp.CategoryGeneral:
1048 if (strpos < string_end) {
1049 char c = str [strpos];
1050 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1052 if (char_group_end != 0)
1053 goto test_char_group_passed;
1058 if (char_group_end == 0)
1066 if (strpos < string_end) {
1067 char c = str [strpos];
1068 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1069 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1071 if (char_group_end != 0)
1072 goto test_char_group_passed;
1073 pc += 3 + program [pc + 2];
1077 if (char_group_end == 0)
1079 pc += 3 + program [pc + 2];
1084 case RxOp.UnicodeBitmap:
1085 if (strpos < string_end) {
1086 char c = str [strpos];
1087 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1088 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1090 if (char_group_end != 0)
1091 goto test_char_group_passed;
1092 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1096 if (char_group_end == 0)
1098 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1100 case RxOp.CharIgnoreCase:
1101 if (strpos < string_end) {
1102 char c = Char.ToLower (str [strpos]);
1103 if (((c == program [pc + 1]))) {
1105 if (char_group_end != 0)
1106 goto test_char_group_passed;
1111 if (char_group_end == 0)
1115 case RxOp.RangeIgnoreCase:
1116 if (strpos < string_end) {
1117 char c = Char.ToLower (str [strpos]);
1118 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1120 if (char_group_end != 0)
1121 goto test_char_group_passed;
1126 if (char_group_end == 0)
1130 case RxOp.UnicodeRangeIgnoreCase:
1131 if (strpos < string_end) {
1132 char c = Char.ToLower (str [strpos]);
1133 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1135 if (char_group_end != 0)
1136 goto test_char_group_passed;
1141 if (char_group_end == 0)
1145 case RxOp.UnicodeCharIgnoreCase:
1146 if (strpos < string_end) {
1147 char c = Char.ToLower (str [strpos]);
1148 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1150 if (char_group_end != 0)
1151 goto test_char_group_passed;
1156 if (char_group_end == 0)
1160 case RxOp.BitmapIgnoreCase:
1161 if (strpos < string_end) {
1162 char c = Char.ToLower (str [strpos]);
1163 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1164 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1166 if (char_group_end != 0)
1167 goto test_char_group_passed;
1168 pc += 3 + program [pc + 2];
1172 if (char_group_end == 0)
1174 pc += 3 + program [pc + 2];
1176 case RxOp.UnicodeBitmapIgnoreCase:
1177 if (strpos < string_end) {
1178 char c = Char.ToLower (str [strpos]);
1179 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1180 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1182 if (char_group_end != 0)
1183 goto test_char_group_passed;
1184 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1188 if (char_group_end == 0)
1190 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1193 if (strpos < string_end) {
1194 char c = str [strpos];
1195 if (!((c == program [pc + 1]))) {
1197 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1199 if (pc + 1 == char_group_end)
1200 goto test_char_group_passed;
1207 if (strpos < string_end) {
1208 char c = str [strpos];
1209 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1211 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1213 if (pc + 1 == char_group_end)
1214 goto test_char_group_passed;
1220 case RxOp.NoUnicodeRange:
1221 if (strpos < string_end) {
1222 char c = str [strpos];
1223 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1225 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1227 if (pc + 1 == char_group_end)
1228 goto test_char_group_passed;
1234 case RxOp.NoUnicodeChar:
1235 if (strpos < string_end) {
1236 char c = str [strpos];
1237 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1239 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1241 if (pc + 1 == char_group_end)
1242 goto test_char_group_passed;
1248 case RxOp.NoCategoryAny:
1249 if (strpos < string_end) {
1250 char c = str [strpos];
1251 if (!((c != '\n'))) {
1253 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1255 if (pc + 1 == char_group_end)
1256 goto test_char_group_passed;
1262 case RxOp.NoCategoryAnySingleline:
1263 if (strpos < string_end) {
1265 char c = str [strpos];
1268 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1270 if (pc + 1 == char_group_end)
1271 goto test_char_group_passed;
1278 case RxOp.NoCategoryWord:
1279 if (strpos < string_end) {
1280 char c = str [strpos];
1281 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1283 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1285 if (pc + 1 == char_group_end)
1286 goto test_char_group_passed;
1292 case RxOp.NoCategoryDigit:
1293 if (strpos < string_end) {
1294 char c = str [strpos];
1295 if (!((Char.IsDigit (c)))) {
1297 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1299 if (pc + 1 == char_group_end)
1300 goto test_char_group_passed;
1306 case RxOp.NoCategoryWhiteSpace:
1307 if (strpos < string_end) {
1308 char c = str [strpos];
1309 if (!((Char.IsWhiteSpace (c)))) {
1311 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1313 if (pc + 1 == char_group_end)
1314 goto test_char_group_passed;
1320 case RxOp.NoCategoryEcmaWord:
1321 if (strpos < string_end) {
1322 char c = str [strpos];
1323 if (!(('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1325 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1327 if (pc + 1 == char_group_end)
1328 goto test_char_group_passed;
1334 case RxOp.NoCategoryEcmaWhiteSpace:
1335 if (strpos < string_end) {
1336 char c = str [strpos];
1337 if (!((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1339 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1341 if (pc + 1 == char_group_end)
1342 goto test_char_group_passed;
1348 case RxOp.NoCategoryUnicodeSpecials:
1349 if (strpos < string_end) {
1350 char c = str [strpos];
1351 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1353 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1355 if (pc + 1 == char_group_end)
1356 goto test_char_group_passed;
1362 case RxOp.NoCategoryUnicode:
1363 if (strpos < string_end) {
1364 char c = str [strpos];
1365 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1367 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1369 if (pc + 1 == char_group_end)
1370 goto test_char_group_passed;
1376 case RxOp.NoCategoryGeneral:
1377 if (strpos < string_end) {
1378 char c = str [strpos];
1379 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1381 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1383 if (pc + 1 == char_group_end)
1384 goto test_char_group_passed;
1391 if (strpos < string_end) {
1392 char c = str [strpos];
1393 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1394 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1395 pc += 3 + program [pc + 2];
1396 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1398 if (pc + 1 == char_group_end)
1399 goto test_char_group_passed;
1405 case RxOp.NoUnicodeBitmap:
1406 if (strpos < string_end) {
1407 char c = str [strpos];
1408 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1409 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1410 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1411 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1413 if (pc + 1 == char_group_end)
1414 goto test_char_group_passed;
1420 case RxOp.NoCharIgnoreCase:
1421 if (strpos < string_end) {
1422 char c = Char.ToLower (str [strpos]);
1423 if (!((c == program [pc + 1]))) {
1425 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1427 if (pc + 1 == char_group_end)
1428 goto test_char_group_passed;
1434 case RxOp.NoRangeIgnoreCase:
1435 if (strpos < string_end) {
1436 char c = Char.ToLower (str [strpos]);
1437 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1439 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1441 if (pc + 1 == char_group_end)
1442 goto test_char_group_passed;
1448 case RxOp.NoUnicodeRangeIgnoreCase:
1449 if (strpos < string_end) {
1450 char c = Char.ToLower (str [strpos]);
1451 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1453 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1455 if (pc + 1 == char_group_end)
1456 goto test_char_group_passed;
1462 case RxOp.NoUnicodeCharIgnoreCase:
1463 if (strpos < string_end) {
1464 char c = Char.ToLower (str [strpos]);
1465 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1467 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1469 if (pc + 1 == char_group_end)
1470 goto test_char_group_passed;
1476 case RxOp.NoBitmapIgnoreCase:
1477 if (strpos < string_end) {
1478 char c = Char.ToLower (str [strpos]);
1479 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1480 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1481 pc += 3 + program [pc + 2];
1482 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1484 if (pc + 1 == char_group_end)
1485 goto test_char_group_passed;
1491 case RxOp.NoUnicodeBitmapIgnoreCase:
1492 if (strpos < string_end) {
1493 char c = Char.ToLower (str [strpos]);
1494 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1495 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1496 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1497 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1499 if (pc + 1 == char_group_end)
1500 goto test_char_group_passed;
1506 case RxOp.CharReverse:
1508 char c = str [strpos - 1];
1509 if (((c == program [pc + 1]))) {
1511 if (char_group_end != 0)
1512 goto test_char_group_passed;
1517 if (char_group_end == 0)
1521 case RxOp.RangeReverse:
1523 char c = str [strpos - 1];
1524 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1526 if (char_group_end != 0)
1527 goto test_char_group_passed;
1532 if (char_group_end == 0)
1536 case RxOp.UnicodeRangeReverse:
1538 char c = str [strpos - 1];
1539 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1541 if (char_group_end != 0)
1542 goto test_char_group_passed;
1547 if (char_group_end == 0)
1551 case RxOp.UnicodeCharReverse:
1553 char c = str [strpos - 1];
1554 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1556 if (char_group_end != 0)
1557 goto test_char_group_passed;
1562 if (char_group_end == 0)
1566 case RxOp.CategoryAnyReverse:
1568 char c = str [strpos - 1];
1569 if (((c != '\n'))) {
1571 if (char_group_end != 0)
1572 goto test_char_group_passed;
1577 if (char_group_end == 0)
1581 case RxOp.CategoryAnySinglelineReverse:
1583 //char c = str [strpos - 1];
1586 if (char_group_end != 0)
1587 goto test_char_group_passed;
1592 if (char_group_end == 0)
1596 case RxOp.CategoryWordReverse:
1598 char c = str [strpos - 1];
1599 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1601 if (char_group_end != 0)
1602 goto test_char_group_passed;
1607 if (char_group_end == 0)
1611 case RxOp.CategoryDigitReverse:
1613 char c = str [strpos - 1];
1614 if (((Char.IsDigit (c)))) {
1616 if (char_group_end != 0)
1617 goto test_char_group_passed;
1622 if (char_group_end == 0)
1626 case RxOp.CategoryWhiteSpaceReverse:
1628 char c = str [strpos - 1];
1629 if (((Char.IsWhiteSpace (c)))) {
1631 if (char_group_end != 0)
1632 goto test_char_group_passed;
1637 if (char_group_end == 0)
1641 case RxOp.CategoryEcmaWordReverse:
1643 char c = str [strpos - 1];
1644 if ((('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1646 if (char_group_end != 0)
1647 goto test_char_group_passed;
1652 if (char_group_end == 0)
1656 case RxOp.CategoryEcmaWhiteSpaceReverse:
1658 char c = str [strpos - 1];
1659 if (((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1661 if (char_group_end != 0)
1662 goto test_char_group_passed;
1667 if (char_group_end == 0)
1671 case RxOp.CategoryUnicodeSpecialsReverse:
1673 char c = str [strpos - 1];
1674 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1676 if (char_group_end != 0)
1677 goto test_char_group_passed;
1682 if (char_group_end == 0)
1686 case RxOp.CategoryUnicodeReverse:
1688 char c = str [strpos - 1];
1689 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1691 if (char_group_end != 0)
1692 goto test_char_group_passed;
1697 if (char_group_end == 0)
1701 case RxOp.CategoryGeneralReverse:
1703 char c = str [strpos - 1];
1704 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1706 if (char_group_end != 0)
1707 goto test_char_group_passed;
1712 if (char_group_end == 0)
1716 case RxOp.BitmapReverse:
1718 char c = str [strpos - 1];
1719 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1720 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1722 if (char_group_end != 0)
1723 goto test_char_group_passed;
1724 pc += 3 + program [pc + 2];
1728 if (char_group_end == 0)
1730 pc += 3 + program [pc + 2];
1732 case RxOp.UnicodeBitmapReverse:
1734 char c = str [strpos - 1];
1735 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1736 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1738 if (char_group_end != 0)
1739 goto test_char_group_passed;
1740 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1744 if (char_group_end == 0)
1746 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1748 case RxOp.CharIgnoreCaseReverse:
1750 char c = Char.ToLower (str [strpos - 1]);
1751 if (((c == program [pc + 1]))) {
1753 if (char_group_end != 0)
1754 goto test_char_group_passed;
1759 if (char_group_end == 0)
1763 case RxOp.RangeIgnoreCaseReverse:
1765 char c = Char.ToLower (str [strpos - 1]);
1766 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1768 if (char_group_end != 0)
1769 goto test_char_group_passed;
1774 if (char_group_end == 0)
1778 case RxOp.UnicodeRangeIgnoreCaseReverse:
1780 char c = Char.ToLower (str [strpos - 1]);
1781 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1783 if (char_group_end != 0)
1784 goto test_char_group_passed;
1789 if (char_group_end == 0)
1793 case RxOp.UnicodeCharIgnoreCaseReverse:
1795 char c = Char.ToLower (str [strpos - 1]);
1796 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1798 if (char_group_end != 0)
1799 goto test_char_group_passed;
1804 if (char_group_end == 0)
1808 case RxOp.BitmapIgnoreCaseReverse:
1810 char c = Char.ToLower (str [strpos - 1]);
1811 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1812 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1814 if (char_group_end != 0)
1815 goto test_char_group_passed;
1816 pc += 3 + program [pc + 2];
1820 if (char_group_end == 0)
1822 pc += 3 + program [pc + 2];
1824 case RxOp.UnicodeBitmapIgnoreCaseReverse:
1826 char c = Char.ToLower (str [strpos - 1]);
1827 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1828 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1830 if (char_group_end != 0)
1831 goto test_char_group_passed;
1832 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1836 if (char_group_end == 0)
1838 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1840 case RxOp.NoCharReverse:
1842 char c = str [strpos - 1];
1843 if (!((c == program [pc + 1]))) {
1845 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1847 if (pc + 1 == char_group_end)
1848 goto test_char_group_passed;
1854 case RxOp.NoRangeReverse:
1856 char c = str [strpos - 1];
1857 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1859 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1861 if (pc + 1 == char_group_end)
1862 goto test_char_group_passed;
1868 case RxOp.NoUnicodeRangeReverse:
1870 char c = str [strpos - 1];
1871 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1873 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1875 if (pc + 1 == char_group_end)
1876 goto test_char_group_passed;
1882 case RxOp.NoUnicodeCharReverse:
1884 char c = str [strpos - 1];
1885 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1887 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1889 if (pc + 1 == char_group_end)
1890 goto test_char_group_passed;
1896 case RxOp.NoCategoryAnyReverse:
1898 char c = str [strpos - 1];
1899 if (!((c != '\n'))) {
1901 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1903 if (pc + 1 == char_group_end)
1904 goto test_char_group_passed;
1910 case RxOp.NoCategoryAnySinglelineReverse:
1913 char c = str [strpos - 1];
1916 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1918 if (pc + 1 == char_group_end)
1919 goto test_char_group_passed;
1926 case RxOp.NoCategoryWordReverse:
1928 char c = str [strpos - 1];
1929 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1931 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1933 if (pc + 1 == char_group_end)
1934 goto test_char_group_passed;
1940 case RxOp.NoCategoryDigitReverse:
1942 char c = str [strpos - 1];
1943 if (!((Char.IsDigit (c)))) {
1945 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1947 if (pc + 1 == char_group_end)
1948 goto test_char_group_passed;
1954 case RxOp.NoCategoryWhiteSpaceReverse:
1956 char c = str [strpos - 1];
1957 if (!((Char.IsWhiteSpace (c)))) {
1959 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1961 if (pc + 1 == char_group_end)
1962 goto test_char_group_passed;
1968 case RxOp.NoCategoryEcmaWordReverse:
1970 char c = str [strpos - 1];
1971 if (!(('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1973 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1975 if (pc + 1 == char_group_end)
1976 goto test_char_group_passed;
1982 case RxOp.NoCategoryEcmaWhiteSpaceReverse:
1984 char c = str [strpos - 1];
1985 if (!((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1987 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1989 if (pc + 1 == char_group_end)
1990 goto test_char_group_passed;
1996 case RxOp.NoCategoryUnicodeSpecialsReverse:
1998 char c = str [strpos - 1];
1999 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
2001 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2003 if (pc + 1 == char_group_end)
2004 goto test_char_group_passed;
2010 case RxOp.NoCategoryUnicodeReverse:
2012 char c = str [strpos - 1];
2013 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
2015 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2017 if (pc + 1 == char_group_end)
2018 goto test_char_group_passed;
2024 case RxOp.NoCategoryGeneralReverse:
2026 char c = str [strpos - 1];
2027 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
2029 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2031 if (pc + 1 == char_group_end)
2032 goto test_char_group_passed;
2038 case RxOp.NoBitmapReverse:
2040 char c = str [strpos - 1];
2041 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
2042 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2043 pc += 3 + program [pc + 2];
2044 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2046 if (pc + 1 == char_group_end)
2047 goto test_char_group_passed;
2053 case RxOp.NoUnicodeBitmapReverse:
2055 char c = str [strpos - 1];
2056 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
2057 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2058 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
2059 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2061 if (pc + 1 == char_group_end)
2062 goto test_char_group_passed;
2068 case RxOp.NoCharIgnoreCaseReverse:
2070 char c = Char.ToLower (str [strpos - 1]);
2071 if (!((c == program [pc + 1]))) {
2073 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2075 if (pc + 1 == char_group_end)
2076 goto test_char_group_passed;
2082 case RxOp.NoRangeIgnoreCaseReverse:
2084 char c = Char.ToLower (str [strpos - 1]);
2085 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
2087 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2089 if (pc + 1 == char_group_end)
2090 goto test_char_group_passed;
2096 case RxOp.NoUnicodeRangeIgnoreCaseReverse:
2098 char c = Char.ToLower (str [strpos - 1]);
2099 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
2101 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2103 if (pc + 1 == char_group_end)
2104 goto test_char_group_passed;
2110 case RxOp.NoUnicodeCharIgnoreCaseReverse:
2112 char c = Char.ToLower (str [strpos - 1]);
2113 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
2115 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2117 if (pc + 1 == char_group_end)
2118 goto test_char_group_passed;
2124 case RxOp.NoBitmapIgnoreCaseReverse:
2126 char c = Char.ToLower (str [strpos - 1]);
2127 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
2128 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2129 pc += 3 + program [pc + 2];
2130 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2132 if (pc + 1 == char_group_end)
2133 goto test_char_group_passed;
2139 case RxOp.NoUnicodeBitmapIgnoreCaseReverse:
2141 char c = Char.ToLower (str [strpos - 1]);
2142 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
2143 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2144 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
2145 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2147 if (pc + 1 == char_group_end)
2148 goto test_char_group_passed;
2155 // END OF GENERATED CODE
2159 if (EvalByteCode (pc + 3, strpos, ref res)) {
2160 strpos_result = res;
2163 //Console.WriteLine ("branch offset: {0}", program [pc + 1] | ((int)program [pc + 2] << 8));
2164 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
2168 case RxOp.RepeatLazy: {
2170 * Repetation is modelled by two opcodes: Repeat and Until which
2171 * contain the the qualified regex between them, i.e.:
2172 * Repeat, <bytecode for the inner regex>, Until, <Tail expr>
2173 * It is processed as follows:
2174 * Repeat, [Until, <inner expr>]*, <Tail>
2175 * This means that nested quantifiers are processed a bit
2176 * strangely: when the inner quantifier fails to match, its
2177 * tail is processed which includes the outer Until.
2179 * This code is from the old interpreter.cs.
2181 * FIXME: Rethink this.
2186 this.repeat = new RepeatContext (
2187 this.repeat, // previous context
2188 ReadInt (program, pc + 3), // minimum
2189 ReadInt (program, pc + 7), // maximum
2190 (RxOp)program [pc] == RxOp.RepeatLazy, // lazy
2191 pc + 11 // subexpression
2194 int until = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
2195 if (!EvalByteCode (until, strpos, ref res)) {
2196 this.repeat = this.repeat.Previous;
2201 strpos_result = strpos;
2205 RepeatContext current = this.repeat;
2209 // Can we avoid recursion?
2211 // Backtracking can be forced in nested quantifiers from the tail of this quantifier.
2212 // Thus, we cannot, in general, use a simple loop on repeat.Expression to handle
2215 // If 'deep' was unmolested, that implies that there was no nested quantifiers.
2216 // Thus, we can safely avoid recursion.
2218 if (deep == current)
2221 start = current.Start;
2222 int start_count = current.Count;
2224 // First match at least 'start' items without backtracking
2225 while (!current.IsMinimum) {
2227 current.Start = strpos;
2229 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2230 current.Start = start;
2231 current.Count = start_count;
2235 if (deep != current) // recursive mode
2239 if (strpos == current.Start) {
2240 // degenerate match ... match tail or fail
2241 this.repeat = current.Previous;
2243 if (EvalByteCode (pc + 1, strpos, ref res)) {
2247 this.repeat = current;
2251 if (current.IsLazy) {
2253 // match tail first ...
2254 this.repeat = current.Previous;
2256 int cp = Checkpoint ();
2257 if (EvalByteCode (pc + 1, strpos, ref res)) {
2264 // ... then match more
2265 this.repeat = current;
2266 if (current.IsMaximum)
2269 current.Start = strpos;
2271 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2272 current.Start = start;
2273 current.Count = start_count;
2277 if (deep != current) // recursive mode
2279 // Degenerate match: ptr has not moved since the last (failed) tail match.
2280 // So, next and subsequent tail matches will fail.
2281 if (strpos == current.Start)
2285 int stack_size = stack.Count;
2287 // match greedily as much as possible
2288 while (!current.IsMaximum) {
2289 int cp = Checkpoint ();
2290 int old_ptr = strpos;
2291 int old_start = current.Start;
2295 Console.WriteLine ("recurse with count {0}.", current.Count);
2296 current.Start = strpos;
2298 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2300 current.Start = old_start;
2305 if (deep != current) {
2306 // recursive mode: no more backtracking, truncate the stack
2307 stack.Count = stack_size;
2311 stack.Push (old_ptr);
2313 // Degenerate match: no point going on
2314 if (strpos == current.Start)
2319 Console.WriteLine ("matching tail: {0} pc={1}", strpos, pc + 1);
2320 // then, match the tail, backtracking as necessary.
2321 this.repeat = current.Previous;
2324 if (EvalByteCode (pc + 1, strpos, ref res)) {
2326 stack.Count = stack_size;
2329 if (stack.Count == stack_size) {
2330 this.repeat = current;
2335 strpos = stack.Pop ();
2336 Backtrack (stack.Pop ());
2338 Console.WriteLine ("backtracking to {0} expr={1} pc={2}", strpos, current.Expression, pc);
2343 case RxOp.FastRepeat:
2344 case RxOp.FastRepeatLazy: {
2346 * A FastRepeat is a simplified version of Repeat which does
2347 * not contain another repeat inside, so backtracking is
2350 bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
2352 int tail = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
2353 start = ReadInt (program, pc + 3);
2354 end = ReadInt (program, pc + 7);
2355 //Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);
2360 // First match at least 'start' items
2361 while (length < start) {
2362 if (!EvalByteCode (pc + 11, strpos, ref res))
2371 int cp = Checkpoint ();
2372 if (EvalByteCode (tail, strpos, ref res)) {
2374 goto repeat_success;
2382 if (!EvalByteCode (pc + 11, strpos, ref res))
2388 // Then match as many items as possible, recording
2389 // backtracking information
2390 int old_stack_size = stack.Count;
2391 while (length < end) {
2392 int cp = Checkpoint ();
2393 if (!EvalByteCode (pc + 11, strpos, ref res)) {
2398 stack.Push (strpos);
2404 throw new Exception ();
2406 // Then, match the tail, backtracking as necessary.
2408 if (EvalByteCode (tail, strpos, ref res)) {
2410 stack.Count = old_stack_size;
2411 goto repeat_success;
2413 if (stack.Count == old_stack_size)
2417 strpos = stack.Pop ();
2418 Backtrack (stack.Pop ());
2420 Console.WriteLine ("backtracking to: {0}", strpos);
2425 // We matched the tail too so just return
2430 Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", (RxOp)program [pc], pc, strpos);
2431 throw new NotSupportedException ();
2436 strpos_result = strpos;
2440 test_char_group_passed:
2441 pc = char_group_end;
2444 } // end of while (true)