System.Text.RegularExpressions.CILCompiler.EmitEvalMethodBody C# (CSharp) Method

EmitEvalMethodBody() private method

private EmitEvalMethodBody ( DynamicMethod m, ILGenerator ilgen, Frame frame, byte program, int pc, int end_pc, bool one_op, bool no_bump, int &out_pc ) : DynamicMethod
m System.Reflection.Emit.DynamicMethod
ilgen System.Reflection.Emit.ILGenerator
frame Frame
program byte
pc int
end_pc int
one_op bool
no_bump bool
out_pc int
return System.Reflection.Emit.DynamicMethod
		private DynamicMethod EmitEvalMethodBody (DynamicMethod m, ILGenerator ilgen,
												  Frame frame, byte[] program,
												  int pc, int end_pc,
 												  bool one_op, bool no_bump,
												  out int out_pc)
		{
			int start, length, end;

			out_pc = 0;

			int group_count = 1 + ReadShort (program, 1);

			while (pc < end_pc) {
				RxOp op = (RxOp)program [pc];

				// FIXME: Optimize this
				if (generic_ops.ContainsKey (pc))
					op = (RxOp)generic_ops [pc];

				if (trace_compile) {
					Console.WriteLine ("compiling {0} pc={1} end_pc={2}, il_offset=0x{3:x}", op, pc, end_pc, GetILOffset (ilgen));
				}

				if (labels != null) {
					Label l;
					if (labels.TryGetValue (pc, out l)) {
						ilgen.MarkLabel (l);
						labels.Remove (pc);
					}
				}

				if (RxInterpreter.trace_rx) {
					//Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", op, pc, strpos);
					ilgen.Emit (OpCodes.Ldstr, "evaluating: {0} at pc: {1}, strpos: {2}");
					ilgen.Emit (OpCodes.Ldc_I4, (int)op);
					ilgen.Emit (OpCodes.Box, typeof (RxOp));
					ilgen.Emit (OpCodes.Ldc_I4, pc);
					ilgen.Emit (OpCodes.Box, typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Box, typeof (int));
					ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object), typeof (object), typeof (object) }));
				}

				switch (op) {
				case RxOp.Anchor:
				case RxOp.AnchorReverse: {
					bool reverse = (RxOp)program [pc] == RxOp.AnchorReverse;
					length = ReadShort (program, pc + 3);
					pc += ReadShort (program, pc + 1);

					// Optimize some common cases by inlining the code generated for the
					// anchor body 
					RxOp anch_op = (RxOp)program [pc];

					// FIXME: Do this even if the archor op is not the last in the regex
					if (!reverse && group_count == 1 && anch_op == RxOp.Char && (RxOp)program [pc + 2] == RxOp.True) {

						/*
						 * while (strpos < string_end) {
						 *   if (str [strpos] == program [pc + 1]) {
						 *     match_start = strpos;
						 *     strpos_result = strpos + 1;
						 *     marks [groups [0]].Start = strpos;
						 *     if (groups.Length > 1)
						 *		marks [groups [0]].End = res;
						 *     return true;
						 *   }
						 *   strpos ++;
						 * }
						 * return false;
						 */
						// Add some locals to avoid an indirection
						LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Stloc, local_string_end);
						LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_str);
						ilgen.Emit (OpCodes.Stloc, local_str);

						//while (strpos < string_end) {
						// -> Done at the end of the loop like mcs does
						Label l1 = ilgen.DefineLabel ();
						Label l2 = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l2);
						ilgen.MarkLabel (l1);

						//  if (str [strpos] == program [pc + 1]) {
						Label l3 = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Ldloc, local_str);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
						ilgen.Emit (OpCodes.Conv_I4);
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (OpCodes.Beq, l3);

						// The true case is done after the loop

						//  }
						//  strpos++;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
						//}
						ilgen.MarkLabel (l2);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, local_string_end);
						ilgen.Emit (OpCodes.Blt, l1);

						//return false;
						ilgen.Emit (OpCodes.Br, frame.label_fail);

						// True case
						ilgen.MarkLabel (l3);
						// call SetStartOfMatch (strpos)
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "SetStartOfMatch", ref mi_set_start_of_match));
						//  strpos++;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
						//    return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

					} else {
						// General case

						//Console.WriteLine ("Anchor op " + anch_op);

						// Add some locals to avoid an indirection
						LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_string_end);

						//while (strpos < string_end + 1) {
						// -> Done at the end of the loop like mcs does
						Label l1 = ilgen.DefineLabel ();
						Label l2 = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l2);
						ilgen.MarkLabel (l1);

						//if (groups.Length > 1) {
						//	ResetGroups ();
						//	marks [groups [0]].Start = strpos;
						//}
						if (group_count > 1) {
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Call, GetMethod ("ResetGroups", ref mi_reset_groups));

							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_marks);
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_groups);
							ilgen.Emit (OpCodes.Ldc_I4_0);
							ilgen.Emit (OpCodes.Ldelem_I4);
							ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Stfld, fi_mark_start);
						}

						//  if (EvalByteCode (pc, strpos, ref res)) {

						Frame new_frame = new Frame (ilgen);

						//  old_stros = strpos;
						LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);

						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, end_pc, false, false, out out_pc);
						if (m == null)
							return null;

						// Pass
						ilgen.MarkLabel (new_frame.label_pass);
						//    marks [groups [0]].Start = old_strpos;
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_marks);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_groups);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ldelem_I4);
						ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Stfld, fi_mark_start);
						//    if (groups.Length > 1)
						//		marks [groups [0]].End = res;
						if (group_count > 1) {
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_marks);
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_groups);
							ilgen.Emit (OpCodes.Ldc_I4_0);
							ilgen.Emit (OpCodes.Ldelem_I4);
							ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Stfld, fi_mark_end);
						}

						//    return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

						// Fail
						ilgen.MarkLabel (new_frame.label_fail);
						//  strpos = old_strpos +/- 1;
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
						//}
						ilgen.MarkLabel (l2);
						if (reverse) {
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Ldc_I4_0);
							ilgen.Emit (OpCodes.Bge, l1);
						} else {
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Ldloc, local_string_end);
							ilgen.Emit (OpCodes.Blt, l1);
						}
						//return false;
						ilgen.Emit (OpCodes.Br, frame.label_fail);
					}

					goto End;
				}
				case RxOp.Branch: {
					//if (EvalByteCode (pc + 3, strpos, ref res)) {

					int target_pc = pc + ReadShort (program, pc + 1);

					// Emit the rest of the code inline instead of making a recursive call
					Frame new_frame = new Frame (ilgen);

					//  old_strpos = strpos;
					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Stloc, local_old_strpos);

					m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target_pc, false, false, out out_pc);
					if (m == null)
						return null;

					// Pass
					ilgen.MarkLabel (new_frame.label_pass);
					//  return true;
					ilgen.Emit (OpCodes.Br, frame.label_pass);

					// Fail
					ilgen.MarkLabel (new_frame.label_fail);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);

					pc = target_pc;
					break;
				}
				case RxOp.Char:
				case RxOp.UnicodeChar:
				case RxOp.Range:
				case RxOp.UnicodeRange: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool negate = (flags & OpFlags.Negate) > 0;
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					//if (strpos < string_end) {
					Label l1 = ilgen.DefineLabel ();
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ble, l1);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bge, l1);
					}

					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);

					//  int c = str [strpos];
					LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					if (reverse) {
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Sub);
					}
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));

					if (op == RxOp.Char) {
						ilgen.Emit (OpCodes.Conv_I4);
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);

						pc += 2;
					} else if (op == RxOp.UnicodeChar) {
						ilgen.Emit (OpCodes.Conv_I4);
						ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
						ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);

						pc += 3;
					} else if (op == RxOp.Range) {
						ilgen.Emit (OpCodes.Stloc, local_c);

						//  if (c >= program [pc + 1] && c <= program [pc + 2]) {
						if (negate) {
							Label l3 = ilgen.DefineLabel ();

							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
							ilgen.Emit (OpCodes.Blt, l3);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
							ilgen.Emit (OpCodes.Bgt, l3);
							ilgen.Emit (OpCodes.Br, l1);
							ilgen.MarkLabel (l3);
						} else {
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
							ilgen.Emit (OpCodes.Blt, l1);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
							ilgen.Emit (OpCodes.Bgt, l1);
						}

						pc += 3;
					} else if (op == RxOp.UnicodeRange) {
						ilgen.Emit (OpCodes.Stloc, local_c);

						//  if (c >= program [pc + 1] && c <= program [pc + 2]) {
						if (negate) {
							Label l3 = ilgen.DefineLabel ();

							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
							ilgen.Emit (OpCodes.Blt, l3);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
							ilgen.Emit (OpCodes.Bgt, l3);
							ilgen.Emit (OpCodes.Br, l1);
							ilgen.MarkLabel (l3);
						} else {
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
							ilgen.Emit (OpCodes.Blt, l1);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
							ilgen.Emit (OpCodes.Bgt, l1);
						}

						pc += 5;
					} else {
						throw new NotSupportedException ();
					}

					//ilgen.EmitWriteLine ("HIT:" + (char)program [pc + 1]);
					if (!no_bump) {
						//  strpos++ / strpos--;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
					}
					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Br, l2);
					//}
					ilgen.MarkLabel (l1);
					//return false;
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l2);

					break;
				}
				case RxOp.True: {
					//  return true;
					ilgen.Emit (OpCodes.Br, frame.label_pass);
					pc++;
					break;
				}
				case RxOp.False: {
					//  return false;
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.AnyPosition: {
					pc++;
					break;
				}
				case RxOp.StartOfString: {
					//if (strpos != 0)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Bgt, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.StartOfLine: {
					// FIXME: windows line endings
					//if (!(strpos == 0 || str [strpos - 1] == '\n'))
					//	return false;
					Label l = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Beq, l);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
					ilgen.Emit (OpCodes.Beq, l);
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l);

					pc++;
					break;
				}
				case RxOp.StartOfScan: {
					//if (strpos != string_start)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_start);
					ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.End: {
					//if (!(strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')))
					//	return false;
					Label l = ilgen.DefineLabel ();

					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Beq, l);

					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Bne_Un, l2);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
					ilgen.Emit (OpCodes.Bne_Un, l2);
					ilgen.Emit (OpCodes.Br, l);
					ilgen.MarkLabel (l2);

					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l);

					pc++;
					break;
				}
				case RxOp.EndOfString: {
					//if (strpos != string_end)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.EndOfLine: {
					//if (!(strpos == string_end || str [strpos] == '\n'))
					//	return false;
					Label l_match = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Beq, l_match);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
					ilgen.Emit (OpCodes.Beq, l_match);
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l_match);
					
					pc++;
					break;
				}
				case RxOp.WordBoundary:
				case RxOp.NoWordBoundary: {
					bool negate = op == RxOp.NoWordBoundary;

					//if (string_end == 0)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Beq, frame.label_fail);

					Label l_match = ilgen.DefineLabel ();

					//if (strpos == 0) {
					Label l1 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Bne_Un, l1);
					//if (!IsWordChar (str [strpos])) {
					//  return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
					ilgen.Emit (OpCodes.Br, l_match);

					//} else if (strpos == string_end) {
					ilgen.MarkLabel (l1);
					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Bne_Un, l2);
					//if (!IsWordChar (str [strpos - 1])) {
					//  return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
					ilgen.Emit (OpCodes.Br, l_match);

					//} else {
					ilgen.MarkLabel (l2);
					//if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
					//  return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, frame.label_fail);
					ilgen.Emit (OpCodes.Br, l_match);

					ilgen.MarkLabel (l_match);

					pc++;
					break;
				}
				case RxOp.Bitmap:
				case RxOp.UnicodeBitmap: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool negate = (flags & OpFlags.Negate) > 0;
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;
					bool unicode = (op == RxOp.UnicodeBitmap);

					//if (strpos < string_end) {
					Label l1 = ilgen.DefineLabel ();
					Label l2 = ilgen.DefineLabel ();
					Label l_match = ilgen.DefineLabel ();
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ble, l1);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bge, l1);
					}
					//  int c = str [strpos];
					LocalBuilder local_c = ilgen.DeclareLocal (typeof (int));
					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					if (reverse) {
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Sub);
					}
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Conv_I4);
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
					//  c -= program [pc + 1];
					if (unicode) {
						ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Stloc, local_c);
						length = ReadShort (program, pc + 3);
						pc += 5;
					} else {
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Stloc, local_c);
						length =  program [pc + 2];
						pc += 3;
					}
					//  if (c < 0 || c >= (length << 3))
					//    return false;
					ilgen.Emit (OpCodes.Ldloc, local_c);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Blt, negate ? l_match : frame.label_fail);
					ilgen.Emit (OpCodes.Ldloc, local_c);
					ilgen.Emit (OpCodes.Ldc_I4, length << 3);
					ilgen.Emit (OpCodes.Bge, negate ? l_match : frame.label_fail);

					// Optimized version for small bitmaps
					if (length <= 4) {
						uint bitmap = program [pc];
						
						if (length > 1)
							bitmap |= ((uint)program [pc + 1] << 8);
						if (length > 2)
							bitmap |= ((uint)program [pc + 2] << 16);
						if (length > 3)
							bitmap |= ((uint)program [pc + 3] << 24);

						//if ((bitmap >> c) & 1)
						ilgen.Emit (OpCodes.Ldc_I4, bitmap);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Shr_Un);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, l1);
					} else {
						//  if ((program [pc + (c >> 3)] & (1 << (c & 0x7))) != 0) {
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_program);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4_3);
						ilgen.Emit (OpCodes.Shr);
						ilgen.Emit (OpCodes.Ldc_I4, pc);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldelem_I1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, 7);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Shl);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, l1);
					}
					ilgen.MarkLabel (l_match);
					if (!no_bump) {
						//  strpos++ / strpos--;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
					}
					//    continue;
					ilgen.Emit (OpCodes.Br, l2);
					//  }
					//}
					//return false;
					ilgen.MarkLabel (l1);
					ilgen.Emit (OpCodes.Br, frame.label_fail);

					ilgen.MarkLabel (l2);

					pc += length;
					break;
				}
				case RxOp.String:
				case RxOp.UnicodeString: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;
					bool unicode = (op == RxOp.UnicodeString);

					if (unicode) {
						start = pc + 3;
						length = ReadShort (program, pc + 1);
					} else {
						start = pc + 2;
						length = program [pc + 1];
					}
					//if (strpos + length > string_end)
					//	return false;
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Blt, frame.label_fail);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bgt, frame.label_fail);
					}

					/* Avoid unsafe code in Moonlight build */
