using System; using System.Collections; using System.Globalization; using System.Reflection; using System.Reflection.Emit; using System.Threading; #if NET_2_0 using System.Collections.Generic; #endif namespace System.Text.RegularExpressions { // // Compiler which generates IL bytecode to perform the matching instead of // interpreting a program. // For simplicity, we inherit from RxCompiler, and generate the IL code based // on the program generated by it. This also allows us to fallback to interpretation // if we can't handle something. // This is net 2.0, since 1.0 doesn't support DynamicMethods // FIXME: Add support for 1.0, and CompileToAssembly // FIXME: Overwrite RxCompiler methods so we don't have to decode char // matching opcodes // #if NET_2_0 class CILCompiler : RxCompiler, ICompiler { DynamicMethod[] eval_methods; bool[] eval_methods_defined; /* * To avoid the overhead of decoding the countless opcode variants created * by RxCompiler, we save the original, 'generic' version and its flags * in these two tables. */ private Dictionary generic_ops; private Dictionary op_flags; private Dictionary labels; static FieldInfo fi_str = typeof (RxInterpreter).GetField ("str", BindingFlags.Instance|BindingFlags.NonPublic); static FieldInfo fi_string_start = typeof (RxInterpreter).GetField ("string_start", BindingFlags.Instance|BindingFlags.NonPublic); static FieldInfo fi_string_end = typeof (RxInterpreter).GetField ("string_end", BindingFlags.Instance|BindingFlags.NonPublic); static FieldInfo fi_program = typeof (RxInterpreter).GetField ("program", BindingFlags.Instance|BindingFlags.NonPublic); static FieldInfo fi_marks = typeof (RxInterpreter).GetField ("marks", BindingFlags.Instance|BindingFlags.NonPublic); static FieldInfo fi_groups = typeof (RxInterpreter).GetField ("groups", BindingFlags.Instance|BindingFlags.NonPublic); static FieldInfo fi_deep = typeof (RxInterpreter).GetField ("deep", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); static FieldInfo fi_stack = typeof (RxInterpreter).GetField ("stack", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); static FieldInfo fi_mark_start = typeof (Mark).GetField ("Start", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); static FieldInfo fi_mark_end = typeof (Mark).GetField ("End", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); //static FieldInfo fi_mark_index = typeof (Mark).GetField ("Index", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); static MethodInfo mi_stack_get_count, mi_stack_set_count, mi_stack_push, mi_stack_pop; static MethodInfo mi_set_start_of_match, mi_is_word_char, mi_reset_groups; static MethodInfo mi_checkpoint, mi_backtrack, mi_open, mi_close; static MethodInfo mi_get_last_defined, mi_mark_get_index, mi_mark_get_length; public static readonly bool trace_compile = Environment.GetEnvironmentVariable ("MONO_TRACE_RX_COMPILE") != null; public CILCompiler () { generic_ops = new Dictionary (); op_flags = new Dictionary (); } IMachineFactory ICompiler.GetMachineFactory () { byte[] code = new byte [curpos]; Buffer.BlockCopy (program, 0, code, 0, curpos); eval_methods = new DynamicMethod [code.Length]; eval_methods_defined = new bool [code.Length]; // The main eval method DynamicMethod main = GetEvalMethod (code, 11); if (main != null) return new RxInterpreterFactory (code, (EvalDelegate)main.CreateDelegate (typeof (EvalDelegate))); else return new RxInterpreterFactory (code, null); } DynamicMethod GetEvalMethod (byte[] program, int pc) { if (eval_methods_defined [pc]) return eval_methods [pc]; // FIXME: Recursion ? eval_methods_defined [pc] = true; eval_methods [pc] = CreateEvalMethod (program, pc); return eval_methods [pc]; } private MethodInfo GetMethod (Type t, string name, ref MethodInfo cached) { if (cached == null) { cached = t.GetMethod (name, BindingFlags.Static|BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); if (cached == null) throw new Exception ("Method not found: " + name); } return cached; } private MethodInfo GetMethod (string name, ref MethodInfo cached) { return GetMethod (typeof (RxInterpreter), name, ref cached); } private int ReadInt (byte[] code, int pc) { int val = code [pc]; val |= code [pc + 1] << 8; val |= code [pc + 2] << 16; val |= code [pc + 3] << 24; return val; } static OpFlags MakeFlags (bool negate, bool ignore, bool reverse, bool lazy) { OpFlags flags = 0; if (negate) flags |= OpFlags.Negate; if (ignore) flags |= OpFlags.IgnoreCase; if (reverse) flags |= OpFlags.RightToLeft; if (lazy) flags |= OpFlags.Lazy; return flags; } void EmitGenericOp (RxOp op, bool negate, bool ignore, bool reverse, bool lazy) { generic_ops [curpos] = (int)op; op_flags [curpos] = (int)MakeFlags (negate, ignore, reverse, false); } public override void EmitOp (RxOp op, bool negate, bool ignore, bool reverse) { EmitGenericOp (op, negate, ignore, reverse, false); base.EmitOp (op, negate, ignore, reverse); } public override void EmitOpIgnoreReverse (RxOp op, bool ignore, bool reverse) { EmitGenericOp (op, false, ignore, reverse, false); base.EmitOpIgnoreReverse (op, ignore, reverse); } public override void EmitOpNegateReverse (RxOp op, bool negate, bool reverse) { EmitGenericOp (op, negate, false, reverse, false); base.EmitOpNegateReverse (op, negate, reverse); } class Frame { public Label label_pass, label_fail; public Frame (ILGenerator ilgen) { label_fail = ilgen.DefineLabel (); label_pass = ilgen.DefineLabel (); } } LocalBuilder local_textinfo; /* * Create a dynamic method which is equivalent to the RxInterpreter.EvalByteCode * method specialized to the given program and a given pc. Return the newly * created method or null if a not-supported opcode was encountered. */ DynamicMethod CreateEvalMethod (byte[] program, int pc) { DynamicMethod m = new DynamicMethod ("Eval_" + pc, typeof (bool), new Type [] { typeof (RxInterpreter), typeof (int), typeof (int).MakeByRefType () }, typeof (RxInterpreter), true); ILGenerator ilgen = m.GetILGenerator (); /* Args: interp - 0 strpos - 1 strpos_result - 2 */ /* * Recursive calls to EvalByteCode are inlined manually by calling * EmitEvalMethodBody with the pc of the recursive call. Frame objects hold * the information required to link together the code generated by the recursive * call with the rest of the code. */ Frame frame = new Frame (ilgen); /* Cache the textinfo used by Char.ToLower () */ local_textinfo = ilgen.DeclareLocal (typeof (TextInfo)); ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentThread")); ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentCulture")); ilgen.Emit (OpCodes.Call, typeof (CultureInfo).GetMethod ("get_TextInfo")); ilgen.Emit (OpCodes.Stloc, local_textinfo); m = EmitEvalMethodBody (m, ilgen, frame, program, pc, program.Length, false, false, out pc); if (m == null) return null; ilgen.MarkLabel (frame.label_pass); ilgen.Emit (OpCodes.Ldarg_2); ilgen.Emit (OpCodes.Ldarg_1); ilgen.Emit (OpCodes.Stind_I4); ilgen.Emit (OpCodes.Ldc_I4_1); ilgen.Emit (OpCodes.Ret); ilgen.MarkLabel (frame.label_fail); ilgen.Emit (OpCodes.Ldc_I4_0); ilgen.Emit (OpCodes.Ret); return m; } private int ReadShort (byte[] program, int pc) { return (int)program [pc] | ((int)program [pc + 1] << 8); } private Label CreateLabelForPC (ILGenerator ilgen, int pc) { if (labels == null) labels = new Dictionary (); Label l; if (!labels.TryGetValue (pc, out l)) { l = ilgen.DefineLabel (); labels [pc] = l; } return l; } private int GetILOffset (ILGenerator ilgen) { return (int)typeof (ILGenerator).GetField ("code_len", BindingFlags.Instance|BindingFlags.NonPublic).GetValue (ilgen); } /* * Emit IL code for a sequence of opcodes between pc and end_pc. If there is a * match, set strpos (Arg 1) to the position after the match, then * branch to frame.label_pass. Otherwise branch to frame.label_fail, * and leave strpos at an undefined position. The caller should * generate code to save the original value of strpos if it needs it. * If one_op is true, only generate code for one opcode and set out_pc * to the next pc after the opcode. * If no_bump is true, don't bump strpos in char matching opcodes. * Keep this in synch with RxInterpreter.EvalByteCode (). It it is sync with * the version in r111969. * FIXME: Modify the regex tests so they are run with RegexOptions.Compiled as * well. */ 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 (); 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 "); // 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 "); 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 "); // 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 "); 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; } } #else class CILCompiler : RxCompiler { } #endif }