2008-11-13 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / class / System / System.Text.RegularExpressions / RxInterpreter.cs
blob77a42c526b8076c8858b30fe35c6b675187409f8
2 // Based upon interpreter.cs, written by Dan Lewis (dlewis@gmx.co.uk)
4 using System;
5 using System.Collections;
6 using System.Globalization;
7 using System.Diagnostics;
9 namespace System.Text.RegularExpressions {
11 internal delegate bool EvalDelegate (RxInterpreter interp, int strpos, ref int strpos_result);
13 sealed class RxInterpreter: BaseMachine {
14 byte[] program;
15 string str;
16 int string_start;
17 int string_end;
18 int group_count;
19 // int match_start;
20 int[] groups;
21 EvalDelegate eval_del; // optimized EvalByteCode method created by the CILCompiler
23 Mark[] marks = null; // mark stack
24 int mark_start; // start of current checkpoint
25 int mark_end; // end of checkpoint/next free mark
27 IntStack stack; // utility stack
29 RepeatContext repeat; // current repeat context
30 RepeatContext deep; // points to the most-nested repeat context
32 /* The readonly ensures the JIT can optimize out if (trace_rx) statements */
33 public static readonly bool trace_rx = Environment.GetEnvironmentVariable ("MONO_TRACE_RX") != null;
35 // private classes
37 internal struct IntStack {
38 int [] values;
39 int count;
40 public int Pop ()
42 return values [--count];
44 public void Push (int value)
46 if (values == null) {
47 values = new int [8];
48 } else if (count == values.Length) {
49 int new_size = values.Length;
50 new_size += new_size >> 1;
51 int [] new_values = new int [new_size];
52 for (int i = 0; i < count; ++i)
53 new_values [i] = values [i];
54 values = new_values;
56 values [count++] = value;
58 public int Top {
59 get { return values [count - 1]; }
61 public int Count {
62 get { return count; }
63 set {
64 if (value > count)
65 throw new SystemException ("can only truncate the stack");
66 count = value;
71 private class RepeatContext {
72 public RepeatContext (RepeatContext previous, int min, int max, bool lazy, int expr_pc) {
73 this.previous = previous;
74 this.min = min;
75 this.max = max;
76 this.lazy = lazy;
77 this.expr_pc = expr_pc;
79 this.start = -1;
80 this.count = 0;
83 public int Count {
84 get { return count; }
85 set { count = value; }
88 public int Start {
89 get { return start; }
90 set { start = value; }
93 public bool IsMinimum {
94 get { return min <= count; }
97 public bool IsMaximum {
98 get { return max <= count; }
101 public bool IsLazy {
102 get { return lazy; }
105 public int Expression {
106 get { return expr_pc; }
109 public RepeatContext Previous {
110 get { return previous; }
113 private int start;
114 private int min, max;
115 private bool lazy;
116 private int expr_pc;
117 private RepeatContext previous;
119 private int count;
122 static int ReadInt (byte[] code, int pc)
124 int val = code [pc];
125 val |= (int)code [pc + 1] << 8;
126 val |= (int)code [pc + 2] << 16;
127 val |= (int)code [pc + 3] << 24;
128 return val;
131 public RxInterpreter (byte[] program, EvalDelegate eval_del)
133 this.program = program;
134 this.eval_del = eval_del;
135 group_count = 1 + (program [1] | ((int)program [2] << 8));
136 groups = new int [group_count];
137 stack = new IntStack ();
139 ResetGroups ();
142 public override Match Scan (Regex regex, string text, int start, int end) {
143 str = text;
144 string_start = start;
145 string_end = end;
146 int res = 0;
148 bool match;
149 if (eval_del != null) {
150 match = eval_del (this, start, ref res);
151 } else {
152 match = EvalByteCode (11, start, ref res);
154 marks [groups [0]].End = res;
155 if (match) {
156 return GenerateMatch (regex);
157 //Match m = new Match (regex, this, text, end, 0, match_start, res - match_start);
158 //return m;
160 return Match.Empty;
163 // capture management
164 private void Open (int gid, int ptr) {
165 int m = groups [gid];
166 if (m < mark_start || marks [m].IsDefined) {
167 m = CreateMark (m);
168 groups [gid] = m;
171 marks [m].Start = ptr;
174 private void Close (int gid, int ptr) {
175 marks [groups [gid]].End = ptr;
178 private bool Balance (int gid, int balance_gid, bool capture, int ptr) {
179 int b = groups [balance_gid];
181 if(b == -1 || marks[b].Index < 0) {
182 //Group not previously matched
183 return false;
185 Debug.Assert (marks [b].IsDefined, "Regex", "Balancng group not closed");
186 if (gid > 0 && capture){
187 Open (gid, marks [b].Index + marks [b].Length);
188 Close (gid, ptr);
191 groups [balance_gid] = marks[b].Previous;
193 return true;
196 private int Checkpoint () {
197 mark_start = mark_end;
198 return mark_start;
201 private void Backtrack (int cp) {
202 for (int i = 0; i < groups.Length; ++ i) {
203 int m = groups [i];
204 while (cp <= m)
205 m = marks [m].Previous;
206 groups [i] = m;
210 private void ResetGroups () {
211 int n = groups.Length;
212 if (marks == null)
213 marks = new Mark [n * 10];
215 for (int i = 0; i < n; ++ i) {
216 groups [i] = i;
218 marks [i].Start = -1;
219 marks [i].End = -1;
220 marks [i].Previous = -1;
222 mark_start = 0;
223 mark_end = n;
226 private int GetLastDefined (int gid) {
227 int m = groups [gid];
228 while (m >= 0 && !marks [m].IsDefined)
229 m = marks [m].Previous;
231 return m;
234 private int CreateMark (int previous) {
235 if (mark_end == marks.Length) {
236 Mark [] dest = new Mark [marks.Length * 2];
237 marks.CopyTo (dest, 0);
238 marks = dest;
241 int m = mark_end ++;
242 marks [m].Start = marks [m].End = -1;
243 marks [m].Previous = previous;
245 return m;
248 private void GetGroupInfo (int gid, out int first_mark_index, out int n_caps)
250 first_mark_index = -1;
251 n_caps = 0;
252 for (int m = groups [gid]; m >= 0; m = marks [m].Previous) {
253 if (!marks [m].IsDefined)
254 continue;
255 if (first_mark_index < 0)
256 first_mark_index = m;
257 ++n_caps;
261 private void PopulateGroup (Group g, int first_mark_index, int n_caps)
263 int i = 1;
264 for (int m = marks [first_mark_index].Previous; m >= 0; m = marks [m].Previous) {
265 if (!marks [m].IsDefined)
266 continue;
267 Capture cap = new Capture (str, marks [m].Index, marks [m].Length);
268 g.Captures.SetValue (cap, n_caps - 1 - i);
269 ++i;
273 private Match GenerateMatch (Regex regex)
275 int n_caps, first_mark_index;
276 Group g;
277 GetGroupInfo (0, out first_mark_index, out n_caps);
279 // Avoid fully populating the Match instance if not needed
280 if (!needs_groups_or_captures)
281 return new Match (regex, this, str, string_end, 0, marks [first_mark_index].Index, marks [first_mark_index].Length);
283 Match retval = new Match (regex, this, str, string_end, groups.Length,
284 marks [first_mark_index].Index, marks [first_mark_index].Length, n_caps);
285 PopulateGroup (retval, first_mark_index, n_caps);
287 for (int gid = 1; gid < groups.Length; ++ gid) {
288 GetGroupInfo (gid, out first_mark_index, out n_caps);
289 if (first_mark_index < 0) {
290 g = Group.Fail;
291 } else {
292 g = new Group (str, marks [first_mark_index].Index, marks [first_mark_index].Length, n_caps);
293 PopulateGroup (g, first_mark_index, n_caps);
295 retval.Groups.SetValue (g, gid);
297 return retval;
300 // used by the IL backend
301 internal void SetStartOfMatch (int pos)
303 marks [groups [0]].Start = pos;
306 static bool IsWordChar (char c)
308 return Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
311 bool EvalByteCode (int pc, int strpos, ref int strpos_result)
313 // luckily the IL engine can deal with char_group_end at compile time
314 // this code offset needs to be checked only in opcodes that handle
315 // a single char and that are included in a TestCharGroup expression:
316 // the engine is supposed to jump to this offset as soons as the
317 // first opcode in the expression matches
318 // The code pattern becomes:
319 // on successfull match: check if char_group_end is nonzero and jump to
320 // test_char_group_passed after adjusting strpos
321 // on failure: try the next expression by simply advancing pc
322 int char_group_end = 0;
323 int length, start, end;
324 while (true) {
325 if (trace_rx) {
326 Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}, cge: {3}", (RxOp)program [pc], pc, strpos, char_group_end);
327 //Console.WriteLine ("deep: " + (deep == null ? 0 : deep.GetHashCode ()) + " repeat: " + (this.repeat == null ? 0 : this.repeat.GetHashCode ()));
329 switch ((RxOp)program [pc]) {
330 case RxOp.True:
331 if (char_group_end != 0) {
332 pc = char_group_end;
333 char_group_end = 0;
334 continue;
336 strpos_result = strpos;
337 return true;
338 case RxOp.False:
339 return false;
340 case RxOp.AnyPosition:
341 pc++;
342 continue;
343 case RxOp.StartOfString:
344 if (strpos != 0)
345 return false;
346 pc++;
347 continue;
348 case RxOp.StartOfLine:
349 if (strpos == 0 || str [strpos - 1] == '\n') {
350 pc++;
351 continue;
353 return false;
354 case RxOp.StartOfScan:
355 if (strpos != string_start)
356 return false;
357 pc++;
358 continue;
359 case RxOp.End:
360 if (strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')) {
361 pc++;
362 continue;
364 return false;
365 case RxOp.EndOfString:
366 if (strpos != string_end)
367 return false;
368 pc++;
369 continue;
370 case RxOp.EndOfLine:
371 if (strpos == string_end || str [strpos] == '\n') {
372 pc++;
373 continue;
375 return false;
376 case RxOp.WordBoundary:
377 if (string_end == 0)
378 return false;
379 if (strpos == 0) {
380 if (IsWordChar (str [strpos])) {
381 pc++;
382 continue;
384 } else if (strpos == string_end) {
385 if (IsWordChar (str [strpos - 1])) {
386 pc++;
387 continue;
389 } else {
390 if (IsWordChar (str [strpos]) != IsWordChar (str [strpos - 1])) {
391 pc++;
392 continue;
395 return false;
396 case RxOp.NoWordBoundary:
397 if (string_end == 0)
398 return false;
399 if (strpos == 0) {
400 if (!IsWordChar (str [strpos])) {
401 pc++;
402 continue;
404 } else if (strpos == string_end) {
405 if (!IsWordChar (str [strpos - 1])) {
406 pc++;
407 continue;
409 } else {
410 if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
411 pc++;
412 continue;
415 return false;
416 case RxOp.Anchor:
417 length = program [pc + 3] | ((int)program [pc + 4] << 8);
418 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
420 RxOp anch_op = (RxOp)(program[pc] & 0x00ff);
422 // Optimize some common cases
424 if (anch_op == RxOp.StartOfString) {
425 if (strpos == 0) {
426 int res = strpos;
427 if (groups.Length > 1) {
428 ResetGroups ();
429 marks [groups [0]].Start = strpos;
431 if (EvalByteCode (pc + 1, strpos, ref res)) {
432 marks [groups [0]].Start = strpos;
433 if (groups.Length > 1)
434 marks [groups [0]].End = res;
435 strpos_result = res;
436 return true;
439 return false;
442 // FIXME: Add more special cases from interpreter.cs
444 // it's important to test also the end of the string
445 // position for things like: "" =~ /$/
446 end = string_end + 1;
447 while (strpos < end) {
448 int res = strpos;
449 if (groups.Length > 1) {
450 ResetGroups ();
451 marks [groups [0]].Start = strpos;
453 if (EvalByteCode (pc, strpos, ref res)) {
454 // match_start = strpos;
455 marks [groups [0]].Start = strpos;
456 if (groups.Length > 1)
457 marks [groups [0]].End = res;
458 strpos_result = res;
459 return true;
461 strpos++;
463 return false;
464 case RxOp.AnchorReverse:
465 length = program [pc + 3] | ((int)program [pc + 4] << 8);
466 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
467 // it's important to test also the end of the string
468 // position for things like: "" =~ /$/
469 end = 0;
470 while (strpos >= 0) {
471 int res = strpos;
472 if (groups.Length > 1) {
473 ResetGroups ();
474 marks [groups [0]].Start = strpos;
476 if (EvalByteCode (pc, strpos, ref res)) {
477 // match_start = strpos;
478 marks [groups [0]].Start = strpos;
479 if (groups.Length > 1)
480 marks [groups [0]].End = res;
481 strpos_result = res;
482 return true;
484 strpos--;
486 return false;
487 case RxOp.Reference:
488 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
489 if (length < 0)
490 return false;
491 start = marks [length].Index;
492 length = marks [length].Length;
493 if (strpos + length > string_end)
494 return false;
495 for (end = start + length; start < end; ++start) {
496 if (str [strpos] != str [start])
497 return false;
498 strpos++;
500 pc += 3;
501 continue;
502 case RxOp.ReferenceIgnoreCase:
503 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
504 if (length < 0)
505 return false;
506 start = marks [length].Index;
507 length = marks [length].Length;
508 if (strpos + length > string_end)
509 return false;
510 for (end = start + length; start < end; ++start) {
511 if (str [strpos] != str [start] && Char.ToLower (str [strpos]) != Char.ToLower (str [start]))
512 return false;
513 strpos++;
515 pc += 3;
516 continue;
517 case RxOp.ReferenceReverse: {
518 length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
519 if (length < 0)
520 return false;
521 start = marks [length].Index;
522 length = marks [length].Length;
523 if (strpos - length < 0)
524 return false;
525 int p = strpos - length;
526 for (end = start + length; start < end; ++start, ++p) {
527 if (str [p] != str [start])
528 return false;
530 strpos -= length;
531 pc += 3;
532 continue;
534 case RxOp.IfDefined:
535 if (GetLastDefined (program [pc + 3] | ((int)program [pc + 4] << 8)) >= 0)
536 pc += 5;
537 else
538 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
539 continue;
540 case RxOp.SubExpression: {
541 int res = 0;
542 if (EvalByteCode (pc + 3, strpos, ref res)) {
543 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
544 strpos = res;
545 continue;
547 return false;
549 case RxOp.Test: {
550 int res = 0;
551 // FIXME: checkpoint
552 if (EvalByteCode (pc + 5, strpos, ref res)) {
553 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
554 } else {
555 pc += program [pc + 3] | ((int)program [pc + 4] << 8);
557 continue;
559 case RxOp.OpenGroup:
560 Open (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
561 pc += 3;
562 continue;
563 case RxOp.CloseGroup:
564 Close (program [pc + 1] | ((int)program [pc + 2] << 8), strpos);
565 pc += 3;
566 continue;
567 case RxOp.BalanceStart: {
568 int res = 0;
570 if (!EvalByteCode (pc + 8, strpos, ref res))
571 goto Fail;
573 int gid = program [pc + 1] | ((int)program [pc + 2] << 8);
574 int balance_gid = program [pc + 3] | ((int)program [pc + 4] << 8);
575 bool capture = program [pc + 5] > 0;
576 if (!Balance (gid, balance_gid, capture, strpos))
577 goto Fail;
579 strpos = res;
580 pc += program[pc + 6] | ((int)program [pc + 7] << 8);
581 break;
583 case RxOp.Balance: {
584 goto Pass;
587 case RxOp.Jump:
588 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
589 continue;
590 case RxOp.TestCharGroup:
591 char_group_end = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
592 pc += 3;
593 continue;
594 case RxOp.String:
595 start = pc + 2;
596 length = program [pc + 1];
597 if (strpos + length > string_end)
598 return false;
599 end = start + length;
600 for (; start < end; ++start) {
601 if (str [strpos] != program [start])
602 return false;
603 strpos++;
605 pc = end;
606 continue;
607 case RxOp.StringIgnoreCase:
608 start = pc + 2;
609 length = program [pc + 1];
610 if (strpos + length > string_end)
611 return false;
612 end = start + length;
613 for (; start < end; ++start) {
614 if (str [strpos] != program [start] && Char.ToLower (str [strpos]) != program [start])
615 return false;
616 strpos++;
618 pc = end;
619 continue;
620 case RxOp.StringReverse: {
621 start = pc + 2;
622 length = program [pc + 1];
623 if (strpos < length)
624 return false;
625 int p = strpos - length;
626 end = start + length;
627 for (; start < end; ++start, ++p) {
628 if (str [p] != program [start])
629 return false;
631 strpos -= length;
632 pc = end;
633 continue;
635 case RxOp.StringIgnoreCaseReverse: {
636 start = pc + 2;
637 length = program [pc + 1];
638 if (strpos < length)
639 return false;
640 int p = strpos - length;
641 end = start + length;
642 for (; start < end; ++start, ++p) {
643 if (str [p] != program [start] && Char.ToLower (str [p]) != program [start])
644 return false;
646 strpos -= length;
647 pc = end;
648 continue;
650 case RxOp.UnicodeString: {
651 start = pc + 3;
652 length = program [pc + 1] | ((int)program [pc + 2] << 8);
653 if (strpos + length > string_end)
654 return false;
655 end = start + length * 2;
656 for (; start < end; start += 2) {
657 int c = program [start] | ((int)program [start + 1] << 8);
658 if (str [strpos] != c)
659 return false;
660 strpos++;
662 pc = end;
663 continue;
665 case RxOp.UnicodeStringIgnoreCase: {
666 start = pc + 3;
667 length = program [pc + 1] | ((int)program [pc + 2] << 8);
668 if (strpos + length > string_end)
669 return false;
670 end = start + length * 2;
671 for (; start < end; start += 2) {
672 int c = program [start] | ((int)program [start + 1] << 8);
673 if (str [strpos] != c && Char.ToLower (str [strpos]) != c)
674 return false;
675 strpos++;
677 pc = end;
678 continue;
680 case RxOp.UnicodeStringReverse: {
681 start = pc + 3;
682 length = program [pc + 1] | ((int)program [pc + 2] << 8);
683 if (strpos < length)
684 return false;
685 int p = strpos - length;
686 end = start + length * 2;
687 for (; start < end; start += 2, p += 2) {
688 int c = program [start] | ((int)program [start + 1] << 8);
689 if (str [p] != c)
690 return false;
692 strpos -= length;
693 pc = end;
694 continue;
696 case RxOp.UnicodeStringIgnoreCaseReverse: {
697 start = pc + 3;
698 length = program [pc + 1] | ((int)program [pc + 2] << 8);
699 if (strpos < length)
700 return false;
701 int p = strpos - length;
702 end = start + length * 2;
703 for (; start < end; start += 2, p += 2) {
704 int c = program [start] | ((int)program [start + 1] << 8);
705 if (str [p] != c && Char.ToLower (str [p]) != c)
706 return false;
708 strpos -= length;
709 pc = end;
710 continue;
714 * The opcodes below are basically specialized versions of one
715 * generic opcode, which has three parameters:
716 * - reverse (Reverse), revert (No), ignore-case (IgnoreCase)
717 * Thus each opcode has 8 variants.
718 * FIXME: Maybe move all unusual variations
719 * (Reverse+IgnoreCase+Unicode) into a generic GenericChar opcode
720 * like in the old interpreter.
721 * FIXME: Move all the Reverse opcodes to a separate method.
723 #if FALSE
724 if (!reverse) {
725 if (strpos < string_end && (COND (str [strpos]))) {
726 if (!revert) {
727 strpos ++;
728 if (char_group_end != 0)
729 goto test_char_group_passed;
730 pc += ins_len;
731 continue;
732 } else {
734 * If we are inside a char group, the cases are ANDed
735 * together, so we have to continue checking the
736 * other cases, and we need to increase strpos after
737 * the final check.
738 * The char group is termined by a True, hence the
739 * + 1 below.
740 * FIXME: Optimize this.
742 pc += ins_len;
743 if (char_group_end == 0 || (pc + 1 == char_group_end))
744 strpos ++;
745 if (pc + 1 == char_group_end)
746 goto test_char_group_passed;
747 continue;
749 } else {
750 if (!revert) {
751 if (char_group_end == 0)
752 return false;
753 pc += ins_len;
754 continue;
755 } else {
756 /* Fail both inside and outside a char group */
757 return false;
760 } else {
761 // Same as above, but use:
762 // - strpos > 0 instead of strpos < string_len
763 // - COND (str [strpos - 1]) instead of COND (str [strpos])
764 // - strpos -- instead of strpos ++
766 #endif
767 // GENERATED BY gen-interp.cs, DO NOT MODIFY
769 /* Char */
771 case RxOp.Char:
772 if (strpos < string_end) {
773 char c = str [strpos];
774 if (((c == program [pc + 1]))) {
775 strpos ++;
776 if (char_group_end != 0)
777 goto test_char_group_passed;
778 pc += 2;
779 continue;
782 if (char_group_end == 0)
783 return false;
784 pc += 2;
785 continue;
787 /* Range */
789 case RxOp.Range:
790 if (strpos < string_end) {
791 char c = str [strpos];
792 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
793 strpos ++;
794 if (char_group_end != 0)
795 goto test_char_group_passed;
796 pc += 3;
797 continue;
800 if (char_group_end == 0)
801 return false;
802 pc += 3;
803 continue;
805 /* UnicodeRange */
807 case RxOp.UnicodeRange:
808 if (strpos < string_end) {
809 char c = str [strpos];
810 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
811 strpos ++;
812 if (char_group_end != 0)
813 goto test_char_group_passed;
814 pc += 5;
815 continue;
818 if (char_group_end == 0)
819 return false;
820 pc += 5;
821 continue;
823 /* UnicodeChar */
825 case RxOp.UnicodeChar:
826 if (strpos < string_end) {
827 char c = str [strpos];
828 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
829 strpos ++;
830 if (char_group_end != 0)
831 goto test_char_group_passed;
832 pc += 3;
833 continue;
836 if (char_group_end == 0)
837 return false;
838 pc += 3;
839 continue;
841 /* CategoryAny */
843 case RxOp.CategoryAny:
844 if (strpos < string_end) {
845 char c = str [strpos];
846 if (((c != '\n'))) {
847 strpos ++;
848 if (char_group_end != 0)
849 goto test_char_group_passed;
850 pc += 1;
851 continue;
854 if (char_group_end == 0)
855 return false;
856 pc += 1;
857 continue;
859 /* CategoryAnySingleline */
861 case RxOp.CategoryAnySingleline:
862 if (strpos < string_end) {
863 char c = str [strpos];
864 if ((true)) {
865 strpos ++;
866 if (char_group_end != 0)
867 goto test_char_group_passed;
868 pc += 1;
869 continue;
872 if (char_group_end == 0)
873 return false;
874 pc += 1;
875 continue;
877 /* CategoryWord */
879 case RxOp.CategoryWord:
880 if (strpos < string_end) {
881 char c = str [strpos];
882 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
883 strpos ++;
884 if (char_group_end != 0)
885 goto test_char_group_passed;
886 pc += 1;
887 continue;
890 if (char_group_end == 0)
891 return false;
892 pc += 1;
893 continue;
895 /* CategoryDigit */
897 case RxOp.CategoryDigit:
898 if (strpos < string_end) {
899 char c = str [strpos];
900 if (((Char.IsDigit (c)))) {
901 strpos ++;
902 if (char_group_end != 0)
903 goto test_char_group_passed;
904 pc += 1;
905 continue;
908 if (char_group_end == 0)
909 return false;
910 pc += 1;
911 continue;
913 /* CategoryWhiteSpace */
915 case RxOp.CategoryWhiteSpace:
916 if (strpos < string_end) {
917 char c = str [strpos];
918 if (((Char.IsWhiteSpace (c)))) {
919 strpos ++;
920 if (char_group_end != 0)
921 goto test_char_group_passed;
922 pc += 1;
923 continue;
926 if (char_group_end == 0)
927 return false;
928 pc += 1;
929 continue;
931 /* CategoryEcmaWord */
933 case RxOp.CategoryEcmaWord:
934 if (strpos < string_end) {
935 char c = str [strpos];
936 if ((('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
937 strpos ++;
938 if (char_group_end != 0)
939 goto test_char_group_passed;
940 pc += 1;
941 continue;
944 if (char_group_end == 0)
945 return false;
946 pc += 1;
947 continue;
949 /* CategoryEcmaWhiteSpace */
951 case RxOp.CategoryEcmaWhiteSpace:
952 if (strpos < string_end) {
953 char c = str [strpos];
954 if (((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
955 strpos ++;
956 if (char_group_end != 0)
957 goto test_char_group_passed;
958 pc += 1;
959 continue;
962 if (char_group_end == 0)
963 return false;
964 pc += 1;
965 continue;
967 /* CategoryUnicodeSpecials */
969 case RxOp.CategoryUnicodeSpecials:
970 if (strpos < string_end) {
971 char c = str [strpos];
972 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
973 strpos ++;
974 if (char_group_end != 0)
975 goto test_char_group_passed;
976 pc += 1;
977 continue;
980 if (char_group_end == 0)
981 return false;
982 pc += 1;
983 continue;
985 /* CategoryUnicode */
987 case RxOp.CategoryUnicode:
988 if (strpos < string_end) {
989 char c = str [strpos];
990 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
991 strpos ++;
992 if (char_group_end != 0)
993 goto test_char_group_passed;
994 pc += 2;
995 continue;
998 if (char_group_end == 0)
999 return false;
1000 pc += 2;
1001 continue;
1003 /* CategoryGeneral */
1005 case RxOp.CategoryGeneral:
1006 if (strpos < string_end) {
1007 char c = str [strpos];
1008 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1009 strpos ++;
1010 if (char_group_end != 0)
1011 goto test_char_group_passed;
1012 pc += 2;
1013 continue;
1016 if (char_group_end == 0)
1017 return false;
1018 pc += 2;
1019 continue;
1021 /* Bitmap */
1023 case RxOp.Bitmap:
1024 if (strpos < string_end) {
1025 char c = str [strpos];
1026 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1027 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1028 strpos ++;
1029 if (char_group_end != 0)
1030 goto test_char_group_passed;
1031 pc += 3 + program [pc + 2];
1032 continue;
1035 if (char_group_end == 0)
1036 return false;
1037 pc += 3 + program [pc + 2];
1038 continue;
1040 /* UnicodeBitmap */
1042 case RxOp.UnicodeBitmap:
1043 if (strpos < string_end) {
1044 char c = str [strpos];
1045 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1046 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1047 strpos ++;
1048 if (char_group_end != 0)
1049 goto test_char_group_passed;
1050 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1051 continue;
1054 if (char_group_end == 0)
1055 return false;
1056 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1057 continue;
1058 case RxOp.CharIgnoreCase:
1059 if (strpos < string_end) {
1060 char c = Char.ToLower (str [strpos]);
1061 if (((c == program [pc + 1]))) {
1062 strpos ++;
1063 if (char_group_end != 0)
1064 goto test_char_group_passed;
1065 pc += 2;
1066 continue;
1069 if (char_group_end == 0)
1070 return false;
1071 pc += 2;
1072 continue;
1073 case RxOp.RangeIgnoreCase:
1074 if (strpos < string_end) {
1075 char c = Char.ToLower (str [strpos]);
1076 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1077 strpos ++;
1078 if (char_group_end != 0)
1079 goto test_char_group_passed;
1080 pc += 3;
1081 continue;
1084 if (char_group_end == 0)
1085 return false;
1086 pc += 3;
1087 continue;
1088 case RxOp.UnicodeRangeIgnoreCase:
1089 if (strpos < string_end) {
1090 char c = Char.ToLower (str [strpos]);
1091 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1092 strpos ++;
1093 if (char_group_end != 0)
1094 goto test_char_group_passed;
1095 pc += 5;
1096 continue;
1099 if (char_group_end == 0)
1100 return false;
1101 pc += 5;
1102 continue;
1103 case RxOp.UnicodeCharIgnoreCase:
1104 if (strpos < string_end) {
1105 char c = Char.ToLower (str [strpos]);
1106 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1107 strpos ++;
1108 if (char_group_end != 0)
1109 goto test_char_group_passed;
1110 pc += 3;
1111 continue;
1114 if (char_group_end == 0)
1115 return false;
1116 pc += 3;
1117 continue;
1118 case RxOp.BitmapIgnoreCase:
1119 if (strpos < string_end) {
1120 char c = Char.ToLower (str [strpos]);
1121 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1122 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1123 strpos ++;
1124 if (char_group_end != 0)
1125 goto test_char_group_passed;
1126 pc += 3 + program [pc + 2];
1127 continue;
1130 if (char_group_end == 0)
1131 return false;
1132 pc += 3 + program [pc + 2];
1133 continue;
1134 case RxOp.UnicodeBitmapIgnoreCase:
1135 if (strpos < string_end) {
1136 char c = Char.ToLower (str [strpos]);
1137 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1138 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1139 strpos ++;
1140 if (char_group_end != 0)
1141 goto test_char_group_passed;
1142 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1143 continue;
1146 if (char_group_end == 0)
1147 return false;
1148 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1149 continue;
1150 case RxOp.NoChar:
1151 if (strpos < string_end) {
1152 char c = str [strpos];
1153 if (!((c == program [pc + 1]))) {
1154 pc += 2;
1155 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1156 strpos ++;
1157 if (pc + 1 == char_group_end)
1158 goto test_char_group_passed;
1160 continue;
1163 return false;
1164 case RxOp.NoRange:
1165 if (strpos < string_end) {
1166 char c = str [strpos];
1167 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1168 pc += 3;
1169 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1170 strpos ++;
1171 if (pc + 1 == char_group_end)
1172 goto test_char_group_passed;
1174 continue;
1177 return false;
1178 case RxOp.NoUnicodeRange:
1179 if (strpos < string_end) {
1180 char c = str [strpos];
1181 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1182 pc += 5;
1183 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1184 strpos ++;
1185 if (pc + 1 == char_group_end)
1186 goto test_char_group_passed;
1188 continue;
1191 return false;
1192 case RxOp.NoUnicodeChar:
1193 if (strpos < string_end) {
1194 char c = str [strpos];
1195 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1196 pc += 3;
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;
1202 continue;
1205 return false;
1206 case RxOp.NoCategoryAny:
1207 if (strpos < string_end) {
1208 char c = str [strpos];
1209 if (!((c != '\n'))) {
1210 pc += 1;
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;
1216 continue;
1219 return false;
1220 case RxOp.NoCategoryAnySingleline:
1221 if (strpos < string_end) {
1222 char c = str [strpos];
1223 if (!(true)) {
1224 pc += 1;
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;
1230 continue;
1233 return false;
1234 case RxOp.NoCategoryWord:
1235 if (strpos < string_end) {
1236 char c = str [strpos];
1237 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1238 pc += 1;
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;
1244 continue;
1247 return false;
1248 case RxOp.NoCategoryDigit:
1249 if (strpos < string_end) {
1250 char c = str [strpos];
1251 if (!((Char.IsDigit (c)))) {
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;
1258 continue;
1261 return false;
1262 case RxOp.NoCategoryWhiteSpace:
1263 if (strpos < string_end) {
1264 char c = str [strpos];
1265 if (!((Char.IsWhiteSpace (c)))) {
1266 pc += 1;
1267 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1268 strpos ++;
1269 if (pc + 1 == char_group_end)
1270 goto test_char_group_passed;
1272 continue;
1275 return false;
1276 case RxOp.NoCategoryEcmaWord:
1277 if (strpos < string_end) {
1278 char c = str [strpos];
1279 if (!(('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1280 pc += 1;
1281 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1282 strpos ++;
1283 if (pc + 1 == char_group_end)
1284 goto test_char_group_passed;
1286 continue;
1289 return false;
1290 case RxOp.NoCategoryEcmaWhiteSpace:
1291 if (strpos < string_end) {
1292 char c = str [strpos];
1293 if (!((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1294 pc += 1;
1295 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1296 strpos ++;
1297 if (pc + 1 == char_group_end)
1298 goto test_char_group_passed;
1300 continue;
1303 return false;
1304 case RxOp.NoCategoryUnicodeSpecials:
1305 if (strpos < string_end) {
1306 char c = str [strpos];
1307 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1308 pc += 1;
1309 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1310 strpos ++;
1311 if (pc + 1 == char_group_end)
1312 goto test_char_group_passed;
1314 continue;
1317 return false;
1318 case RxOp.NoCategoryUnicode:
1319 if (strpos < string_end) {
1320 char c = str [strpos];
1321 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1322 pc += 2;
1323 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1324 strpos ++;
1325 if (pc + 1 == char_group_end)
1326 goto test_char_group_passed;
1328 continue;
1331 return false;
1332 case RxOp.NoCategoryGeneral:
1333 if (strpos < string_end) {
1334 char c = str [strpos];
1335 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1336 pc += 2;
1337 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1338 strpos ++;
1339 if (pc + 1 == char_group_end)
1340 goto test_char_group_passed;
1342 continue;
1345 return false;
1346 case RxOp.NoBitmap:
1347 if (strpos < string_end) {
1348 char c = str [strpos];
1349 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1350 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1351 pc += 3 + program [pc + 2];
1352 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1353 strpos ++;
1354 if (pc + 1 == char_group_end)
1355 goto test_char_group_passed;
1357 continue;
1360 return false;
1361 case RxOp.NoUnicodeBitmap:
1362 if (strpos < string_end) {
1363 char c = str [strpos];
1364 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1365 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1366 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
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;
1372 continue;
1375 return false;
1376 case RxOp.NoCharIgnoreCase:
1377 if (strpos < string_end) {
1378 char c = Char.ToLower (str [strpos]);
1379 if (!((c == program [pc + 1]))) {
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;
1386 continue;
1389 return false;
1390 case RxOp.NoRangeIgnoreCase:
1391 if (strpos < string_end) {
1392 char c = Char.ToLower (str [strpos]);
1393 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1394 pc += 3;
1395 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1396 strpos ++;
1397 if (pc + 1 == char_group_end)
1398 goto test_char_group_passed;
1400 continue;
1403 return false;
1404 case RxOp.NoUnicodeRangeIgnoreCase:
1405 if (strpos < string_end) {
1406 char c = Char.ToLower (str [strpos]);
1407 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1408 pc += 5;
1409 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1410 strpos ++;
1411 if (pc + 1 == char_group_end)
1412 goto test_char_group_passed;
1414 continue;
1417 return false;
1418 case RxOp.NoUnicodeCharIgnoreCase:
1419 if (strpos < string_end) {
1420 char c = Char.ToLower (str [strpos]);
1421 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1422 pc += 3;
1423 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1424 strpos ++;
1425 if (pc + 1 == char_group_end)
1426 goto test_char_group_passed;
1428 continue;
1431 return false;
1432 case RxOp.NoBitmapIgnoreCase:
1433 if (strpos < string_end) {
1434 char c = Char.ToLower (str [strpos]);
1435 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1436 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1437 pc += 3 + program [pc + 2];
1438 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1439 strpos ++;
1440 if (pc + 1 == char_group_end)
1441 goto test_char_group_passed;
1443 continue;
1446 return false;
1447 case RxOp.NoUnicodeBitmapIgnoreCase:
1448 if (strpos < string_end) {
1449 char c = Char.ToLower (str [strpos]);
1450 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1451 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1452 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
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;
1458 continue;
1461 return false;
1462 case RxOp.CharReverse:
1463 if (strpos > 0) {
1464 char c = str [strpos - 1];
1465 if (((c == program [pc + 1]))) {
1466 strpos --;
1467 if (char_group_end != 0)
1468 goto test_char_group_passed;
1469 pc += 2;
1470 continue;
1473 if (char_group_end == 0)
1474 return false;
1475 pc += 2;
1476 continue;
1477 case RxOp.RangeReverse:
1478 if (strpos > 0) {
1479 char c = str [strpos - 1];
1480 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1481 strpos --;
1482 if (char_group_end != 0)
1483 goto test_char_group_passed;
1484 pc += 3;
1485 continue;
1488 if (char_group_end == 0)
1489 return false;
1490 pc += 3;
1491 continue;
1492 case RxOp.UnicodeRangeReverse:
1493 if (strpos > 0) {
1494 char c = str [strpos - 1];
1495 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1496 strpos --;
1497 if (char_group_end != 0)
1498 goto test_char_group_passed;
1499 pc += 5;
1500 continue;
1503 if (char_group_end == 0)
1504 return false;
1505 pc += 5;
1506 continue;
1507 case RxOp.UnicodeCharReverse:
1508 if (strpos > 0) {
1509 char c = str [strpos - 1];
1510 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1511 strpos --;
1512 if (char_group_end != 0)
1513 goto test_char_group_passed;
1514 pc += 3;
1515 continue;
1518 if (char_group_end == 0)
1519 return false;
1520 pc += 3;
1521 continue;
1522 case RxOp.CategoryAnyReverse:
1523 if (strpos > 0) {
1524 char c = str [strpos - 1];
1525 if (((c != '\n'))) {
1526 strpos --;
1527 if (char_group_end != 0)
1528 goto test_char_group_passed;
1529 pc += 1;
1530 continue;
1533 if (char_group_end == 0)
1534 return false;
1535 pc += 1;
1536 continue;
1537 case RxOp.CategoryAnySinglelineReverse:
1538 if (strpos > 0) {
1539 char c = str [strpos - 1];
1540 if ((true)) {
1541 strpos --;
1542 if (char_group_end != 0)
1543 goto test_char_group_passed;
1544 pc += 1;
1545 continue;
1548 if (char_group_end == 0)
1549 return false;
1550 pc += 1;
1551 continue;
1552 case RxOp.CategoryWordReverse:
1553 if (strpos > 0) {
1554 char c = str [strpos - 1];
1555 if (((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1556 strpos --;
1557 if (char_group_end != 0)
1558 goto test_char_group_passed;
1559 pc += 1;
1560 continue;
1563 if (char_group_end == 0)
1564 return false;
1565 pc += 1;
1566 continue;
1567 case RxOp.CategoryDigitReverse:
1568 if (strpos > 0) {
1569 char c = str [strpos - 1];
1570 if (((Char.IsDigit (c)))) {
1571 strpos --;
1572 if (char_group_end != 0)
1573 goto test_char_group_passed;
1574 pc += 1;
1575 continue;
1578 if (char_group_end == 0)
1579 return false;
1580 pc += 1;
1581 continue;
1582 case RxOp.CategoryWhiteSpaceReverse:
1583 if (strpos > 0) {
1584 char c = str [strpos - 1];
1585 if (((Char.IsWhiteSpace (c)))) {
1586 strpos --;
1587 if (char_group_end != 0)
1588 goto test_char_group_passed;
1589 pc += 1;
1590 continue;
1593 if (char_group_end == 0)
1594 return false;
1595 pc += 1;
1596 continue;
1597 case RxOp.CategoryEcmaWordReverse:
1598 if (strpos > 0) {
1599 char c = str [strpos - 1];
1600 if ((('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1601 strpos --;
1602 if (char_group_end != 0)
1603 goto test_char_group_passed;
1604 pc += 1;
1605 continue;
1608 if (char_group_end == 0)
1609 return false;
1610 pc += 1;
1611 continue;
1612 case RxOp.CategoryEcmaWhiteSpaceReverse:
1613 if (strpos > 0) {
1614 char c = str [strpos - 1];
1615 if (((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1616 strpos --;
1617 if (char_group_end != 0)
1618 goto test_char_group_passed;
1619 pc += 1;
1620 continue;
1623 if (char_group_end == 0)
1624 return false;
1625 pc += 1;
1626 continue;
1627 case RxOp.CategoryUnicodeSpecialsReverse:
1628 if (strpos > 0) {
1629 char c = str [strpos - 1];
1630 if ((('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1631 strpos --;
1632 if (char_group_end != 0)
1633 goto test_char_group_passed;
1634 pc += 1;
1635 continue;
1638 if (char_group_end == 0)
1639 return false;
1640 pc += 1;
1641 continue;
1642 case RxOp.CategoryUnicodeReverse:
1643 if (strpos > 0) {
1644 char c = str [strpos - 1];
1645 if (((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1646 strpos --;
1647 if (char_group_end != 0)
1648 goto test_char_group_passed;
1649 pc += 2;
1650 continue;
1653 if (char_group_end == 0)
1654 return false;
1655 pc += 2;
1656 continue;
1657 case RxOp.CategoryGeneralReverse:
1658 if (strpos > 0) {
1659 char c = str [strpos - 1];
1660 if (((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1661 strpos --;
1662 if (char_group_end != 0)
1663 goto test_char_group_passed;
1664 pc += 2;
1665 continue;
1668 if (char_group_end == 0)
1669 return false;
1670 pc += 2;
1671 continue;
1672 case RxOp.BitmapReverse:
1673 if (strpos > 0) {
1674 char c = str [strpos - 1];
1675 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1676 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1677 strpos --;
1678 if (char_group_end != 0)
1679 goto test_char_group_passed;
1680 pc += 3 + program [pc + 2];
1681 continue;
1684 if (char_group_end == 0)
1685 return false;
1686 pc += 3 + program [pc + 2];
1687 continue;
1688 case RxOp.UnicodeBitmapReverse:
1689 if (strpos > 0) {
1690 char c = str [strpos - 1];
1691 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1692 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1693 strpos --;
1694 if (char_group_end != 0)
1695 goto test_char_group_passed;
1696 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1697 continue;
1700 if (char_group_end == 0)
1701 return false;
1702 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1703 continue;
1704 case RxOp.CharIgnoreCaseReverse:
1705 if (strpos > 0) {
1706 char c = Char.ToLower (str [strpos - 1]);
1707 if (((c == program [pc + 1]))) {
1708 strpos --;
1709 if (char_group_end != 0)
1710 goto test_char_group_passed;
1711 pc += 2;
1712 continue;
1715 if (char_group_end == 0)
1716 return false;
1717 pc += 2;
1718 continue;
1719 case RxOp.RangeIgnoreCaseReverse:
1720 if (strpos > 0) {
1721 char c = Char.ToLower (str [strpos - 1]);
1722 if (((c >= program [pc + 1] && c <= program [pc + 2]))) {
1723 strpos --;
1724 if (char_group_end != 0)
1725 goto test_char_group_passed;
1726 pc += 3;
1727 continue;
1730 if (char_group_end == 0)
1731 return false;
1732 pc += 3;
1733 continue;
1734 case RxOp.UnicodeRangeIgnoreCaseReverse:
1735 if (strpos > 0) {
1736 char c = Char.ToLower (str [strpos - 1]);
1737 if (((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1738 strpos --;
1739 if (char_group_end != 0)
1740 goto test_char_group_passed;
1741 pc += 5;
1742 continue;
1745 if (char_group_end == 0)
1746 return false;
1747 pc += 5;
1748 continue;
1749 case RxOp.UnicodeCharIgnoreCaseReverse:
1750 if (strpos > 0) {
1751 char c = Char.ToLower (str [strpos - 1]);
1752 if (((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1753 strpos --;
1754 if (char_group_end != 0)
1755 goto test_char_group_passed;
1756 pc += 3;
1757 continue;
1760 if (char_group_end == 0)
1761 return false;
1762 pc += 3;
1763 continue;
1764 case RxOp.BitmapIgnoreCaseReverse:
1765 if (strpos > 0) {
1766 char c = Char.ToLower (str [strpos - 1]);
1767 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1768 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1769 strpos --;
1770 if (char_group_end != 0)
1771 goto test_char_group_passed;
1772 pc += 3 + program [pc + 2];
1773 continue;
1776 if (char_group_end == 0)
1777 return false;
1778 pc += 3 + program [pc + 2];
1779 continue;
1780 case RxOp.UnicodeBitmapIgnoreCaseReverse:
1781 if (strpos > 0) {
1782 char c = Char.ToLower (str [strpos - 1]);
1783 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
1784 if (((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1785 strpos --;
1786 if (char_group_end != 0)
1787 goto test_char_group_passed;
1788 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1789 continue;
1792 if (char_group_end == 0)
1793 return false;
1794 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
1795 continue;
1796 case RxOp.NoCharReverse:
1797 if (strpos > 0) {
1798 char c = str [strpos - 1];
1799 if (!((c == program [pc + 1]))) {
1800 pc += 2;
1801 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1802 strpos --;
1803 if (pc + 1 == char_group_end)
1804 goto test_char_group_passed;
1806 continue;
1809 return false;
1810 case RxOp.NoRangeReverse:
1811 if (strpos > 0) {
1812 char c = str [strpos - 1];
1813 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
1814 pc += 3;
1815 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1816 strpos --;
1817 if (pc + 1 == char_group_end)
1818 goto test_char_group_passed;
1820 continue;
1823 return false;
1824 case RxOp.NoUnicodeRangeReverse:
1825 if (strpos > 0) {
1826 char c = str [strpos - 1];
1827 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
1828 pc += 5;
1829 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1830 strpos --;
1831 if (pc + 1 == char_group_end)
1832 goto test_char_group_passed;
1834 continue;
1837 return false;
1838 case RxOp.NoUnicodeCharReverse:
1839 if (strpos > 0) {
1840 char c = str [strpos - 1];
1841 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
1842 pc += 3;
1843 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1844 strpos --;
1845 if (pc + 1 == char_group_end)
1846 goto test_char_group_passed;
1848 continue;
1851 return false;
1852 case RxOp.NoCategoryAnyReverse:
1853 if (strpos > 0) {
1854 char c = str [strpos - 1];
1855 if (!((c != '\n'))) {
1856 pc += 1;
1857 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1858 strpos --;
1859 if (pc + 1 == char_group_end)
1860 goto test_char_group_passed;
1862 continue;
1865 return false;
1866 case RxOp.NoCategoryAnySinglelineReverse:
1867 if (strpos > 0) {
1868 char c = str [strpos - 1];
1869 if (!(true)) {
1870 pc += 1;
1871 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1872 strpos --;
1873 if (pc + 1 == char_group_end)
1874 goto test_char_group_passed;
1876 continue;
1879 return false;
1880 case RxOp.NoCategoryWordReverse:
1881 if (strpos > 0) {
1882 char c = str [strpos - 1];
1883 if (!((Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation))) {
1884 pc += 1;
1885 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1886 strpos --;
1887 if (pc + 1 == char_group_end)
1888 goto test_char_group_passed;
1890 continue;
1893 return false;
1894 case RxOp.NoCategoryDigitReverse:
1895 if (strpos > 0) {
1896 char c = str [strpos - 1];
1897 if (!((Char.IsDigit (c)))) {
1898 pc += 1;
1899 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1900 strpos --;
1901 if (pc + 1 == char_group_end)
1902 goto test_char_group_passed;
1904 continue;
1907 return false;
1908 case RxOp.NoCategoryWhiteSpaceReverse:
1909 if (strpos > 0) {
1910 char c = str [strpos - 1];
1911 if (!((Char.IsWhiteSpace (c)))) {
1912 pc += 1;
1913 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1914 strpos --;
1915 if (pc + 1 == char_group_end)
1916 goto test_char_group_passed;
1918 continue;
1921 return false;
1922 case RxOp.NoCategoryEcmaWordReverse:
1923 if (strpos > 0) {
1924 char c = str [strpos - 1];
1925 if (!(('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_'))) {
1926 pc += 1;
1927 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1928 strpos --;
1929 if (pc + 1 == char_group_end)
1930 goto test_char_group_passed;
1932 continue;
1935 return false;
1936 case RxOp.NoCategoryEcmaWhiteSpaceReverse:
1937 if (strpos > 0) {
1938 char c = str [strpos - 1];
1939 if (!((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'))) {
1940 pc += 1;
1941 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1942 strpos --;
1943 if (pc + 1 == char_group_end)
1944 goto test_char_group_passed;
1946 continue;
1949 return false;
1950 case RxOp.NoCategoryUnicodeSpecialsReverse:
1951 if (strpos > 0) {
1952 char c = str [strpos - 1];
1953 if (!(('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD'))) {
1954 pc += 1;
1955 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1956 strpos --;
1957 if (pc + 1 == char_group_end)
1958 goto test_char_group_passed;
1960 continue;
1963 return false;
1964 case RxOp.NoCategoryUnicodeReverse:
1965 if (strpos > 0) {
1966 char c = str [strpos - 1];
1967 if (!((Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]))) {
1968 pc += 2;
1969 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1970 strpos --;
1971 if (pc + 1 == char_group_end)
1972 goto test_char_group_passed;
1974 continue;
1977 return false;
1978 case RxOp.NoCategoryGeneralReverse:
1979 if (strpos > 0) {
1980 char c = str [strpos - 1];
1981 if (!((CategoryUtils.IsCategory ((Category)program [pc + 1], c)))) {
1982 pc += 2;
1983 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1984 strpos --;
1985 if (pc + 1 == char_group_end)
1986 goto test_char_group_passed;
1988 continue;
1991 return false;
1992 case RxOp.NoBitmapReverse:
1993 if (strpos > 0) {
1994 char c = str [strpos - 1];
1995 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
1996 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
1997 pc += 3 + program [pc + 2];
1998 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
1999 strpos --;
2000 if (pc + 1 == char_group_end)
2001 goto test_char_group_passed;
2003 continue;
2006 return false;
2007 case RxOp.NoUnicodeBitmapReverse:
2008 if (strpos > 0) {
2009 char c = str [strpos - 1];
2010 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
2011 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2012 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
2013 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2014 strpos --;
2015 if (pc + 1 == char_group_end)
2016 goto test_char_group_passed;
2018 continue;
2021 return false;
2022 case RxOp.NoCharIgnoreCaseReverse:
2023 if (strpos > 0) {
2024 char c = Char.ToLower (str [strpos - 1]);
2025 if (!((c == program [pc + 1]))) {
2026 pc += 2;
2027 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2028 strpos --;
2029 if (pc + 1 == char_group_end)
2030 goto test_char_group_passed;
2032 continue;
2035 return false;
2036 case RxOp.NoRangeIgnoreCaseReverse:
2037 if (strpos > 0) {
2038 char c = Char.ToLower (str [strpos - 1]);
2039 if (!((c >= program [pc + 1] && c <= program [pc + 2]))) {
2040 pc += 3;
2041 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2042 strpos --;
2043 if (pc + 1 == char_group_end)
2044 goto test_char_group_passed;
2046 continue;
2049 return false;
2050 case RxOp.NoUnicodeRangeIgnoreCaseReverse:
2051 if (strpos > 0) {
2052 char c = Char.ToLower (str [strpos - 1]);
2053 if (!((c >= (program [pc + 1] | ((int)program [pc + 2] << 8))) && (c <= (program [pc + 3] | ((int)program [pc + 4] << 8))))) {
2054 pc += 5;
2055 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2056 strpos --;
2057 if (pc + 1 == char_group_end)
2058 goto test_char_group_passed;
2060 continue;
2063 return false;
2064 case RxOp.NoUnicodeCharIgnoreCaseReverse:
2065 if (strpos > 0) {
2066 char c = Char.ToLower (str [strpos - 1]);
2067 if (!((c == (program [pc + 1] | ((int)program [pc + 2] << 8))))) {
2068 pc += 3;
2069 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2070 strpos --;
2071 if (pc + 1 == char_group_end)
2072 goto test_char_group_passed;
2074 continue;
2077 return false;
2078 case RxOp.NoBitmapIgnoreCaseReverse:
2079 if (strpos > 0) {
2080 char c = Char.ToLower (str [strpos - 1]);
2081 int c2 = (int)c; c2 -= program [pc + 1]; length = program [pc + 2];
2082 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 3 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2083 pc += 3 + program [pc + 2];
2084 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2085 strpos --;
2086 if (pc + 1 == char_group_end)
2087 goto test_char_group_passed;
2089 continue;
2092 return false;
2093 case RxOp.NoUnicodeBitmapIgnoreCaseReverse:
2094 if (strpos > 0) {
2095 char c = Char.ToLower (str [strpos - 1]);
2096 int c2 = (int)c; c2 -= (program [pc + 1] | ((int)program [pc + 2] << 8)); length = (program [pc + 3] | ((int)program [pc + 4] << 8));
2097 if (!((c2 >= 0 && c2 < (length << 3) && (program [pc + 5 + (c2 >> 3)] & (1 << (c2 & 0x7))) != 0))) {
2098 pc += 5 + (program [pc + 3] | ((int)program [pc + 4] << 8));
2099 if (char_group_end == 0 || (pc + 1 == char_group_end)) {
2100 strpos --;
2101 if (pc + 1 == char_group_end)
2102 goto test_char_group_passed;
2104 continue;
2107 return false;
2109 // END OF GENERATED CODE
2111 case RxOp.Branch: {
2112 int res = 0;
2113 if (EvalByteCode (pc + 3, strpos, ref res)) {
2114 strpos_result = res;
2115 return true;
2117 //Console.WriteLine ("branch offset: {0}", program [pc + 1] | ((int)program [pc + 2] << 8));
2118 pc += program [pc + 1] | ((int)program [pc + 2] << 8);
2119 continue;
2121 case RxOp.Repeat:
2122 case RxOp.RepeatLazy: {
2124 * Repetation is modelled by two opcodes: Repeat and Until which
2125 * contain the the qualified regex between them, i.e.:
2126 * Repeat, <bytecode for the inner regex>, Until, <Tail expr>
2127 * It is processed as follows:
2128 * Repeat, [Until, <inner expr>]*, <Tail>
2129 * This means that nested quantifiers are processed a bit
2130 * strangely: when the inner quantifier fails to match, its
2131 * tail is processed which includes the outer Until.
2133 * This code is from the old interpreter.cs.
2135 * FIXME: Rethink this.
2138 int res = 0;
2140 this.repeat = new RepeatContext (
2141 this.repeat, // previous context
2142 ReadInt (program, pc + 3), // minimum
2143 ReadInt (program, pc + 7), // maximum
2144 (RxOp)program [pc] == RxOp.RepeatLazy, // lazy
2145 pc + 11 // subexpression
2148 int until = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
2149 if (!EvalByteCode (until, strpos, ref res)) {
2150 this.repeat = this.repeat.Previous;
2151 return false;
2154 strpos = res;
2155 strpos_result = strpos;
2156 return true;
2158 case RxOp.Until: {
2159 RepeatContext current = this.repeat;
2160 int res = 0;
2163 // Can we avoid recursion?
2165 // Backtracking can be forced in nested quantifiers from the tail of this quantifier.
2166 // Thus, we cannot, in general, use a simple loop on repeat.Expression to handle
2167 // quantifiers.
2169 // If 'deep' was unmolested, that implies that there was no nested quantifiers.
2170 // Thus, we can safely avoid recursion.
2172 if (deep == current)
2173 goto Pass;
2175 start = current.Start;
2176 int start_count = current.Count;
2178 // First match at least 'start' items without backtracking
2179 while (!current.IsMinimum) {
2180 ++ current.Count;
2181 current.Start = strpos;
2182 deep = current;
2183 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2184 current.Start = start;
2185 current.Count = start_count;
2186 goto Fail;
2188 strpos = res;
2189 if (deep != current) // recursive mode
2190 goto Pass;
2193 if (strpos == current.Start) {
2194 // degenerate match ... match tail or fail
2195 this.repeat = current.Previous;
2196 deep = null;
2197 if (EvalByteCode (pc + 1, strpos, ref res)) {
2198 strpos = res;
2199 goto Pass;
2201 this.repeat = current;
2202 goto Fail;
2205 if (current.IsLazy) {
2206 for (;;) {
2207 // match tail first ...
2208 this.repeat = current.Previous;
2209 deep = null;
2210 int cp = Checkpoint ();
2211 if (EvalByteCode (pc + 1, strpos, ref res)) {
2212 strpos = res;
2213 goto Pass;
2216 Backtrack (cp);
2218 // ... then match more
2219 this.repeat = current;
2220 if (current.IsMaximum)
2221 goto Fail;
2222 ++ current.Count;
2223 current.Start = strpos;
2224 deep = current;
2225 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2226 current.Start = start;
2227 current.Count = start_count;
2228 goto Fail;
2230 strpos = res;
2231 if (deep != current) // recursive mode
2232 goto Pass;
2233 // Degenerate match: ptr has not moved since the last (failed) tail match.
2234 // So, next and subsequent tail matches will fail.
2235 if (strpos == current.Start)
2236 goto Fail;
2238 } else {
2239 int stack_size = stack.Count;
2241 // match greedily as much as possible
2242 while (!current.IsMaximum) {
2243 int cp = Checkpoint ();
2244 int old_ptr = strpos;
2245 int old_start = current.Start;
2247 ++ current.Count;
2248 if (trace_rx)
2249 Console.WriteLine ("recurse with count {0}.", current.Count);
2250 current.Start = strpos;
2251 deep = current;
2252 if (!EvalByteCode (current.Expression, strpos, ref res)) {
2253 -- current.Count;
2254 current.Start = old_start;
2255 Backtrack (cp);
2256 break;
2258 strpos = res;
2259 if (deep != current) {
2260 // recursive mode: no more backtracking, truncate the stack
2261 stack.Count = stack_size;
2262 goto Pass;
2264 stack.Push (cp);
2265 stack.Push (old_ptr);
2267 // Degenerate match: no point going on
2268 if (strpos == current.Start)
2269 break;
2272 if (trace_rx)
2273 Console.WriteLine ("matching tail: {0} pc={1}", strpos, pc + 1);
2274 // then, match the tail, backtracking as necessary.
2275 this.repeat = current.Previous;
2276 for (;;) {
2277 deep = null;
2278 if (EvalByteCode (pc + 1, strpos, ref res)) {
2279 strpos = res;
2280 stack.Count = stack_size;
2281 goto Pass;
2283 if (stack.Count == stack_size) {
2284 this.repeat = current;
2285 goto Fail;
2288 --current.Count;
2289 strpos = stack.Pop ();
2290 Backtrack (stack.Pop ());
2291 if (trace_rx)
2292 Console.WriteLine ("backtracking to {0} expr={1} pc={2}", strpos, current.Expression, pc);
2297 case RxOp.FastRepeat:
2298 case RxOp.FastRepeatLazy: {
2300 * A FastRepeat is a simplified version of Repeat which does
2301 * not contain another repeat inside, so backtracking is
2302 * easier.
2304 bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
2305 int res = 0;
2306 int tail = pc + (program [pc + 1] | ((int)program [pc + 2] << 8));
2307 start = ReadInt (program, pc + 3);
2308 end = ReadInt (program, pc + 7);
2309 //Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);
2310 length = 0;
2312 deep = null;
2314 // First match at least 'start' items
2315 while (length < start) {
2316 if (!EvalByteCode (pc + 11, strpos, ref res))
2317 return false;
2318 strpos = res;
2319 length++;
2322 if (lazy) {
2323 while (true) {
2324 // Match the tail
2325 int cp = Checkpoint ();
2326 if (EvalByteCode (tail, strpos, ref res)) {
2327 strpos = res;
2328 goto repeat_success;
2330 Backtrack (cp);
2332 if (length >= end)
2333 return false;
2335 // Match an item
2336 if (!EvalByteCode (pc + 11, strpos, ref res))
2337 return false;
2338 strpos = res;
2339 length ++;
2341 } else {
2342 // Then match as many items as possible, recording
2343 // backtracking information
2344 int old_stack_size = stack.Count;
2345 while (length < end) {
2346 int cp = Checkpoint ();
2347 if (!EvalByteCode (pc + 11, strpos, ref res)) {
2348 Backtrack (cp);
2349 break;
2351 stack.Push (cp);
2352 stack.Push (strpos);
2353 strpos = res;
2354 length++;
2357 if (tail <= pc)
2358 throw new Exception ();
2360 // Then, match the tail, backtracking as necessary.
2361 while (true) {
2362 if (EvalByteCode (tail, strpos, ref res)) {
2363 strpos = res;
2364 stack.Count = old_stack_size;
2365 goto repeat_success;
2367 if (stack.Count == old_stack_size)
2368 return false;
2370 // Backtrack
2371 strpos = stack.Pop ();
2372 Backtrack (stack.Pop ());
2373 if (trace_rx)
2374 Console.WriteLine ("backtracking to: {0}", strpos);
2378 repeat_success:
2379 // We matched the tail too so just return
2380 goto Pass;
2383 default:
2384 Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", (RxOp)program [pc], pc, strpos);
2385 throw new NotSupportedException ();
2387 continue;
2389 Pass:
2390 strpos_result = strpos;
2391 return true;
2392 Fail:
2393 return false;
2394 test_char_group_passed:
2395 pc = char_group_end;
2396 char_group_end = 0;
2397 continue;
2398 } // end of while (true)