#if false && !NET_2_1
					// FIXME:
					if (reverse || unicode)
						throw new NotImplementedException ();
					int i;
					LocalBuilder local_strptr = ilgen.DeclareLocal (typeof (char).MakePointerType ());
					// char *strptr = &str.start_char + strpos
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldflda, typeof (String).GetField ("start_char", BindingFlags.Instance|BindingFlags.NonPublic));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Shl);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Stloc, local_strptr);

					end = start + length;
					for (i = 0; i < length; ++i) {
						// if (*(strptr + i) != program [start + i])
						//   return false;
						if (ignore)
							ilgen.Emit (OpCodes.Ldloc, local_textinfo);
						ilgen.Emit (OpCodes.Ldloc, local_strptr);
						ilgen.Emit (OpCodes.Ldc_I4, i * 2);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldind_I2);
						if (ignore)
							ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [start + i]);
						ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					}

					// strpos += length
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4, length);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Starg, 1);

#else
					// Allocate a local for 'str' to save an indirection
					LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Stloc, local_str);

					if (reverse) {
						// strpos -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
					}

					// FIXME: Emit a loop for long strings
					end = start + (unicode ? length * 2 : length);
					while (start < end) {
						//if (str [strpos] != program [start])
						//	return false;
						if (ignore)
							ilgen.Emit (OpCodes.Ldloc, local_textinfo);
						ilgen.Emit (OpCodes.Ldloc, local_str);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
						if (ignore)
							ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, unicode ? ReadShort (program, start) : (int)program [start]);
						ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
						//strpos++;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);

						if (unicode)
							start += 2;
						else
							start ++;
					}

					if (reverse) {
						// strpos -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
					}
