2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System / System.Text.RegularExpressions / RxInterpreter.cs
1
2 // Based upon interpreter.cs, written by Dan Lewis (dlewis@gmx.co.uk)
3
4 using System;
5 using System.Collections;
6 using System.Globalization;
7 using System.Diagnostics;
8
9 namespace System.Text.RegularExpressions {
10
11         internal delegate bool EvalDelegate (RxInterpreter interp, int strpos, ref int strpos_result);
12
13         sealed class RxInterpreter: BaseMachine {
14                 byte[] program;
15                 string str;
16                 int string_start;
17                 int string_end;
18                 int group_count;
19 //              int match_start;
20                 int[] groups;
21                 EvalDelegate eval_del; // optimized EvalByteCode method created by the CILCompiler
22
23                 Mark[] marks = null; // mark stack
24                 int mark_start; // start of current checkpoint
25                 int mark_end; // end of checkpoint/next free mark
26
27                 IntStack stack; // utility stack
28
29                 RepeatContext repeat;   // current repeat context
30                 RepeatContext deep;             // points to the most-nested repeat context
31
32                 /* The readonly ensures the JIT can optimize out if (trace_rx) statements */
33                 public static readonly bool trace_rx =
34 #if !NET_2_1
35                         Environment.GetEnvironmentVariable ("MONO_TRACE_RX") != null;
36 #else
37                         false;
38 #endif
39
40                 // private classes
41
42                 internal struct IntStack {
43                         int [] values;
44                         int count;
45                         public int Pop ()
46                         {
47                                 return values [--count];
48                         }
49                         public void Push (int value)
50                         {
51                                 if (values == null) {
52                                         values = new int [8];
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];
59                                         values = new_values;
60                                 }
61                                 values [count++] = value;
62                         }
63                         public int Top {
64                                 get { return values [count - 1]; }
65                         }
66                         public int Count {
67                                 get { return count; }
68                                 set {
69                                         if (value > count)
70                                                 throw new SystemException ("can only truncate the stack");
71                                         count = value;
72                                 }
73                         }
74                 }
75
76                 private class RepeatContext {
77                         public RepeatContext (RepeatContext previous, int min, int max, bool lazy, int expr_pc) {
78                                 this.previous = previous;
79                                 this.min = min;
80                                 this.max = max;
81                                 this.lazy = lazy;
82                                 this.expr_pc = expr_pc;
83                                 
84                                 this.start = -1;
85                                 this.count = 0;
86                         }
87
88                         public int Count {
89                                 get { return count; }
90                                 set { count = value; }
91                         }
92
93                         public int Start {
94                                 get { return start; }
95                                 set { start = value; }
96                         }
97
98                         public bool IsMinimum {
99                                 get { return min <= count; }
100                         }
101
102                         public bool IsMaximum {
103                                 get { return max <= count; }
104                         }
105
106                         public bool IsLazy {
107                                 get { return lazy; }
108                         }
109
110                         public int Expression {
111                                 get { return expr_pc; }
112                         }
113
114                         public RepeatContext Previous {
115                                 get { return previous; }
116                         }
117                 
118                         private int start;
119                         private int min, max;
120                         private bool lazy;
121                         private int expr_pc;
122                         private RepeatContext previous;
123
124                         private int count;
125                 }
126
127                 static int ReadInt (byte[] code, int pc)
128                 {
129                         int val = code [pc];
130                         val |= (int)code [pc + 1] << 8;
131                         val |= (int)code [pc + 2] << 16;
132                         val |= (int)code [pc + 3] << 24;
133                         return val;
134                 }
135
136                 public RxInterpreter (byte[] program, EvalDelegate eval_del)
137                 {
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 ();
143
144                         ResetGroups ();
145                 }
146
147                 public override Match Scan (Regex regex, string text, int start, int end) {
148                         str = text;
149                         string_start = start;
150                         string_end = end;
151                         int res = 0;
152
153                         bool match;
154                         if (eval_del != null) {
155                                 match = eval_del (this, start, ref res);
156                         } else {
157                                 match = EvalByteCode (11, start, ref res);
158                         }
159                         marks [groups [0]].End = res;
160                         if (match) {
161                                 return GenerateMatch (regex);
162                                 //Match m = new Match (regex, this, text, end, 0, match_start, res - match_start);
163                                 //return m;
164                         }
165                         return Match.Empty;
166                 }
167
168                 // capture management
169                 private void Open (int gid, int ptr) {
170                         int m = groups [gid];
171                         if (m < mark_start || marks [m].IsDefined) {
172                                 m = CreateMark (m);
173                                 groups [gid] = m;
174                         }
175
176                         marks [m].Start = ptr;
177                 }
178
179                 private void Close (int gid, int ptr) {
180                         marks [groups [gid]].End = ptr;
181                 }
182
183                 private bool Balance (int gid, int balance_gid, bool capture, int ptr) {
184                         int b = groups [balance_gid];
185
186                         if(b == -1 || marks[b].Index < 0) {
187                                 //Group not previously matched
188                                 return false;
189                         }
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);
193                                 Close (gid, ptr);
194                         }
195
196                         groups [balance_gid] = marks[b].Previous;
197
198                         return true;
199                 }
200
201                 private int Checkpoint () {
202                         mark_start = mark_end;
203                         return mark_start;
204                 }
205
206                 private void Backtrack (int cp) {
207                         for (int i = 0; i < groups.Length; ++ i) {
208                                 int m = groups [i];
209                                 while (cp <= m)
210                                         m = marks [m].Previous;
211                                 groups [i] = m;
212                         }
213                 }
214
215                 private void ResetGroups () {
216                         int n = groups.Length;
217                         if (marks == null)
218                                 marks = new Mark [n];
219
220                         for (int i = 0; i < n; ++ i) {
221                                 groups [i] = i;
222
223                                 marks [i].Start = -1;
224                                 marks [i].End = -1;
225                                 marks [i].Previous = -1;
226                         }
227                         mark_start = 0;
228                         mark_end = n;
229                 }
230
231                 private int GetLastDefined (int gid) {
232                         int m = groups [gid];
233                         while (m >= 0 && !marks [m].IsDefined)
234                                 m = marks [m].Previous;
235
236                         return m;
237                 }
238
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);
243                                 marks = dest;
244                         }
245
246                         int m = mark_end ++;
247                         marks [m].Start = marks [m].End = -1;
248                         marks [m].Previous = previous;
249
250                         return m;
251                 }
252
253                 private void GetGroupInfo (int gid, out int first_mark_index, out int n_caps)
254                 {
255                         first_mark_index = -1;
256                         n_caps = 0;
257                         for (int m = groups [gid]; m >= 0; m = marks [m].Previous) {
258                                 if (!marks [m].IsDefined)
259                                         continue;
260                                 if (first_mark_index < 0)
261                                         first_mark_index = m;
262                                 ++n_caps;
263                         }
264                 }
265
266                 private void PopulateGroup (Group g, int first_mark_index, int n_caps)
267                 {
268                         int i = 1;
269                         for (int m = marks [first_mark_index].Previous; m >= 0; m = marks [m].Previous) {
270                                 if (!marks [m].IsDefined)
271                                         continue;
272                                 Capture cap = new Capture (str, marks [m].Index, marks [m].Length);
273                                 g.Captures.SetValue (cap, n_caps - 1 - i);
274                                 ++i;
275                         }
276                 }
277
278                 private Match GenerateMatch (Regex regex)
279                 {
280                         int n_caps, first_mark_index;
281                         Group g;
282                         GetGroupInfo (0, out first_mark_index, out n_caps);
283
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);
287
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);
291
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) {
295                                         g = Group.Fail;
296                                 } else {
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);
299                                 }
300                                 retval.Groups.SetValue (g, gid);
301                         }
302                         return retval;
303                 }
304
305                 // used by the IL backend
306             internal void SetStartOfMatch (int pos)
307                 {
308                         marks [groups [0]].Start = pos;
309                 }
310
311                 static bool IsWordChar (char c)
312                 {
313                         return Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
314                 }
315
316                 bool EvalByteCode (int pc, int strpos, ref int strpos_result)
317                 {
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;
329                         while (true) {
330                                 if (trace_rx) {
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 ()));
333                                 }
334                                 switch ((RxOp)program [pc]) {
335                                 case RxOp.True:
336                                         if (char_group_end != 0) {
337                                                 pc = char_group_end;
338                                                 char_group_end = 0;
339                                                 continue;
340                                         }
341                                         strpos_result = strpos;
342                                         return true;
343                                 case RxOp.False:
344                                         return false;
345                                 case RxOp.AnyPosition:
346                                         pc++;
347                                         continue;
348                                 case RxOp.StartOfString:
349                                         if (strpos != 0)
350                                                 return false;
351                                         pc++;
352                                         continue;
353                                 case RxOp.StartOfLine:
354                                         if (strpos == 0 || str [strpos - 1] == '\n') {
355                                                 pc++;
356                                                 continue;
357                                         }
358                                         return false;
359                                 case RxOp.StartOfScan:
360                                         if (strpos != string_start)
361                                                 return false;
362                                         pc++;
363                                         continue;
364                                 case RxOp.End:
365                                         if (strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')) {
366                                                 pc++;
367                                                 continue;
368                                         }
369                                         return false;
370                                 case RxOp.EndOfString:
371                                         if (strpos != string_end)
372                                                 return false;
373                                         pc++;
374                                         continue;
375                                 case RxOp.EndOfLine:
376                                         if (strpos == string_end || str [strpos] == '\n') {
377                                                 pc++;
378                                                 continue;
379                                         }
380                                         return false;
381                                 case RxOp.WordBoundary:
382                                         if (string_end == 0)
383                                                 return false;
384                                         if (strpos == 0) {
385                                                 if (IsWordChar (str [strpos])) {
386                                                         pc++;
387                                                         continue;
388                                                 }
389                                         } else if (strpos == string_end) {
390                                                 if (IsWordChar (str [strpos - 1])) {
391                                                         pc++;
392                                                         continue;
393                                                 }
394                                         } else {
395                                                 if (IsWordChar (str [strpos]) != IsWordChar (str [strpos - 1])) {
396                                                         pc++;
397                                                         continue;
398                                                 }
399                                         }
400                                         return false;
401                                 case RxOp.NoWordBoundary:
402                                         if (string_end == 0)
403                                                 return false;
404                                         if (strpos == 0) {
405                                                 if (!IsWordChar (str [strpos])) {
406                                                         pc++;
407                                                         continue;
408                                                 }
409                                         } else if (strpos == string_end) {
410                                                 if (!IsWordChar (str [strpos - 1])) {
411                                                         pc++;
412                                                         continue;
413                                                 }
414                                         } else {
415                                                 if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
416                                                         pc++;
417                                                         continue;
418                                                 }
419                                         }
420                                         return false;
421                                 case RxOp.Anchor:
422                                         int skip = program [pc + 1] | ((int)program [pc + 2] << 8);
423                                         int anch_offset = program [pc + 3] | ((int)program [pc + 4] << 8);
424
425                                         /*
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.
429                                          */
430                                         int anch_pc = pc + 5;
431                                         RxOp anch_op = (RxOp)(program[anch_pc] & 0x00ff);
432
433                                         bool spec_anch = false;
434
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) {
438                                                         // Anchor
439                                                         //      String
440                                                         //      True
441                                                         spec_anch = true;
442                                                         if (trace_rx)
443                                                                 Console.WriteLine ("  string anchor at {0}, offset {1}", anch_pc, anch_offset);
444                                                 }
445                                         }
446
447                                         pc += skip;
448
449                                         if ((RxOp)program [pc] == RxOp.StartOfString) {
450                                                 if (strpos == 0) {
451                                                         int res = strpos;
452                                                         if (groups.Length > 1) {
453                                                                 ResetGroups ();
454                                                                 marks [groups [0]].Start = strpos;
455                                                         }
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;
460                                                                 strpos_result = res;
461                                                                 return true;
462                                                         }
463                                                 }
464                                                 return false;
465                                         }
466
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) {
471                                                 if (spec_anch) {
472                                                         if (anch_op == RxOp.String || anch_op == RxOp.StringIgnoreCase) {
473                                                                 /* 
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.
479                                                                  */
480                                                                 int tmp_res = strpos;
481                                                                 if (!EvalByteCode (anch_pc, strpos + anch_offset, ref tmp_res)) {
482                                                                         strpos ++;
483                                                                         continue;
484                                                                 }
485                                                         }
486                                                 }
487                                                 int res = strpos;
488                                                 if (groups.Length > 1) {
489                                                         ResetGroups ();
490                                                         marks [groups [0]].Start = strpos;
491                                                 }
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;
497                                                         strpos_result = res;
498                                                         return true;
499                                                 }
500                                                 strpos++;
501                                         }
502                                         return false;
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: "" =~ /$/
508                                         end = 0;
509                                         while (strpos >= 0) {
510                                                 int res = strpos;
511                                                 if (groups.Length > 1) {
512                                                         ResetGroups ();
513                                                         marks [groups [0]].Start = strpos;
514                                                 }
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;
520                                                         strpos_result = res;
521                                                         return true;
522                                                 }
523                                                 strpos--;
524                                         }
525                                         return false;
526                                 case RxOp.Reference:
527                                         length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
528                                         if (length < 0)
529                                                 return false;
530                                         start = marks [length].Index;
531                                         length = marks [length].Length;
532                                         if (strpos + length > string_end)
533                                                 return false;
534                                         for (end = start + length; start < end; ++start) {
535                                                 if (str [strpos] != str [start])
536                                                         return false;
537                                                 strpos++;
538                                         }
539                                         pc += 3;
540                                         continue;
541                                 case RxOp.ReferenceIgnoreCase:
542                                         length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
543                                         if (length < 0)
544                                                 return false;
545                                         start = marks [length].Index;
546                                         length = marks [length].Length;
547                                         if (strpos + length > string_end)
548                                                 return false;
549                                         for (end = start + length; start < end; ++start) {
550                                                 if (str [strpos] != str [start] && Char.ToLower (str [strpos]) != Char.ToLower (str [start]))
551                                                         return false;
552                                                 strpos++;
553                                         }
554                                         pc += 3;
555                                         continue;
556                                 case RxOp.ReferenceReverse: {
557                                         length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
558                                         if (length < 0)
559                                                 return false;
560                                         start = marks [length].Index;
561                                         length = marks [length].Length;
562                                         if (strpos - length < 0)
563                                                 return false;
564                                         int p = strpos - length;
565                                         for (end = start + length; start < end; ++start, ++p) {
566                                                 if (str [p] != str [start])
567                                                         return false;
568                                         }
569                                         strpos -= length;
570                                         pc += 3;
571                                         continue;
572                                 }
573                                 case RxOp.IfDefined:
574                                         if (GetLastDefined (program [pc + 3] | ((int)program [pc + 4] << 8)) >= 0)
575                                                 pc += 5;
576                                         else
577                                                 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
578                                         continue;
579                                 case RxOp.SubExpression: {
580                                         int res = 0;
581                                         if (EvalByteCode (pc + 3, strpos, ref res)) {
582                                                 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
583                                                 strpos = res;
584                                                 continue;
585                                         }
586                                         return false;
587                                 }
588                                 case RxOp.Test: {
589                                         int res = 0;
590                                         // FIXME: checkpoint
591                                         if (EvalByteCode (pc + 5, strpos, ref res)) {
592                                                 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
593                                         } else {
594                                                 pc += program [pc + 3] | ((int)program [pc + 4] << 8);
595                                         }
596                                         continue;
597                                 }
598                                 case RxOp.OpenGroup:
599                                         Open (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
600                                         pc += 3;
601                                         continue;
602                                 case RxOp.CloseGroup:
603                                         Close (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
604                                         pc += 3;
605                                         continue;
606                                 case RxOp.BalanceStart: {
607                                         int res = 0;
608
609                                         if (!EvalByteCode (pc + 8, strpos, ref res))
610                                                 goto Fail;
611
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))
616                                                 goto Fail;
617
618                                         strpos = res;                                   
619                                         pc += program[pc + 6] | ((int)program [pc + 7] << 8);
620                                         break;
621                                 }
622                                 case RxOp.Balance: {
623                                         goto Pass;
624                                 }
625
626                                 case RxOp.Jump:
627                                         pc += program [pc + 1] | ((int)program [pc + 2] << 8);
628                                         continue;
629                                 case RxOp.TestCharGroup:
630                                         char_group_end = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
631                                         pc += 3;
632                                         continue;
633                                 case RxOp.String:
634                                         start = pc + 2;
635                                         length = program [pc + 1];
636                                         if (strpos + length > string_end)
637                                                 return false;
638                                         end = start + length;
639                                         for (; start < end; ++start) {
640                                                 if (str [strpos] != program [start])
641                                                         return false;
642                                                 strpos++;
643                                         }
644                                         pc = end;
645                                         continue;
646                                 case RxOp.StringIgnoreCase:
647                                         start = pc + 2;
648                                         length = program [pc + 1];
649                                         if (strpos + length > string_end)
650                                                 return false;
651                                         end = start + length;
652                                         for (; start < end; ++start) {
653                                                 if (str [strpos] != program [start] && Char.ToLower (str [strpos]) != program [start])
654                                                         return false;
655                                                 strpos++;
656                                         }
657                                         pc = end;
658                                         continue;
659                                 case RxOp.StringReverse: {
660                                         start = pc + 2;
661                                         length = program [pc + 1];
662                                         if (strpos < length)
663                                                 return false;
664                                         int p = strpos - length;
665                                         end = start + length;
666                                         for (; start < end; ++start, ++p) {
667                                                 if (str [p] != program [start])
668                                                         return false;
669                                         }
670                                         strpos -= length;
671                                         pc = end;
672                                         continue;
673                                 }
674                                 case RxOp.StringIgnoreCaseReverse: {
675                                         start = pc + 2;
676                                         length = program [pc + 1];
677                                         if (strpos < length)
678                                                 return false;
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])
683                                                         return false;
684                                         }
685                                         strpos -= length;
686                                         pc = end;
687                                         continue;
688                                 }
689                                 case RxOp.UnicodeString: {
690                                         start = pc + 3;
691                                         length = program [pc + 1] | ((int)program [pc + 2] << 8);
692                                         if (strpos + length > string_end)
693                                                 return false;
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)
698                                                         return false;
699                                                 strpos++;
700                                         }
701                                         pc = end;
702                                         continue;
703                                 }
704                                 case RxOp.UnicodeStringIgnoreCase: {
705                                         start = pc + 3;
706                                         length = program [pc + 1] | ((int)program [pc + 2] << 8);
707                                         if (strpos + length > string_end)
708                                                 return false;
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)
713                                                         return false;
714                                                 strpos++;
715                                         }
716                                         pc = end;
717                                         continue;
718                                 }
719                                 case RxOp.UnicodeStringReverse: {
720                                         start = pc + 3;
721                                         length = program [pc + 1] | ((int)program [pc + 2] << 8);
722                                         if (strpos < length)
723                                                 return false;
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);
728                                                 if (str [p] != c)
729                                                         return false;
730                                         }
731                                         strpos -= length;
732                                         pc = end;
733                                         continue;
734                                 }
735                                 case RxOp.UnicodeStringIgnoreCaseReverse: {
736                                         start = pc + 3;
737                                         length = program [pc + 1] | ((int)program [pc + 2] << 8);
738                                         if (strpos < length)
739                                                 return false;
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)
745                                                         return false;
746                                         }
747                                         strpos -= length;
748                                         pc = end;
749                                         continue;
750                                 }
751
752                                         /*
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.
761                                          */
762 #if FALSE
763                                         if (!reverse) {
764                                                 if (strpos < string_end && (COND (str [strpos]))) {
765                                                         if (!revert) {
766                                                                 strpos ++;
767                                                                 if (char_group_end != 0)
768                                                                         goto test_char_group_passed;
769                                                                 pc += ins_len;
770                                                                 continue;
771                                                         } else {
772                                                                 /*
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 
776                                                                  * the final check.
777                                                                  * The char group is termined by a True, hence the
778                                                                  * + 1 below.
779                                                                  * FIXME: Optimize this.
780                                                                  */
781                                                                 pc += ins_len;
782                                                                 if (char_group_end == 0 || (pc + 1 == char_group_end))
783                                                                         strpos ++;
784                                                                 if (pc + 1 == char_group_end)
785                                                                         goto test_char_group_passed;
786                                                                 continue;
787                                                         }
788                                                 } else {
789                                                         if (!revert) {
790                                                                 if (char_group_end == 0)
791                                                                         return false;
792                                                                 pc += ins_len;
793                                                                 continue;
794                                                         } else {
795                                                                 /* Fail both inside and outside a char group */
796                                                                 return false;
797                                                         }
798                                                 }
799                                         } else {
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 ++
804                                         }
805 #endif
806                                 // GENERATED BY gen-interp.cs, DO NOT MODIFY
807                                 
808                                 /* Char */
809                                 
810                                 case RxOp.Char:
811                                         if (strpos < string_end) {
812                                                 char c = str [strpos];
813                                                 if (((c == program [pc + 1]))) {
814                                                         strpos ++;
815                                                         if (char_group_end != 0)
816                                                                 goto test_char_group_passed;
817                                                         pc += 2;
818                                                         continue;
819                                                 }
820                                         }
821                                         if (char_group_end == 0)
822                                                 return false;
823                                         pc += 2;
824                                         continue;
825                                 
826                                 /* Range */
827                                 
828                                 case RxOp.Range:
829                                         if (strpos < string_end) {
830                                                 char c = str [strpos];
831                                                 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
832                                                         strpos ++;
833                                                         if (char_group_end != 0)
834                                                                 goto test_char_group_passed;
835                                                         pc += 3;
836                                                         continue;
837                                                 }
838                                         }
839                                         if (char_group_end == 0)
840                                                 return false;
841                                         pc += 3;
842                                         continue;
843                                 
844                                 /* UnicodeRange */
845                                 
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))))) {
850                                                         strpos ++;
851                                                         if (char_group_end != 0)
852                                                                 goto test_char_group_passed;
853                                                         pc += 5;
854                                                         continue;
855                                                 }
856                                         }
857                                         if (char_group_end == 0)
858                                                 return false;
859                                         pc += 5;
860                                         continue;
861                                 
862                                 /* UnicodeChar */
863                                 
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))))) {
868                                                         strpos ++;
869                                                         if (char_group_end != 0)
870                                                                 goto test_char_group_passed;
871                                                         pc += 3;
872                                                         continue;
873                                                 }
874                                         }
875                                         if (char_group_end == 0)
876                                                 return false;
877                                         pc += 3;
878                                         continue;
879                                 
880                                 /* CategoryAny */
881                                 
882                                 case RxOp.CategoryAny:
883                                         if (strpos < string_end) {
884                                                 char c = str [strpos];
885                                                 if (((c != '\n'))) {
886                                                         strpos ++;
887                                                         if (char_group_end != 0)
888                                                                 goto test_char_group_passed;
889                                                         pc += 1;
890                                                         continue;
891                                                 }
892                                         }
893                                         if (char_group_end == 0)
894                                                 return false;
895                                         pc += 1;
896                                         continue;
897                                 
898                                 /* CategoryAnySingleline */
899                                 
900                                 case RxOp.CategoryAnySingleline:
901                                         if (strpos < string_end) {
902                                                 char c = str [strpos];
903                                                 if ((true)) {
904                                                         strpos ++;
905                                                         if (char_group_end != 0)
906                                                                 goto test_char_group_passed;
907                                                         pc += 1;
908                                                         continue;
909                                                 }
910                                         }
911                                         if (char_group_end == 0)
912                                                 return false;
913                                         pc += 1;
914                                         continue;
915                                 
916                                 /* CategoryWord */
917                                 
918                                 case RxOp.CategoryWord:
919                                         if (strpos < string_end) {
920                                                 char c = str [strpos];
921                                                 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
922                                                         strpos ++;
923                                                         if (char_group_end != 0)
924                                                                 goto test_char_group_passed;
925                                                         pc += 1;
926                                                         continue;
927                                                 }
928                                         }
929                                         if (char_group_end == 0)
930                                                 return false;
931                                         pc += 1;
932                                         continue;
933                                 
934                                 /* CategoryDigit */
935                                 
936                                 case RxOp.CategoryDigit:
937                                         if (strpos < string_end) {
938                                                 char c = str [strpos];
939                                                 if (((Char.IsDigit (c)))) {
940                                                         strpos ++;
941                                                         if (char_group_end != 0)
942                                                                 goto test_char_group_passed;
943                                                         pc += 1;
944                                                         continue;
945                                                 }
946                                         }
947                                         if (char_group_end == 0)
948                                                 return false;
949                                         pc += 1;
950                                         continue;
951                                 
952                                 /* CategoryWhiteSpace */
953                                 
954                                 case RxOp.CategoryWhiteSpace:
955                                         if (strpos < string_end) {
956                                                 char c = str [strpos];
957                                                 if (((Char.IsWhiteSpace (c)))) {
958                                                         strpos ++;
959                                                         if (char_group_end != 0)
960                                                                 goto test_char_group_passed;
961                                                         pc += 1;
962                                                         continue;
963                                                 }
964                                         }
965                                         if (char_group_end == 0)
966                                                 return false;
967                                         pc += 1;
968                                         continue;
969                                 
970                                 /* CategoryEcmaWord */
971                                 
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 == '_'))) {
976                                                         strpos ++;
977                                                         if (char_group_end != 0)
978                                                                 goto test_char_group_passed;
979                                                         pc += 1;
980                                                         continue;
981                                                 }
982                                         }
983                                         if (char_group_end == 0)
984                                                 return false;
985                                         pc += 1;
986                                         continue;
987                                 
988                                 /* CategoryEcmaWhiteSpace */
989                                 
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'))) {
994                                                         strpos ++;
995                                                         if (char_group_end != 0)
996                                                                 goto test_char_group_passed;
997                                                         pc += 1;
998                                                         continue;
999                                                 }
1000                                         }
1001                                         if (char_group_end == 0)
1002                                                 return false;
1003                                         pc += 1;
1004                                         continue;
1005                                 
1006                                 /* CategoryUnicodeSpecials */
1007                                 
1008                                 case RxOp.CategoryUnicodeSpecials:
1009                                         if (strpos < string_end) {
1010                                                 char c = str [strpos];
1011                                                 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1012                                                         strpos ++;
1013                                                         if (char_group_end != 0)
1014                                                                 goto test_char_group_passed;
1015                                                         pc += 1;
1016                                                         continue;
1017                                                 }
1018                                         }
1019                                         if (char_group_end == 0)
1020                                                 return false;
1021                                         pc += 1;
1022                                         continue;
1023                                 
1024                                 /* CategoryUnicode */
1025                                 
1026                                 case RxOp.CategoryUnicode:
1027                                         if (strpos < string_end) {
1028                                                 char c = str [strpos];
1029                                                 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1030                                                         strpos ++;
1031                                                         if (char_group_end != 0)
1032                                                                 goto test_char_group_passed;
1033                                                         pc += 2;
1034                                                         continue;
1035                                                 }
1036                                         }
1037                                         if (char_group_end == 0)
1038                                                 return false;
1039                                         pc += 2;
1040                                         continue;
1041                                 
1042                                 /* CategoryGeneral */
1043                                 
1044                                 case RxOp.CategoryGeneral:
1045                                         if (strpos < string_end) {
1046                                                 char c = str [strpos];
1047                                                 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1048                                                         strpos ++;
1049                                                         if (char_group_end != 0)
1050                                                                 goto test_char_group_passed;
1051                                                         pc += 2;
1052                                                         continue;
1053                                                 }
1054                                         }
1055                                         if (char_group_end == 0)
1056                                                 return false;
1057                                         pc += 2;
1058                                         continue;
1059                                 
1060                                 /* Bitmap */
1061                                 
1062                                 case RxOp.Bitmap:
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))) {
1067                                                         strpos ++;
1068                                                         if (char_group_end != 0)
1069                                                                 goto test_char_group_passed;
1070                                                         pc += 3 + program [pc + 2];
1071                                                         continue;
1072                                                 }
1073                                         }
1074                                         if (char_group_end == 0)
1075                                                 return false;
1076                                         pc += 3 + program [pc + 2];
1077                                         continue;
1078                                 
1079                                 /* UnicodeBitmap */
1080                                 
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))) {
1086                                                         strpos ++;
1087                                                         if (char_group_end != 0)
1088                                                                 goto test_char_group_passed;
1089                                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1090                                                         continue;
1091                                                 }
1092                                         }
1093                                         if (char_group_end == 0)
1094                                                 return false;
1095                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1096                                         continue;
1097                                 case RxOp.CharIgnoreCase:
1098                                         if (strpos < string_end) {
1099                                                 char c = Char.ToLower (str [strpos]);
1100                                                 if (((c == program [pc + 1]))) {
1101                                                         strpos ++;
1102                                                         if (char_group_end != 0)
1103                                                                 goto test_char_group_passed;
1104                                                         pc += 2;
1105                                                         continue;
1106                                                 }
1107                                         }
1108                                         if (char_group_end == 0)
1109                                                 return false;
1110                                         pc += 2;
1111                                         continue;
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]))) {
1116                                                         strpos ++;
1117                                                         if (char_group_end != 0)
1118                                                                 goto test_char_group_passed;
1119                                                         pc += 3;
1120                                                         continue;
1121                                                 }
1122                                         }
1123                                         if (char_group_end == 0)
1124                                                 return false;
1125                                         pc += 3;
1126                                         continue;
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))))) {
1131                                                         strpos ++;
1132                                                         if (char_group_end != 0)
1133                                                                 goto test_char_group_passed;
1134                                                         pc += 5;
1135                                                         continue;
1136                                                 }
1137                                         }
1138                                         if (char_group_end == 0)
1139                                                 return false;
1140                                         pc += 5;
1141                                         continue;
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))))) {
1146                                                         strpos ++;
1147                                                         if (char_group_end != 0)
1148                                                                 goto test_char_group_passed;
1149                                                         pc += 3;
1150                                                         continue;
1151                                                 }
1152                                         }
1153                                         if (char_group_end == 0)
1154                                                 return false;
1155                                         pc += 3;
1156                                         continue;
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))) {
1162                                                         strpos ++;
1163                                                         if (char_group_end != 0)
1164                                                                 goto test_char_group_passed;
1165                                                         pc += 3 + program [pc + 2];
1166                                                         continue;
1167                                                 }
1168                                         }
1169                                         if (char_group_end == 0)
1170                                                 return false;
1171                                         pc += 3 + program [pc + 2];
1172                                         continue;
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))) {
1178                                                         strpos ++;
1179                                                         if (char_group_end != 0)
1180                                                                 goto test_char_group_passed;
1181                                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1182                                                         continue;
1183                                                 }
1184                                         }
1185                                         if (char_group_end == 0)
1186                                                 return false;
1187                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1188                                         continue;
1189                                 case RxOp.NoChar:
1190                                         if (strpos < string_end) {
1191                                                 char c = str [strpos];
1192                                                 if (!((c == program [pc + 1]))) {
1193                                                         pc += 2;
1194                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1195                                                                 strpos ++;
1196                                                         if (pc + 1 == char_group_end)
1197                                                                 goto test_char_group_passed;
1198                                                         }
1199                                                         continue;
1200                                                 }
1201                                         }
1202                                         return false;
1203                                 case RxOp.NoRange:
1204                                         if (strpos < string_end) {
1205                                                 char c = str [strpos];
1206                                                 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1207                                                         pc += 3;
1208                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1209                                                                 strpos ++;
1210                                                         if (pc + 1 == char_group_end)
1211                                                                 goto test_char_group_passed;
1212                                                         }
1213                                                         continue;
1214                                                 }
1215                                         }
1216                                         return false;
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))))) {
1221                                                         pc += 5;
1222                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1223                                                                 strpos ++;
1224                                                         if (pc + 1 == char_group_end)
1225                                                                 goto test_char_group_passed;
1226                                                         }
1227                                                         continue;
1228                                                 }
1229                                         }
1230                                         return false;
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))))) {
1235                                                         pc += 3;
1236                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1237                                                                 strpos ++;
1238                                                         if (pc + 1 == char_group_end)
1239                                                                 goto test_char_group_passed;
1240                                                         }
1241                                                         continue;
1242                                                 }
1243                                         }
1244                                         return false;
1245                                 case RxOp.NoCategoryAny:
1246                                         if (strpos < string_end) {
1247                                                 char c = str [strpos];
1248                                                 if (!((c != '\n'))) {
1249                                                         pc += 1;
1250                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1251                                                                 strpos ++;
1252                                                         if (pc + 1 == char_group_end)
1253                                                                 goto test_char_group_passed;
1254                                                         }
1255                                                         continue;
1256                                                 }
1257                                         }
1258                                         return false;
1259                                 case RxOp.NoCategoryAnySingleline:
1260                                         if (strpos < string_end) {
1261                                                 char c = str [strpos];
1262                                                 if (!(true)) {
1263                                                         pc += 1;
1264                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1265                                                                 strpos ++;
1266                                                         if (pc + 1 == char_group_end)
1267                                                                 goto test_char_group_passed;
1268                                                         }
1269                                                         continue;
1270                                                 }
1271                                         }
1272                                         return false;
1273                                 case RxOp.NoCategoryWord:
1274                                         if (strpos < string_end) {
1275                                                 char c = str [strpos];
1276                                                 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1277                                                         pc += 1;
1278                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1279                                                                 strpos ++;
1280                                                         if (pc + 1 == char_group_end)
1281                                                                 goto test_char_group_passed;
1282                                                         }
1283                                                         continue;
1284                                                 }
1285                                         }
1286                                         return false;
1287                                 case RxOp.NoCategoryDigit:
1288                                         if (strpos < string_end) {
1289                                                 char c = str [strpos];
1290                                                 if (!((Char.IsDigit (c)))) {
1291                                                         pc += 1;
1292                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1293                                                                 strpos ++;
1294                                                         if (pc + 1 == char_group_end)
1295                                                                 goto test_char_group_passed;
1296                                                         }
1297                                                         continue;
1298                                                 }
1299                                         }
1300                                         return false;
1301                                 case RxOp.NoCategoryWhiteSpace:
1302                                         if (strpos < string_end) {
1303                                                 char c = str [strpos];
1304                                                 if (!((Char.IsWhiteSpace (c)))) {
1305                                                         pc += 1;
1306                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1307                                                                 strpos ++;
1308                                                         if (pc + 1 == char_group_end)
1309                                                                 goto test_char_group_passed;
1310                                                         }
1311                                                         continue;
1312                                                 }
1313                                         }
1314                                         return false;
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 == '_'))) {
1319                                                         pc += 1;
1320                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1321                                                                 strpos ++;
1322                                                         if (pc + 1 == char_group_end)
1323                                                                 goto test_char_group_passed;
1324                                                         }
1325                                                         continue;
1326                                                 }
1327                                         }
1328                                         return false;
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'))) {
1333                                                         pc += 1;
1334                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1335                                                                 strpos ++;
1336                                                         if (pc + 1 == char_group_end)
1337                                                                 goto test_char_group_passed;
1338                                                         }
1339                                                         continue;
1340                                                 }
1341                                         }
1342                                         return false;
1343                                 case RxOp.NoCategoryUnicodeSpecials:
1344                                         if (strpos < string_end) {
1345                                                 char c = str [strpos];
1346                                                 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1347                                                         pc += 1;
1348                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1349                                                                 strpos ++;
1350                                                         if (pc + 1 == char_group_end)
1351                                                                 goto test_char_group_passed;
1352                                                         }
1353                                                         continue;
1354                                                 }
1355                                         }
1356                                         return false;
1357                                 case RxOp.NoCategoryUnicode:
1358                                         if (strpos < string_end) {
1359                                                 char c = str [strpos];
1360                                                 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1361                                                         pc += 2;
1362                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1363                                                                 strpos ++;
1364                                                         if (pc + 1 == char_group_end)
1365                                                                 goto test_char_group_passed;
1366                                                         }
1367                                                         continue;
1368                                                 }
1369                                         }
1370                                         return false;
1371                                 case RxOp.NoCategoryGeneral:
1372                                         if (strpos < string_end) {
1373                                                 char c = str [strpos];
1374                                                 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1375                                                         pc += 2;
1376                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1377                                                                 strpos ++;
1378                                                         if (pc + 1 == char_group_end)
1379                                                                 goto test_char_group_passed;
1380                                                         }
1381                                                         continue;
1382                                                 }
1383                                         }
1384                                         return false;
1385                                 case RxOp.NoBitmap:
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)) {
1392                                                                 strpos ++;
1393                                                         if (pc + 1 == char_group_end)
1394                                                                 goto test_char_group_passed;
1395                                                         }
1396                                                         continue;
1397                                                 }
1398                                         }
1399                                         return false;
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)) {
1407                                                                 strpos ++;
1408                                                         if (pc + 1 == char_group_end)
1409                                                                 goto test_char_group_passed;
1410                                                         }
1411                                                         continue;
1412                                                 }
1413                                         }
1414                                         return false;
1415                                 case RxOp.NoCharIgnoreCase:
1416                                         if (strpos < string_end) {
1417                                                 char c = Char.ToLower (str [strpos]);
1418                                                 if (!((c == program [pc + 1]))) {
1419                                                         pc += 2;
1420                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1421                                                                 strpos ++;
1422                                                         if (pc + 1 == char_group_end)
1423                                                                 goto test_char_group_passed;
1424                                                         }
1425                                                         continue;
1426                                                 }
1427                                         }
1428                                         return false;
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]))) {
1433                                                         pc += 3;
1434                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1435                                                                 strpos ++;
1436                                                         if (pc + 1 == char_group_end)
1437                                                                 goto test_char_group_passed;
1438                                                         }
1439                                                         continue;
1440                                                 }
1441                                         }
1442                                         return false;
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))))) {
1447                                                         pc += 5;
1448                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1449                                                                 strpos ++;
1450                                                         if (pc + 1 == char_group_end)
1451                                                                 goto test_char_group_passed;
1452                                                         }
1453                                                         continue;
1454                                                 }
1455                                         }
1456                                         return false;
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))))) {
1461                                                         pc += 3;
1462                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1463                                                                 strpos ++;
1464                                                         if (pc + 1 == char_group_end)
1465                                                                 goto test_char_group_passed;
1466                                                         }
1467                                                         continue;
1468                                                 }
1469                                         }
1470                                         return false;
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)) {
1478                                                                 strpos ++;
1479                                                         if (pc + 1 == char_group_end)
1480                                                                 goto test_char_group_passed;
1481                                                         }
1482                                                         continue;
1483                                                 }
1484                                         }
1485                                         return false;
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)) {
1493                                                                 strpos ++;
1494                                                         if (pc + 1 == char_group_end)
1495                                                                 goto test_char_group_passed;
1496                                                         }
1497                                                         continue;
1498                                                 }
1499                                         }
1500                                         return false;
1501                                 case RxOp.CharReverse:
1502                                         if (strpos > 0) {
1503                                                 char c = str [strpos - 1];
1504                                                 if (((c == program [pc + 1]))) {
1505                                                         strpos --;
1506                                                         if (char_group_end != 0)
1507                                                                 goto test_char_group_passed;
1508                                                         pc += 2;
1509                                                         continue;
1510                                                 }
1511                                         }
1512                                         if (char_group_end == 0)
1513                                                 return false;
1514                                         pc += 2;
1515                                         continue;
1516                                 case RxOp.RangeReverse:
1517                                         if (strpos > 0) {
1518                                                 char c = str [strpos - 1];
1519                                                 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1520                                                         strpos --;
1521                                                         if (char_group_end != 0)
1522                                                                 goto test_char_group_passed;
1523                                                         pc += 3;
1524                                                         continue;
1525                                                 }
1526                                         }
1527                                         if (char_group_end == 0)
1528                                                 return false;
1529                                         pc += 3;
1530                                         continue;
1531                                 case RxOp.UnicodeRangeReverse:
1532                                         if (strpos > 0) {
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))))) {
1535                                                         strpos --;
1536                                                         if (char_group_end != 0)
1537                                                                 goto test_char_group_passed;
1538                                                         pc += 5;
1539                                                         continue;
1540                                                 }
1541                                         }
1542                                         if (char_group_end == 0)
1543                                                 return false;
1544                                         pc += 5;
1545                                         continue;
1546                                 case RxOp.UnicodeCharReverse:
1547                                         if (strpos > 0) {
1548                                                 char c = str [strpos - 1];
1549                                                 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1550                                                         strpos --;
1551                                                         if (char_group_end != 0)
1552                                                                 goto test_char_group_passed;
1553                                                         pc += 3;
1554                                                         continue;
1555                                                 }
1556                                         }
1557                                         if (char_group_end == 0)
1558                                                 return false;
1559                                         pc += 3;
1560                                         continue;
1561                                 case RxOp.CategoryAnyReverse:
1562                                         if (strpos > 0) {
1563                                                 char c = str [strpos - 1];
1564                                                 if (((c != '\n'))) {
1565                                                         strpos --;
1566                                                         if (char_group_end != 0)
1567                                                                 goto test_char_group_passed;
1568                                                         pc += 1;
1569                                                         continue;
1570                                                 }
1571                                         }
1572                                         if (char_group_end == 0)
1573                                                 return false;
1574                                         pc += 1;
1575                                         continue;
1576                                 case RxOp.CategoryAnySinglelineReverse:
1577                                         if (strpos > 0) {
1578                                                 char c = str [strpos - 1];
1579                                                 if ((true)) {
1580                                                         strpos --;
1581                                                         if (char_group_end != 0)
1582                                                                 goto test_char_group_passed;
1583                                                         pc += 1;
1584                                                         continue;
1585                                                 }
1586                                         }
1587                                         if (char_group_end == 0)
1588                                                 return false;
1589                                         pc += 1;
1590                                         continue;
1591                                 case RxOp.CategoryWordReverse:
1592                                         if (strpos > 0) {
1593                                                 char c = str [strpos - 1];
1594                                                 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1595                                                         strpos --;
1596                                                         if (char_group_end != 0)
1597                                                                 goto test_char_group_passed;
1598                                                         pc += 1;
1599                                                         continue;
1600                                                 }
1601                                         }
1602                                         if (char_group_end == 0)
1603                                                 return false;
1604                                         pc += 1;
1605                                         continue;
1606                                 case RxOp.CategoryDigitReverse:
1607                                         if (strpos > 0) {
1608                                                 char c = str [strpos - 1];
1609                                                 if (((Char.IsDigit (c)))) {
1610                                                         strpos --;
1611                                                         if (char_group_end != 0)
1612                                                                 goto test_char_group_passed;
1613                                                         pc += 1;
1614                                                         continue;
1615                                                 }
1616                                         }
1617                                         if (char_group_end == 0)
1618                                                 return false;
1619                                         pc += 1;
1620                                         continue;
1621                                 case RxOp.CategoryWhiteSpaceReverse:
1622                                         if (strpos > 0) {
1623                                                 char c = str [strpos - 1];
1624                                                 if (((Char.IsWhiteSpace (c)))) {
1625                                                         strpos --;
1626                                                         if (char_group_end != 0)
1627                                                                 goto test_char_group_passed;
1628                                                         pc += 1;
1629                                                         continue;
1630                                                 }
1631                                         }
1632                                         if (char_group_end == 0)
1633                                                 return false;
1634                                         pc += 1;
1635                                         continue;
1636                                 case RxOp.CategoryEcmaWordReverse:
1637                                         if (strpos > 0) {
1638                                                 char c = str [strpos - 1];
1639                                                 if ((('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1640                                                         strpos --;
1641                                                         if (char_group_end != 0)
1642                                                                 goto test_char_group_passed;
1643                                                         pc += 1;
1644                                                         continue;
1645                                                 }
1646                                         }
1647                                         if (char_group_end == 0)
1648                                                 return false;
1649                                         pc += 1;
1650                                         continue;
1651                                 case RxOp.CategoryEcmaWhiteSpaceReverse:
1652                                         if (strpos > 0) {
1653                                                 char c = str [strpos - 1];
1654                                                 if (((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1655                                                         strpos --;
1656                                                         if (char_group_end != 0)
1657                                                                 goto test_char_group_passed;
1658                                                         pc += 1;
1659                                                         continue;
1660                                                 }
1661                                         }
1662                                         if (char_group_end == 0)
1663                                                 return false;
1664                                         pc += 1;
1665                                         continue;
1666                                 case RxOp.CategoryUnicodeSpecialsReverse:
1667                                         if (strpos > 0) {
1668                                                 char c = str [strpos - 1];
1669                                                 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1670                                                         strpos --;
1671                                                         if (char_group_end != 0)
1672                                                                 goto test_char_group_passed;
1673                                                         pc += 1;
1674                                                         continue;
1675                                                 }
1676                                         }
1677                                         if (char_group_end == 0)
1678                                                 return false;
1679                                         pc += 1;
1680                                         continue;
1681                                 case RxOp.CategoryUnicodeReverse:
1682                                         if (strpos > 0) {
1683                                                 char c = str [strpos - 1];
1684                                                 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1685                                                         strpos --;
1686                                                         if (char_group_end != 0)
1687                                                                 goto test_char_group_passed;
1688                                                         pc += 2;
1689                                                         continue;
1690                                                 }
1691                                         }
1692                                         if (char_group_end == 0)
1693                                                 return false;
1694                                         pc += 2;
1695                                         continue;
1696                                 case RxOp.CategoryGeneralReverse:
1697                                         if (strpos > 0) {
1698                                                 char c = str [strpos - 1];
1699                                                 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1700                                                         strpos --;
1701                                                         if (char_group_end != 0)
1702                                                                 goto test_char_group_passed;
1703                                                         pc += 2;
1704                                                         continue;
1705                                                 }
1706                                         }
1707                                         if (char_group_end == 0)
1708                                                 return false;
1709                                         pc += 2;
1710                                         continue;
1711                                 case RxOp.BitmapReverse:
1712                                         if (strpos > 0) {
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))) {
1716                                                         strpos --;
1717                                                         if (char_group_end != 0)
1718                                                                 goto test_char_group_passed;
1719                                                         pc += 3 + program [pc + 2];
1720                                                         continue;
1721                                                 }
1722                                         }
1723                                         if (char_group_end == 0)
1724                                                 return false;
1725                                         pc += 3 + program [pc + 2];
1726                                         continue;
1727                                 case RxOp.UnicodeBitmapReverse:
1728                                         if (strpos > 0) {
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))) {
1732                                                         strpos --;
1733                                                         if (char_group_end != 0)
1734                                                                 goto test_char_group_passed;
1735                                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1736                                                         continue;
1737                                                 }
1738                                         }
1739                                         if (char_group_end == 0)
1740                                                 return false;
1741                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1742                                         continue;
1743                                 case RxOp.CharIgnoreCaseReverse:
1744                                         if (strpos > 0) {
1745                                                 char c = Char.ToLower (str [strpos - 1]);
1746                                                 if (((c == program [pc + 1]))) {
1747                                                         strpos --;
1748                                                         if (char_group_end != 0)
1749                                                                 goto test_char_group_passed;
1750                                                         pc += 2;
1751                                                         continue;
1752                                                 }
1753                                         }
1754                                         if (char_group_end == 0)
1755                                                 return false;
1756                                         pc += 2;
1757                                         continue;
1758                                 case RxOp.RangeIgnoreCaseReverse:
1759                                         if (strpos > 0) {
1760                                                 char c = Char.ToLower (str [strpos - 1]);
1761                                                 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1762                                                         strpos --;
1763                                                         if (char_group_end != 0)
1764                                                                 goto test_char_group_passed;
1765                                                         pc += 3;
1766                                                         continue;
1767                                                 }
1768                                         }
1769                                         if (char_group_end == 0)
1770                                                 return false;
1771                                         pc += 3;
1772                                         continue;
1773                                 case RxOp.UnicodeRangeIgnoreCaseReverse:
1774                                         if (strpos > 0) {
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))))) {
1777                                                         strpos --;
1778                                                         if (char_group_end != 0)
1779                                                                 goto test_char_group_passed;
1780                                                         pc += 5;
1781                                                         continue;
1782                                                 }
1783                                         }
1784                                         if (char_group_end == 0)
1785                                                 return false;
1786                                         pc += 5;
1787                                         continue;
1788                                 case RxOp.UnicodeCharIgnoreCaseReverse:
1789                                         if (strpos > 0) {
1790                                                 char c = Char.ToLower (str [strpos - 1]);
1791                                                 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1792                                                         strpos --;
1793                                                         if (char_group_end != 0)
1794                                                                 goto test_char_group_passed;
1795                                                         pc += 3;
1796                                                         continue;
1797                                                 }
1798                                         }
1799                                         if (char_group_end == 0)
1800                                                 return false;
1801                                         pc += 3;
1802                                         continue;
1803                                 case RxOp.BitmapIgnoreCaseReverse:
1804                                         if (strpos > 0) {
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))) {
1808                                                         strpos --;
1809                                                         if (char_group_end != 0)
1810                                                                 goto test_char_group_passed;
1811                                                         pc += 3 + program [pc + 2];
1812                                                         continue;
1813                                                 }
1814                                         }
1815                                         if (char_group_end == 0)
1816                                                 return false;
1817                                         pc += 3 + program [pc + 2];
1818                                         continue;
1819                                 case RxOp.UnicodeBitmapIgnoreCaseReverse:
1820                                         if (strpos > 0) {
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))) {
1824                                                         strpos --;
1825                                                         if (char_group_end != 0)
1826                                                                 goto test_char_group_passed;
1827                                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1828                                                         continue;
1829                                                 }
1830                                         }
1831                                         if (char_group_end == 0)
1832                                                 return false;
1833                                         pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1834                                         continue;
1835                                 case RxOp.NoCharReverse:
1836                                         if (strpos > 0) {
1837                                                 char c = str [strpos - 1];
1838                                                 if (!((c == program [pc + 1]))) {
1839                                                         pc += 2;
1840                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1841                                                                 strpos --;
1842                                                         if (pc + 1 == char_group_end)
1843                                                                 goto test_char_group_passed;
1844                                                         }
1845                                                         continue;
1846                                                 }
1847                                         }
1848                                         return false;
1849                                 case RxOp.NoRangeReverse:
1850                                         if (strpos > 0) {
1851                                                 char c = str [strpos - 1];
1852                                                 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1853                                                         pc += 3;
1854                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1855                                                                 strpos --;
1856                                                         if (pc + 1 == char_group_end)
1857                                                                 goto test_char_group_passed;
1858                                                         }
1859                                                         continue;
1860                                                 }
1861                                         }
1862                                         return false;
1863                                 case RxOp.NoUnicodeRangeReverse:
1864                                         if (strpos > 0) {
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))))) {
1867                                                         pc += 5;
1868                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1869                                                                 strpos --;
1870                                                         if (pc + 1 == char_group_end)
1871                                                                 goto test_char_group_passed;
1872                                                         }
1873                                                         continue;
1874                                                 }
1875                                         }
1876                                         return false;
1877                                 case RxOp.NoUnicodeCharReverse:
1878                                         if (strpos > 0) {
1879                                                 char c = str [strpos - 1];
1880                                                 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1881                                                         pc += 3;
1882                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1883                                                                 strpos --;
1884                                                         if (pc + 1 == char_group_end)
1885                                                                 goto test_char_group_passed;
1886                                                         }
1887                                                         continue;
1888                                                 }
1889                                         }
1890                                         return false;
1891                                 case RxOp.NoCategoryAnyReverse:
1892                                         if (strpos > 0) {
1893                                                 char c = str [strpos - 1];
1894                                                 if (!((c != '\n'))) {
1895                                                         pc += 1;
1896                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1897                                                                 strpos --;
1898                                                         if (pc + 1 == char_group_end)
1899                                                                 goto test_char_group_passed;
1900                                                         }
1901                                                         continue;
1902                                                 }
1903                                         }
1904                                         return false;
1905                                 case RxOp.NoCategoryAnySinglelineReverse:
1906                                         if (strpos > 0) {
1907                                                 char c = str [strpos - 1];
1908                                                 if (!(true)) {
1909                                                         pc += 1;
1910                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1911                                                                 strpos --;
1912                                                         if (pc + 1 == char_group_end)
1913                                                                 goto test_char_group_passed;
1914                                                         }
1915                                                         continue;
1916                                                 }
1917                                         }
1918                                         return false;
1919                                 case RxOp.NoCategoryWordReverse:
1920                                         if (strpos > 0) {
1921                                                 char c = str [strpos - 1];
1922                                                 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1923                                                         pc += 1;
1924                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1925                                                                 strpos --;
1926                                                         if (pc + 1 == char_group_end)
1927                                                                 goto test_char_group_passed;
1928                                                         }
1929                                                         continue;
1930                                                 }
1931                                         }
1932                                         return false;
1933                                 case RxOp.NoCategoryDigitReverse:
1934                                         if (strpos > 0) {
1935                                                 char c = str [strpos - 1];
1936                                                 if (!((Char.IsDigit (c)))) {
1937                                                         pc += 1;
1938                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1939                                                                 strpos --;
1940                                                         if (pc + 1 == char_group_end)
1941                                                                 goto test_char_group_passed;
1942                                                         }
1943                                                         continue;
1944                                                 }
1945                                         }
1946                                         return false;
1947                                 case RxOp.NoCategoryWhiteSpaceReverse:
1948                                         if (strpos > 0) {
1949                                                 char c = str [strpos - 1];
1950                                                 if (!((Char.IsWhiteSpace (c)))) {
1951                                                         pc += 1;
1952                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1953                                                                 strpos --;
1954                                                         if (pc + 1 == char_group_end)
1955                                                                 goto test_char_group_passed;
1956                                                         }
1957                                                         continue;
1958                                                 }
1959                                         }
1960                                         return false;
1961                                 case RxOp.NoCategoryEcmaWordReverse:
1962                                         if (strpos > 0) {
1963                                                 char c = str [strpos - 1];
1964                                                 if (!(('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1965                                                         pc += 1;
1966                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1967                                                                 strpos --;
1968                                                         if (pc + 1 == char_group_end)
1969                                                                 goto test_char_group_passed;
1970                                                         }
1971                                                         continue;
1972                                                 }
1973                                         }
1974                                         return false;
1975                                 case RxOp.NoCategoryEcmaWhiteSpaceReverse:
1976                                         if (strpos > 0) {
1977                                                 char c = str [strpos - 1];
1978                                                 if (!((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1979                                                         pc += 1;
1980                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1981                                                                 strpos --;
1982                                                         if (pc + 1 == char_group_end)
1983                                                                 goto test_char_group_passed;
1984                                                         }
1985                                                         continue;
1986                                                 }
1987                                         }
1988                                         return false;
1989                                 case RxOp.NoCategoryUnicodeSpecialsReverse:
1990                                         if (strpos > 0) {
1991                                                 char c = str [strpos - 1];
1992                                                 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1993                                                         pc += 1;
1994                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1995                                                                 strpos --;
1996                                                         if (pc + 1 == char_group_end)
1997                                                                 goto test_char_group_passed;
1998                                                         }
1999                                                         continue;
2000                                                 }
2001                                         }
2002                                         return false;
2003                                 case RxOp.NoCategoryUnicodeReverse:
2004                                         if (strpos > 0) {
2005                                                 char c = str [strpos - 1];
2006                                                 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
2007                                                         pc += 2;
2008                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2009                                                                 strpos --;
2010                                                         if (pc + 1 == char_group_end)
2011                                                                 goto test_char_group_passed;
2012                                                         }
2013                                                         continue;
2014                                                 }
2015                                         }
2016                                         return false;
2017                                 case RxOp.NoCategoryGeneralReverse:
2018                                         if (strpos > 0) {
2019                                                 char c = str [strpos - 1];
2020                                                 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
2021                                                         pc += 2;
2022                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2023                                                                 strpos --;
2024                                                         if (pc + 1 == char_group_end)
2025                                                                 goto test_char_group_passed;
2026                                                         }
2027                                                         continue;
2028                                                 }
2029                                         }
2030                                         return false;
2031                                 case RxOp.NoBitmapReverse:
2032                                         if (strpos > 0) {
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)) {
2038                                                                 strpos --;
2039                                                         if (pc + 1 == char_group_end)
2040                                                                 goto test_char_group_passed;
2041                                                         }
2042                                                         continue;
2043                                                 }
2044                                         }
2045                                         return false;
2046                                 case RxOp.NoUnicodeBitmapReverse:
2047                                         if (strpos > 0) {
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)) {
2053                                                                 strpos --;
2054                                                         if (pc + 1 == char_group_end)
2055                                                                 goto test_char_group_passed;
2056                                                         }
2057                                                         continue;
2058                                                 }
2059                                         }
2060                                         return false;
2061                                 case RxOp.NoCharIgnoreCaseReverse:
2062                                         if (strpos > 0) {
2063                                                 char c = Char.ToLower (str [strpos - 1]);
2064                                                 if (!((c == program [pc + 1]))) {
2065                                                         pc += 2;
2066                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2067                                                                 strpos --;
2068                                                         if (pc + 1 == char_group_end)
2069                                                                 goto test_char_group_passed;
2070                                                         }
2071                                                         continue;
2072                                                 }
2073                                         }
2074                                         return false;
2075                                 case RxOp.NoRangeIgnoreCaseReverse:
2076                                         if (strpos > 0) {
2077                                                 char c = Char.ToLower (str [strpos - 1]);
2078                                                 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
2079                                                         pc += 3;
2080                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2081                                                                 strpos --;
2082                                                         if (pc + 1 == char_group_end)
2083                                                                 goto test_char_group_passed;
2084                                                         }
2085                                                         continue;
2086                                                 }
2087                                         }
2088                                         return false;
2089                                 case RxOp.NoUnicodeRangeIgnoreCaseReverse:
2090                                         if (strpos > 0) {
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))))) {
2093                                                         pc += 5;
2094                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2095                                                                 strpos --;
2096                                                         if (pc + 1 == char_group_end)
2097                                                                 goto test_char_group_passed;
2098                                                         }
2099                                                         continue;
2100                                                 }
2101                                         }
2102                                         return false;
2103                                 case RxOp.NoUnicodeCharIgnoreCaseReverse:
2104                                         if (strpos > 0) {
2105                                                 char c = Char.ToLower (str [strpos - 1]);
2106                                                 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
2107                                                         pc += 3;
2108                                                         if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2109                                                                 strpos --;
2110                                                         if (pc + 1 == char_group_end)
2111                                                                 goto test_char_group_passed;
2112                                                         }
2113                                                         continue;
2114                                                 }
2115                                         }
2116                                         return false;
2117                                 case RxOp.NoBitmapIgnoreCaseReverse:
2118                                         if (strpos > 0) {
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)) {
2124                                                                 strpos --;
2125                                                         if (pc + 1 == char_group_end)
2126                                                                 goto test_char_group_passed;
2127                                                         }
2128                                                         continue;
2129                                                 }
2130                                         }
2131                                         return false;
2132                                 case RxOp.NoUnicodeBitmapIgnoreCaseReverse:
2133                                         if (strpos > 0) {
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)) {
2139                                                                 strpos --;
2140                                                         if (pc + 1 == char_group_end)
2141                                                                 goto test_char_group_passed;
2142                                                         }
2143                                                         continue;
2144                                                 }
2145                                         }
2146                                         return false;
2147                                 
2148                                 // END OF GENERATED CODE
2149
2150                                 case RxOp.Branch: {
2151                                         int res = 0;
2152                                         if (EvalByteCode (pc + 3, strpos, ref res)) {
2153                                                 strpos_result = res;
2154                                                 return true;
2155                                         }
2156                                         //Console.WriteLine ("branch offset: {0}", program [pc + 1] | ((int)program [pc + 2] << 8));
2157                                         pc += program [pc + 1] | ((int)program [pc + 2] << 8);
2158                                         continue;
2159                                 }
2160                                 case RxOp.Repeat:
2161                                 case RxOp.RepeatLazy: {
2162                                         /*
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.
2171                                          *
2172                                          * This code is from the old interpreter.cs.
2173                                          *
2174                                          * FIXME: Rethink this.
2175                                          */
2176
2177                                         int res = 0;
2178
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
2185                                         );
2186
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;
2190                                                 return false;
2191                                         }
2192
2193                                         strpos = res;
2194                                         strpos_result = strpos;
2195                                         return true;
2196                                 }
2197                                 case RxOp.Until: {
2198                                         RepeatContext current = this.repeat;
2199                                         int res = 0;
2200
2201                                         //
2202                                         // Can we avoid recursion?
2203                                         //
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
2206                                         // quantifiers.
2207                                         //
2208                                         // If 'deep' was unmolested, that implies that there was no nested quantifiers.
2209                                         // Thus, we can safely avoid recursion.
2210                                         //
2211                                         if (deep == current)
2212                                                 goto Pass;
2213
2214                                         start = current.Start;
2215                                         int start_count = current.Count;
2216
2217                                         // First match at least 'start' items without backtracking
2218                                         while (!current.IsMinimum) {
2219                                                 ++ current.Count;
2220                                                 current.Start = strpos;
2221                                                 deep = current;
2222                                                 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2223                                                         current.Start = start;
2224                                                         current.Count = start_count;
2225                                                         goto Fail;
2226                                                 }
2227                                                 strpos = res;
2228                                                 if (deep != current)    // recursive mode
2229                                                         goto Pass;
2230                                         }
2231
2232                                         if (strpos == current.Start) {
2233                                                 // degenerate match ... match tail or fail
2234                                                 this.repeat = current.Previous;
2235                                                 deep = null;
2236                                                 if (EvalByteCode (pc + 1, strpos, ref res)) {
2237                                                         strpos = res;
2238                                                         goto Pass;
2239                                                 }
2240                                                 this.repeat = current;
2241                                                 goto Fail;
2242                                         }
2243
2244                                         if (current.IsLazy) {
2245                                                 for (;;) {
2246                                                         // match tail first ...
2247                                                         this.repeat = current.Previous;
2248                                                         deep = null;
2249                                                         int cp = Checkpoint ();
2250                                                         if (EvalByteCode (pc + 1, strpos, ref res)) {
2251                                                                 strpos = res;
2252                                                                 goto Pass;
2253                                                         }
2254
2255                                                         Backtrack (cp);
2256
2257                                                         // ... then match more
2258                                                         this.repeat = current;
2259                                                         if (current.IsMaximum)
2260                                                                 goto Fail;
2261                                                         ++ current.Count;
2262                                                         current.Start = strpos;
2263                                                         deep = current;
2264                                                         if (!EvalByteCode (current.Expression, strpos, ref res)) {
2265                                                                 current.Start = start;
2266                                                                 current.Count = start_count;
2267                                                                 goto Fail;
2268                                                         }
2269                                                         strpos = res;
2270                                                         if (deep != current)    // recursive mode
2271                                                                 goto Pass;
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)
2275                                                                 goto Fail;
2276                                                 }
2277                                         } else {
2278                                                 int stack_size = stack.Count;
2279
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;
2285
2286                                                         ++ current.Count;
2287                                                         if (trace_rx)
2288                                                                 Console.WriteLine ("recurse with count {0}.", current.Count);
2289                                                         current.Start = strpos;
2290                                                         deep = current;
2291                                                         if (!EvalByteCode (current.Expression, strpos, ref res)) {
2292                                                                 -- current.Count;
2293                                                                 current.Start = old_start;
2294                                                                 Backtrack (cp);
2295                                                                 break;
2296                                                         }
2297                                                         strpos = res;
2298                                                         if (deep != current) {
2299                                                                 // recursive mode: no more backtracking, truncate the stack
2300                                                                 stack.Count = stack_size;
2301                                                                 goto Pass;
2302                                                         }
2303                                                         stack.Push (cp);
2304                                                         stack.Push (old_ptr);
2305
2306                                                         // Degenerate match: no point going on
2307                                                         if (strpos == current.Start)
2308                                                                 break;
2309                                                 }
2310
2311                                                 if (trace_rx)
2312                                                         Console.WriteLine ("matching tail: {0} pc={1}", strpos, pc + 1);
2313                                                 // then, match the tail, backtracking as necessary.
2314                                                 this.repeat = current.Previous;
2315                                                 for (;;) {
2316                                                         deep = null;
2317                                                         if (EvalByteCode (pc + 1, strpos, ref res)) {
2318                                                                 strpos = res;
2319                                                                 stack.Count = stack_size;
2320                                                                 goto Pass;
2321                                                         }
2322                                                         if (stack.Count == stack_size) {
2323                                                                 this.repeat = current;
2324                                                                 goto Fail;
2325                                                         }
2326
2327                                                         --current.Count;
2328                                                         strpos = stack.Pop ();
2329                                                         Backtrack (stack.Pop ());
2330                                                         if (trace_rx)
2331                                                                 Console.WriteLine ("backtracking to {0} expr={1} pc={2}", strpos, current.Expression, pc);
2332                                                 }
2333                                         }
2334                                 }
2335
2336                                 case RxOp.FastRepeat:
2337                                 case RxOp.FastRepeatLazy: {
2338                                         /*
2339                                          * A FastRepeat is a simplified version of Repeat which does
2340                                          * not contain another repeat inside, so backtracking is 
2341                                          * easier.
2342                                          */
2343                                         bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
2344                                         int res = 0;
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);
2349                                         length = 0;
2350
2351                                         deep = null;
2352
2353                                         // First match at least 'start' items
2354                                         while (length < start) {
2355                                                 if (!EvalByteCode (pc + 11, strpos, ref res))
2356                                                         return false;
2357                                                 strpos = res;
2358                                                 length++;
2359                                         }
2360                                         
2361                                         if (lazy) {
2362                                                 while (true) {
2363                                                         // Match the tail
2364                                                         int cp = Checkpoint ();
2365                                                         if (EvalByteCode (tail, strpos, ref res)) {
2366                                                                 strpos = res;
2367                                                                 goto repeat_success;
2368                                                         }
2369                                                         Backtrack (cp);
2370
2371                                                         if (length >= end)
2372                                                                 return false;
2373
2374                                                         // Match an item
2375                                                         if (!EvalByteCode (pc + 11, strpos, ref res))
2376                                                                 return false;
2377                                                         strpos = res;
2378                                                         length ++;
2379                                                 }
2380                                         } else {
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)) {
2387                                                                 Backtrack (cp);
2388                                                                 break;
2389                                                         }
2390                                                         stack.Push (cp);
2391                                                         stack.Push (strpos);
2392                                                         strpos = res;
2393                                                         length++;
2394                                                 }       
2395
2396                                                 if (tail <= pc)
2397                                                         throw new Exception ();
2398
2399                                                 // Then, match the tail, backtracking as necessary.
2400                                                 while (true) {
2401                                                         if (EvalByteCode (tail, strpos, ref res)) {
2402                                                                 strpos = res;
2403                                                                 stack.Count = old_stack_size;
2404                                                                 goto repeat_success;
2405                                                         }
2406                                                         if (stack.Count == old_stack_size)
2407                                                                 return false;
2408
2409                                                         // Backtrack
2410                                                         strpos = stack.Pop ();
2411                                                         Backtrack (stack.Pop ());
2412                                                         if (trace_rx)
2413                                                                 Console.WriteLine ("backtracking to: {0}", strpos);
2414                                                 }
2415                                         }
2416
2417                                 repeat_success:
2418                                         // We matched the tail too so just return
2419                                         goto Pass;
2420                                 }
2421
2422                                 default:
2423                                         Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", (RxOp)program [pc], pc, strpos);
2424                                         throw new NotSupportedException ();
2425                                 }
2426                                 continue;
2427
2428                         Pass:
2429                                 strpos_result = strpos;
2430                                 return true;
2431                         Fail:
2432                                 return false;
2433                         test_char_group_passed:
2434                                 pc = char_group_end;
2435                                 char_group_end = 0;
2436                                 continue;
2437                         } // end of while (true)
2438                 }
2439         }
2440 }