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