#endif

					pc = end;
					break;
				}
				case RxOp.OpenGroup: {
					//Open (program [pc + 1] | (program [pc + 2] << 8), strpos);
					int group_id = ReadShort (program, pc + 1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldc_I4, group_id);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Call, GetMethod ("Open", ref mi_open));

					pc += 3;
					break;
				}
				case RxOp.CloseGroup: {
					//Close (program [pc + 1] | (program [pc + 2] << 8), strpos);
					int group_id = ReadShort (program, pc + 1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldc_I4, group_id);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Call, GetMethod ("Close", ref mi_close));

					pc += 3;
					break;
				}
				case RxOp.Jump: {
					int target_pc = pc + ReadShort (program, pc + 1);
					if (target_pc > end_pc)
						/* 
						 * This breaks the our code generation logic, see
						 * https://bugzilla.novell.com/show_bug.cgi?id=466151
						 * for an example.
						 */
						return null;
					if (trace_compile)
						Console.WriteLine ("\tjump target: {0}", target_pc);
					if (labels == null)
						labels = new Dictionary <int, Label> ();
					Label l = CreateLabelForPC (ilgen, target_pc);
					ilgen.Emit (OpCodes.Br, l);
					pc += 3;
 					break;
				}
				case RxOp.Test: {
					int target1 = pc + ReadShort (program, pc + 1);
					int target2 = pc + ReadShort (program, pc + 3);

					if (trace_compile)
						Console.WriteLine ("\temitting <test_expr>");

					//  old_stros = strpos;
					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Stloc, local_old_strpos);

					Frame new_frame = new Frame (ilgen);
					m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 5, target1 < target2 ? target1 : target2, false, false, out pc);
					if (m == null)
						return null;						

					if (trace_compile) {
						Console.WriteLine ("\temitted <test_expr>");
						Console.WriteLine ("\ttarget1 = {0}", target1);
						Console.WriteLine ("\ttarget2 = {0}", target2);
					}

					Label l1 = CreateLabelForPC (ilgen, target1);
					Label l2 = CreateLabelForPC (ilgen, target2);

					// Pass
					ilgen.MarkLabel (new_frame.label_pass);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);
					ilgen.Emit (OpCodes.Br, l1);
						
					// Fail
					ilgen.MarkLabel (new_frame.label_fail);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);
					ilgen.Emit (OpCodes.Br, l2);

					// Continue at pc, which should equal to target1
					break;
				}
				case RxOp.SubExpression: {
					int target = pc + ReadShort (program, pc + 1);

					if (trace_compile)
						Console.WriteLine ("\temitting <sub_expr>");

					//  old_stros = strpos;
					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Stloc, local_old_strpos);

					Frame new_frame = new Frame (ilgen);
					m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target, false, false, out pc);
					if (m == null)
						return null;						

					if (trace_compile) {
						Console.WriteLine ("\temitted <sub_expr>");
						Console.WriteLine ("\ttarget = {0}", target);
					}

					Label l1 = CreateLabelForPC (ilgen, target);

					// Pass
					ilgen.MarkLabel (new_frame.label_pass);
					ilgen.Emit (OpCodes.Br, l1);
						
					// Fail
					ilgen.MarkLabel (new_frame.label_fail);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);
					ilgen.Emit (OpCodes.Br, frame.label_fail);

					// Continue at pc, which should equal to target
					break;
				}
				case RxOp.TestCharGroup: {
					int char_group_end = pc + ReadShort (program, pc + 1);
					pc += 3;

					Label label_match = ilgen.DefineLabel ();

					/* Determine the negate/reverse flags by examining the first op */
					OpFlags flags = (OpFlags)op_flags [pc];

					/* Determine whenever this is a negated character class */
					/* If it is, then the conditions are ANDed together, not ORed */
					bool revert = (flags & OpFlags.Negate) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					/*
					 * Generate code for all the matching ops in the group
					 */
					while (pc < char_group_end) {
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, Int32.MaxValue, true, true, out pc);
						if (m == null)
							return null;						

						if (!revert) {
							// Pass
							ilgen.MarkLabel (new_frame.label_pass);
							ilgen.Emit (OpCodes.Br, label_match);
						
							// Fail
							// Just fall through to the next test
							ilgen.MarkLabel (new_frame.label_fail);
						} else {
							// Pass
							// Just fall through to the next test
							ilgen.MarkLabel (new_frame.label_pass);
							Label l2 = ilgen.DefineLabel ();
							ilgen.Emit (OpCodes.Br, l2);

							// Fail
							// Fail completely
							ilgen.MarkLabel (new_frame.label_fail);
							ilgen.Emit (OpCodes.Br, frame.label_fail);

							ilgen.MarkLabel (l2);
						}
					}

					if (revert) {
						/* Success */
						ilgen.Emit (OpCodes.Br, label_match);
					} else {
						// If we reached here, all the matching ops have failed
						ilgen.Emit (OpCodes.Br, frame.label_fail);
					}

					ilgen.MarkLabel (label_match);

					//  strpos++ / strpos--;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					if (reverse)
						ilgen.Emit (OpCodes.Sub);
					else
						ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Starg, 1);

					break;
				}
				case RxOp.FastRepeat:
				case RxOp.FastRepeatLazy: {
					/*
					 * A FastRepeat is a simplified version of Repeat which does
					 * not contain another repeat inside, so backtracking is 
					 * easier.
					 * FIXME: Implement faster backtracking versions for
					 * simple inner exceptions like chars/strings.
					 */
					bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
					int tail = pc + ReadShort (program, pc + 1);
 					start = ReadInt (program, pc + 3);
 					end = ReadInt (program, pc + 7);
					//Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);

					//  deep = null;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldnull);
					ilgen.Emit (OpCodes.Stfld, fi_deep);

					LocalBuilder local_length = ilgen.DeclareLocal (typeof (int));

					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Stloc, local_length);

					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					
					// First match at least 'start' items
					if (start > 0) {
						//for (length = 0; length < start; ++length) {
						Label l_loop_footer = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						Label l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);

						// int old_strpos = strpos;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);
						
						// if (!EvalByteCode (pc + 11, strpos, ref res))
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
						if (m == null)
							return null;

						// Fail
						// return false;
						ilgen.MarkLabel (new_frame.label_fail);
						ilgen.Emit (OpCodes.Br, frame.label_fail);

						// Pass
						ilgen.MarkLabel (new_frame.label_pass);
						// length++
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_length);
						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4, start);
						ilgen.Emit (OpCodes.Blt, l_loop_body);
					}

					if (lazy) {
						Label l_loop_footer = ilgen.DefineLabel ();
						//while (true) {
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						Label l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);
						// Match the tail
						//  int cp = Checkpoint ();
						LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
						ilgen.Emit (OpCodes.Stloc, local_cp);

						// int old_strpos = strpos;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);

						//  if (EvalByteCode (tail, strpos, ref res)) {
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
						if (m == null)
							return null;

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);
						//    return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);
						//  Backtrack (cp);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldloc, local_cp);
						ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
						// strpos = old_strpos;
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Starg, 1);

						//if (length >= end)
						//  return false;
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4, end);
						ilgen.Emit (OpCodes.Bge, frame.label_fail);

						// Match an item
						//if (!EvalByteCode (pc + 11, strpos, ref res))
						new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
						if (m == null)
							return null;

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);
						// length ++;
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_length);
						ilgen.Emit (OpCodes.Br, l_loop_body);
						
						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);
						// return false;
						ilgen.Emit (OpCodes.Br, frame.label_fail);

						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Br, l_loop_body);
					} else {
						// Then match as many items as possible, recording
						// backtracking information
						
						//int old_stack_size = stack.Count;
						LocalBuilder local_old_stack_size = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
						ilgen.Emit (OpCodes.Stloc, local_old_stack_size);
						//while (length < end) {
						Label l_loop_footer = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						Label l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);
						//  int cp = Checkpoint ();
						LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
						ilgen.Emit (OpCodes.Stloc, local_cp);

						// int old_strpos = strpos;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);

						//  if (!EvalByteCode (pc + 11, strpos, ref res)) {
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
						if (m == null)
							return null;

						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);
						// strpos = old_strpos
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Starg, 1);
						//    Backtrack (cp);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldloc, local_cp);
						ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));

						//    break;
						Label l_after_loop = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_after_loop);

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);

						//stack.Push (cp);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Ldloc, local_cp);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
						//stack.Push (strpos);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
						// length++
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_length);
						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4, end);
						ilgen.Emit (OpCodes.Blt, l_loop_body);

						ilgen.MarkLabel (l_after_loop);

						// Then, match the tail, backtracking as necessary.

						//while (true) {
						l_loop_footer = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);

						if (RxInterpreter.trace_rx) {
							ilgen.Emit (OpCodes.Ldstr, "matching tail at: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						//  if (EvalByteCode (tail, strpos, ref res)) {
						new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
						if (m == null)
							return null;

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);

						if (RxInterpreter.trace_rx) {
							ilgen.Emit (OpCodes.Ldstr, "tail matched at: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						//	stack.Count = old_stack_size;
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "set_Count", ref mi_stack_set_count));
						//  return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);

						if (RxInterpreter.trace_rx) {
							ilgen.Emit (OpCodes.Ldstr, "tail failed to match at: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						//  if (stack.Count == old_stack_size)
						//		return false;
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
						ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
						ilgen.Emit (OpCodes.Beq, frame.label_fail);
						
						// Backtrack
						//strpos = stack.Pop ();
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
						ilgen.Emit (OpCodes.Starg, 1);
						//Backtrack (stack.Pop ());
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
						ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));

						if (RxInterpreter.trace_rx) {
							//Console.WriteLine ("backtracking to: {0}", strpos);
							ilgen.Emit (OpCodes.Ldstr, "backtracking to: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Br, l_loop_body);
					}

					// We already processed the tail
					pc = out_pc;
					goto End;
				}

				case RxOp.CategoryAny:
				case RxOp.CategoryAnySingleline:
				case RxOp.CategoryWord:
				case RxOp.CategoryDigit:
				case RxOp.CategoryWhiteSpace:
				case RxOp.CategoryEcmaWord:
				case RxOp.CategoryEcmaWhiteSpace:
				case RxOp.CategoryUnicodeSpecials:
				case RxOp.CategoryUnicode: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool negate = (flags & OpFlags.Negate) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					//if (strpos < string_end) {
					Label l_nomatch = ilgen.DefineLabel ();
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ble, l_nomatch);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bge, l_nomatch);
					}

					//  int c = str [strpos];
					LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					if (reverse) {
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Sub);
					}
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Stloc, local_c);

					Label l_match = ilgen.DefineLabel ();

					Label l_true, l_false;

					l_true = negate ? l_nomatch : l_match;
					l_false = negate ? l_match : l_nomatch;

					switch (op) {
					case RxOp.CategoryAny:
						// if (str [strpos] != '\n') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
						ilgen.Emit (OpCodes.Bne_Un, l_true);
						break;
					case RxOp.CategoryAnySingleline:
						ilgen.Emit (OpCodes.Br, l_true);
						break;
					case RxOp.CategoryWord:
						//  if (Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation) {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsLetterOrDigit", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Brtrue, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, (int)UnicodeCategory.ConnectorPunctuation);
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					case RxOp.CategoryDigit:
						// if (Char.IsDigit (c)) {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsDigit", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Brtrue, l_true);
						break;
					case RxOp.CategoryWhiteSpace:
						// if (Char.IsWhiteSpace (c)) {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsWhiteSpace", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Brtrue, l_true);
						break;
					case RxOp.CategoryEcmaWord:
						// if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'a' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'z' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'A' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'Z' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'0' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'9' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'_');
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					case RxOp.CategoryEcmaWhiteSpace:
						// if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)' ');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\t');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\r');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\f');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\v');
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					case RxOp.CategoryUnicodeSpecials:
						// if ('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFF0' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFFD' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);
						break;
					case RxOp.CategoryUnicode:
						// if (Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]) {						
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					}

					ilgen.Emit (OpCodes.Br, l_false);

					ilgen.MarkLabel (l_match);

					//    strpos++;
					if (!no_bump) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
					}
					//  }
					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Br, l2);
					//}
					ilgen.MarkLabel (l_nomatch);
					//return false;
					ilgen.Emit (OpCodes.Br, frame.label_fail);

					ilgen.MarkLabel (l2);

					if (op == RxOp.CategoryUnicode)
						pc += 2;
					else
						pc++;
					break;
				}
				case RxOp.Reference: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					//length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
					LocalBuilder loc_length = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1)); 
					ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "GetLastDefined", ref mi_get_last_defined));					
					ilgen.Emit (OpCodes.Stloc, loc_length);
					//if (length < 0)
					//  return false;
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Blt, frame.label_fail);
					//start = marks [length].Index;
					LocalBuilder loc_start = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_marks);
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
					ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Index", ref mi_mark_get_index));
					ilgen.Emit (OpCodes.Stloc, loc_start);
					// length = marks [length].Length;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_marks);
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
					ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Length", ref mi_mark_get_length));
					ilgen.Emit (OpCodes.Stloc, loc_length);
					if (reverse) {
						//ptr -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, loc_length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
						//if (ptr < 0)
						//goto Fail;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Blt, frame.label_fail);
					} else {
						//if (strpos + length > string_end)
						//  return false;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, loc_length);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bgt, frame.label_fail);
					}

					LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Stloc, local_str);

					// end = start + length;
					LocalBuilder loc_end = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Stloc, loc_end);
					//for (; start < end; ++start) {
					Label l_loop_footer = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Br, l_loop_footer);
					Label l_loop_body = ilgen.DefineLabel ();
					ilgen.MarkLabel (l_loop_body);
					//if (str [strpos] != str [start])
					//return false;
					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);
					ilgen.Emit (OpCodes.Ldloc, local_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);
					ilgen.Emit (OpCodes.Ldloc, local_str);
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
					ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					// strpos++;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Starg, 1);
					// start++
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Stloc, loc_start);
					// Loop footer
					ilgen.MarkLabel (l_loop_footer);
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Ldloc, loc_end);
					ilgen.Emit (OpCodes.Blt, l_loop_body);

					if (reverse) {
						//ptr -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, loc_length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
					}

					pc += 3;
					break;
				}
				case RxOp.Repeat:
				case RxOp.RepeatLazy:
				case RxOp.IfDefined:
					// FIXME:
					if (RxInterpreter.trace_rx || trace_compile)
						Console.WriteLine ("Opcode " + op + " not supported.");
					return null;
				default:
					throw new NotImplementedException ("Opcode '" + op + "' not supported by the regex->IL compiler.");
			    }

				if (one_op)
					break;
			}

			End:

			out_pc = pc;

			return m;
		}
	}