2 using System.Collections;
3 using System.Globalization;
4 using System.Reflection;
5 using System.Reflection.Emit;
6 using System.Threading;
8 using System.Collections.Generic;
10 namespace System.Text.RegularExpressions {
13 // Compiler which generates IL bytecode to perform the matching instead of
14 // interpreting a program.
15 // For simplicity, we inherit from RxCompiler, and generate the IL code based
16 // on the program generated by it. This also allows us to fallback to interpretation
17 // if we can't handle something.
18 // This is net 2.0, since 1.0 doesn't support DynamicMethods
19 // FIXME: Add support for 1.0, and CompileToAssembly
20 // FIXME: Overwrite RxCompiler methods so we don't have to decode char
24 class CILCompiler : RxCompiler, ICompiler {
25 DynamicMethod[] eval_methods;
26 bool[] eval_methods_defined;
29 * To avoid the overhead of decoding the countless opcode variants created
30 * by RxCompiler, we save the original, 'generic' version and its flags
31 * in these two tables.
33 private Dictionary<int, int> generic_ops;
34 private Dictionary<int, int> op_flags;
35 private Dictionary<int, Label> labels;
37 static FieldInfo fi_str = typeof (RxInterpreter).GetField ("str", BindingFlags.Instance|BindingFlags.NonPublic);
38 static FieldInfo fi_string_start = typeof (RxInterpreter).GetField ("string_start", BindingFlags.Instance|BindingFlags.NonPublic);
39 static FieldInfo fi_string_end = typeof (RxInterpreter).GetField ("string_end", BindingFlags.Instance|BindingFlags.NonPublic);
40 static FieldInfo fi_program = typeof (RxInterpreter).GetField ("program", BindingFlags.Instance|BindingFlags.NonPublic);
41 static FieldInfo fi_marks = typeof (RxInterpreter).GetField ("marks", BindingFlags.Instance|BindingFlags.NonPublic);
42 static FieldInfo fi_groups = typeof (RxInterpreter).GetField ("groups", BindingFlags.Instance|BindingFlags.NonPublic);
43 static FieldInfo fi_deep = typeof (RxInterpreter).GetField ("deep", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
44 static FieldInfo fi_stack = typeof (RxInterpreter).GetField ("stack", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
45 static FieldInfo fi_mark_start = typeof (Mark).GetField ("Start", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
46 static FieldInfo fi_mark_end = typeof (Mark).GetField ("End", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
47 //static FieldInfo fi_mark_index = typeof (Mark).GetField ("Index", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
49 static MethodInfo mi_stack_get_count, mi_stack_set_count, mi_stack_push, mi_stack_pop;
50 static MethodInfo mi_set_start_of_match, mi_is_word_char, mi_reset_groups;
51 static MethodInfo mi_checkpoint, mi_backtrack, mi_open, mi_close;
52 static MethodInfo mi_get_last_defined, mi_mark_get_index, mi_mark_get_length;
54 public static readonly bool trace_compile = Environment.GetEnvironmentVariable ("MONO_TRACE_RX_COMPILE") != null;
56 public CILCompiler () {
57 generic_ops = new Dictionary <int, int> ();
58 op_flags = new Dictionary <int, int> ();
61 IMachineFactory ICompiler.GetMachineFactory () {
62 byte[] code = new byte [curpos];
63 Buffer.BlockCopy (program, 0, code, 0, curpos);
65 eval_methods = new DynamicMethod [code.Length];
66 eval_methods_defined = new bool [code.Length];
68 // The main eval method
69 DynamicMethod main = GetEvalMethod (code, 11);
72 return new RxInterpreterFactory (code, (EvalDelegate)main.CreateDelegate (typeof (EvalDelegate)));
74 return new RxInterpreterFactory (code, null);
77 DynamicMethod GetEvalMethod (byte[] program, int pc) {
78 if (eval_methods_defined [pc])
79 return eval_methods [pc];
82 eval_methods_defined [pc] = true;
84 eval_methods [pc] = CreateEvalMethod (program, pc);
85 return eval_methods [pc];
88 private MethodInfo GetMethod (Type t, string name, ref MethodInfo cached) {
90 cached = t.GetMethod (name, BindingFlags.Static|BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
92 throw new Exception ("Method not found: " + name);
97 private MethodInfo GetMethod (string name, ref MethodInfo cached) {
98 return GetMethod (typeof (RxInterpreter), name, ref cached);
101 private int ReadInt (byte[] code, int pc) {
103 val |= code [pc + 1] << 8;
104 val |= code [pc + 2] << 16;
105 val |= code [pc + 3] << 24;
109 static OpFlags MakeFlags (bool negate, bool ignore, bool reverse, bool lazy) {
111 if (negate) flags |= OpFlags.Negate;
112 if (ignore) flags |= OpFlags.IgnoreCase;
113 if (reverse) flags |= OpFlags.RightToLeft;
114 if (lazy) flags |= OpFlags.Lazy;
119 void EmitGenericOp (RxOp op, bool negate, bool ignore, bool reverse, bool lazy) {
120 generic_ops [curpos] = (int)op;
121 op_flags [curpos] = (int)MakeFlags (negate, ignore, reverse, false);
124 public override void EmitOp (RxOp op, bool negate, bool ignore, bool reverse) {
125 EmitGenericOp (op, negate, ignore, reverse, false);
126 base.EmitOp (op, negate, ignore, reverse);
129 public override void EmitOpIgnoreReverse (RxOp op, bool ignore, bool reverse) {
130 EmitGenericOp (op, false, ignore, reverse, false);
131 base.EmitOpIgnoreReverse (op, ignore, reverse);
134 public override void EmitOpNegateReverse (RxOp op, bool negate, bool reverse) {
135 EmitGenericOp (op, negate, false, reverse, false);
136 base.EmitOpNegateReverse (op, negate, reverse);
140 public Label label_pass, label_fail;
142 public Frame (ILGenerator ilgen) {
143 label_fail = ilgen.DefineLabel ();
144 label_pass = ilgen.DefineLabel ();
148 LocalBuilder local_textinfo;
151 * Create a dynamic method which is equivalent to the RxInterpreter.EvalByteCode
152 * method specialized to the given program and a given pc. Return the newly
153 * created method or null if a not-supported opcode was encountered.
155 DynamicMethod CreateEvalMethod (byte[] program, int pc) {
156 DynamicMethod m = new DynamicMethod ("Eval_" + pc, typeof (bool), new Type [] { typeof (RxInterpreter), typeof (int), typeof (int).MakeByRefType () }, typeof (RxInterpreter), true);
157 ILGenerator ilgen = m.GetILGenerator ();
167 * Recursive calls to EvalByteCode are inlined manually by calling
168 * EmitEvalMethodBody with the pc of the recursive call. Frame objects hold
169 * the information required to link together the code generated by the recursive
170 * call with the rest of the code.
172 Frame frame = new Frame (ilgen);
174 /* Cache the textinfo used by Char.ToLower () */
175 local_textinfo = ilgen.DeclareLocal (typeof (TextInfo));
176 ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentThread"));
177 ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentCulture"));
178 ilgen.Emit (OpCodes.Call, typeof (CultureInfo).GetMethod ("get_TextInfo"));
179 ilgen.Emit (OpCodes.Stloc, local_textinfo);
181 m = EmitEvalMethodBody (m, ilgen, frame, program, pc, program.Length, false, false, out pc);
185 ilgen.MarkLabel (frame.label_pass);
186 ilgen.Emit (OpCodes.Ldarg_2);
187 ilgen.Emit (OpCodes.Ldarg_1);
188 ilgen.Emit (OpCodes.Stind_I4);
189 ilgen.Emit (OpCodes.Ldc_I4_1);
190 ilgen.Emit (OpCodes.Ret);
192 ilgen.MarkLabel (frame.label_fail);
193 ilgen.Emit (OpCodes.Ldc_I4_0);
194 ilgen.Emit (OpCodes.Ret);
199 private int ReadShort (byte[] program, int pc) {
200 return (int)program [pc] | ((int)program [pc + 1] << 8);
203 private Label CreateLabelForPC (ILGenerator ilgen, int pc) {
205 labels = new Dictionary <int, Label> ();
207 if (!labels.TryGetValue (pc, out l)) {
208 l = ilgen.DefineLabel ();
215 private int GetILOffset (ILGenerator ilgen) {
216 return (int)typeof (ILGenerator).GetField ("code_len", BindingFlags.Instance|BindingFlags.NonPublic).GetValue (ilgen);
220 * Emit IL code for a sequence of opcodes between pc and end_pc. If there is a
221 * match, set strpos (Arg 1) to the position after the match, then
222 * branch to frame.label_pass. Otherwise branch to frame.label_fail,
223 * and leave strpos at an undefined position. The caller should
224 * generate code to save the original value of strpos if it needs it.
225 * If one_op is true, only generate code for one opcode and set out_pc
226 * to the next pc after the opcode.
227 * If no_bump is true, don't bump strpos in char matching opcodes.
228 * Keep this in synch with RxInterpreter.EvalByteCode (). It it is sync with
229 * the version in r111969.
230 * FIXME: Modify the regex tests so they are run with RegexOptions.Compiled as
233 private DynamicMethod EmitEvalMethodBody (DynamicMethod m, ILGenerator ilgen,
234 Frame frame, byte[] program,
236 bool one_op, bool no_bump,
239 int start, length, end;
243 int group_count = 1 + ReadShort (program, 1);
245 while (pc < end_pc) {
246 RxOp op = (RxOp)program [pc];
248 // FIXME: Optimize this
249 if (generic_ops.ContainsKey (pc))
250 op = (RxOp)generic_ops [pc];
253 Console.WriteLine ("compiling {0} pc={1} end_pc={2}, il_offset=0x{3:x}", op, pc, end_pc, GetILOffset (ilgen));
256 if (labels != null) {
258 if (labels.TryGetValue (pc, out l)) {
264 if (RxInterpreter.trace_rx) {
265 //Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", op, pc, strpos);
266 ilgen.Emit (OpCodes.Ldstr, "evaluating: {0} at pc: {1}, strpos: {2}");
267 ilgen.Emit (OpCodes.Ldc_I4, (int)op);
268 ilgen.Emit (OpCodes.Box, typeof (RxOp));
269 ilgen.Emit (OpCodes.Ldc_I4, pc);
270 ilgen.Emit (OpCodes.Box, typeof (int));
271 ilgen.Emit (OpCodes.Ldarg_1);
272 ilgen.Emit (OpCodes.Box, typeof (int));
273 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object), typeof (object), typeof (object) }));
278 case RxOp.AnchorReverse: {
279 bool reverse = (RxOp)program [pc] == RxOp.AnchorReverse;
280 length = ReadShort (program, pc + 3);
281 pc += ReadShort (program, pc + 1);
283 // Optimize some common cases by inlining the code generated for the
285 RxOp anch_op = (RxOp)program [pc];
287 // FIXME: Do this even if the archor op is not the last in the regex
288 if (!reverse && group_count == 1 && anch_op == RxOp.Char && (RxOp)program [pc + 2] == RxOp.True) {
291 * while (strpos < string_end) {
292 * if (str [strpos] == program [pc + 1]) {
293 * match_start = strpos;
294 * strpos_result = strpos + 1;
295 * marks [groups [0]].Start = strpos;
296 * if (groups.Length > 1)
297 * marks [groups [0]].End = res;
304 // Add some locals to avoid an indirection
305 LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
306 ilgen.Emit (OpCodes.Ldarg_0);
307 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
308 ilgen.Emit (OpCodes.Stloc, local_string_end);
309 LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
310 ilgen.Emit (OpCodes.Ldarg_0);
311 ilgen.Emit (OpCodes.Ldfld, fi_str);
312 ilgen.Emit (OpCodes.Stloc, local_str);
314 //while (strpos < string_end) {
315 // -> Done at the end of the loop like mcs does
316 Label l1 = ilgen.DefineLabel ();
317 Label l2 = ilgen.DefineLabel ();
318 ilgen.Emit (OpCodes.Br, l2);
319 ilgen.MarkLabel (l1);
321 // if (str [strpos] == program [pc + 1]) {
322 Label l3 = ilgen.DefineLabel ();
323 ilgen.Emit (OpCodes.Ldloc, local_str);
324 ilgen.Emit (OpCodes.Ldarg_1);
325 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
326 ilgen.Emit (OpCodes.Conv_I4);
327 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
328 ilgen.Emit (OpCodes.Beq, l3);
330 // The true case is done after the loop
334 ilgen.Emit (OpCodes.Ldarg_1);
335 ilgen.Emit (OpCodes.Ldc_I4_1);
336 ilgen.Emit (OpCodes.Add);
337 ilgen.Emit (OpCodes.Starg, 1);
339 ilgen.MarkLabel (l2);
340 ilgen.Emit (OpCodes.Ldarg_1);
341 ilgen.Emit (OpCodes.Ldloc, local_string_end);
342 ilgen.Emit (OpCodes.Blt, l1);
345 ilgen.Emit (OpCodes.Br, frame.label_fail);
348 ilgen.MarkLabel (l3);
349 // call SetStartOfMatch (strpos)
350 ilgen.Emit (OpCodes.Ldarg_0);
351 ilgen.Emit (OpCodes.Ldarg_1);
352 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "SetStartOfMatch", ref mi_set_start_of_match));
354 ilgen.Emit (OpCodes.Ldarg_1);
355 ilgen.Emit (OpCodes.Ldc_I4_1);
356 ilgen.Emit (OpCodes.Add);
357 ilgen.Emit (OpCodes.Starg, 1);
359 ilgen.Emit (OpCodes.Br, frame.label_pass);
364 //Console.WriteLine ("Anchor op " + anch_op);
366 // Add some locals to avoid an indirection
367 LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
368 ilgen.Emit (OpCodes.Ldarg_0);
369 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
370 ilgen.Emit (OpCodes.Ldc_I4_1);
371 ilgen.Emit (OpCodes.Add);
372 ilgen.Emit (OpCodes.Stloc, local_string_end);
374 //while (strpos < string_end + 1) {
375 // -> Done at the end of the loop like mcs does
376 Label l1 = ilgen.DefineLabel ();
377 Label l2 = ilgen.DefineLabel ();
378 ilgen.Emit (OpCodes.Br, l2);
379 ilgen.MarkLabel (l1);
381 //if (groups.Length > 1) {
383 // marks [groups [0]].Start = strpos;
385 if (group_count > 1) {
386 ilgen.Emit (OpCodes.Ldarg_0);
387 ilgen.Emit (OpCodes.Call, GetMethod ("ResetGroups", ref mi_reset_groups));
389 ilgen.Emit (OpCodes.Ldarg_0);
390 ilgen.Emit (OpCodes.Ldfld, fi_marks);
391 ilgen.Emit (OpCodes.Ldarg_0);
392 ilgen.Emit (OpCodes.Ldfld, fi_groups);
393 ilgen.Emit (OpCodes.Ldc_I4_0);
394 ilgen.Emit (OpCodes.Ldelem_I4);
395 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
396 ilgen.Emit (OpCodes.Ldarg_1);
397 ilgen.Emit (OpCodes.Stfld, fi_mark_start);
400 // if (EvalByteCode (pc, strpos, ref res)) {
402 Frame new_frame = new Frame (ilgen);
404 // old_stros = strpos;
405 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
406 ilgen.Emit (OpCodes.Ldarg_1);
407 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
409 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, end_pc, false, false, out out_pc);
414 ilgen.MarkLabel (new_frame.label_pass);
415 // marks [groups [0]].Start = old_strpos;
416 ilgen.Emit (OpCodes.Ldarg_0);
417 ilgen.Emit (OpCodes.Ldfld, fi_marks);
418 ilgen.Emit (OpCodes.Ldarg_0);
419 ilgen.Emit (OpCodes.Ldfld, fi_groups);
420 ilgen.Emit (OpCodes.Ldc_I4_0);
421 ilgen.Emit (OpCodes.Ldelem_I4);
422 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
423 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
424 ilgen.Emit (OpCodes.Stfld, fi_mark_start);
425 // if (groups.Length > 1)
426 // marks [groups [0]].End = res;
427 if (group_count > 1) {
428 ilgen.Emit (OpCodes.Ldarg_0);
429 ilgen.Emit (OpCodes.Ldfld, fi_marks);
430 ilgen.Emit (OpCodes.Ldarg_0);
431 ilgen.Emit (OpCodes.Ldfld, fi_groups);
432 ilgen.Emit (OpCodes.Ldc_I4_0);
433 ilgen.Emit (OpCodes.Ldelem_I4);
434 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
435 ilgen.Emit (OpCodes.Ldarg_1);
436 ilgen.Emit (OpCodes.Stfld, fi_mark_end);
440 ilgen.Emit (OpCodes.Br, frame.label_pass);
443 ilgen.MarkLabel (new_frame.label_fail);
444 // strpos = old_strpos +/- 1;
445 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
446 ilgen.Emit (OpCodes.Ldc_I4_1);
448 ilgen.Emit (OpCodes.Sub);
450 ilgen.Emit (OpCodes.Add);
451 ilgen.Emit (OpCodes.Starg, 1);
453 ilgen.MarkLabel (l2);
455 ilgen.Emit (OpCodes.Ldarg_1);
456 ilgen.Emit (OpCodes.Ldc_I4_0);
457 ilgen.Emit (OpCodes.Bge, l1);
459 ilgen.Emit (OpCodes.Ldarg_1);
460 ilgen.Emit (OpCodes.Ldloc, local_string_end);
461 ilgen.Emit (OpCodes.Blt, l1);
464 ilgen.Emit (OpCodes.Br, frame.label_fail);
470 //if (EvalByteCode (pc + 3, strpos, ref res)) {
472 int target_pc = pc + ReadShort (program, pc + 1);
474 // Emit the rest of the code inline instead of making a recursive call
475 Frame new_frame = new Frame (ilgen);
477 // old_strpos = strpos;
478 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
479 ilgen.Emit (OpCodes.Ldarg_1);
480 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
482 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target_pc, false, false, out out_pc);
487 ilgen.MarkLabel (new_frame.label_pass);
489 ilgen.Emit (OpCodes.Br, frame.label_pass);
492 ilgen.MarkLabel (new_frame.label_fail);
493 // strpos = old_strpos;
494 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
495 ilgen.Emit (OpCodes.Starg, 1);
501 case RxOp.UnicodeChar:
503 case RxOp.UnicodeRange: {
504 OpFlags flags = (OpFlags)op_flags [pc];
505 bool negate = (flags & OpFlags.Negate) > 0;
506 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
507 bool reverse = (flags & OpFlags.RightToLeft) > 0;
509 //if (strpos < string_end) {
510 Label l1 = ilgen.DefineLabel ();
512 ilgen.Emit (OpCodes.Ldarg_1);
513 ilgen.Emit (OpCodes.Ldc_I4_0);
514 ilgen.Emit (OpCodes.Ble, l1);
516 ilgen.Emit (OpCodes.Ldarg_1);
517 ilgen.Emit (OpCodes.Ldarg_0);
518 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
519 ilgen.Emit (OpCodes.Bge, l1);
523 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
525 // int c = str [strpos];
526 LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
527 ilgen.Emit (OpCodes.Ldarg_0);
528 ilgen.Emit (OpCodes.Ldfld, fi_str);
529 ilgen.Emit (OpCodes.Ldarg_1);
531 ilgen.Emit (OpCodes.Ldc_I4_1);
532 ilgen.Emit (OpCodes.Sub);
534 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
536 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
538 if (op == RxOp.Char) {
539 ilgen.Emit (OpCodes.Conv_I4);
540 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
541 ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);
544 } else if (op == RxOp.UnicodeChar) {
545 ilgen.Emit (OpCodes.Conv_I4);
546 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
547 ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);
550 } else if (op == RxOp.Range) {
551 ilgen.Emit (OpCodes.Stloc, local_c);
553 // if (c >= program [pc + 1] && c <= program [pc + 2]) {
555 Label l3 = ilgen.DefineLabel ();
557 ilgen.Emit (OpCodes.Ldloc, local_c);
558 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
559 ilgen.Emit (OpCodes.Blt, l3);
560 ilgen.Emit (OpCodes.Ldloc, local_c);
561 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
562 ilgen.Emit (OpCodes.Bgt, l3);
563 ilgen.Emit (OpCodes.Br, l1);
564 ilgen.MarkLabel (l3);
566 ilgen.Emit (OpCodes.Ldloc, local_c);
567 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
568 ilgen.Emit (OpCodes.Blt, l1);
569 ilgen.Emit (OpCodes.Ldloc, local_c);
570 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
571 ilgen.Emit (OpCodes.Bgt, l1);
575 } else if (op == RxOp.UnicodeRange) {
576 ilgen.Emit (OpCodes.Stloc, local_c);
578 // if (c >= program [pc + 1] && c <= program [pc + 2]) {
580 Label l3 = ilgen.DefineLabel ();
582 ilgen.Emit (OpCodes.Ldloc, local_c);
583 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
584 ilgen.Emit (OpCodes.Blt, l3);
585 ilgen.Emit (OpCodes.Ldloc, local_c);
586 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
587 ilgen.Emit (OpCodes.Bgt, l3);
588 ilgen.Emit (OpCodes.Br, l1);
589 ilgen.MarkLabel (l3);
591 ilgen.Emit (OpCodes.Ldloc, local_c);
592 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
593 ilgen.Emit (OpCodes.Blt, l1);
594 ilgen.Emit (OpCodes.Ldloc, local_c);
595 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
596 ilgen.Emit (OpCodes.Bgt, l1);
601 throw new NotSupportedException ();
604 //ilgen.EmitWriteLine ("HIT:" + (char)program [pc + 1]);
606 // strpos++ / strpos--;
607 ilgen.Emit (OpCodes.Ldarg_1);
608 ilgen.Emit (OpCodes.Ldc_I4_1);
610 ilgen.Emit (OpCodes.Sub);
612 ilgen.Emit (OpCodes.Add);
613 ilgen.Emit (OpCodes.Starg, 1);
615 Label l2 = ilgen.DefineLabel ();
616 ilgen.Emit (OpCodes.Br, l2);
618 ilgen.MarkLabel (l1);
620 ilgen.Emit (OpCodes.Br, frame.label_fail);
621 ilgen.MarkLabel (l2);
627 ilgen.Emit (OpCodes.Br, frame.label_pass);
633 ilgen.Emit (OpCodes.Br, frame.label_fail);
637 case RxOp.AnyPosition: {
641 case RxOp.StartOfString: {
644 ilgen.Emit (OpCodes.Ldarg_1);
645 ilgen.Emit (OpCodes.Ldc_I4_0);
646 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
650 case RxOp.StartOfLine: {
651 // FIXME: windows line endings
652 //if (!(strpos == 0 || str [strpos - 1] == '\n'))
654 Label l = ilgen.DefineLabel ();
655 ilgen.Emit (OpCodes.Ldarg_1);
656 ilgen.Emit (OpCodes.Ldc_I4_0);
657 ilgen.Emit (OpCodes.Beq, l);
658 ilgen.Emit (OpCodes.Ldarg_0);
659 ilgen.Emit (OpCodes.Ldfld, fi_str);
660 ilgen.Emit (OpCodes.Ldarg_1);
661 ilgen.Emit (OpCodes.Ldc_I4_1);
662 ilgen.Emit (OpCodes.Sub);
663 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
664 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
665 ilgen.Emit (OpCodes.Beq, l);
666 ilgen.Emit (OpCodes.Br, frame.label_fail);
672 case RxOp.StartOfScan: {
673 //if (strpos != string_start)
675 ilgen.Emit (OpCodes.Ldarg_1);
676 ilgen.Emit (OpCodes.Ldarg_0);
677 ilgen.Emit (OpCodes.Ldfld, fi_string_start);
678 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
683 //if (!(strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')))
685 Label l = ilgen.DefineLabel ();
687 ilgen.Emit (OpCodes.Ldarg_1);
688 ilgen.Emit (OpCodes.Ldarg_0);
689 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
690 ilgen.Emit (OpCodes.Beq, l);
692 Label l2 = ilgen.DefineLabel ();
693 ilgen.Emit (OpCodes.Ldarg_1);
694 ilgen.Emit (OpCodes.Ldarg_0);
695 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
696 ilgen.Emit (OpCodes.Ldc_I4_1);
697 ilgen.Emit (OpCodes.Sub);
698 ilgen.Emit (OpCodes.Bne_Un, l2);
699 ilgen.Emit (OpCodes.Ldarg_0);
700 ilgen.Emit (OpCodes.Ldfld, fi_str);
701 ilgen.Emit (OpCodes.Ldarg_1);
702 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
703 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
704 ilgen.Emit (OpCodes.Bne_Un, l2);
705 ilgen.Emit (OpCodes.Br, l);
706 ilgen.MarkLabel (l2);
708 ilgen.Emit (OpCodes.Br, frame.label_fail);
714 case RxOp.EndOfString: {
715 //if (strpos != string_end)
717 ilgen.Emit (OpCodes.Ldarg_1);
718 ilgen.Emit (OpCodes.Ldarg_0);
719 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
720 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
724 case RxOp.EndOfLine: {
725 //if (!(strpos == string_end || str [strpos] == '\n'))
727 Label l_match = ilgen.DefineLabel ();
728 ilgen.Emit (OpCodes.Ldarg_1);
729 ilgen.Emit (OpCodes.Ldarg_0);
730 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
731 ilgen.Emit (OpCodes.Beq, l_match);
732 ilgen.Emit (OpCodes.Ldarg_0);
733 ilgen.Emit (OpCodes.Ldfld, fi_str);
734 ilgen.Emit (OpCodes.Ldarg_1);
735 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
736 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
737 ilgen.Emit (OpCodes.Beq, l_match);
738 ilgen.Emit (OpCodes.Br, frame.label_fail);
739 ilgen.MarkLabel (l_match);
744 case RxOp.WordBoundary:
745 case RxOp.NoWordBoundary: {
746 bool negate = op == RxOp.NoWordBoundary;
748 //if (string_end == 0)
750 ilgen.Emit (OpCodes.Ldarg_0);
751 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
752 ilgen.Emit (OpCodes.Ldc_I4_0);
753 ilgen.Emit (OpCodes.Beq, frame.label_fail);
755 Label l_match = ilgen.DefineLabel ();
758 Label l1 = ilgen.DefineLabel ();
759 ilgen.Emit (OpCodes.Ldarg_1);
760 ilgen.Emit (OpCodes.Ldc_I4_0);
761 ilgen.Emit (OpCodes.Bne_Un, l1);
762 //if (!IsWordChar (str [strpos])) {
764 ilgen.Emit (OpCodes.Ldarg_0);
765 ilgen.Emit (OpCodes.Ldfld, fi_str);
766 ilgen.Emit (OpCodes.Ldarg_1);
767 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
768 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
769 ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
770 ilgen.Emit (OpCodes.Br, l_match);
772 //} else if (strpos == string_end) {
773 ilgen.MarkLabel (l1);
774 Label l2 = ilgen.DefineLabel ();
775 ilgen.Emit (OpCodes.Ldarg_1);
776 ilgen.Emit (OpCodes.Ldarg_0);
777 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
778 ilgen.Emit (OpCodes.Bne_Un, l2);
779 //if (!IsWordChar (str [strpos - 1])) {
781 ilgen.Emit (OpCodes.Ldarg_0);
782 ilgen.Emit (OpCodes.Ldfld, fi_str);
783 ilgen.Emit (OpCodes.Ldarg_1);
784 ilgen.Emit (OpCodes.Ldc_I4_1);
785 ilgen.Emit (OpCodes.Sub);
786 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
787 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
788 ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
789 ilgen.Emit (OpCodes.Br, l_match);
792 ilgen.MarkLabel (l2);
793 //if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
795 ilgen.Emit (OpCodes.Ldarg_0);
796 ilgen.Emit (OpCodes.Ldfld, fi_str);
797 ilgen.Emit (OpCodes.Ldarg_1);
798 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
799 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
800 ilgen.Emit (OpCodes.Ldarg_0);
801 ilgen.Emit (OpCodes.Ldfld, fi_str);
802 ilgen.Emit (OpCodes.Ldarg_1);
803 ilgen.Emit (OpCodes.Ldc_I4_1);
804 ilgen.Emit (OpCodes.Sub);
805 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
806 ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
807 ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, frame.label_fail);
808 ilgen.Emit (OpCodes.Br, l_match);
810 ilgen.MarkLabel (l_match);
816 case RxOp.UnicodeBitmap: {
817 OpFlags flags = (OpFlags)op_flags [pc];
818 bool negate = (flags & OpFlags.Negate) > 0;
819 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
820 bool reverse = (flags & OpFlags.RightToLeft) > 0;
821 bool unicode = (op == RxOp.UnicodeBitmap);
823 //if (strpos < string_end) {
824 Label l1 = ilgen.DefineLabel ();
825 Label l2 = ilgen.DefineLabel ();
826 Label l_match = ilgen.DefineLabel ();
828 ilgen.Emit (OpCodes.Ldarg_1);
829 ilgen.Emit (OpCodes.Ldc_I4_0);
830 ilgen.Emit (OpCodes.Ble, l1);
832 ilgen.Emit (OpCodes.Ldarg_1);
833 ilgen.Emit (OpCodes.Ldarg_0);
834 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
835 ilgen.Emit (OpCodes.Bge, l1);
837 // int c = str [strpos];
838 LocalBuilder local_c = ilgen.DeclareLocal (typeof (int));
840 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
841 ilgen.Emit (OpCodes.Ldarg_0);
842 ilgen.Emit (OpCodes.Ldfld, fi_str);
843 ilgen.Emit (OpCodes.Ldarg_1);
845 ilgen.Emit (OpCodes.Ldc_I4_1);
846 ilgen.Emit (OpCodes.Sub);
848 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
849 ilgen.Emit (OpCodes.Conv_I4);
851 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
852 // c -= program [pc + 1];
854 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
855 ilgen.Emit (OpCodes.Sub);
856 ilgen.Emit (OpCodes.Stloc, local_c);
857 length = ReadShort (program, pc + 3);
860 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
861 ilgen.Emit (OpCodes.Sub);
862 ilgen.Emit (OpCodes.Stloc, local_c);
863 length = program [pc + 2];
866 // if (c < 0 || c >= (length << 3))
868 ilgen.Emit (OpCodes.Ldloc, local_c);
869 ilgen.Emit (OpCodes.Ldc_I4_0);
870 ilgen.Emit (OpCodes.Blt, negate ? l_match : frame.label_fail);
871 ilgen.Emit (OpCodes.Ldloc, local_c);
872 ilgen.Emit (OpCodes.Ldc_I4, length << 3);
873 ilgen.Emit (OpCodes.Bge, negate ? l_match : frame.label_fail);
875 // Optimized version for small bitmaps
877 uint bitmap = program [pc];
880 bitmap |= ((uint)program [pc + 1] << 8);
882 bitmap |= ((uint)program [pc + 2] << 16);
884 bitmap |= ((uint)program [pc + 3] << 24);
886 //if ((bitmap >> c) & 1)
887 ilgen.Emit (OpCodes.Ldc_I4, bitmap);
888 ilgen.Emit (OpCodes.Ldloc, local_c);
889 ilgen.Emit (OpCodes.Shr_Un);
890 ilgen.Emit (OpCodes.Ldc_I4_1);
891 ilgen.Emit (OpCodes.And);
892 ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, l1);
894 // if ((program [pc + (c >> 3)] & (1 << (c & 0x7))) != 0) {
895 ilgen.Emit (OpCodes.Ldarg_0);
896 ilgen.Emit (OpCodes.Ldfld, fi_program);
897 ilgen.Emit (OpCodes.Ldloc, local_c);
898 ilgen.Emit (OpCodes.Ldc_I4_3);
899 ilgen.Emit (OpCodes.Shr);
900 ilgen.Emit (OpCodes.Ldc_I4, pc);
901 ilgen.Emit (OpCodes.Add);
902 ilgen.Emit (OpCodes.Ldelem_I1);
903 ilgen.Emit (OpCodes.Ldc_I4_1);
904 ilgen.Emit (OpCodes.Ldloc, local_c);
905 ilgen.Emit (OpCodes.Ldc_I4, 7);
906 ilgen.Emit (OpCodes.And);
907 ilgen.Emit (OpCodes.Shl);
908 ilgen.Emit (OpCodes.And);
909 ilgen.Emit (OpCodes.Ldc_I4_0);
910 ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, l1);
912 ilgen.MarkLabel (l_match);
914 // strpos++ / strpos--;
915 ilgen.Emit (OpCodes.Ldarg_1);
916 ilgen.Emit (OpCodes.Ldc_I4_1);
918 ilgen.Emit (OpCodes.Sub);
920 ilgen.Emit (OpCodes.Add);
921 ilgen.Emit (OpCodes.Starg, 1);
924 ilgen.Emit (OpCodes.Br, l2);
928 ilgen.MarkLabel (l1);
929 ilgen.Emit (OpCodes.Br, frame.label_fail);
931 ilgen.MarkLabel (l2);
937 case RxOp.UnicodeString: {
938 OpFlags flags = (OpFlags)op_flags [pc];
939 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
940 bool reverse = (flags & OpFlags.RightToLeft) > 0;
941 bool unicode = (op == RxOp.UnicodeString);
945 length = ReadShort (program, pc + 1);
948 length = program [pc + 1];
950 //if (strpos + length > string_end)
953 ilgen.Emit (OpCodes.Ldarg_1);
954 ilgen.Emit (OpCodes.Ldc_I4, length);
955 ilgen.Emit (OpCodes.Blt, frame.label_fail);
957 ilgen.Emit (OpCodes.Ldarg_1);
958 ilgen.Emit (OpCodes.Ldc_I4, length);
959 ilgen.Emit (OpCodes.Add);
960 ilgen.Emit (OpCodes.Ldarg_0);
961 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
962 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
965 /* Avoid unsafe code in Moonlight build */
966 #if false && !NET_2_1
968 if (reverse || unicode)
969 throw new NotImplementedException ();
971 LocalBuilder local_strptr = ilgen.DeclareLocal (typeof (char).MakePointerType ());
972 // char *strptr = &str.start_char + strpos
973 ilgen.Emit (OpCodes.Ldarg_0);
974 ilgen.Emit (OpCodes.Ldfld, fi_str);
975 ilgen.Emit (OpCodes.Ldflda, typeof (String).GetField ("start_char", BindingFlags.Instance|BindingFlags.NonPublic));
976 ilgen.Emit (OpCodes.Ldarg_1);
977 ilgen.Emit (OpCodes.Ldc_I4_1);
978 ilgen.Emit (OpCodes.Shl);
979 ilgen.Emit (OpCodes.Add);
980 ilgen.Emit (OpCodes.Stloc, local_strptr);
982 end = start + length;
983 for (i = 0; i < length; ++i) {
984 // if (*(strptr + i) != program [start + i])
987 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
988 ilgen.Emit (OpCodes.Ldloc, local_strptr);
989 ilgen.Emit (OpCodes.Ldc_I4, i * 2);
990 ilgen.Emit (OpCodes.Add);
991 ilgen.Emit (OpCodes.Ldind_I2);
993 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
994 ilgen.Emit (OpCodes.Ldc_I4, (int)program [start + i]);
995 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
999 ilgen.Emit (OpCodes.Ldarg_1);
1000 ilgen.Emit (OpCodes.Ldc_I4, length);
1001 ilgen.Emit (OpCodes.Add);
1002 ilgen.Emit (OpCodes.Starg, 1);
1005 // Allocate a local for 'str' to save an indirection
1006 LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
1007 ilgen.Emit (OpCodes.Ldarg_0);
1008 ilgen.Emit (OpCodes.Ldfld, fi_str);
1009 ilgen.Emit (OpCodes.Stloc, local_str);
1012 // strpos -= length;
1013 ilgen.Emit (OpCodes.Ldarg_1);
1014 ilgen.Emit (OpCodes.Ldc_I4, length);
1015 ilgen.Emit (OpCodes.Sub);
1016 ilgen.Emit (OpCodes.Starg, 1);
1019 // FIXME: Emit a loop for long strings
1020 end = start + (unicode ? length * 2 : length);
1021 while (start < end) {
1022 //if (str [strpos] != program [start])
1025 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1026 ilgen.Emit (OpCodes.Ldloc, local_str);
1027 ilgen.Emit (OpCodes.Ldarg_1);
1028 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1030 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1031 ilgen.Emit (OpCodes.Ldc_I4, unicode ? ReadShort (program, start) : (int)program [start]);
1032 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
1034 ilgen.Emit (OpCodes.Ldarg_1);
1035 ilgen.Emit (OpCodes.Ldc_I4_1);
1036 ilgen.Emit (OpCodes.Add);
1037 ilgen.Emit (OpCodes.Starg, 1);
1046 // strpos -= length;
1047 ilgen.Emit (OpCodes.Ldarg_1);
1048 ilgen.Emit (OpCodes.Ldc_I4, length);
1049 ilgen.Emit (OpCodes.Sub);
1050 ilgen.Emit (OpCodes.Starg, 1);
1057 case RxOp.OpenGroup: {
1058 //Open (program [pc + 1] | (program [pc + 2] << 8), strpos);
1059 int group_id = ReadShort (program, pc + 1);
1060 ilgen.Emit (OpCodes.Ldarg_0);
1061 ilgen.Emit (OpCodes.Ldc_I4, group_id);
1062 ilgen.Emit (OpCodes.Ldarg_1);
1063 ilgen.Emit (OpCodes.Call, GetMethod ("Open", ref mi_open));
1068 case RxOp.CloseGroup: {
1069 //Close (program [pc + 1] | (program [pc + 2] << 8), strpos);
1070 int group_id = ReadShort (program, pc + 1);
1071 ilgen.Emit (OpCodes.Ldarg_0);
1072 ilgen.Emit (OpCodes.Ldc_I4, group_id);
1073 ilgen.Emit (OpCodes.Ldarg_1);
1074 ilgen.Emit (OpCodes.Call, GetMethod ("Close", ref mi_close));
1080 int target_pc = pc + ReadShort (program, pc + 1);
1081 if (target_pc > end_pc)
1083 * This breaks the our code generation logic, see
1084 * https://bugzilla.novell.com/show_bug.cgi?id=466151
1089 Console.WriteLine ("\tjump target: {0}", target_pc);
1091 labels = new Dictionary <int, Label> ();
1092 Label l = CreateLabelForPC (ilgen, target_pc);
1093 ilgen.Emit (OpCodes.Br, l);
1098 int target1 = pc + ReadShort (program, pc + 1);
1099 int target2 = pc + ReadShort (program, pc + 3);
1102 Console.WriteLine ("\temitting <test_expr>");
1104 // old_stros = strpos;
1105 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1106 ilgen.Emit (OpCodes.Ldarg_1);
1107 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1109 Frame new_frame = new Frame (ilgen);
1110 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 5, target1 < target2 ? target1 : target2, false, false, out pc);
1114 if (trace_compile) {
1115 Console.WriteLine ("\temitted <test_expr>");
1116 Console.WriteLine ("\ttarget1 = {0}", target1);
1117 Console.WriteLine ("\ttarget2 = {0}", target2);
1120 Label l1 = CreateLabelForPC (ilgen, target1);
1121 Label l2 = CreateLabelForPC (ilgen, target2);
1124 ilgen.MarkLabel (new_frame.label_pass);
1125 // strpos = old_strpos;
1126 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1127 ilgen.Emit (OpCodes.Starg, 1);
1128 ilgen.Emit (OpCodes.Br, l1);
1131 ilgen.MarkLabel (new_frame.label_fail);
1132 // strpos = old_strpos;
1133 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1134 ilgen.Emit (OpCodes.Starg, 1);
1135 ilgen.Emit (OpCodes.Br, l2);
1137 // Continue at pc, which should equal to target1
1140 case RxOp.SubExpression: {
1141 int target = pc + ReadShort (program, pc + 1);
1144 Console.WriteLine ("\temitting <sub_expr>");
1146 // old_stros = strpos;
1147 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1148 ilgen.Emit (OpCodes.Ldarg_1);
1149 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1151 Frame new_frame = new Frame (ilgen);
1152 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target, false, false, out pc);
1156 if (trace_compile) {
1157 Console.WriteLine ("\temitted <sub_expr>");
1158 Console.WriteLine ("\ttarget = {0}", target);
1161 Label l1 = CreateLabelForPC (ilgen, target);
1164 ilgen.MarkLabel (new_frame.label_pass);
1165 ilgen.Emit (OpCodes.Br, l1);
1168 ilgen.MarkLabel (new_frame.label_fail);
1169 // strpos = old_strpos;
1170 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1171 ilgen.Emit (OpCodes.Starg, 1);
1172 ilgen.Emit (OpCodes.Br, frame.label_fail);
1174 // Continue at pc, which should equal to target
1177 case RxOp.TestCharGroup: {
1178 int char_group_end = pc + ReadShort (program, pc + 1);
1181 Label label_match = ilgen.DefineLabel ();
1183 /* Determine the negate/reverse flags by examining the first op */
1184 OpFlags flags = (OpFlags)op_flags [pc];
1186 /* Determine whenever this is a negated character class */
1187 /* If it is, then the conditions are ANDed together, not ORed */
1188 bool revert = (flags & OpFlags.Negate) > 0;
1189 bool reverse = (flags & OpFlags.RightToLeft) > 0;
1192 * Generate code for all the matching ops in the group
1194 while (pc < char_group_end) {
1195 Frame new_frame = new Frame (ilgen);
1196 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, Int32.MaxValue, true, true, out pc);
1202 ilgen.MarkLabel (new_frame.label_pass);
1203 ilgen.Emit (OpCodes.Br, label_match);
1206 // Just fall through to the next test
1207 ilgen.MarkLabel (new_frame.label_fail);
1210 // Just fall through to the next test
1211 ilgen.MarkLabel (new_frame.label_pass);
1212 Label l2 = ilgen.DefineLabel ();
1213 ilgen.Emit (OpCodes.Br, l2);
1217 ilgen.MarkLabel (new_frame.label_fail);
1218 ilgen.Emit (OpCodes.Br, frame.label_fail);
1220 ilgen.MarkLabel (l2);
1226 ilgen.Emit (OpCodes.Br, label_match);
1228 // If we reached here, all the matching ops have failed
1229 ilgen.Emit (OpCodes.Br, frame.label_fail);
1232 ilgen.MarkLabel (label_match);
1234 // strpos++ / strpos--;
1235 ilgen.Emit (OpCodes.Ldarg_1);
1236 ilgen.Emit (OpCodes.Ldc_I4_1);
1238 ilgen.Emit (OpCodes.Sub);
1240 ilgen.Emit (OpCodes.Add);
1241 ilgen.Emit (OpCodes.Starg, 1);
1245 case RxOp.FastRepeat:
1246 case RxOp.FastRepeatLazy: {
1248 * A FastRepeat is a simplified version of Repeat which does
1249 * not contain another repeat inside, so backtracking is
1251 * FIXME: Implement faster backtracking versions for
1252 * simple inner exceptions like chars/strings.
1254 bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
1255 int tail = pc + ReadShort (program, pc + 1);
1256 start = ReadInt (program, pc + 3);
1257 end = ReadInt (program, pc + 7);
1258 //Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);
1261 ilgen.Emit (OpCodes.Ldarg_0);
1262 ilgen.Emit (OpCodes.Ldnull);
1263 ilgen.Emit (OpCodes.Stfld, fi_deep);
1265 LocalBuilder local_length = ilgen.DeclareLocal (typeof (int));
1267 ilgen.Emit (OpCodes.Ldc_I4_0);
1268 ilgen.Emit (OpCodes.Stloc, local_length);
1270 LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
1272 // First match at least 'start' items
1274 //for (length = 0; length < start; ++length) {
1275 Label l_loop_footer = ilgen.DefineLabel ();
1276 ilgen.Emit (OpCodes.Br, l_loop_footer);
1277 Label l_loop_body = ilgen.DefineLabel ();
1278 ilgen.MarkLabel (l_loop_body);
1280 // int old_strpos = strpos;
1281 ilgen.Emit (OpCodes.Ldarg_1);
1282 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1284 // if (!EvalByteCode (pc + 11, strpos, ref res))
1285 Frame new_frame = new Frame (ilgen);
1286 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1292 ilgen.MarkLabel (new_frame.label_fail);
1293 ilgen.Emit (OpCodes.Br, frame.label_fail);
1296 ilgen.MarkLabel (new_frame.label_pass);
1298 ilgen.Emit (OpCodes.Ldloc, local_length);
1299 ilgen.Emit (OpCodes.Ldc_I4_1);
1300 ilgen.Emit (OpCodes.Add);
1301 ilgen.Emit (OpCodes.Stloc, local_length);
1303 ilgen.MarkLabel (l_loop_footer);
1304 ilgen.Emit (OpCodes.Ldloc, local_length);
1305 ilgen.Emit (OpCodes.Ldc_I4, start);
1306 ilgen.Emit (OpCodes.Blt, l_loop_body);
1310 Label l_loop_footer = ilgen.DefineLabel ();
1312 ilgen.Emit (OpCodes.Br, l_loop_footer);
1313 Label l_loop_body = ilgen.DefineLabel ();
1314 ilgen.MarkLabel (l_loop_body);
1316 // int cp = Checkpoint ();
1317 LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
1318 ilgen.Emit (OpCodes.Ldarg_0);
1319 ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
1320 ilgen.Emit (OpCodes.Stloc, local_cp);
1322 // int old_strpos = strpos;
1323 ilgen.Emit (OpCodes.Ldarg_1);
1324 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1326 // if (EvalByteCode (tail, strpos, ref res)) {
1327 Frame new_frame = new Frame (ilgen);
1328 m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
1333 ilgen.MarkLabel (new_frame.label_pass);
1335 ilgen.Emit (OpCodes.Br, frame.label_pass);
1338 ilgen.MarkLabel (new_frame.label_fail);
1340 ilgen.Emit (OpCodes.Ldarg_0);
1341 ilgen.Emit (OpCodes.Ldloc, local_cp);
1342 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1343 // strpos = old_strpos;
1344 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1345 ilgen.Emit (OpCodes.Starg, 1);
1347 //if (length >= end)
1349 ilgen.Emit (OpCodes.Ldloc, local_length);
1350 ilgen.Emit (OpCodes.Ldc_I4, end);
1351 ilgen.Emit (OpCodes.Bge, frame.label_fail);
1354 //if (!EvalByteCode (pc + 11, strpos, ref res))
1355 new_frame = new Frame (ilgen);
1356 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1361 ilgen.MarkLabel (new_frame.label_pass);
1363 ilgen.Emit (OpCodes.Ldloc, local_length);
1364 ilgen.Emit (OpCodes.Ldc_I4_1);
1365 ilgen.Emit (OpCodes.Add);
1366 ilgen.Emit (OpCodes.Stloc, local_length);
1367 ilgen.Emit (OpCodes.Br, l_loop_body);
1370 ilgen.MarkLabel (new_frame.label_fail);
1372 ilgen.Emit (OpCodes.Br, frame.label_fail);
1375 ilgen.MarkLabel (l_loop_footer);
1376 ilgen.Emit (OpCodes.Br, l_loop_body);
1378 // Then match as many items as possible, recording
1379 // backtracking information
1381 //int old_stack_size = stack.Count;
1382 LocalBuilder local_old_stack_size = ilgen.DeclareLocal (typeof (int));
1383 ilgen.Emit (OpCodes.Ldarg_0);
1384 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1385 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
1386 ilgen.Emit (OpCodes.Stloc, local_old_stack_size);
1387 //while (length < end) {
1388 Label l_loop_footer = ilgen.DefineLabel ();
1389 ilgen.Emit (OpCodes.Br, l_loop_footer);
1390 Label l_loop_body = ilgen.DefineLabel ();
1391 ilgen.MarkLabel (l_loop_body);
1392 // int cp = Checkpoint ();
1393 LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
1394 ilgen.Emit (OpCodes.Ldarg_0);
1395 ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
1396 ilgen.Emit (OpCodes.Stloc, local_cp);
1398 // int old_strpos = strpos;
1399 ilgen.Emit (OpCodes.Ldarg_1);
1400 ilgen.Emit (OpCodes.Stloc, local_old_strpos);
1402 // if (!EvalByteCode (pc + 11, strpos, ref res)) {
1403 Frame new_frame = new Frame (ilgen);
1404 m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
1409 ilgen.MarkLabel (new_frame.label_fail);
1410 // strpos = old_strpos
1411 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1412 ilgen.Emit (OpCodes.Starg, 1);
1414 ilgen.Emit (OpCodes.Ldarg_0);
1415 ilgen.Emit (OpCodes.Ldloc, local_cp);
1416 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1419 Label l_after_loop = ilgen.DefineLabel ();
1420 ilgen.Emit (OpCodes.Br, l_after_loop);
1423 ilgen.MarkLabel (new_frame.label_pass);
1426 ilgen.Emit (OpCodes.Ldarg_0);
1427 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1428 ilgen.Emit (OpCodes.Ldloc, local_cp);
1429 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
1430 //stack.Push (strpos);
1431 ilgen.Emit (OpCodes.Ldarg_0);
1432 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1433 ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
1434 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
1436 ilgen.Emit (OpCodes.Ldloc, local_length);
1437 ilgen.Emit (OpCodes.Ldc_I4_1);
1438 ilgen.Emit (OpCodes.Add);
1439 ilgen.Emit (OpCodes.Stloc, local_length);
1441 ilgen.MarkLabel (l_loop_footer);
1442 ilgen.Emit (OpCodes.Ldloc, local_length);
1443 ilgen.Emit (OpCodes.Ldc_I4, end);
1444 ilgen.Emit (OpCodes.Blt, l_loop_body);
1446 ilgen.MarkLabel (l_after_loop);
1448 // Then, match the tail, backtracking as necessary.
1451 l_loop_footer = ilgen.DefineLabel ();
1452 ilgen.Emit (OpCodes.Br, l_loop_footer);
1453 l_loop_body = ilgen.DefineLabel ();
1454 ilgen.MarkLabel (l_loop_body);
1456 if (RxInterpreter.trace_rx) {
1457 ilgen.Emit (OpCodes.Ldstr, "matching tail at: {0}");
1458 ilgen.Emit (OpCodes.Ldarg_1);
1459 ilgen.Emit (OpCodes.Box, typeof (int));
1460 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1463 // if (EvalByteCode (tail, strpos, ref res)) {
1464 new_frame = new Frame (ilgen);
1465 m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
1470 ilgen.MarkLabel (new_frame.label_pass);
1472 if (RxInterpreter.trace_rx) {
1473 ilgen.Emit (OpCodes.Ldstr, "tail matched at: {0}");
1474 ilgen.Emit (OpCodes.Ldarg_1);
1475 ilgen.Emit (OpCodes.Box, typeof (int));
1476 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1479 // stack.Count = old_stack_size;
1480 ilgen.Emit (OpCodes.Ldarg_0);
1481 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1482 ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
1483 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "set_Count", ref mi_stack_set_count));
1485 ilgen.Emit (OpCodes.Br, frame.label_pass);
1488 ilgen.MarkLabel (new_frame.label_fail);
1490 if (RxInterpreter.trace_rx) {
1491 ilgen.Emit (OpCodes.Ldstr, "tail failed to match at: {0}");
1492 ilgen.Emit (OpCodes.Ldarg_1);
1493 ilgen.Emit (OpCodes.Box, typeof (int));
1494 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1497 // if (stack.Count == old_stack_size)
1499 ilgen.Emit (OpCodes.Ldarg_0);
1500 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1501 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
1502 ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
1503 ilgen.Emit (OpCodes.Beq, frame.label_fail);
1506 //strpos = stack.Pop ();
1507 ilgen.Emit (OpCodes.Ldarg_0);
1508 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1509 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
1510 ilgen.Emit (OpCodes.Starg, 1);
1511 //Backtrack (stack.Pop ());
1512 ilgen.Emit (OpCodes.Ldarg_0);
1513 ilgen.Emit (OpCodes.Ldarg_0);
1514 ilgen.Emit (OpCodes.Ldflda, fi_stack);
1515 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
1516 ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
1518 if (RxInterpreter.trace_rx) {
1519 //Console.WriteLine ("backtracking to: {0}", strpos);
1520 ilgen.Emit (OpCodes.Ldstr, "backtracking to: {0}");
1521 ilgen.Emit (OpCodes.Ldarg_1);
1522 ilgen.Emit (OpCodes.Box, typeof (int));
1523 ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
1527 ilgen.MarkLabel (l_loop_footer);
1528 ilgen.Emit (OpCodes.Br, l_loop_body);
1531 // We already processed the tail
1536 case RxOp.CategoryAny:
1537 case RxOp.CategoryAnySingleline:
1538 case RxOp.CategoryWord:
1539 case RxOp.CategoryDigit:
1540 case RxOp.CategoryWhiteSpace:
1541 case RxOp.CategoryEcmaWord:
1542 case RxOp.CategoryEcmaWhiteSpace:
1543 case RxOp.CategoryUnicodeSpecials:
1544 case RxOp.CategoryUnicode: {
1545 OpFlags flags = (OpFlags)op_flags [pc];
1546 bool negate = (flags & OpFlags.Negate) > 0;
1547 bool reverse = (flags & OpFlags.RightToLeft) > 0;
1549 //if (strpos < string_end) {
1550 Label l_nomatch = ilgen.DefineLabel ();
1552 ilgen.Emit (OpCodes.Ldarg_1);
1553 ilgen.Emit (OpCodes.Ldc_I4_0);
1554 ilgen.Emit (OpCodes.Ble, l_nomatch);
1556 ilgen.Emit (OpCodes.Ldarg_1);
1557 ilgen.Emit (OpCodes.Ldarg_0);
1558 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
1559 ilgen.Emit (OpCodes.Bge, l_nomatch);
1562 // int c = str [strpos];
1563 LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
1564 ilgen.Emit (OpCodes.Ldarg_0);
1565 ilgen.Emit (OpCodes.Ldfld, fi_str);
1566 ilgen.Emit (OpCodes.Ldarg_1);
1568 ilgen.Emit (OpCodes.Ldc_I4_1);
1569 ilgen.Emit (OpCodes.Sub);
1571 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1572 ilgen.Emit (OpCodes.Stloc, local_c);
1574 Label l_match = ilgen.DefineLabel ();
1576 Label l_true, l_false;
1578 l_true = negate ? l_nomatch : l_match;
1579 l_false = negate ? l_match : l_nomatch;
1582 case RxOp.CategoryAny:
1583 // if (str [strpos] != '\n') {
1584 ilgen.Emit (OpCodes.Ldloc, local_c);
1585 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
1586 ilgen.Emit (OpCodes.Bne_Un, l_true);
1588 case RxOp.CategoryAnySingleline:
1589 ilgen.Emit (OpCodes.Br, l_true);
1591 case RxOp.CategoryWord:
1592 // if (Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation) {
1593 ilgen.Emit (OpCodes.Ldloc, local_c);
1594 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsLetterOrDigit", new Type [] { typeof (char) }));
1595 ilgen.Emit (OpCodes.Brtrue, l_true);
1596 ilgen.Emit (OpCodes.Ldloc, local_c);
1597 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
1598 ilgen.Emit (OpCodes.Ldc_I4, (int)UnicodeCategory.ConnectorPunctuation);
1599 ilgen.Emit (OpCodes.Beq, l_true);
1601 case RxOp.CategoryDigit:
1602 // if (Char.IsDigit (c)) {
1603 ilgen.Emit (OpCodes.Ldloc, local_c);
1604 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsDigit", new Type [] { typeof (char) }));
1605 ilgen.Emit (OpCodes.Brtrue, l_true);
1607 case RxOp.CategoryWhiteSpace:
1608 // if (Char.IsWhiteSpace (c)) {
1609 ilgen.Emit (OpCodes.Ldloc, local_c);
1610 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsWhiteSpace", new Type [] { typeof (char) }));
1611 ilgen.Emit (OpCodes.Brtrue, l_true);
1613 case RxOp.CategoryEcmaWord:
1614 // if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_') {
1615 ilgen.Emit (OpCodes.Ldloc, local_c);
1616 ilgen.Emit (OpCodes.Ldc_I4, (int)'a' - 1);
1617 ilgen.Emit (OpCodes.Cgt);
1618 ilgen.Emit (OpCodes.Ldloc, local_c);
1619 ilgen.Emit (OpCodes.Ldc_I4, (int)'z' + 1);
1620 ilgen.Emit (OpCodes.Clt);
1621 ilgen.Emit (OpCodes.And);
1622 ilgen.Emit (OpCodes.Brtrue, l_true);
1624 ilgen.Emit (OpCodes.Ldloc, local_c);
1625 ilgen.Emit (OpCodes.Ldc_I4, (int)'A' - 1);
1626 ilgen.Emit (OpCodes.Cgt);
1627 ilgen.Emit (OpCodes.Ldloc, local_c);
1628 ilgen.Emit (OpCodes.Ldc_I4, (int)'Z' + 1);
1629 ilgen.Emit (OpCodes.Clt);
1630 ilgen.Emit (OpCodes.And);
1631 ilgen.Emit (OpCodes.Brtrue, l_true);
1633 ilgen.Emit (OpCodes.Ldloc, local_c);
1634 ilgen.Emit (OpCodes.Ldc_I4, (int)'0' - 1);
1635 ilgen.Emit (OpCodes.Cgt);
1636 ilgen.Emit (OpCodes.Ldloc, local_c);
1637 ilgen.Emit (OpCodes.Ldc_I4, (int)'9' + 1);
1638 ilgen.Emit (OpCodes.Clt);
1639 ilgen.Emit (OpCodes.And);
1640 ilgen.Emit (OpCodes.Brtrue, l_true);
1642 ilgen.Emit (OpCodes.Ldloc, local_c);
1643 ilgen.Emit (OpCodes.Ldc_I4, (int)'_');
1644 ilgen.Emit (OpCodes.Beq, l_true);
1646 case RxOp.CategoryEcmaWhiteSpace:
1647 // if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') {
1648 ilgen.Emit (OpCodes.Ldloc, local_c);
1649 ilgen.Emit (OpCodes.Ldc_I4, (int)' ');
1650 ilgen.Emit (OpCodes.Beq, l_true);
1651 ilgen.Emit (OpCodes.Ldloc, local_c);
1652 ilgen.Emit (OpCodes.Ldc_I4, (int)'\t');
1653 ilgen.Emit (OpCodes.Beq, l_true);
1654 ilgen.Emit (OpCodes.Ldloc, local_c);
1655 ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
1656 ilgen.Emit (OpCodes.Beq, l_true);
1657 ilgen.Emit (OpCodes.Ldloc, local_c);
1658 ilgen.Emit (OpCodes.Ldc_I4, (int)'\r');
1659 ilgen.Emit (OpCodes.Beq, l_true);
1660 ilgen.Emit (OpCodes.Ldloc, local_c);
1661 ilgen.Emit (OpCodes.Ldc_I4, (int)'\f');
1662 ilgen.Emit (OpCodes.Beq, l_true);
1663 ilgen.Emit (OpCodes.Ldloc, local_c);
1664 ilgen.Emit (OpCodes.Ldc_I4, (int)'\v');
1665 ilgen.Emit (OpCodes.Beq, l_true);
1667 case RxOp.CategoryUnicodeSpecials:
1668 // if ('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD') {
1669 ilgen.Emit (OpCodes.Ldloc, local_c);
1670 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' - 1);
1671 ilgen.Emit (OpCodes.Cgt);
1672 ilgen.Emit (OpCodes.Ldloc, local_c);
1673 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' + 1);
1674 ilgen.Emit (OpCodes.Clt);
1675 ilgen.Emit (OpCodes.And);
1676 ilgen.Emit (OpCodes.Brtrue, l_true);
1678 ilgen.Emit (OpCodes.Ldloc, local_c);
1679 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFF0' - 1);
1680 ilgen.Emit (OpCodes.Cgt);
1681 ilgen.Emit (OpCodes.Ldloc, local_c);
1682 ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFFD' + 1);
1683 ilgen.Emit (OpCodes.Clt);
1684 ilgen.Emit (OpCodes.And);
1685 ilgen.Emit (OpCodes.Brtrue, l_true);
1687 case RxOp.CategoryUnicode:
1688 // if (Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]) {
1689 ilgen.Emit (OpCodes.Ldloc, local_c);
1690 ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
1691 ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
1692 ilgen.Emit (OpCodes.Beq, l_true);
1696 ilgen.Emit (OpCodes.Br, l_false);
1698 ilgen.MarkLabel (l_match);
1702 ilgen.Emit (OpCodes.Ldarg_1);
1703 ilgen.Emit (OpCodes.Ldc_I4_1);
1705 ilgen.Emit (OpCodes.Sub);
1707 ilgen.Emit (OpCodes.Add);
1708 ilgen.Emit (OpCodes.Starg, 1);
1711 Label l2 = ilgen.DefineLabel ();
1712 ilgen.Emit (OpCodes.Br, l2);
1714 ilgen.MarkLabel (l_nomatch);
1716 ilgen.Emit (OpCodes.Br, frame.label_fail);
1718 ilgen.MarkLabel (l2);
1720 if (op == RxOp.CategoryUnicode)
1726 case RxOp.Reference: {
1727 OpFlags flags = (OpFlags)op_flags [pc];
1728 bool ignore = (flags & OpFlags.IgnoreCase) > 0;
1729 bool reverse = (flags & OpFlags.RightToLeft) > 0;
1731 //length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
1732 LocalBuilder loc_length = ilgen.DeclareLocal (typeof (int));
1733 ilgen.Emit (OpCodes.Ldarg_0);
1734 ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
1735 ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "GetLastDefined", ref mi_get_last_defined));
1736 ilgen.Emit (OpCodes.Stloc, loc_length);
1739 ilgen.Emit (OpCodes.Ldloc, loc_length);
1740 ilgen.Emit (OpCodes.Ldc_I4_0);
1741 ilgen.Emit (OpCodes.Blt, frame.label_fail);
1742 //start = marks [length].Index;
1743 LocalBuilder loc_start = ilgen.DeclareLocal (typeof (int));
1744 ilgen.Emit (OpCodes.Ldarg_0);
1745 ilgen.Emit (OpCodes.Ldfld, fi_marks);
1746 ilgen.Emit (OpCodes.Ldloc, loc_length);
1747 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
1748 ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Index", ref mi_mark_get_index));
1749 ilgen.Emit (OpCodes.Stloc, loc_start);
1750 // length = marks [length].Length;
1751 ilgen.Emit (OpCodes.Ldarg_0);
1752 ilgen.Emit (OpCodes.Ldfld, fi_marks);
1753 ilgen.Emit (OpCodes.Ldloc, loc_length);
1754 ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
1755 ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Length", ref mi_mark_get_length));
1756 ilgen.Emit (OpCodes.Stloc, loc_length);
1759 ilgen.Emit (OpCodes.Ldarg_1);
1760 ilgen.Emit (OpCodes.Ldloc, loc_length);
1761 ilgen.Emit (OpCodes.Sub);
1762 ilgen.Emit (OpCodes.Starg, 1);
1765 ilgen.Emit (OpCodes.Ldarg_1);
1766 ilgen.Emit (OpCodes.Ldc_I4_0);
1767 ilgen.Emit (OpCodes.Blt, frame.label_fail);
1769 //if (strpos + length > string_end)
1771 ilgen.Emit (OpCodes.Ldarg_1);
1772 ilgen.Emit (OpCodes.Ldloc, loc_length);
1773 ilgen.Emit (OpCodes.Add);
1774 ilgen.Emit (OpCodes.Ldarg_0);
1775 ilgen.Emit (OpCodes.Ldfld, fi_string_end);
1776 ilgen.Emit (OpCodes.Bgt, frame.label_fail);
1779 LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
1780 ilgen.Emit (OpCodes.Ldarg_0);
1781 ilgen.Emit (OpCodes.Ldfld, fi_str);
1782 ilgen.Emit (OpCodes.Stloc, local_str);
1784 // end = start + length;
1785 LocalBuilder loc_end = ilgen.DeclareLocal (typeof (int));
1786 ilgen.Emit (OpCodes.Ldloc, loc_start);
1787 ilgen.Emit (OpCodes.Ldloc, loc_length);
1788 ilgen.Emit (OpCodes.Add);
1789 ilgen.Emit (OpCodes.Stloc, loc_end);
1790 //for (; start < end; ++start) {
1791 Label l_loop_footer = ilgen.DefineLabel ();
1792 ilgen.Emit (OpCodes.Br, l_loop_footer);
1793 Label l_loop_body = ilgen.DefineLabel ();
1794 ilgen.MarkLabel (l_loop_body);
1795 //if (str [strpos] != str [start])
1798 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1799 ilgen.Emit (OpCodes.Ldloc, local_str);
1800 ilgen.Emit (OpCodes.Ldarg_1);
1801 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1803 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1805 ilgen.Emit (OpCodes.Ldloc, local_textinfo);
1806 ilgen.Emit (OpCodes.Ldloc, local_str);
1807 ilgen.Emit (OpCodes.Ldloc, loc_start);
1808 ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
1810 ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
1811 ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
1813 ilgen.Emit (OpCodes.Ldarg_1);
1814 ilgen.Emit (OpCodes.Ldc_I4_1);
1815 ilgen.Emit (OpCodes.Add);
1816 ilgen.Emit (OpCodes.Starg, 1);
1818 ilgen.Emit (OpCodes.Ldloc, loc_start);
1819 ilgen.Emit (OpCodes.Ldc_I4_1);
1820 ilgen.Emit (OpCodes.Add);
1821 ilgen.Emit (OpCodes.Stloc, loc_start);
1823 ilgen.MarkLabel (l_loop_footer);
1824 ilgen.Emit (OpCodes.Ldloc, loc_start);
1825 ilgen.Emit (OpCodes.Ldloc, loc_end);
1826 ilgen.Emit (OpCodes.Blt, l_loop_body);
1830 ilgen.Emit (OpCodes.Ldarg_1);
1831 ilgen.Emit (OpCodes.Ldloc, loc_length);
1832 ilgen.Emit (OpCodes.Sub);
1833 ilgen.Emit (OpCodes.Starg, 1);
1840 case RxOp.RepeatLazy:
1841 case RxOp.IfDefined:
1843 if (RxInterpreter.trace_rx || trace_compile)
1844 Console.WriteLine ("Opcode " + op + " not supported.");
1847 throw new NotImplementedException ("Opcode '" + op + "' not supported by the regex->IL compiler.");