2 using System.Collections;
3 using System.Globalization;
4 using System.Reflection;
5 using System.Reflection.Emit;
6 using System.Threading;
9 using System.Collections.Generic;
12 namespace System.Text.RegularExpressions {
15 // Compiler which generates IL bytecode to perform the matching instead of
16 // interpreting a program.
17 // For simplicity, we inherit from RxCompiler, and generate the IL code based
18 // on the program generated by it. This also allows us to fallback to interpretation
19 // if we can't handle something.
20 // This is net 2.0, since 1.0 doesn't support DynamicMethods
21 // FIXME: Add support for 1.0, and CompileToAssembly
22 // FIXME: Overwrite RxCompiler methods so we don't have to decode char
27 class CILCompiler : RxCompiler, ICompiler {
28 DynamicMethod[] eval_methods;
29 bool[] eval_methods_defined;
32 * To avoid the overhead of decoding the countless opcode variants created
33 * by RxCompiler, we save the original, 'generic' version and its flags
34 * in these two tables.
36 private Dictionary<int, int> generic_ops;
37 private Dictionary<int, int> op_flags;
38 private Dictionary<int, Label> labels;
40 static FieldInfo fi_str = typeof (RxInterpreter).GetField ("str", BindingFlags.Instance|BindingFlags.NonPublic);
41 static FieldInfo fi_string_start = typeof (RxInterpreter).GetField ("string_start", BindingFlags.Instance|BindingFlags.NonPublic);
42 static FieldInfo fi_string_end = typeof (RxInterpreter).GetField ("string_end", BindingFlags.Instance|BindingFlags.NonPublic);
43 static FieldInfo fi_program = typeof (RxInterpreter).GetField ("program", BindingFlags.Instance|BindingFlags.NonPublic);
44 static FieldInfo fi_marks = typeof (RxInterpreter).GetField ("marks", BindingFlags.Instance|BindingFlags.NonPublic);
45 static FieldInfo fi_groups = typeof (RxInterpreter).GetField ("groups", BindingFlags.Instance|BindingFlags.NonPublic);
46 static FieldInfo fi_deep = typeof (RxInterpreter).GetField ("deep", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
47 static FieldInfo fi_stack = typeof (RxInterpreter).GetField ("stack", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
48 static FieldInfo fi_mark_start = typeof (Mark).GetField ("Start", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
49 static FieldInfo fi_mark_end = typeof (Mark).GetField ("End", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
50 //static FieldInfo fi_mark_index = typeof (Mark).GetField ("Index", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
52 static MethodInfo mi_stack_get_count, mi_stack_set_count, mi_stack_push, mi_stack_pop;
53 static MethodInfo mi_set_start_of_match, mi_is_word_char, mi_reset_groups;
54 static MethodInfo mi_checkpoint, mi_backtrack, mi_open, mi_close;
55 static MethodInfo mi_get_last_defined, mi_mark_get_index, mi_mark_get_length;
57 public static readonly bool trace_compile = Environment.GetEnvironmentVariable ("MONO_TRACE_RX_COMPILE") != null;
59 public CILCompiler () {
60 generic_ops = new Dictionary <int, int> ();
61 op_flags = new Dictionary <int, int> ();
64 IMachineFactory ICompiler.GetMachineFactory () {
65 byte[] code = new byte [curpos];
66 Buffer.BlockCopy (program, 0, code, 0, curpos);
68 eval_methods = new DynamicMethod [code.Length];
69 eval_methods_defined = new bool [code.Length];
71 // The main eval method
72 DynamicMethod main = GetEvalMethod (code, 11);
75 return new RxInterpreterFactory (code, (EvalDelegate)main.CreateDelegate (typeof (EvalDelegate)));
77 return new RxInterpreterFactory (code, null);
80 DynamicMethod GetEvalMethod (byte[] program, int pc) {
81 if (eval_methods_defined [pc])
82 return eval_methods [pc];
85 eval_methods_defined [pc] = true;
87 eval_methods [pc] = CreateEvalMethod (program, pc);
88 return eval_methods [pc];
91 private MethodInfo GetMethod (Type t, string name, ref MethodInfo cached) {
93 cached = t.GetMethod (name, BindingFlags.Static|BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
95 throw new Exception ("Method not found: " + name);
100 private MethodInfo GetMethod (string name, ref MethodInfo cached) {
101 return GetMethod (typeof (RxInterpreter), name, ref cached);
104 private int ReadInt (byte[] code, int pc) {
106 val |= code [pc + 1] << 8;
107 val |= code [pc + 2] << 16;
108 val |= code [pc + 3] << 24;
112 static OpFlags MakeFlags (bool negate, bool ignore, bool reverse, bool lazy) {
114 if (negate) flags |= OpFlags.Negate;
115 if (ignore) flags |= OpFlags.IgnoreCase;
116 if (reverse) flags |= OpFlags.RightToLeft;
117 if (lazy) flags |= OpFlags.Lazy;
122 void EmitGenericOp (RxOp op, bool negate, bool ignore, bool reverse, bool lazy) {
123 generic_ops [curpos] = (int)op;
124 op_flags [curpos] = (int)MakeFlags (negate, ignore, reverse, false);
127 public override void EmitOp (RxOp op, bool negate, bool ignore, bool reverse) {
128 EmitGenericOp (op, negate, ignore, reverse, false);
129 base.EmitOp (op, negate, ignore, reverse);
132 public override void EmitOpIgnoreReverse (RxOp op, bool ignore, bool reverse) {
133 EmitGenericOp (op, false, ignore, reverse, false);
134 base.EmitOpIgnoreReverse (op, ignore, reverse);
137 public override void EmitOpNegateReverse (RxOp op, bool negate, bool reverse) {
138 EmitGenericOp (op, negate, false, reverse, false);
139 base.EmitOpNegateReverse (op, negate, reverse);
143 public Label label_pass, label_fail;
145 public Frame (ILGenerator ilgen) {
146 label_fail = ilgen.DefineLabel ();
147 label_pass = ilgen.DefineLabel ();
151 LocalBuilder local_textinfo;
154 * Create a dynamic method which is equivalent to the RxInterpreter.EvalByteCode
155 * method specialized to the given program and a given pc. Return the newly
156 * created method or null if a not-supported opcode was encountered.
158 DynamicMethod CreateEvalMethod (byte[] program, int pc) {
159 DynamicMethod m = new DynamicMethod ("Eval_" + pc, typeof (bool), new Type [] { typeof (RxInterpreter), typeof (int), typeof (int).MakeByRefType () }, typeof (RxInterpreter), true);
160 ILGenerator ilgen = m.GetILGenerator ();
170 * Recursive calls to EvalByteCode are inlined manually by calling
171 * EmitEvalMethodBody with the pc of the recursive call. Frame objects hold
172 * the information required to link together the code generated by the recursive
173 * call with the rest of the code.
175 Frame frame = new Frame (ilgen);
177 /* Cache the textinfo used by Char.ToLower () */
178 local_textinfo = ilgen.DeclareLocal (typeof (TextInfo));
179 ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentThread"));
180 ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentCulture"));
181 ilgen.Emit (OpCodes.Call, typeof (CultureInfo).GetMethod ("get_TextInfo"));
182 ilgen.Emit (OpCodes.Stloc, local_textinfo);
184 m = EmitEvalMethodBody (m, ilgen, frame, program, pc, program.Length, false, false, out pc);
188 ilgen.MarkLabel (frame.label_pass);
189 ilgen.Emit (OpCodes.Ldarg_2);
190 ilgen.Emit (OpCodes.Ldarg_1);
191 ilgen.Emit (OpCodes.Stind_I4);
192 ilgen.Emit (OpCodes.Ldc_I4_1);
193 ilgen.Emit (OpCodes.Ret);
195 ilgen.MarkLabel (frame.label_fail);
196 ilgen.Emit (OpCodes.Ldc_I4_0);
197 ilgen.Emit (OpCodes.Ret);
202 private int ReadShort (byte[] program, int pc) {
203 return (int)program [pc] | ((int)program [pc + 1] << 8);
206 private Label CreateLabelForPC (ILGenerator ilgen, int pc) {
208 labels = new Dictionary <int, Label> ();
210 if (!labels.TryGetValue (pc, out l)) {
211 l = ilgen.DefineLabel ();
218 private int GetILOffset (ILGenerator ilgen) {
219 return (int)typeof (ILGenerator).GetField ("code_len", BindingFlags.Instance|BindingFlags.NonPublic).GetValue (ilgen);
223 * Emit IL code for a sequence of opcodes between pc and end_pc. If there is a
224 * match, set strpos (Arg 1) to the position after the match, then
225 * branch to frame.label_pass. Otherwise branch to frame.label_fail,
226 * and leave strpos at an undefined position. The caller should
227 * generate code to save the original value of strpos if it needs it.
228 * If one_op is true, only generate code for one opcode and set out_pc
229 * to the next pc after the opcode.
230 * If no_bump is true, don't bump strpos in char matching opcodes.
231 * Keep this in synch with RxInterpreter.EvalByteCode (). It it is sync with
232 * the version in r111969.
233 * FIXME: Modify the regex tests so they are run with RegexOptions.Compiled as
236 private DynamicMethod EmitEvalMethodBody (DynamicMethod m, ILGenerator ilgen,
237 Frame frame, byte[] program,
239 bool one_op, bool no_bump,
242 int start, length, end;
246 int group_count = 1 + ReadShort (program, 1);
248 while (pc < end_pc) {
249 RxOp op = (RxOp)program [pc];
251 // FIXME: Optimize this
252 if (generic_ops.ContainsKey (pc))
253 op = (RxOp)generic_ops [pc];
256 Console.WriteLine ("compiling {0} pc={1} end_pc={2}, il_offset=0x{3:x}", op, pc, end_pc, GetILOffset (ilgen));
259 if (labels != null) {
261 if (labels.TryGetValue (pc, out l)) {
267 if (RxInterpreter.trace_rx) {
268 //Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", op, pc, strpos);
269 ilgen.Emit (OpCodes.Ldstr, "evaluating: {0} at pc: {1}, strpos: {2}");
270 ilgen.Emit (OpCodes.Ldc_I4, (int)op);
271 ilgen.Emit (OpCodes.Box, typeof (RxOp));
272 ilgen.Emit (OpCodes.Ldc_I4, pc);
273 ilgen.Emit (OpCodes.Box, typeof (int));
274 ilgen.Emit (OpCodes.Ldarg_1);
275 ilgen.Emit (OpCodes.Box, typeof (int));
276 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object), typeof (object), typeof (object) }));
281 case RxOp.AnchorReverse: {
282 bool reverse = (RxOp)program [pc] == RxOp.AnchorReverse;
283 length = ReadShort (program, pc + 3);
284 pc += ReadShort (program, pc + 1);
286 // Optimize some common cases by inlining the code generated for the
288 RxOp anch_op = (RxOp)program [pc];
290 // FIXME: Do this even if the archor op is not the last in the regex
291 if (!reverse && group_count == 1 && anch_op == RxOp.Char && (RxOp)program [pc + 2] == RxOp.True) {
294 * while (strpos < string_end) {
295 * if (str [strpos] == program [pc + 1]) {
296 * match_start = strpos;
297 * strpos_result = strpos + 1;
298 * marks [groups [0]].Start = strpos;
299 * if (groups.Length > 1)
300 * marks [groups [0]].End = res;
307 // Add some locals to avoid an indirection
308 LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
309 ilgen.Emit (OpCodes.Ldarg_0);
310 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
311 ilgen.Emit (OpCodes.Stloc, local_string_end);
312 LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
313 ilgen.Emit (OpCodes.Ldarg_0);
314 ilgen.Emit (OpCodes.Ldfld, fi_str);
315 ilgen.Emit (OpCodes.Stloc, local_str);
317 //while (strpos < string_end) {
318 // -> Done at the end of the loop like mcs does
319 Label l1 = ilgen.DefineLabel ();
320 Label l2 = ilgen.DefineLabel ();
321 ilgen.Emit (OpCodes.Br, l2);
322 ilgen.MarkLabel (l1);
324 // if (str [strpos] == program [pc + 1]) {
325 Label l3 = ilgen.DefineLabel ();
326 ilgen.Emit (OpCodes.Ldloc, local_str);
327 ilgen.Emit (OpCodes.Ldarg_1);
328 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
329 ilgen.Emit (OpCodes.Conv_I4);
330 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
331 ilgen.Emit (OpCodes.Beq, l3);
333 // The true case is done after the loop
337 ilgen.Emit (OpCodes.Ldarg_1);
338 ilgen.Emit (OpCodes.Ldc_I4_1);
339 ilgen.Emit (OpCodes.Add);
340 ilgen.Emit (OpCodes.Starg, 1);
342 ilgen.MarkLabel (l2);
343 ilgen.Emit (OpCodes.Ldarg_1);
344 ilgen.Emit (OpCodes.Ldloc, local_string_end);
345 ilgen.Emit (OpCodes.Blt, l1);
348 ilgen.Emit (OpCodes.Br, frame.label_fail);
351 ilgen.MarkLabel (l3);
352 // call SetStartOfMatch (strpos)
353 ilgen.Emit (OpCodes.Ldarg_0);
354 ilgen.Emit (OpCodes.Ldarg_1);
355 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "SetStartOfMatch", ref mi_set_start_of_match));
357 ilgen.Emit (OpCodes.Ldarg_1);
358 ilgen.Emit (OpCodes.Ldc_I4_1);
359 ilgen.Emit (OpCodes.Add);
360 ilgen.Emit (OpCodes.Starg, 1);
362 ilgen.Emit (OpCodes.Br, frame.label_pass);
367 //Console.WriteLine ("Anchor op " + anch_op);
369 // Add some locals to avoid an indirection
370 LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
371 ilgen.Emit (OpCodes.Ldarg_0);
372 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
373 ilgen.Emit (OpCodes.Ldc_I4_1);
374 ilgen.Emit (OpCodes.Add);
375 ilgen.Emit (OpCodes.Stloc, local_string_end);
377 //while (strpos < string_end + 1) {
378 // -> Done at the end of the loop like mcs does
379 Label l1 = ilgen.DefineLabel ();
380 Label l2 = ilgen.DefineLabel ();
381 ilgen.Emit (OpCodes.Br, l2);
382 ilgen.MarkLabel (l1);
384 //if (groups.Length > 1) {
386 // marks [groups [0]].Start = strpos;
388 if (group_count > 1) {
389 ilgen.Emit (OpCodes.Ldarg_0);
390 ilgen.Emit (OpCodes.Call, GetMethod ("ResetGroups", ref mi_reset_groups));
392 ilgen.Emit (OpCodes.Ldarg_0);
393 ilgen.Emit (OpCodes.Ldfld, fi_marks);
394 ilgen.Emit (OpCodes.Ldarg_0);
395 ilgen.Emit (OpCodes.Ldfld, fi_groups);
396 ilgen.Emit (OpCodes.Ldc_I4_0);
397 ilgen.Emit (OpCodes.Ldelem_I4);
398 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
399 ilgen.Emit (OpCodes.Ldarg_1);
400 ilgen.Emit (OpCodes.Stfld, fi_mark_start);
403 // if (EvalByteCode (pc, strpos, ref res)) {
405 Frame new_frame = new Frame (ilgen);
407 // old_stros = strpos;
408 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
409 ilgen.Emit (OpCodes.Ldarg_1);
410 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
412 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, end_pc, false, false, out out_pc);
417 ilgen.MarkLabel (new_frame.label_pass);
418 // marks [groups [0]].Start = old_strpos;
419 ilgen.Emit (OpCodes.Ldarg_0);
420 ilgen.Emit (OpCodes.Ldfld, fi_marks);
421 ilgen.Emit (OpCodes.Ldarg_0);
422 ilgen.Emit (OpCodes.Ldfld, fi_groups);
423 ilgen.Emit (OpCodes.Ldc_I4_0);
424 ilgen.Emit (OpCodes.Ldelem_I4);
425 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
426 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
427 ilgen.Emit (OpCodes.Stfld, fi_mark_start);
428 // if (groups.Length > 1)
429 // marks [groups [0]].End = res;
430 if (group_count > 1) {
431 ilgen.Emit (OpCodes.Ldarg_0);
432 ilgen.Emit (OpCodes.Ldfld, fi_marks);
433 ilgen.Emit (OpCodes.Ldarg_0);
434 ilgen.Emit (OpCodes.Ldfld, fi_groups);
435 ilgen.Emit (OpCodes.Ldc_I4_0);
436 ilgen.Emit (OpCodes.Ldelem_I4);
437 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
438 ilgen.Emit (OpCodes.Ldarg_1);
439 ilgen.Emit (OpCodes.Stfld, fi_mark_end);
443 ilgen.Emit (OpCodes.Br, frame.label_pass);
446 ilgen.MarkLabel (new_frame.label_fail);
447 // strpos = old_strpos +/- 1;
448 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
449 ilgen.Emit (OpCodes.Ldc_I4_1);
451 ilgen.Emit (OpCodes.Sub);
453 ilgen.Emit (OpCodes.Add);
454 ilgen.Emit (OpCodes.Starg, 1);
456 ilgen.MarkLabel (l2);
458 ilgen.Emit (OpCodes.Ldarg_1);
459 ilgen.Emit (OpCodes.Ldc_I4_0);
460 ilgen.Emit (OpCodes.Bge, l1);
462 ilgen.Emit (OpCodes.Ldarg_1);
463 ilgen.Emit (OpCodes.Ldloc, local_string_end);
464 ilgen.Emit (OpCodes.Blt, l1);
467 ilgen.Emit (OpCodes.Br, frame.label_fail);
473 //if (EvalByteCode (pc + 3, strpos, ref res)) {
475 int target_pc = pc + ReadShort (program, pc + 1);
477 // Emit the rest of the code inline instead of making a recursive call
478 Frame new_frame = new Frame (ilgen);
480 // old_strpos = strpos;
481 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
482 ilgen.Emit (OpCodes.Ldarg_1);
483 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
485 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target_pc, false, false, out out_pc);
490 ilgen.MarkLabel (new_frame.label_pass);
492 ilgen.Emit (OpCodes.Br, frame.label_pass);
495 ilgen.MarkLabel (new_frame.label_fail);
496 // strpos = old_strpos;
497 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
498 ilgen.Emit (OpCodes.Starg, 1);
504 case RxOp.UnicodeChar:
506 case RxOp.UnicodeRange: {
507 OpFlags flags = (OpFlags)op_flags [pc];
508 bool negate = (flags & OpFlags.Negate) > 0;
509 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
510 bool reverse = (flags & OpFlags.RightToLeft) > 0;
512 //if (strpos < string_end) {
513 Label l1 = ilgen.DefineLabel ();
515 ilgen.Emit (OpCodes.Ldarg_1);
516 ilgen.Emit (OpCodes.Ldc_I4_0);
517 ilgen.Emit (OpCodes.Ble, l1);
519 ilgen.Emit (OpCodes.Ldarg_1);
520 ilgen.Emit (OpCodes.Ldarg_0);
521 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
522 ilgen.Emit (OpCodes.Bge, l1);
526 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
528 // int c = str [strpos];
529 LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
530 ilgen.Emit (OpCodes.Ldarg_0);
531 ilgen.Emit (OpCodes.Ldfld, fi_str);
532 ilgen.Emit (OpCodes.Ldarg_1);
534 ilgen.Emit (OpCodes.Ldc_I4_1);
535 ilgen.Emit (OpCodes.Sub);
537 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
539 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
541 if (op == RxOp.Char) {
542 ilgen.Emit (OpCodes.Conv_I4);
543 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
544 ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);
547 } else if (op == RxOp.UnicodeChar) {
548 ilgen.Emit (OpCodes.Conv_I4);
549 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
550 ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);
553 } else if (op == RxOp.Range) {
554 ilgen.Emit (OpCodes.Stloc, local_c);
556 // if (c >= program [pc + 1] && c <= program [pc + 2]) {
558 Label l3 = ilgen.DefineLabel ();
560 ilgen.Emit (OpCodes.Ldloc, local_c);
561 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
562 ilgen.Emit (OpCodes.Blt, l3);
563 ilgen.Emit (OpCodes.Ldloc, local_c);
564 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
565 ilgen.Emit (OpCodes.Bgt, l3);
566 ilgen.Emit (OpCodes.Br, l1);
567 ilgen.MarkLabel (l3);
569 ilgen.Emit (OpCodes.Ldloc, local_c);
570 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
571 ilgen.Emit (OpCodes.Blt, l1);
572 ilgen.Emit (OpCodes.Ldloc, local_c);
573 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
574 ilgen.Emit (OpCodes.Bgt, l1);
578 } else if (op == RxOp.UnicodeRange) {
579 ilgen.Emit (OpCodes.Stloc, local_c);
581 // if (c >= program [pc + 1] && c <= program [pc + 2]) {
583 Label l3 = ilgen.DefineLabel ();
585 ilgen.Emit (OpCodes.Ldloc, local_c);
586 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
587 ilgen.Emit (OpCodes.Blt, l3);
588 ilgen.Emit (OpCodes.Ldloc, local_c);
589 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
590 ilgen.Emit (OpCodes.Bgt, l3);
591 ilgen.Emit (OpCodes.Br, l1);
592 ilgen.MarkLabel (l3);
594 ilgen.Emit (OpCodes.Ldloc, local_c);
595 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
596 ilgen.Emit (OpCodes.Blt, l1);
597 ilgen.Emit (OpCodes.Ldloc, local_c);
598 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
599 ilgen.Emit (OpCodes.Bgt, l1);
604 throw new NotSupportedException ();
607 //ilgen.EmitWriteLine ("HIT:" + (char)program [pc + 1]);
609 // strpos++ / strpos--;
610 ilgen.Emit (OpCodes.Ldarg_1);
611 ilgen.Emit (OpCodes.Ldc_I4_1);
613 ilgen.Emit (OpCodes.Sub);
615 ilgen.Emit (OpCodes.Add);
616 ilgen.Emit (OpCodes.Starg, 1);
618 Label l2 = ilgen.DefineLabel ();
619 ilgen.Emit (OpCodes.Br, l2);
621 ilgen.MarkLabel (l1);
623 ilgen.Emit (OpCodes.Br, frame.label_fail);
624 ilgen.MarkLabel (l2);
630 ilgen.Emit (OpCodes.Br, frame.label_pass);
636 ilgen.Emit (OpCodes.Br, frame.label_fail);
640 case RxOp.AnyPosition: {
644 case RxOp.StartOfString: {
647 ilgen.Emit (OpCodes.Ldarg_1);
648 ilgen.Emit (OpCodes.Ldc_I4_0);
649 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
653 case RxOp.StartOfLine: {
654 // FIXME: windows line endings
655 //if (!(strpos == 0 || str [strpos - 1] == '\n'))
657 Label l = ilgen.DefineLabel ();
658 ilgen.Emit (OpCodes.Ldarg_1);
659 ilgen.Emit (OpCodes.Ldc_I4_0);
660 ilgen.Emit (OpCodes.Beq, l);
661 ilgen.Emit (OpCodes.Ldarg_0);
662 ilgen.Emit (OpCodes.Ldfld, fi_str);
663 ilgen.Emit (OpCodes.Ldarg_1);
664 ilgen.Emit (OpCodes.Ldc_I4_1);
665 ilgen.Emit (OpCodes.Sub);
666 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
667 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
668 ilgen.Emit (OpCodes.Beq, l);
669 ilgen.Emit (OpCodes.Br, frame.label_fail);
675 case RxOp.StartOfScan: {
676 //if (strpos != string_start)
678 ilgen.Emit (OpCodes.Ldarg_1);
679 ilgen.Emit (OpCodes.Ldarg_0);
680 ilgen.Emit (OpCodes.Ldfld, fi_string_start);
681 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
686 //if (!(strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')))
688 Label l = ilgen.DefineLabel ();
690 ilgen.Emit (OpCodes.Ldarg_1);
691 ilgen.Emit (OpCodes.Ldarg_0);
692 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
693 ilgen.Emit (OpCodes.Beq, l);
695 Label l2 = ilgen.DefineLabel ();
696 ilgen.Emit (OpCodes.Ldarg_1);
697 ilgen.Emit (OpCodes.Ldarg_0);
698 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
699 ilgen.Emit (OpCodes.Ldc_I4_1);
700 ilgen.Emit (OpCodes.Sub);
701 ilgen.Emit (OpCodes.Bne_Un, l2);
702 ilgen.Emit (OpCodes.Ldarg_0);
703 ilgen.Emit (OpCodes.Ldfld, fi_str);
704 ilgen.Emit (OpCodes.Ldarg_1);
705 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
706 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
707 ilgen.Emit (OpCodes.Bne_Un, l2);
708 ilgen.Emit (OpCodes.Br, l);
709 ilgen.MarkLabel (l2);
711 ilgen.Emit (OpCodes.Br, frame.label_fail);
717 case RxOp.EndOfString: {
718 //if (strpos != string_end)
720 ilgen.Emit (OpCodes.Ldarg_1);
721 ilgen.Emit (OpCodes.Ldarg_0);
722 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
723 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
727 case RxOp.EndOfLine: {
728 //if (!(strpos == string_end || str [strpos] == '\n'))
730 Label l_match = ilgen.DefineLabel ();
731 ilgen.Emit (OpCodes.Ldarg_1);
732 ilgen.Emit (OpCodes.Ldarg_0);
733 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
734 ilgen.Emit (OpCodes.Beq, l_match);
735 ilgen.Emit (OpCodes.Ldarg_0);
736 ilgen.Emit (OpCodes.Ldfld, fi_str);
737 ilgen.Emit (OpCodes.Ldarg_1);
738 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
739 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
740 ilgen.Emit (OpCodes.Beq, l_match);
741 ilgen.Emit (OpCodes.Br, frame.label_fail);
742 ilgen.MarkLabel (l_match);
747 case RxOp.WordBoundary:
748 case RxOp.NoWordBoundary: {
749 bool negate = op == RxOp.NoWordBoundary;
751 //if (string_end == 0)
753 ilgen.Emit (OpCodes.Ldarg_0);
754 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
755 ilgen.Emit (OpCodes.Ldc_I4_0);
756 ilgen.Emit (OpCodes.Beq, frame.label_fail);
758 Label l_match = ilgen.DefineLabel ();
761 Label l1 = ilgen.DefineLabel ();
762 ilgen.Emit (OpCodes.Ldarg_1);
763 ilgen.Emit (OpCodes.Ldc_I4_0);
764 ilgen.Emit (OpCodes.Bne_Un, l1);
765 //if (!IsWordChar (str [strpos])) {
767 ilgen.Emit (OpCodes.Ldarg_0);
768 ilgen.Emit (OpCodes.Ldfld, fi_str);
769 ilgen.Emit (OpCodes.Ldarg_1);
770 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
771 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
772 ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
773 ilgen.Emit (OpCodes.Br, l_match);
775 //} else if (strpos == string_end) {
776 ilgen.MarkLabel (l1);
777 Label l2 = ilgen.DefineLabel ();
778 ilgen.Emit (OpCodes.Ldarg_1);
779 ilgen.Emit (OpCodes.Ldarg_0);
780 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
781 ilgen.Emit (OpCodes.Bne_Un, l2);
782 //if (!IsWordChar (str [strpos - 1])) {
784 ilgen.Emit (OpCodes.Ldarg_0);
785 ilgen.Emit (OpCodes.Ldfld, fi_str);
786 ilgen.Emit (OpCodes.Ldarg_1);
787 ilgen.Emit (OpCodes.Ldc_I4_1);
788 ilgen.Emit (OpCodes.Sub);
789 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
790 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
791 ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
792 ilgen.Emit (OpCodes.Br, l_match);
795 ilgen.MarkLabel (l2);
796 //if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
798 ilgen.Emit (OpCodes.Ldarg_0);
799 ilgen.Emit (OpCodes.Ldfld, fi_str);
800 ilgen.Emit (OpCodes.Ldarg_1);
801 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
802 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
803 ilgen.Emit (OpCodes.Ldarg_0);
804 ilgen.Emit (OpCodes.Ldfld, fi_str);
805 ilgen.Emit (OpCodes.Ldarg_1);
806 ilgen.Emit (OpCodes.Ldc_I4_1);
807 ilgen.Emit (OpCodes.Sub);
808 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
809 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
810 ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, frame.label_fail);
811 ilgen.Emit (OpCodes.Br, l_match);
813 ilgen.MarkLabel (l_match);
819 case RxOp.UnicodeBitmap: {
820 OpFlags flags = (OpFlags)op_flags [pc];
821 bool negate = (flags & OpFlags.Negate) > 0;
822 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
823 bool reverse = (flags & OpFlags.RightToLeft) > 0;
824 bool unicode = (op == RxOp.UnicodeBitmap);
826 //if (strpos < string_end) {
827 Label l1 = ilgen.DefineLabel ();
828 Label l2 = ilgen.DefineLabel ();
829 Label l_match = ilgen.DefineLabel ();
831 ilgen.Emit (OpCodes.Ldarg_1);
832 ilgen.Emit (OpCodes.Ldc_I4_0);
833 ilgen.Emit (OpCodes.Ble, l1);
835 ilgen.Emit (OpCodes.Ldarg_1);
836 ilgen.Emit (OpCodes.Ldarg_0);
837 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
838 ilgen.Emit (OpCodes.Bge, l1);
840 // int c = str [strpos];
841 LocalBuilder local_c = ilgen.DeclareLocal (typeof (int));
843 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
844 ilgen.Emit (OpCodes.Ldarg_0);
845 ilgen.Emit (OpCodes.Ldfld, fi_str);
846 ilgen.Emit (OpCodes.Ldarg_1);
848 ilgen.Emit (OpCodes.Ldc_I4_1);
849 ilgen.Emit (OpCodes.Sub);
851 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
852 ilgen.Emit (OpCodes.Conv_I4);
854 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
855 // c -= program [pc + 1];
857 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
858 ilgen.Emit (OpCodes.Sub);
859 ilgen.Emit (OpCodes.Stloc, local_c);
860 length = ReadShort (program, pc + 3);
863 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
864 ilgen.Emit (OpCodes.Sub);
865 ilgen.Emit (OpCodes.Stloc, local_c);
866 length = program [pc + 2];
869 // if (c < 0 || c >= (length << 3))
871 ilgen.Emit (OpCodes.Ldloc, local_c);
872 ilgen.Emit (OpCodes.Ldc_I4_0);
873 ilgen.Emit (OpCodes.Blt, negate ? l_match : frame.label_fail);
874 ilgen.Emit (OpCodes.Ldloc, local_c);
875 ilgen.Emit (OpCodes.Ldc_I4, length << 3);
876 ilgen.Emit (OpCodes.Bge, negate ? l_match : frame.label_fail);
878 // Optimized version for small bitmaps
880 uint bitmap = program [pc];
883 bitmap |= ((uint)program [pc + 1] << 8);
885 bitmap |= ((uint)program [pc + 2] << 16);
887 bitmap |= ((uint)program [pc + 3] << 24);
889 //if ((bitmap >> c) & 1)
890 ilgen.Emit (OpCodes.Ldc_I4, bitmap);
891 ilgen.Emit (OpCodes.Ldloc, local_c);
892 ilgen.Emit (OpCodes.Shr_Un);
893 ilgen.Emit (OpCodes.Ldc_I4_1);
894 ilgen.Emit (OpCodes.And);
895 ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, l1);
897 // if ((program [pc + (c >> 3)] & (1 << (c & 0x7))) != 0) {
898 ilgen.Emit (OpCodes.Ldarg_0);
899 ilgen.Emit (OpCodes.Ldfld, fi_program);
900 ilgen.Emit (OpCodes.Ldloc, local_c);
901 ilgen.Emit (OpCodes.Ldc_I4_3);
902 ilgen.Emit (OpCodes.Shr);
903 ilgen.Emit (OpCodes.Ldc_I4, pc);
904 ilgen.Emit (OpCodes.Add);
905 ilgen.Emit (OpCodes.Ldelem_I1);
906 ilgen.Emit (OpCodes.Ldc_I4_1);
907 ilgen.Emit (OpCodes.Ldloc, local_c);
908 ilgen.Emit (OpCodes.Ldc_I4, 7);
909 ilgen.Emit (OpCodes.And);
910 ilgen.Emit (OpCodes.Shl);
911 ilgen.Emit (OpCodes.And);
912 ilgen.Emit (OpCodes.Ldc_I4_0);
913 ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, l1);
915 ilgen.MarkLabel (l_match);
917 // strpos++ / strpos--;
918 ilgen.Emit (OpCodes.Ldarg_1);
919 ilgen.Emit (OpCodes.Ldc_I4_1);
921 ilgen.Emit (OpCodes.Sub);
923 ilgen.Emit (OpCodes.Add);
924 ilgen.Emit (OpCodes.Starg, 1);
927 ilgen.Emit (OpCodes.Br, l2);
931 ilgen.MarkLabel (l1);
932 ilgen.Emit (OpCodes.Br, frame.label_fail);
934 ilgen.MarkLabel (l2);
940 case RxOp.UnicodeString: {
941 OpFlags flags = (OpFlags)op_flags [pc];
942 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
943 bool reverse = (flags & OpFlags.RightToLeft) > 0;
944 bool unicode = (op == RxOp.UnicodeString);
948 length = ReadShort (program, pc + 1);
951 length = program [pc + 1];
953 //if (strpos + length > string_end)
956 ilgen.Emit (OpCodes.Ldarg_1);
957 ilgen.Emit (OpCodes.Ldc_I4, length);
958 ilgen.Emit (OpCodes.Blt, frame.label_fail);
960 ilgen.Emit (OpCodes.Ldarg_1);
961 ilgen.Emit (OpCodes.Ldc_I4, length);
962 ilgen.Emit (OpCodes.Add);
963 ilgen.Emit (OpCodes.Ldarg_0);
964 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
965 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
968 /* Avoid unsafe code in Moonlight build */
969 #if false && !NET_2_1
971 if (reverse || unicode)
972 throw new NotImplementedException ();
974 LocalBuilder local_strptr = ilgen.DeclareLocal (typeof (char).MakePointerType ());
975 // char *strptr = &str.start_char + strpos
976 ilgen.Emit (OpCodes.Ldarg_0);
977 ilgen.Emit (OpCodes.Ldfld, fi_str);
978 ilgen.Emit (OpCodes.Ldflda, typeof (String).GetField ("start_char", BindingFlags.Instance|BindingFlags.NonPublic));
979 ilgen.Emit (OpCodes.Ldarg_1);
980 ilgen.Emit (OpCodes.Ldc_I4_1);
981 ilgen.Emit (OpCodes.Shl);
982 ilgen.Emit (OpCodes.Add);
983 ilgen.Emit (OpCodes.Stloc, local_strptr);
985 end = start + length;
986 for (i = 0; i < length; ++i) {
987 // if (*(strptr + i) != program [start + i])
990 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
991 ilgen.Emit (OpCodes.Ldloc, local_strptr);
992 ilgen.Emit (OpCodes.Ldc_I4, i * 2);
993 ilgen.Emit (OpCodes.Add);
994 ilgen.Emit (OpCodes.Ldind_I2);
996 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
997 ilgen.Emit (OpCodes.Ldc_I4, (int)program [start + i]);
998 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
1002 ilgen.Emit (OpCodes.Ldarg_1);
1003 ilgen.Emit (OpCodes.Ldc_I4, length);
1004 ilgen.Emit (OpCodes.Add);
1005 ilgen.Emit (OpCodes.Starg, 1);
1008 // Allocate a local for 'str' to save an indirection
1009 LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
1010 ilgen.Emit (OpCodes.Ldarg_0);
1011 ilgen.Emit (OpCodes.Ldfld, fi_str);
1012 ilgen.Emit (OpCodes.Stloc, local_str);
1015 // strpos -= length;
1016 ilgen.Emit (OpCodes.Ldarg_1);
1017 ilgen.Emit (OpCodes.Ldc_I4, length);
1018 ilgen.Emit (OpCodes.Sub);
1019 ilgen.Emit (OpCodes.Starg, 1);
1022 // FIXME: Emit a loop for long strings
1023 end = start + (unicode ? length * 2 : length);
1024 while (start < end) {
1025 //if (str [strpos] != program [start])
1028 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1029 ilgen.Emit (OpCodes.Ldloc, local_str);
1030 ilgen.Emit (OpCodes.Ldarg_1);
1031 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1033 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1034 ilgen.Emit (OpCodes.Ldc_I4, unicode ? ReadShort (program, start) : (int)program [start]);
1035 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
1037 ilgen.Emit (OpCodes.Ldarg_1);
1038 ilgen.Emit (OpCodes.Ldc_I4_1);
1039 ilgen.Emit (OpCodes.Add);
1040 ilgen.Emit (OpCodes.Starg, 1);
1049 // strpos -= length;
1050 ilgen.Emit (OpCodes.Ldarg_1);
1051 ilgen.Emit (OpCodes.Ldc_I4, length);
1052 ilgen.Emit (OpCodes.Sub);
1053 ilgen.Emit (OpCodes.Starg, 1);
1060 case RxOp.OpenGroup: {
1061 //Open (program [pc + 1] | (program [pc + 2] << 8), strpos);
1062 int group_id = ReadShort (program, pc + 1);
1063 ilgen.Emit (OpCodes.Ldarg_0);
1064 ilgen.Emit (OpCodes.Ldc_I4, group_id);
1065 ilgen.Emit (OpCodes.Ldarg_1);
1066 ilgen.Emit (OpCodes.Call, GetMethod ("Open", ref mi_open));
1071 case RxOp.CloseGroup: {
1072 //Close (program [pc + 1] | (program [pc + 2] << 8), strpos);
1073 int group_id = ReadShort (program, pc + 1);
1074 ilgen.Emit (OpCodes.Ldarg_0);
1075 ilgen.Emit (OpCodes.Ldc_I4, group_id);
1076 ilgen.Emit (OpCodes.Ldarg_1);
1077 ilgen.Emit (OpCodes.Call, GetMethod ("Close", ref mi_close));
1083 int target_pc = pc + ReadShort (program, pc + 1);
1084 if (target_pc > end_pc)
1086 * This breaks the our code generation logic, see
1087 * https://bugzilla.novell.com/show_bug.cgi?id=466151
1092 Console.WriteLine ("\tjump target: {0}", target_pc);
1094 labels = new Dictionary <int, Label> ();
1095 Label l = CreateLabelForPC (ilgen, target_pc);
1096 ilgen.Emit (OpCodes.Br, l);
1101 int target1 = pc + ReadShort (program, pc + 1);
1102 int target2 = pc + ReadShort (program, pc + 3);
1105 Console.WriteLine ("\temitting <test_expr>");
1107 // old_stros = strpos;
1108 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1109 ilgen.Emit (OpCodes.Ldarg_1);
1110 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1112 Frame new_frame = new Frame (ilgen);
1113 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 5, target1 < target2 ? target1 : target2, false, false, out pc);
1117 if (trace_compile) {
1118 Console.WriteLine ("\temitted <test_expr>");
1119 Console.WriteLine ("\ttarget1 = {0}", target1);
1120 Console.WriteLine ("\ttarget2 = {0}", target2);
1123 Label l1 = CreateLabelForPC (ilgen, target1);
1124 Label l2 = CreateLabelForPC (ilgen, target2);
1127 ilgen.MarkLabel (new_frame.label_pass);
1128 // strpos = old_strpos;
1129 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1130 ilgen.Emit (OpCodes.Starg, 1);
1131 ilgen.Emit (OpCodes.Br, l1);
1134 ilgen.MarkLabel (new_frame.label_fail);
1135 // strpos = old_strpos;
1136 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1137 ilgen.Emit (OpCodes.Starg, 1);
1138 ilgen.Emit (OpCodes.Br, l2);
1140 // Continue at pc, which should equal to target1
1143 case RxOp.SubExpression: {
1144 int target = pc + ReadShort (program, pc + 1);
1147 Console.WriteLine ("\temitting <sub_expr>");
1149 // old_stros = strpos;
1150 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1151 ilgen.Emit (OpCodes.Ldarg_1);
1152 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1154 Frame new_frame = new Frame (ilgen);
1155 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target, false, false, out pc);
1159 if (trace_compile) {
1160 Console.WriteLine ("\temitted <sub_expr>");
1161 Console.WriteLine ("\ttarget = {0}", target);
1164 Label l1 = CreateLabelForPC (ilgen, target);
1167 ilgen.MarkLabel (new_frame.label_pass);
1168 ilgen.Emit (OpCodes.Br, l1);
1171 ilgen.MarkLabel (new_frame.label_fail);
1172 // strpos = old_strpos;
1173 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1174 ilgen.Emit (OpCodes.Starg, 1);
1175 ilgen.Emit (OpCodes.Br, frame.label_fail);
1177 // Continue at pc, which should equal to target
1180 case RxOp.TestCharGroup: {
1181 int char_group_end = pc + ReadShort (program, pc + 1);
1184 Label label_match = ilgen.DefineLabel ();
1186 /* Determine the negate/reverse flags by examining the first op */
1187 OpFlags flags = (OpFlags)op_flags [pc];
1189 /* Determine whenever this is a negated character class */
1190 /* If it is, then the conditions are ANDed together, not ORed */
1191 bool revert = (flags & OpFlags.Negate) > 0;
1192 bool reverse = (flags & OpFlags.RightToLeft) > 0;
1195 * Generate code for all the matching ops in the group
1197 while (pc < char_group_end) {
1198 Frame new_frame = new Frame (ilgen);
1199 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, Int32.MaxValue, true, true, out pc);
1205 ilgen.MarkLabel (new_frame.label_pass);
1206 ilgen.Emit (OpCodes.Br, label_match);
1209 // Just fall through to the next test
1210 ilgen.MarkLabel (new_frame.label_fail);
1213 // Just fall through to the next test
1214 ilgen.MarkLabel (new_frame.label_pass);
1215 Label l2 = ilgen.DefineLabel ();
1216 ilgen.Emit (OpCodes.Br, l2);
1220 ilgen.MarkLabel (new_frame.label_fail);
1221 ilgen.Emit (OpCodes.Br, frame.label_fail);
1223 ilgen.MarkLabel (l2);
1229 ilgen.Emit (OpCodes.Br, label_match);
1231 // If we reached here, all the matching ops have failed
1232 ilgen.Emit (OpCodes.Br, frame.label_fail);
1235 ilgen.MarkLabel (label_match);
1237 // strpos++ / strpos--;
1238 ilgen.Emit (OpCodes.Ldarg_1);
1239 ilgen.Emit (OpCodes.Ldc_I4_1);
1241 ilgen.Emit (OpCodes.Sub);
1243 ilgen.Emit (OpCodes.Add);
1244 ilgen.Emit (OpCodes.Starg, 1);
1248 case RxOp.FastRepeat:
1249 case RxOp.FastRepeatLazy: {
1251 * A FastRepeat is a simplified version of Repeat which does
1252 * not contain another repeat inside, so backtracking is
1254 * FIXME: Implement faster backtracking versions for
1255 * simple inner exceptions like chars/strings.
1257 bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
1258 int tail = pc + ReadShort (program, pc + 1);
1259 start = ReadInt (program, pc + 3);
1260 end = ReadInt (program, pc + 7);
1261 //Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);
1264 ilgen.Emit (OpCodes.Ldarg_0);
1265 ilgen.Emit (OpCodes.Ldnull);
1266 ilgen.Emit (OpCodes.Stfld, fi_deep);
1268 LocalBuilder local_length = ilgen.DeclareLocal (typeof (int));
1270 ilgen.Emit (OpCodes.Ldc_I4_0);
1271 ilgen.Emit (OpCodes.Stloc, local_length);
1273 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1275 // First match at least 'start' items
1277 //for (length = 0; length < start; ++length) {
1278 Label l_loop_footer = ilgen.DefineLabel ();
1279 ilgen.Emit (OpCodes.Br, l_loop_footer);
1280 Label l_loop_body = ilgen.DefineLabel ();
1281 ilgen.MarkLabel (l_loop_body);
1283 // int old_strpos = strpos;
1284 ilgen.Emit (OpCodes.Ldarg_1);
1285 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1287 // if (!EvalByteCode (pc + 11, strpos, ref res))
1288 Frame new_frame = new Frame (ilgen);
1289 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1295 ilgen.MarkLabel (new_frame.label_fail);
1296 ilgen.Emit (OpCodes.Br, frame.label_fail);
1299 ilgen.MarkLabel (new_frame.label_pass);
1301 ilgen.Emit (OpCodes.Ldloc, local_length);
1302 ilgen.Emit (OpCodes.Ldc_I4_1);
1303 ilgen.Emit (OpCodes.Add);
1304 ilgen.Emit (OpCodes.Stloc, local_length);
1306 ilgen.MarkLabel (l_loop_footer);
1307 ilgen.Emit (OpCodes.Ldloc, local_length);
1308 ilgen.Emit (OpCodes.Ldc_I4, start);
1309 ilgen.Emit (OpCodes.Blt, l_loop_body);
1313 Label l_loop_footer = ilgen.DefineLabel ();
1315 ilgen.Emit (OpCodes.Br, l_loop_footer);
1316 Label l_loop_body = ilgen.DefineLabel ();
1317 ilgen.MarkLabel (l_loop_body);
1319 // int cp = Checkpoint ();
1320 LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
1321 ilgen.Emit (OpCodes.Ldarg_0);
1322 ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
1323 ilgen.Emit (OpCodes.Stloc, local_cp);
1325 // int old_strpos = strpos;
1326 ilgen.Emit (OpCodes.Ldarg_1);
1327 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1329 // if (EvalByteCode (tail, strpos, ref res)) {
1330 Frame new_frame = new Frame (ilgen);
1331 m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
1336 ilgen.MarkLabel (new_frame.label_pass);
1338 ilgen.Emit (OpCodes.Br, frame.label_pass);
1341 ilgen.MarkLabel (new_frame.label_fail);
1343 ilgen.Emit (OpCodes.Ldarg_0);
1344 ilgen.Emit (OpCodes.Ldloc, local_cp);
1345 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1346 // strpos = old_strpos;
1347 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1348 ilgen.Emit (OpCodes.Starg, 1);
1350 //if (length >= end)
1352 ilgen.Emit (OpCodes.Ldloc, local_length);
1353 ilgen.Emit (OpCodes.Ldc_I4, end);
1354 ilgen.Emit (OpCodes.Bge, frame.label_fail);
1357 //if (!EvalByteCode (pc + 11, strpos, ref res))
1358 new_frame = new Frame (ilgen);
1359 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1364 ilgen.MarkLabel (new_frame.label_pass);
1366 ilgen.Emit (OpCodes.Ldloc, local_length);
1367 ilgen.Emit (OpCodes.Ldc_I4_1);
1368 ilgen.Emit (OpCodes.Add);
1369 ilgen.Emit (OpCodes.Stloc, local_length);
1370 ilgen.Emit (OpCodes.Br, l_loop_body);
1373 ilgen.MarkLabel (new_frame.label_fail);
1375 ilgen.Emit (OpCodes.Br, frame.label_fail);
1378 ilgen.MarkLabel (l_loop_footer);
1379 ilgen.Emit (OpCodes.Br, l_loop_body);
1381 // Then match as many items as possible, recording
1382 // backtracking information
1384 //int old_stack_size = stack.Count;
1385 LocalBuilder local_old_stack_size = ilgen.DeclareLocal (typeof (int));
1386 ilgen.Emit (OpCodes.Ldarg_0);
1387 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1388 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
1389 ilgen.Emit (OpCodes.Stloc, local_old_stack_size);
1390 //while (length < end) {
1391 Label l_loop_footer = ilgen.DefineLabel ();
1392 ilgen.Emit (OpCodes.Br, l_loop_footer);
1393 Label l_loop_body = ilgen.DefineLabel ();
1394 ilgen.MarkLabel (l_loop_body);
1395 // int cp = Checkpoint ();
1396 LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
1397 ilgen.Emit (OpCodes.Ldarg_0);
1398 ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
1399 ilgen.Emit (OpCodes.Stloc, local_cp);
1401 // int old_strpos = strpos;
1402 ilgen.Emit (OpCodes.Ldarg_1);
1403 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1405 // if (!EvalByteCode (pc + 11, strpos, ref res)) {
1406 Frame new_frame = new Frame (ilgen);
1407 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1412 ilgen.MarkLabel (new_frame.label_fail);
1413 // strpos = old_strpos
1414 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1415 ilgen.Emit (OpCodes.Starg, 1);
1417 ilgen.Emit (OpCodes.Ldarg_0);
1418 ilgen.Emit (OpCodes.Ldloc, local_cp);
1419 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1422 Label l_after_loop = ilgen.DefineLabel ();
1423 ilgen.Emit (OpCodes.Br, l_after_loop);
1426 ilgen.MarkLabel (new_frame.label_pass);
1429 ilgen.Emit (OpCodes.Ldarg_0);
1430 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1431 ilgen.Emit (OpCodes.Ldloc, local_cp);
1432 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
1433 //stack.Push (strpos);
1434 ilgen.Emit (OpCodes.Ldarg_0);
1435 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1436 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1437 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
1439 ilgen.Emit (OpCodes.Ldloc, local_length);
1440 ilgen.Emit (OpCodes.Ldc_I4_1);
1441 ilgen.Emit (OpCodes.Add);
1442 ilgen.Emit (OpCodes.Stloc, local_length);
1444 ilgen.MarkLabel (l_loop_footer);
1445 ilgen.Emit (OpCodes.Ldloc, local_length);
1446 ilgen.Emit (OpCodes.Ldc_I4, end);
1447 ilgen.Emit (OpCodes.Blt, l_loop_body);
1449 ilgen.MarkLabel (l_after_loop);
1451 // Then, match the tail, backtracking as necessary.
1454 l_loop_footer = ilgen.DefineLabel ();
1455 ilgen.Emit (OpCodes.Br, l_loop_footer);
1456 l_loop_body = ilgen.DefineLabel ();
1457 ilgen.MarkLabel (l_loop_body);
1459 if (RxInterpreter.trace_rx) {
1460 ilgen.Emit (OpCodes.Ldstr, "matching tail at: {0}");
1461 ilgen.Emit (OpCodes.Ldarg_1);
1462 ilgen.Emit (OpCodes.Box, typeof (int));
1463 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1466 // if (EvalByteCode (tail, strpos, ref res)) {
1467 new_frame = new Frame (ilgen);
1468 m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
1473 ilgen.MarkLabel (new_frame.label_pass);
1475 if (RxInterpreter.trace_rx) {
1476 ilgen.Emit (OpCodes.Ldstr, "tail matched at: {0}");
1477 ilgen.Emit (OpCodes.Ldarg_1);
1478 ilgen.Emit (OpCodes.Box, typeof (int));
1479 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1482 // stack.Count = old_stack_size;
1483 ilgen.Emit (OpCodes.Ldarg_0);
1484 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1485 ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
1486 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "set_Count", ref mi_stack_set_count));
1488 ilgen.Emit (OpCodes.Br, frame.label_pass);
1491 ilgen.MarkLabel (new_frame.label_fail);
1493 if (RxInterpreter.trace_rx) {
1494 ilgen.Emit (OpCodes.Ldstr, "tail failed to match at: {0}");
1495 ilgen.Emit (OpCodes.Ldarg_1);
1496 ilgen.Emit (OpCodes.Box, typeof (int));
1497 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1500 // if (stack.Count == old_stack_size)
1502 ilgen.Emit (OpCodes.Ldarg_0);
1503 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1504 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
1505 ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
1506 ilgen.Emit (OpCodes.Beq, frame.label_fail);
1509 //strpos = stack.Pop ();
1510 ilgen.Emit (OpCodes.Ldarg_0);
1511 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1512 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
1513 ilgen.Emit (OpCodes.Starg, 1);
1514 //Backtrack (stack.Pop ());
1515 ilgen.Emit (OpCodes.Ldarg_0);
1516 ilgen.Emit (OpCodes.Ldarg_0);
1517 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1518 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
1519 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1521 if (RxInterpreter.trace_rx) {
1522 //Console.WriteLine ("backtracking to: {0}", strpos);
1523 ilgen.Emit (OpCodes.Ldstr, "backtracking to: {0}");
1524 ilgen.Emit (OpCodes.Ldarg_1);
1525 ilgen.Emit (OpCodes.Box, typeof (int));
1526 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1530 ilgen.MarkLabel (l_loop_footer);
1531 ilgen.Emit (OpCodes.Br, l_loop_body);
1534 // We already processed the tail
1539 case RxOp.CategoryAny:
1540 case RxOp.CategoryAnySingleline:
1541 case RxOp.CategoryWord:
1542 case RxOp.CategoryDigit:
1543 case RxOp.CategoryWhiteSpace:
1544 case RxOp.CategoryEcmaWord:
1545 case RxOp.CategoryEcmaWhiteSpace:
1546 case RxOp.CategoryUnicodeSpecials:
1547 case RxOp.CategoryUnicode: {
1548 OpFlags flags = (OpFlags)op_flags [pc];
1549 bool negate = (flags & OpFlags.Negate) > 0;
1550 bool reverse = (flags & OpFlags.RightToLeft) > 0;
1552 //if (strpos < string_end) {
1553 Label l_nomatch = ilgen.DefineLabel ();
1555 ilgen.Emit (OpCodes.Ldarg_1);
1556 ilgen.Emit (OpCodes.Ldc_I4_0);
1557 ilgen.Emit (OpCodes.Ble, l_nomatch);
1559 ilgen.Emit (OpCodes.Ldarg_1);
1560 ilgen.Emit (OpCodes.Ldarg_0);
1561 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
1562 ilgen.Emit (OpCodes.Bge, l_nomatch);
1565 // int c = str [strpos];
1566 LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
1567 ilgen.Emit (OpCodes.Ldarg_0);
1568 ilgen.Emit (OpCodes.Ldfld, fi_str);
1569 ilgen.Emit (OpCodes.Ldarg_1);
1571 ilgen.Emit (OpCodes.Ldc_I4_1);
1572 ilgen.Emit (OpCodes.Sub);
1574 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1575 ilgen.Emit (OpCodes.Stloc, local_c);
1577 Label l_match = ilgen.DefineLabel ();
1579 Label l_true, l_false;
1581 l_true = negate ? l_nomatch : l_match;
1582 l_false = negate ? l_match : l_nomatch;
1585 case RxOp.CategoryAny:
1586 // if (str [strpos] != '\n') {
1587 ilgen.Emit (OpCodes.Ldloc, local_c);
1588 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
1589 ilgen.Emit (OpCodes.Bne_Un, l_true);
1591 case RxOp.CategoryAnySingleline:
1592 ilgen.Emit (OpCodes.Br, l_true);
1594 case RxOp.CategoryWord:
1595 // if (Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation) {
1596 ilgen.Emit (OpCodes.Ldloc, local_c);
1597 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsLetterOrDigit", new Type [] { typeof (char) }));
1598 ilgen.Emit (OpCodes.Brtrue, l_true);
1599 ilgen.Emit (OpCodes.Ldloc, local_c);
1600 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
1601 ilgen.Emit (OpCodes.Ldc_I4, (int)UnicodeCategory.ConnectorPunctuation);
1602 ilgen.Emit (OpCodes.Beq, l_true);
1604 case RxOp.CategoryDigit:
1605 // if (Char.IsDigit (c)) {
1606 ilgen.Emit (OpCodes.Ldloc, local_c);
1607 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsDigit", new Type [] { typeof (char) }));
1608 ilgen.Emit (OpCodes.Brtrue, l_true);
1610 case RxOp.CategoryWhiteSpace:
1611 // if (Char.IsWhiteSpace (c)) {
1612 ilgen.Emit (OpCodes.Ldloc, local_c);
1613 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsWhiteSpace", new Type [] { typeof (char) }));
1614 ilgen.Emit (OpCodes.Brtrue, l_true);
1616 case RxOp.CategoryEcmaWord:
1617 // if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_') {
1618 ilgen.Emit (OpCodes.Ldloc, local_c);
1619 ilgen.Emit (OpCodes.Ldc_I4, (int)'a' - 1);
1620 ilgen.Emit (OpCodes.Cgt);
1621 ilgen.Emit (OpCodes.Ldloc, local_c);
1622 ilgen.Emit (OpCodes.Ldc_I4, (int)'z' + 1);
1623 ilgen.Emit (OpCodes.Clt);
1624 ilgen.Emit (OpCodes.And);
1625 ilgen.Emit (OpCodes.Brtrue, l_true);
1627 ilgen.Emit (OpCodes.Ldloc, local_c);
1628 ilgen.Emit (OpCodes.Ldc_I4, (int)'A' - 1);
1629 ilgen.Emit (OpCodes.Cgt);
1630 ilgen.Emit (OpCodes.Ldloc, local_c);
1631 ilgen.Emit (OpCodes.Ldc_I4, (int)'Z' + 1);
1632 ilgen.Emit (OpCodes.Clt);
1633 ilgen.Emit (OpCodes.And);
1634 ilgen.Emit (OpCodes.Brtrue, l_true);
1636 ilgen.Emit (OpCodes.Ldloc, local_c);
1637 ilgen.Emit (OpCodes.Ldc_I4, (int)'0' - 1);
1638 ilgen.Emit (OpCodes.Cgt);
1639 ilgen.Emit (OpCodes.Ldloc, local_c);
1640 ilgen.Emit (OpCodes.Ldc_I4, (int)'9' + 1);
1641 ilgen.Emit (OpCodes.Clt);
1642 ilgen.Emit (OpCodes.And);
1643 ilgen.Emit (OpCodes.Brtrue, l_true);
1645 ilgen.Emit (OpCodes.Ldloc, local_c);
1646 ilgen.Emit (OpCodes.Ldc_I4, (int)'_');
1647 ilgen.Emit (OpCodes.Beq, l_true);
1649 case RxOp.CategoryEcmaWhiteSpace:
1650 // if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') {
1651 ilgen.Emit (OpCodes.Ldloc, local_c);
1652 ilgen.Emit (OpCodes.Ldc_I4, (int)' ');
1653 ilgen.Emit (OpCodes.Beq, l_true);
1654 ilgen.Emit (OpCodes.Ldloc, local_c);
1655 ilgen.Emit (OpCodes.Ldc_I4, (int)'\t');
1656 ilgen.Emit (OpCodes.Beq, l_true);
1657 ilgen.Emit (OpCodes.Ldloc, local_c);
1658 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
1659 ilgen.Emit (OpCodes.Beq, l_true);
1660 ilgen.Emit (OpCodes.Ldloc, local_c);
1661 ilgen.Emit (OpCodes.Ldc_I4, (int)'\r');
1662 ilgen.Emit (OpCodes.Beq, l_true);
1663 ilgen.Emit (OpCodes.Ldloc, local_c);
1664 ilgen.Emit (OpCodes.Ldc_I4, (int)'\f');
1665 ilgen.Emit (OpCodes.Beq, l_true);
1666 ilgen.Emit (OpCodes.Ldloc, local_c);
1667 ilgen.Emit (OpCodes.Ldc_I4, (int)'\v');
1668 ilgen.Emit (OpCodes.Beq, l_true);
1670 case RxOp.CategoryUnicodeSpecials:
1671 // if ('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD') {
1672 ilgen.Emit (OpCodes.Ldloc, local_c);
1673 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' - 1);
1674 ilgen.Emit (OpCodes.Cgt);
1675 ilgen.Emit (OpCodes.Ldloc, local_c);
1676 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' + 1);
1677 ilgen.Emit (OpCodes.Clt);
1678 ilgen.Emit (OpCodes.And);
1679 ilgen.Emit (OpCodes.Brtrue, l_true);
1681 ilgen.Emit (OpCodes.Ldloc, local_c);
1682 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFF0' - 1);
1683 ilgen.Emit (OpCodes.Cgt);
1684 ilgen.Emit (OpCodes.Ldloc, local_c);
1685 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFFD' + 1);
1686 ilgen.Emit (OpCodes.Clt);
1687 ilgen.Emit (OpCodes.And);
1688 ilgen.Emit (OpCodes.Brtrue, l_true);
1690 case RxOp.CategoryUnicode:
1691 // if (Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]) {
1692 ilgen.Emit (OpCodes.Ldloc, local_c);
1693 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
1694 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
1695 ilgen.Emit (OpCodes.Beq, l_true);
1699 ilgen.Emit (OpCodes.Br, l_false);
1701 ilgen.MarkLabel (l_match);
1705 ilgen.Emit (OpCodes.Ldarg_1);
1706 ilgen.Emit (OpCodes.Ldc_I4_1);
1708 ilgen.Emit (OpCodes.Sub);
1710 ilgen.Emit (OpCodes.Add);
1711 ilgen.Emit (OpCodes.Starg, 1);
1714 Label l2 = ilgen.DefineLabel ();
1715 ilgen.Emit (OpCodes.Br, l2);
1717 ilgen.MarkLabel (l_nomatch);
1719 ilgen.Emit (OpCodes.Br, frame.label_fail);
1721 ilgen.MarkLabel (l2);
1723 if (op == RxOp.CategoryUnicode)
1729 case RxOp.Reference: {
1730 OpFlags flags = (OpFlags)op_flags [pc];
1731 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
1732 bool reverse = (flags & OpFlags.RightToLeft) > 0;
1734 //length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
1735 LocalBuilder loc_length = ilgen.DeclareLocal (typeof (int));
1736 ilgen.Emit (OpCodes.Ldarg_0);
1737 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
1738 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "GetLastDefined", ref mi_get_last_defined));
1739 ilgen.Emit (OpCodes.Stloc, loc_length);
1742 ilgen.Emit (OpCodes.Ldloc, loc_length);
1743 ilgen.Emit (OpCodes.Ldc_I4_0);
1744 ilgen.Emit (OpCodes.Blt, frame.label_fail);
1745 //start = marks [length].Index;
1746 LocalBuilder loc_start = ilgen.DeclareLocal (typeof (int));
1747 ilgen.Emit (OpCodes.Ldarg_0);
1748 ilgen.Emit (OpCodes.Ldfld, fi_marks);
1749 ilgen.Emit (OpCodes.Ldloc, loc_length);
1750 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
1751 ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Index", ref mi_mark_get_index));
1752 ilgen.Emit (OpCodes.Stloc, loc_start);
1753 // length = marks [length].Length;
1754 ilgen.Emit (OpCodes.Ldarg_0);
1755 ilgen.Emit (OpCodes.Ldfld, fi_marks);
1756 ilgen.Emit (OpCodes.Ldloc, loc_length);
1757 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
1758 ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Length", ref mi_mark_get_length));
1759 ilgen.Emit (OpCodes.Stloc, loc_length);
1762 ilgen.Emit (OpCodes.Ldarg_1);
1763 ilgen.Emit (OpCodes.Ldloc, loc_length);
1764 ilgen.Emit (OpCodes.Sub);
1765 ilgen.Emit (OpCodes.Starg, 1);
1768 ilgen.Emit (OpCodes.Ldarg_1);
1769 ilgen.Emit (OpCodes.Ldc_I4_0);
1770 ilgen.Emit (OpCodes.Blt, frame.label_fail);
1772 //if (strpos + length > string_end)
1774 ilgen.Emit (OpCodes.Ldarg_1);
1775 ilgen.Emit (OpCodes.Ldloc, loc_length);
1776 ilgen.Emit (OpCodes.Add);
1777 ilgen.Emit (OpCodes.Ldarg_0);
1778 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
1779 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
1782 LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
1783 ilgen.Emit (OpCodes.Ldarg_0);
1784 ilgen.Emit (OpCodes.Ldfld, fi_str);
1785 ilgen.Emit (OpCodes.Stloc, local_str);
1787 // end = start + length;
1788 LocalBuilder loc_end = ilgen.DeclareLocal (typeof (int));
1789 ilgen.Emit (OpCodes.Ldloc, loc_start);
1790 ilgen.Emit (OpCodes.Ldloc, loc_length);
1791 ilgen.Emit (OpCodes.Add);
1792 ilgen.Emit (OpCodes.Stloc, loc_end);
1793 //for (; start < end; ++start) {
1794 Label l_loop_footer = ilgen.DefineLabel ();
1795 ilgen.Emit (OpCodes.Br, l_loop_footer);
1796 Label l_loop_body = ilgen.DefineLabel ();
1797 ilgen.MarkLabel (l_loop_body);
1798 //if (str [strpos] != str [start])
1801 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1802 ilgen.Emit (OpCodes.Ldloc, local_str);
1803 ilgen.Emit (OpCodes.Ldarg_1);
1804 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1806 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1808 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1809 ilgen.Emit (OpCodes.Ldloc, local_str);
1810 ilgen.Emit (OpCodes.Ldloc, loc_start);
1811 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1813 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1814 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
1816 ilgen.Emit (OpCodes.Ldarg_1);
1817 ilgen.Emit (OpCodes.Ldc_I4_1);
1818 ilgen.Emit (OpCodes.Add);
1819 ilgen.Emit (OpCodes.Starg, 1);
1821 ilgen.Emit (OpCodes.Ldloc, loc_start);
1822 ilgen.Emit (OpCodes.Ldc_I4_1);
1823 ilgen.Emit (OpCodes.Add);
1824 ilgen.Emit (OpCodes.Stloc, loc_start);
1826 ilgen.MarkLabel (l_loop_footer);
1827 ilgen.Emit (OpCodes.Ldloc, loc_start);
1828 ilgen.Emit (OpCodes.Ldloc, loc_end);
1829 ilgen.Emit (OpCodes.Blt, l_loop_body);
1833 ilgen.Emit (OpCodes.Ldarg_1);
1834 ilgen.Emit (OpCodes.Ldloc, loc_length);
1835 ilgen.Emit (OpCodes.Sub);
1836 ilgen.Emit (OpCodes.Starg, 1);
1843 case RxOp.RepeatLazy:
1844 case RxOp.IfDefined:
1846 if (RxInterpreter.trace_rx || trace_compile)
1847 Console.WriteLine ("Opcode " + op + " not supported.");
1850 throw new NotImplementedException ("Opcode '" + op + "' not supported by the regex->IL compiler.");
1865 class CILCompiler : RxCompiler {