2 // Based upon interpreter.cs, written by Dan Lewis (dlewis@gmx.co.uk)
5 using System.Collections;
6 using System.Globalization;
7 using System.Diagnostics;
9 namespace System.Text.RegularExpressions {
11 internal delegate bool EvalDelegate (RxInterpreter interp, int strpos, ref int strpos_result);
13 sealed class RxInterpreter: BaseMachine {
21 EvalDelegate eval_del; // optimized EvalByteCode method created by the CILCompiler
23 Mark[] marks = null; // mark stack
24 int mark_start; // start of current checkpoint
25 int mark_end; // end of checkpoint/next free mark
27 IntStack stack; // utility stack
29 RepeatContext repeat; // current repeat context
30 RepeatContext deep; // points to the most-nested repeat context
32 /* The readonly ensures the JIT can optimize out if (trace_rx) statements */
33 public static readonly bool trace_rx =
35 Environment.GetEnvironmentVariable ("MONO_TRACE_RX") != null;
42 internal struct IntStack {
47 return values [--count];
49 public void Push (int value)
53 } else if (count == values.Length) {
54 int new_size = values.Length;
55 new_size += new_size >> 1;
56 int [] new_values = new int [new_size];
57 for (int i = 0; i < count; ++i)
58 new_values [i] = values [i];
61 values [count++] = value;
64 get { return values [count - 1]; }
70 throw new SystemException ("can only truncate the stack");
76 private class RepeatContext {
77 public RepeatContext (RepeatContext previous, int min, int max, bool lazy, int expr_pc) {
78 this.previous = previous;
82 this.expr_pc = expr_pc;
90 set { count = value; }
95 set { start = value; }
98 public bool IsMinimum {
99 get { return min <= count; }
102 public bool IsMaximum {
103 get { return max <= count; }
110 public int Expression {
111 get { return expr_pc; }
114 public RepeatContext Previous {
115 get { return previous; }
119 private int min, max;
122 private RepeatContext previous;
127 static int ReadInt (byte[] code, int pc)
130 val |= (int)code [pc + 1] << 8;
131 val |= (int)code [pc + 2] << 16;
132 val |= (int)code [pc + 3] << 24;
136 public RxInterpreter (byte[] program, EvalDelegate eval_del)
138 this.program = program;
139 this.eval_del = eval_del;
140 group_count = 1 + (program [1] | ((int)program [2] << 8));
141 groups = new int [group_count];
142 stack = new IntStack ();
147 public override Match Scan (Regex regex, string text, int start, int end) {
149 string_start = start;
154 if (eval_del != null) {
155 match = eval_del (this, start, ref res);
157 match = EvalByteCode (11, start, ref res);
159 marks [groups [0]].End = res;
161 return GenerateMatch (regex);
162 //Match m = new Match (regex, this, text, end, 0, match_start, res - match_start);
168 // capture management
169 private void Open (int gid, int ptr) {
170 int m = groups [gid];
171 if (m < mark_start || marks [m].IsDefined) {
176 marks [m].Start = ptr;
179 private void Close (int gid, int ptr) {
180 marks [groups [gid]].End = ptr;
183 private bool Balance (int gid, int balance_gid, bool capture, int ptr) {
184 int b = groups [balance_gid];
186 if(b == -1 || marks[b].Index < 0) {
187 //Group not previously matched
190 Debug.Assert (marks [b].IsDefined, "Regex", "Balancng group not closed");
191 if (gid > 0 && capture){
192 Open (gid, marks [b].Index + marks [b].Length);
196 groups [balance_gid] = marks[b].Previous;
201 private int Checkpoint () {
202 mark_start = mark_end;
206 private void Backtrack (int cp) {
207 for (int i = 0; i < groups.Length; ++ i) {
210 m = marks [m].Previous;
215 private void ResetGroups () {
216 int n = groups.Length;
218 marks = new Mark [n];
220 for (int i = 0; i < n; ++ i) {
223 marks [i].Start = -1;
225 marks [i].Previous = -1;
231 private int GetLastDefined (int gid) {
232 int m = groups [gid];
233 while (m >= 0 && !marks [m].IsDefined)
234 m = marks [m].Previous;
239 private int CreateMark (int previous) {
240 if (mark_end == marks.Length) {
241 Mark [] dest = new Mark [marks.Length * 2];
242 marks.CopyTo (dest, 0);
247 marks [m].Start = marks [m].End = -1;
248 marks [m].Previous = previous;
253 private void GetGroupInfo (int gid, out int first_mark_index, out int n_caps)
255 first_mark_index = -1;
257 for (int m = groups [gid]; m >= 0; m = marks [m].Previous) {
258 if (!marks [m].IsDefined)
260 if (first_mark_index < 0)
261 first_mark_index = m;
266 private void PopulateGroup (Group g, int first_mark_index, int n_caps)
269 for (int m = marks [first_mark_index].Previous; m >= 0; m = marks [m].Previous) {
270 if (!marks [m].IsDefined)
272 Capture cap = new Capture (str, marks [m].Index, marks [m].Length);
273 g.Captures.SetValue (cap, n_caps - 1 - i);
278 private Match GenerateMatch (Regex regex)
280 int n_caps, first_mark_index;
282 GetGroupInfo (0, out first_mark_index, out n_caps);
284 // Avoid fully populating the Match instance if not needed
285 if (!needs_groups_or_captures)
286 return new Match (regex, this, str, string_end, 0, marks [first_mark_index].Index, marks [first_mark_index].Length);
288 Match retval = new Match (regex, this, str, string_end, groups.Length,
289 marks [first_mark_index].Index, marks [first_mark_index].Length, n_caps);
290 PopulateGroup (retval, first_mark_index, n_caps);
292 for (int gid = 1; gid < groups.Length; ++ gid) {
293 GetGroupInfo (gid, out first_mark_index, out n_caps);
294 if (first_mark_index < 0) {
297 g = new Group (str, marks [first_mark_index].Index, marks [first_mark_index].Length, n_caps);
298 PopulateGroup (g, first_mark_index, n_caps);
300 retval.Groups.SetValue (g, gid);
305 // used by the IL backend
306 internal void SetStartOfMatch (int pos)
308 marks [groups [0]].Start = pos;
311 static bool IsWordChar (char c)
313 return Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
316 bool EvalByteCode (int pc, int strpos, ref int strpos_result)
318 // luckily the IL engine can deal with char_group_end at compile time
319 // this code offset needs to be checked only in opcodes that handle
320 // a single char and that are included in a TestCharGroup expression:
321 // the engine is supposed to jump to this offset as soons as the
322 // first opcode in the expression matches
323 // The code pattern becomes:
324 // on successfull match: check if char_group_end is nonzero and jump to
325 // test_char_group_passed after adjusting strpos
326 // on failure: try the next expression by simply advancing pc
327 int char_group_end = 0;
328 int length, start, end;
331 Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}, cge: {3}", (RxOp)program [pc], pc, strpos, char_group_end);
332 //Console.WriteLine ("deep: " + (deep == null ? 0 : deep.GetHashCode ()) + " repeat: " + (this.repeat == null ? 0 : this.repeat.GetHashCode ()));
334 switch ((RxOp)program [pc]) {
336 if (char_group_end != 0) {
341 strpos_result = strpos;
345 case RxOp.AnyPosition:
348 case RxOp.StartOfString:
353 case RxOp.StartOfLine:
354 if (strpos == 0 || str [strpos - 1] == '\n') {
359 case RxOp.StartOfScan:
360 if (strpos != string_start)
365 if (strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')) {
370 case RxOp.EndOfString:
371 if (strpos != string_end)
376 if (strpos == string_end || str [strpos] == '\n') {
381 case RxOp.WordBoundary:
385 if (IsWordChar (str [strpos])) {
389 } else if (strpos == string_end) {
390 if (IsWordChar (str [strpos - 1])) {
395 if (IsWordChar (str [strpos]) != IsWordChar (str [strpos - 1])) {
401 case RxOp.NoWordBoundary:
405 if (!IsWordChar (str [strpos])) {
409 } else if (strpos == string_end) {
410 if (!IsWordChar (str [strpos - 1])) {
415 if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
422 int skip = program [pc + 1] | ((int)program [pc + 2] << 8);
423 int anch_offset = program [pc + 3] | ((int)program [pc + 4] << 8);
426 * In the general case, we have to evaluate the bytecode
427 * starting at pc + skip, however the optimizer emits some
428 * special cases, whose bytecode begins at pc + 5.
430 int anch_pc = pc + 5;
431 RxOp anch_op = (RxOp)(program[anch_pc] & 0x00ff);
433 bool spec_anch = false;
435 // FIXME: Add more special cases from interpreter.cs
436 if (anch_op == RxOp.String || anch_op == RxOp.StringIgnoreCase) {
437 if (pc + skip == anch_pc + 2 + program [anch_pc + 1] + 1) {
443 Console.WriteLine (" string anchor at {0}, offset {1}", anch_pc, anch_offset);
449 if ((RxOp)program [pc] == RxOp.StartOfString) {
452 if (groups.Length > 1) {
454 marks [groups [0]].Start = strpos;
456 if (EvalByteCode (pc + 1, strpos, ref res)) {
457 marks [groups [0]].Start = strpos;
458 if (groups.Length > 1)
459 marks [groups [0]].End = res;
467 // it's important to test also the end of the string
468 // position for things like: "" =~ /$/
469 end = string_end + 1;
470 while (strpos < end) {
472 if (anch_op == RxOp.String || anch_op == RxOp.StringIgnoreCase) {
474 * This means the match must contain a given
475 * string at a constant position, so we can skip
476 * forward until the string matches. This is a win if
477 * the rest of the regex
478 * has a complex positive lookbehind for example.
480 int tmp_res = strpos;
481 if (!EvalByteCode (anch_pc, strpos + anch_offset, ref tmp_res)) {
488 if (groups.Length > 1) {
490 marks [groups [0]].Start = strpos;
492 if (EvalByteCode (pc, strpos, ref res)) {
493 // match_start = strpos;
494 marks [groups [0]].Start = strpos;
495 if (groups.Length > 1)
496 marks [groups [0]].End = res;
503 case RxOp.AnchorReverse:
504 length = program [pc + 3] | ((int)program [pc + 4] << 8);
505 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
506 // it's important to test also the end of the string
507 // position for things like: "" =~ /$/
509 while (strpos >= 0) {
511 if (groups.Length > 1) {
513 marks [groups [0]].Start = strpos;
515 if (EvalByteCode (pc, strpos, ref res)) {
516 // match_start = strpos;
517 marks [groups [0]].Start = strpos;
518 if (groups.Length > 1)
519 marks [groups [0]].End = res;
527 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
530 start = marks [length].Index;
531 length = marks [length].Length;
532 if (strpos + length > string_end)
534 for (end = start + length; start < end; ++start) {
535 if (str [strpos] != str [start])
541 case RxOp.ReferenceIgnoreCase:
542 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
545 start = marks [length].Index;
546 length = marks [length].Length;
547 if (strpos + length > string_end)
549 for (end = start + length; start < end; ++start) {
550 if (str [strpos] != str [start] && Char.ToLower (str [strpos]) != Char.ToLower (str [start]))
556 case RxOp.ReferenceReverse: {
557 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
560 start = marks [length].Index;
561 length = marks [length].Length;
562 if (strpos - length < 0)
564 int p = strpos - length;
565 for (end = start + length; start < end; ++start, ++p) {
566 if (str [p] != str [start])
574 if (GetLastDefined (program [pc + 3] | ((int)program [pc + 4] << 8)) >= 0)
577 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
579 case RxOp.SubExpression: {
581 if (EvalByteCode (pc + 3, strpos, ref res)) {
582 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
591 if (EvalByteCode (pc + 5, strpos, ref res)) {
592 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
594 pc += program [pc + 3] | ((int)program [pc + 4] << 8);
599 Open (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
602 case RxOp.CloseGroup:
603 Close (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
606 case RxOp.BalanceStart: {
609 if (!EvalByteCode (pc + 8, strpos, ref res))
612 int gid = program [pc + 1] | ((int)program [pc + 2] << 8);
613 int balance_gid = program [pc + 3] | ((int)program [pc + 4] << 8);
614 bool capture = program [pc + 5] > 0;
615 if (!Balance (gid, balance_gid, capture, strpos))
619 pc += program[pc + 6] | ((int)program [pc + 7] << 8);
627 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
629 case RxOp.TestCharGroup:
630 char_group_end = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
635 length = program [pc + 1];
636 if (strpos + length > string_end)
638 end = start + length;
639 for (; start < end; ++start) {
640 if (str [strpos] != program [start])
646 case RxOp.StringIgnoreCase:
648 length = program [pc + 1];
649 if (strpos + length > string_end)
651 end = start + length;
652 for (; start < end; ++start) {
653 if (str [strpos] != program [start] && Char.ToLower (str [strpos]) != program [start])
659 case RxOp.StringReverse: {
661 length = program [pc + 1];
664 int p = strpos - length;
665 end = start + length;
666 for (; start < end; ++start, ++p) {
667 if (str [p] != program [start])
674 case RxOp.StringIgnoreCaseReverse: {
676 length = program [pc + 1];
679 int p = strpos - length;
680 end = start + length;
681 for (; start < end; ++start, ++p) {
682 if (str [p] != program [start] && Char.ToLower (str [p]) != program [start])
689 case RxOp.UnicodeString: {
691 length = program [pc + 1] | ((int)program [pc + 2] << 8);
692 if (strpos + length > string_end)
694 end = start + length * 2;
695 for (; start < end; start += 2) {
696 int c = program [start] | ((int)program [start + 1] << 8);
697 if (str [strpos] != c)
704 case RxOp.UnicodeStringIgnoreCase: {
706 length = program [pc + 1] | ((int)program [pc + 2] << 8);
707 if (strpos + length > string_end)
709 end = start + length * 2;
710 for (; start < end; start += 2) {
711 int c = program [start] | ((int)program [start + 1] << 8);
712 if (str [strpos] != c && Char.ToLower (str [strpos]) != c)
719 case RxOp.UnicodeStringReverse: {
721 length = program [pc + 1] | ((int)program [pc + 2] << 8);
724 int p = strpos - length;
725 end = start + length * 2;
726 for (; start < end; start += 2, p += 2) {
727 int c = program [start] | ((int)program [start + 1] << 8);
735 case RxOp.UnicodeStringIgnoreCaseReverse: {
737 length = program [pc + 1] | ((int)program [pc + 2] << 8);
740 int p = strpos - length;
741 end = start + length * 2;
742 for (; start < end; start += 2, p += 2) {
743 int c = program [start] | ((int)program [start + 1] << 8);
744 if (str [p] != c && Char.ToLower (str [p]) != c)
753 * The opcodes below are basically specialized versions of one
754 * generic opcode, which has three parameters:
755 * - reverse (Reverse), revert (No), ignore-case (IgnoreCase)
756 * Thus each opcode has 8 variants.
757 * FIXME: Maybe move all unusual variations
758 * (Reverse+IgnoreCase+Unicode) into a generic GenericChar opcode
759 * like in the old interpreter.
760 * FIXME: Move all the Reverse opcodes to a separate method.
764 if (strpos < string_end && (COND (str [strpos]))) {
767 if (char_group_end != 0)
768 goto test_char_group_passed;
773 * If we are inside a char group, the cases are ANDed
774 * together, so we have to continue checking the
775 * other cases, and we need to increase strpos after
777 * The char group is termined by a True, hence the
779 * FIXME: Optimize this.
782 if (char_group_end == 0 || (pc + 1 == char_group_end))
784 if (pc + 1 == char_group_end)
785 goto test_char_group_passed;
790 if (char_group_end == 0)
795 /* Fail both inside and outside a char group */
800 // Same as above, but use:
801 // - strpos > 0 instead of strpos < string_len
802 // - COND (str [strpos - 1]) instead of COND (str [strpos])
803 // - strpos -- instead of strpos ++
806 // GENERATED BY gen-interp.cs, DO NOT MODIFY
811 if (strpos < string_end) {
812 char c = str [strpos];
813 if (((c == program [pc + 1]))) {
815 if (char_group_end != 0)
816 goto test_char_group_passed;
821 if (char_group_end == 0)
829 if (strpos < string_end) {
830 char c = str [strpos];
831 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
833 if (char_group_end != 0)
834 goto test_char_group_passed;
839 if (char_group_end == 0)
846 case RxOp.UnicodeRange:
847 if (strpos < string_end) {
848 char c = str [strpos];
849 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
851 if (char_group_end != 0)
852 goto test_char_group_passed;
857 if (char_group_end == 0)
864 case RxOp.UnicodeChar:
865 if (strpos < string_end) {
866 char c = str [strpos];
867 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
869 if (char_group_end != 0)
870 goto test_char_group_passed;
875 if (char_group_end == 0)
882 case RxOp.CategoryAny:
883 if (strpos < string_end) {
884 char c = str [strpos];
887 if (char_group_end != 0)
888 goto test_char_group_passed;
893 if (char_group_end == 0)
898 /* CategoryAnySingleline */
900 case RxOp.CategoryAnySingleline:
901 if (strpos < string_end) {
902 char c = str [strpos];
905 if (char_group_end != 0)
906 goto test_char_group_passed;
911 if (char_group_end == 0)
918 case RxOp.CategoryWord:
919 if (strpos < string_end) {
920 char c = str [strpos];
921 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
923 if (char_group_end != 0)
924 goto test_char_group_passed;
929 if (char_group_end == 0)
936 case RxOp.CategoryDigit:
937 if (strpos < string_end) {
938 char c = str [strpos];
939 if (((Char.IsDigit (c)))) {
941 if (char_group_end != 0)
942 goto test_char_group_passed;
947 if (char_group_end == 0)
952 /* CategoryWhiteSpace */
954 case RxOp.CategoryWhiteSpace:
955 if (strpos < string_end) {
956 char c = str [strpos];
957 if (((Char.IsWhiteSpace (c)))) {
959 if (char_group_end != 0)
960 goto test_char_group_passed;
965 if (char_group_end == 0)
970 /* CategoryEcmaWord */
972 case RxOp.CategoryEcmaWord:
973 if (strpos < string_end) {
974 char c = str [strpos];
975 if ((('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
977 if (char_group_end != 0)
978 goto test_char_group_passed;
983 if (char_group_end == 0)
988 /* CategoryEcmaWhiteSpace */
990 case RxOp.CategoryEcmaWhiteSpace:
991 if (strpos < string_end) {
992 char c = str [strpos];
993 if (((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
995 if (char_group_end != 0)
996 goto test_char_group_passed;
1001 if (char_group_end == 0)
1006 /* CategoryUnicodeSpecials */
1008 case RxOp.CategoryUnicodeSpecials:
1009 if (strpos < string_end) {
1010 char c = str [strpos];
1011 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1013 if (char_group_end != 0)
1014 goto test_char_group_passed;
1019 if (char_group_end == 0)
1024 /* CategoryUnicode */
1026 case RxOp.CategoryUnicode:
1027 if (strpos < string_end) {
1028 char c = str [strpos];
1029 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1031 if (char_group_end != 0)
1032 goto test_char_group_passed;
1037 if (char_group_end == 0)
1042 /* CategoryGeneral */
1044 case RxOp.CategoryGeneral:
1045 if (strpos < string_end) {
1046 char c = str [strpos];
1047 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1049 if (char_group_end != 0)
1050 goto test_char_group_passed;
1055 if (char_group_end == 0)
1063 if (strpos < string_end) {
1064 char c = str [strpos];
1065 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1066 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1068 if (char_group_end != 0)
1069 goto test_char_group_passed;
1070 pc += 3 + program [pc + 2];
1074 if (char_group_end == 0)
1076 pc += 3 + program [pc + 2];
1081 case RxOp.UnicodeBitmap:
1082 if (strpos < string_end) {
1083 char c = str [strpos];
1084 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1085 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1087 if (char_group_end != 0)
1088 goto test_char_group_passed;
1089 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1093 if (char_group_end == 0)
1095 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1097 case RxOp.CharIgnoreCase:
1098 if (strpos < string_end) {
1099 char c = Char.ToLower (str [strpos]);
1100 if (((c == program [pc + 1]))) {
1102 if (char_group_end != 0)
1103 goto test_char_group_passed;
1108 if (char_group_end == 0)
1112 case RxOp.RangeIgnoreCase:
1113 if (strpos < string_end) {
1114 char c = Char.ToLower (str [strpos]);
1115 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1117 if (char_group_end != 0)
1118 goto test_char_group_passed;
1123 if (char_group_end == 0)
1127 case RxOp.UnicodeRangeIgnoreCase:
1128 if (strpos < string_end) {
1129 char c = Char.ToLower (str [strpos]);
1130 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1132 if (char_group_end != 0)
1133 goto test_char_group_passed;
1138 if (char_group_end == 0)
1142 case RxOp.UnicodeCharIgnoreCase:
1143 if (strpos < string_end) {
1144 char c = Char.ToLower (str [strpos]);
1145 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1147 if (char_group_end != 0)
1148 goto test_char_group_passed;
1153 if (char_group_end == 0)
1157 case RxOp.BitmapIgnoreCase:
1158 if (strpos < string_end) {
1159 char c = Char.ToLower (str [strpos]);
1160 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1161 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1163 if (char_group_end != 0)
1164 goto test_char_group_passed;
1165 pc += 3 + program [pc + 2];
1169 if (char_group_end == 0)
1171 pc += 3 + program [pc + 2];
1173 case RxOp.UnicodeBitmapIgnoreCase:
1174 if (strpos < string_end) {
1175 char c = Char.ToLower (str [strpos]);
1176 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1177 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1179 if (char_group_end != 0)
1180 goto test_char_group_passed;
1181 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1185 if (char_group_end == 0)
1187 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1190 if (strpos < string_end) {
1191 char c = str [strpos];
1192 if (!((c == program [pc + 1]))) {
1194 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1196 if (pc + 1 == char_group_end)
1197 goto test_char_group_passed;
1204 if (strpos < string_end) {
1205 char c = str [strpos];
1206 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1208 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1210 if (pc + 1 == char_group_end)
1211 goto test_char_group_passed;
1217 case RxOp.NoUnicodeRange:
1218 if (strpos < string_end) {
1219 char c = str [strpos];
1220 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1222 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1224 if (pc + 1 == char_group_end)
1225 goto test_char_group_passed;
1231 case RxOp.NoUnicodeChar:
1232 if (strpos < string_end) {
1233 char c = str [strpos];
1234 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1236 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1238 if (pc + 1 == char_group_end)
1239 goto test_char_group_passed;
1245 case RxOp.NoCategoryAny:
1246 if (strpos < string_end) {
1247 char c = str [strpos];
1248 if (!((c != '\n'))) {
1250 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1252 if (pc + 1 == char_group_end)
1253 goto test_char_group_passed;
1259 case RxOp.NoCategoryAnySingleline:
1260 if (strpos < string_end) {
1261 char c = str [strpos];
1264 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1266 if (pc + 1 == char_group_end)
1267 goto test_char_group_passed;
1273 case RxOp.NoCategoryWord:
1274 if (strpos < string_end) {
1275 char c = str [strpos];
1276 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1278 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1280 if (pc + 1 == char_group_end)
1281 goto test_char_group_passed;
1287 case RxOp.NoCategoryDigit:
1288 if (strpos < string_end) {
1289 char c = str [strpos];
1290 if (!((Char.IsDigit (c)))) {
1292 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1294 if (pc + 1 == char_group_end)
1295 goto test_char_group_passed;
1301 case RxOp.NoCategoryWhiteSpace:
1302 if (strpos < string_end) {
1303 char c = str [strpos];
1304 if (!((Char.IsWhiteSpace (c)))) {
1306 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1308 if (pc + 1 == char_group_end)
1309 goto test_char_group_passed;
1315 case RxOp.NoCategoryEcmaWord:
1316 if (strpos < string_end) {
1317 char c = str [strpos];
1318 if (!(('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1320 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1322 if (pc + 1 == char_group_end)
1323 goto test_char_group_passed;
1329 case RxOp.NoCategoryEcmaWhiteSpace:
1330 if (strpos < string_end) {
1331 char c = str [strpos];
1332 if (!((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1334 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1336 if (pc + 1 == char_group_end)
1337 goto test_char_group_passed;
1343 case RxOp.NoCategoryUnicodeSpecials:
1344 if (strpos < string_end) {
1345 char c = str [strpos];
1346 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1348 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1350 if (pc + 1 == char_group_end)
1351 goto test_char_group_passed;
1357 case RxOp.NoCategoryUnicode:
1358 if (strpos < string_end) {
1359 char c = str [strpos];
1360 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1362 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1364 if (pc + 1 == char_group_end)
1365 goto test_char_group_passed;
1371 case RxOp.NoCategoryGeneral:
1372 if (strpos < string_end) {
1373 char c = str [strpos];
1374 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1376 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1378 if (pc + 1 == char_group_end)
1379 goto test_char_group_passed;
1386 if (strpos < string_end) {
1387 char c = str [strpos];
1388 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1389 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1390 pc += 3 + program [pc + 2];
1391 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1393 if (pc + 1 == char_group_end)
1394 goto test_char_group_passed;
1400 case RxOp.NoUnicodeBitmap:
1401 if (strpos < string_end) {
1402 char c = str [strpos];
1403 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1404 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1405 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1406 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1408 if (pc + 1 == char_group_end)
1409 goto test_char_group_passed;
1415 case RxOp.NoCharIgnoreCase:
1416 if (strpos < string_end) {
1417 char c = Char.ToLower (str [strpos]);
1418 if (!((c == program [pc + 1]))) {
1420 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1422 if (pc + 1 == char_group_end)
1423 goto test_char_group_passed;
1429 case RxOp.NoRangeIgnoreCase:
1430 if (strpos < string_end) {
1431 char c = Char.ToLower (str [strpos]);
1432 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1434 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1436 if (pc + 1 == char_group_end)
1437 goto test_char_group_passed;
1443 case RxOp.NoUnicodeRangeIgnoreCase:
1444 if (strpos < string_end) {
1445 char c = Char.ToLower (str [strpos]);
1446 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1448 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1450 if (pc + 1 == char_group_end)
1451 goto test_char_group_passed;
1457 case RxOp.NoUnicodeCharIgnoreCase:
1458 if (strpos < string_end) {
1459 char c = Char.ToLower (str [strpos]);
1460 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1462 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1464 if (pc + 1 == char_group_end)
1465 goto test_char_group_passed;
1471 case RxOp.NoBitmapIgnoreCase:
1472 if (strpos < string_end) {
1473 char c = Char.ToLower (str [strpos]);
1474 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1475 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1476 pc += 3 + program [pc + 2];
1477 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1479 if (pc + 1 == char_group_end)
1480 goto test_char_group_passed;
1486 case RxOp.NoUnicodeBitmapIgnoreCase:
1487 if (strpos < string_end) {
1488 char c = Char.ToLower (str [strpos]);
1489 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1490 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1491 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1492 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1494 if (pc + 1 == char_group_end)
1495 goto test_char_group_passed;
1501 case RxOp.CharReverse:
1503 char c = str [strpos - 1];
1504 if (((c == program [pc + 1]))) {
1506 if (char_group_end != 0)
1507 goto test_char_group_passed;
1512 if (char_group_end == 0)
1516 case RxOp.RangeReverse:
1518 char c = str [strpos - 1];
1519 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1521 if (char_group_end != 0)
1522 goto test_char_group_passed;
1527 if (char_group_end == 0)
1531 case RxOp.UnicodeRangeReverse:
1533 char c = str [strpos - 1];
1534 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1536 if (char_group_end != 0)
1537 goto test_char_group_passed;
1542 if (char_group_end == 0)
1546 case RxOp.UnicodeCharReverse:
1548 char c = str [strpos - 1];
1549 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1551 if (char_group_end != 0)
1552 goto test_char_group_passed;
1557 if (char_group_end == 0)
1561 case RxOp.CategoryAnyReverse:
1563 char c = str [strpos - 1];
1564 if (((c != '\n'))) {
1566 if (char_group_end != 0)
1567 goto test_char_group_passed;
1572 if (char_group_end == 0)
1576 case RxOp.CategoryAnySinglelineReverse:
1578 char c = str [strpos - 1];
1581 if (char_group_end != 0)
1582 goto test_char_group_passed;
1587 if (char_group_end == 0)
1591 case RxOp.CategoryWordReverse:
1593 char c = str [strpos - 1];
1594 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1596 if (char_group_end != 0)
1597 goto test_char_group_passed;
1602 if (char_group_end == 0)
1606 case RxOp.CategoryDigitReverse:
1608 char c = str [strpos - 1];
1609 if (((Char.IsDigit (c)))) {
1611 if (char_group_end != 0)
1612 goto test_char_group_passed;
1617 if (char_group_end == 0)
1621 case RxOp.CategoryWhiteSpaceReverse:
1623 char c = str [strpos - 1];
1624 if (((Char.IsWhiteSpace (c)))) {
1626 if (char_group_end != 0)
1627 goto test_char_group_passed;
1632 if (char_group_end == 0)
1636 case RxOp.CategoryEcmaWordReverse:
1638 char c = str [strpos - 1];
1639 if ((('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1641 if (char_group_end != 0)
1642 goto test_char_group_passed;
1647 if (char_group_end == 0)
1651 case RxOp.CategoryEcmaWhiteSpaceReverse:
1653 char c = str [strpos - 1];
1654 if (((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1656 if (char_group_end != 0)
1657 goto test_char_group_passed;
1662 if (char_group_end == 0)
1666 case RxOp.CategoryUnicodeSpecialsReverse:
1668 char c = str [strpos - 1];
1669 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1671 if (char_group_end != 0)
1672 goto test_char_group_passed;
1677 if (char_group_end == 0)
1681 case RxOp.CategoryUnicodeReverse:
1683 char c = str [strpos - 1];
1684 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1686 if (char_group_end != 0)
1687 goto test_char_group_passed;
1692 if (char_group_end == 0)
1696 case RxOp.CategoryGeneralReverse:
1698 char c = str [strpos - 1];
1699 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1701 if (char_group_end != 0)
1702 goto test_char_group_passed;
1707 if (char_group_end == 0)
1711 case RxOp.BitmapReverse:
1713 char c = str [strpos - 1];
1714 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1715 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1717 if (char_group_end != 0)
1718 goto test_char_group_passed;
1719 pc += 3 + program [pc + 2];
1723 if (char_group_end == 0)
1725 pc += 3 + program [pc + 2];
1727 case RxOp.UnicodeBitmapReverse:
1729 char c = str [strpos - 1];
1730 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1731 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1733 if (char_group_end != 0)
1734 goto test_char_group_passed;
1735 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1739 if (char_group_end == 0)
1741 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1743 case RxOp.CharIgnoreCaseReverse:
1745 char c = Char.ToLower (str [strpos - 1]);
1746 if (((c == program [pc + 1]))) {
1748 if (char_group_end != 0)
1749 goto test_char_group_passed;
1754 if (char_group_end == 0)
1758 case RxOp.RangeIgnoreCaseReverse:
1760 char c = Char.ToLower (str [strpos - 1]);
1761 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1763 if (char_group_end != 0)
1764 goto test_char_group_passed;
1769 if (char_group_end == 0)
1773 case RxOp.UnicodeRangeIgnoreCaseReverse:
1775 char c = Char.ToLower (str [strpos - 1]);
1776 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1778 if (char_group_end != 0)
1779 goto test_char_group_passed;
1784 if (char_group_end == 0)
1788 case RxOp.UnicodeCharIgnoreCaseReverse:
1790 char c = Char.ToLower (str [strpos - 1]);
1791 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1793 if (char_group_end != 0)
1794 goto test_char_group_passed;
1799 if (char_group_end == 0)
1803 case RxOp.BitmapIgnoreCaseReverse:
1805 char c = Char.ToLower (str [strpos - 1]);
1806 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1807 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1809 if (char_group_end != 0)
1810 goto test_char_group_passed;
1811 pc += 3 + program [pc + 2];
1815 if (char_group_end == 0)
1817 pc += 3 + program [pc + 2];
1819 case RxOp.UnicodeBitmapIgnoreCaseReverse:
1821 char c = Char.ToLower (str [strpos - 1]);
1822 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1823 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1825 if (char_group_end != 0)
1826 goto test_char_group_passed;
1827 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1831 if (char_group_end == 0)
1833 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1835 case RxOp.NoCharReverse:
1837 char c = str [strpos - 1];
1838 if (!((c == program [pc + 1]))) {
1840 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1842 if (pc + 1 == char_group_end)
1843 goto test_char_group_passed;
1849 case RxOp.NoRangeReverse:
1851 char c = str [strpos - 1];
1852 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1854 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1856 if (pc + 1 == char_group_end)
1857 goto test_char_group_passed;
1863 case RxOp.NoUnicodeRangeReverse:
1865 char c = str [strpos - 1];
1866 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1868 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1870 if (pc + 1 == char_group_end)
1871 goto test_char_group_passed;
1877 case RxOp.NoUnicodeCharReverse:
1879 char c = str [strpos - 1];
1880 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1882 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1884 if (pc + 1 == char_group_end)
1885 goto test_char_group_passed;
1891 case RxOp.NoCategoryAnyReverse:
1893 char c = str [strpos - 1];
1894 if (!((c != '\n'))) {
1896 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1898 if (pc + 1 == char_group_end)
1899 goto test_char_group_passed;
1905 case RxOp.NoCategoryAnySinglelineReverse:
1907 char c = str [strpos - 1];
1910 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1912 if (pc + 1 == char_group_end)
1913 goto test_char_group_passed;
1919 case RxOp.NoCategoryWordReverse:
1921 char c = str [strpos - 1];
1922 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1924 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1926 if (pc + 1 == char_group_end)
1927 goto test_char_group_passed;
1933 case RxOp.NoCategoryDigitReverse:
1935 char c = str [strpos - 1];
1936 if (!((Char.IsDigit (c)))) {
1938 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1940 if (pc + 1 == char_group_end)
1941 goto test_char_group_passed;
1947 case RxOp.NoCategoryWhiteSpaceReverse:
1949 char c = str [strpos - 1];
1950 if (!((Char.IsWhiteSpace (c)))) {
1952 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1954 if (pc + 1 == char_group_end)
1955 goto test_char_group_passed;
1961 case RxOp.NoCategoryEcmaWordReverse:
1963 char c = str [strpos - 1];
1964 if (!(('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1966 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1968 if (pc + 1 == char_group_end)
1969 goto test_char_group_passed;
1975 case RxOp.NoCategoryEcmaWhiteSpaceReverse:
1977 char c = str [strpos - 1];
1978 if (!((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1980 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1982 if (pc + 1 == char_group_end)
1983 goto test_char_group_passed;
1989 case RxOp.NoCategoryUnicodeSpecialsReverse:
1991 char c = str [strpos - 1];
1992 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1994 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1996 if (pc + 1 == char_group_end)
1997 goto test_char_group_passed;
2003 case RxOp.NoCategoryUnicodeReverse:
2005 char c = str [strpos - 1];
2006 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
2008 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2010 if (pc + 1 == char_group_end)
2011 goto test_char_group_passed;
2017 case RxOp.NoCategoryGeneralReverse:
2019 char c = str [strpos - 1];
2020 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
2022 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2024 if (pc + 1 == char_group_end)
2025 goto test_char_group_passed;
2031 case RxOp.NoBitmapReverse:
2033 char c = str [strpos - 1];
2034 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
2035 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2036 pc += 3 + program [pc + 2];
2037 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2039 if (pc + 1 == char_group_end)
2040 goto test_char_group_passed;
2046 case RxOp.NoUnicodeBitmapReverse:
2048 char c = str [strpos - 1];
2049 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
2050 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2051 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
2052 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2054 if (pc + 1 == char_group_end)
2055 goto test_char_group_passed;
2061 case RxOp.NoCharIgnoreCaseReverse:
2063 char c = Char.ToLower (str [strpos - 1]);
2064 if (!((c == program [pc + 1]))) {
2066 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2068 if (pc + 1 == char_group_end)
2069 goto test_char_group_passed;
2075 case RxOp.NoRangeIgnoreCaseReverse:
2077 char c = Char.ToLower (str [strpos - 1]);
2078 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
2080 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2082 if (pc + 1 == char_group_end)
2083 goto test_char_group_passed;
2089 case RxOp.NoUnicodeRangeIgnoreCaseReverse:
2091 char c = Char.ToLower (str [strpos - 1]);
2092 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
2094 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2096 if (pc + 1 == char_group_end)
2097 goto test_char_group_passed;
2103 case RxOp.NoUnicodeCharIgnoreCaseReverse:
2105 char c = Char.ToLower (str [strpos - 1]);
2106 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
2108 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2110 if (pc + 1 == char_group_end)
2111 goto test_char_group_passed;
2117 case RxOp.NoBitmapIgnoreCaseReverse:
2119 char c = Char.ToLower (str [strpos - 1]);
2120 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
2121 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2122 pc += 3 + program [pc + 2];
2123 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2125 if (pc + 1 == char_group_end)
2126 goto test_char_group_passed;
2132 case RxOp.NoUnicodeBitmapIgnoreCaseReverse:
2134 char c = Char.ToLower (str [strpos - 1]);
2135 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
2136 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2137 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
2138 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2140 if (pc + 1 == char_group_end)
2141 goto test_char_group_passed;
2148 // END OF GENERATED CODE
2152 if (EvalByteCode (pc + 3, strpos, ref res)) {
2153 strpos_result = res;
2156 //Console.WriteLine ("branch offset: {0}", program [pc + 1] | ((int)program [pc + 2] << 8));
2157 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
2161 case RxOp.RepeatLazy: {
2163 * Repetation is modelled by two opcodes: Repeat and Until which
2164 * contain the the qualified regex between them, i.e.:
2165 * Repeat, <bytecode for the inner regex>, Until, <Tail expr>
2166 * It is processed as follows:
2167 * Repeat, [Until, <inner expr>]*, <Tail>
2168 * This means that nested quantifiers are processed a bit
2169 * strangely: when the inner quantifier fails to match, its
2170 * tail is processed which includes the outer Until.
2172 * This code is from the old interpreter.cs.
2174 * FIXME: Rethink this.
2179 this.repeat = new RepeatContext (
2180 this.repeat, // previous context
2181 ReadInt (program, pc + 3), // minimum
2182 ReadInt (program, pc + 7), // maximum
2183 (RxOp)program [pc] == RxOp.RepeatLazy, // lazy
2184 pc + 11 // subexpression
2187 int until = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
2188 if (!EvalByteCode (until, strpos, ref res)) {
2189 this.repeat = this.repeat.Previous;
2194 strpos_result = strpos;
2198 RepeatContext current = this.repeat;
2202 // Can we avoid recursion?
2204 // Backtracking can be forced in nested quantifiers from the tail of this quantifier.
2205 // Thus, we cannot, in general, use a simple loop on repeat.Expression to handle
2208 // If 'deep' was unmolested, that implies that there was no nested quantifiers.
2209 // Thus, we can safely avoid recursion.
2211 if (deep == current)
2214 start = current.Start;
2215 int start_count = current.Count;
2217 // First match at least 'start' items without backtracking
2218 while (!current.IsMinimum) {
2220 current.Start = strpos;
2222 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2223 current.Start = start;
2224 current.Count = start_count;
2228 if (deep != current) // recursive mode
2232 if (strpos == current.Start) {
2233 // degenerate match ... match tail or fail
2234 this.repeat = current.Previous;
2236 if (EvalByteCode (pc + 1, strpos, ref res)) {
2240 this.repeat = current;
2244 if (current.IsLazy) {
2246 // match tail first ...
2247 this.repeat = current.Previous;
2249 int cp = Checkpoint ();
2250 if (EvalByteCode (pc + 1, strpos, ref res)) {
2257 // ... then match more
2258 this.repeat = current;
2259 if (current.IsMaximum)
2262 current.Start = strpos;
2264 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2265 current.Start = start;
2266 current.Count = start_count;
2270 if (deep != current) // recursive mode
2272 // Degenerate match: ptr has not moved since the last (failed) tail match.
2273 // So, next and subsequent tail matches will fail.
2274 if (strpos == current.Start)
2278 int stack_size = stack.Count;
2280 // match greedily as much as possible
2281 while (!current.IsMaximum) {
2282 int cp = Checkpoint ();
2283 int old_ptr = strpos;
2284 int old_start = current.Start;
2288 Console.WriteLine ("recurse with count {0}.", current.Count);
2289 current.Start = strpos;
2291 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2293 current.Start = old_start;
2298 if (deep != current) {
2299 // recursive mode: no more backtracking, truncate the stack
2300 stack.Count = stack_size;
2304 stack.Push (old_ptr);
2306 // Degenerate match: no point going on
2307 if (strpos == current.Start)
2312 Console.WriteLine ("matching tail: {0} pc={1}", strpos, pc + 1);
2313 // then, match the tail, backtracking as necessary.
2314 this.repeat = current.Previous;
2317 if (EvalByteCode (pc + 1, strpos, ref res)) {
2319 stack.Count = stack_size;
2322 if (stack.Count == stack_size) {
2323 this.repeat = current;
2328 strpos = stack.Pop ();
2329 Backtrack (stack.Pop ());
2331 Console.WriteLine ("backtracking to {0} expr={1} pc={2}", strpos, current.Expression, pc);
2336 case RxOp.FastRepeat:
2337 case RxOp.FastRepeatLazy: {
2339 * A FastRepeat is a simplified version of Repeat which does
2340 * not contain another repeat inside, so backtracking is
2343 bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
2345 int tail = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
2346 start = ReadInt (program, pc + 3);
2347 end = ReadInt (program, pc + 7);
2348 //Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);
2353 // First match at least 'start' items
2354 while (length < start) {
2355 if (!EvalByteCode (pc + 11, strpos, ref res))
2364 int cp = Checkpoint ();
2365 if (EvalByteCode (tail, strpos, ref res)) {
2367 goto repeat_success;
2375 if (!EvalByteCode (pc + 11, strpos, ref res))
2381 // Then match as many items as possible, recording
2382 // backtracking information
2383 int old_stack_size = stack.Count;
2384 while (length < end) {
2385 int cp = Checkpoint ();
2386 if (!EvalByteCode (pc + 11, strpos, ref res)) {
2391 stack.Push (strpos);
2397 throw new Exception ();
2399 // Then, match the tail, backtracking as necessary.
2401 if (EvalByteCode (tail, strpos, ref res)) {
2403 stack.Count = old_stack_size;
2404 goto repeat_success;
2406 if (stack.Count == old_stack_size)
2410 strpos = stack.Pop ();
2411 Backtrack (stack.Pop ());
2413 Console.WriteLine ("backtracking to: {0}", strpos);
2418 // We matched the tail too so just return
2423 Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", (RxOp)program [pc], pc, strpos);
2424 throw new NotSupportedException ();
2429 strpos_result = strpos;
2433 test_char_group_passed:
2434 pc = char_group_end;
2437 } // end of while (true)