From 2a0e157985d790e6cbd83d61690da2709dfab9dd Mon Sep 17 00:00:00 2001 From: Tedd Hansen Date: Wed, 8 Aug 2007 14:05:13 +0000 Subject: Added ScriptEngine.DotNetEngine --- .../DotNetEngine.Compiler.LSL/temp_rc.cs | 3293 ++++++++++++++++++++ 1 file changed, 3293 insertions(+) create mode 100644 OpenSim/Region/ScriptEngine/DotNetEngine.Compiler.LSL/temp_rc.cs (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine.Compiler.LSL/temp_rc.cs') diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine.Compiler.LSL/temp_rc.cs b/OpenSim/Region/ScriptEngine/DotNetEngine.Compiler.LSL/temp_rc.cs new file mode 100644 index 0000000..fa7de2b --- /dev/null +++ b/OpenSim/Region/ScriptEngine/DotNetEngine.Compiler.LSL/temp_rc.cs @@ -0,0 +1,3293 @@ +//------------------------------------------------------------------------------ +// +// +// Copyright (c) 2002 Microsoft Corporation. All rights reserved. +// +// The use and distribution terms for this software are contained in the file +// named license.txt, which can be found in the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// You must not remove this notice, or any other, from this software. +// +// +//------------------------------------------------------------------------------ + +// The RegexCompiler class is internal to the Regex package. +// It translates a block of RegexCode to MSIL, and creates a +// subclass of the RegexRunner type. +// +#define ECMA + +namespace System.Text.RegularExpressions +{ + + using System.Collections; + using System.Threading; + using System.Reflection; + using System.Reflection.Emit; + using System.Security; + using System.Security.Permissions; + using System.Diagnostics; + using System.Globalization; + + // RegexDynamicModule + // + // Because dynamic modules are expensive and not thread-safe, we create + // one dynamic module per-thread, and cache as much information about it + // as we can. + // + // While we're at it, we just create one RegexCompiler per thread + // as well, and have RegexCompiler inherit from RegexDynamicModule. + internal class RegexDynamicModule + { + internal AssemblyBuilder _assembly; + internal ModuleBuilder _module; + + // fields that never change (making them saves about 6% overall running time) + + internal static FieldInfo _textbegF; + internal static FieldInfo _textendF; + internal static FieldInfo _textstartF; + internal static FieldInfo _textposF; + internal static FieldInfo _textF; + internal static FieldInfo _trackposF; + internal static FieldInfo _trackF; + internal static FieldInfo _stackposF; + internal static FieldInfo _stackF; + internal static FieldInfo _crawlposF; + internal static FieldInfo _crawlF; + internal static FieldInfo _matchF; + internal static FieldInfo _trackcountF; + + // note some methods + + internal static MethodInfo _ensurestorageM; + internal static MethodInfo _captureM; + internal static MethodInfo _transferM; + internal static MethodInfo _uncaptureM; + internal static MethodInfo _ismatchedM; + internal static MethodInfo _matchlengthM; + internal static MethodInfo _matchindexM; + internal static MethodInfo _isboundaryM; + internal static MethodInfo _isECMABoundaryM; + internal static MethodInfo _chartolowerM; + internal static MethodInfo _getcharM; + internal static MethodInfo _crawlposM; + internal static MethodInfo _charInSetM; + internal static MethodInfo _getCurrentCulture; + internal static MethodInfo _getInvariantCulture; +#if DBG + internal static MethodInfo _dumpstateM; +#endif + + + protected RegexDynamicModule(int moduleNum, AssemblyName an, CustomAttributeBuilder[] attribs, String resourceFile) + { + new ReflectionPermission(PermissionState.Unrestricted).Assert(); + try + { + if (an == null) + { + an = new AssemblyName(); + an.Name = "RegexAssembly" + AppDomain.CurrentDomain.GetHashCode().ToString() + "_" + moduleNum.ToString(); + _assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); + } + else + { + _assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave); + } + + _module = _assembly.DefineDynamicModule(an.Name + ".dll"); + + if (attribs != null) + { + for (int i = 0; i < attribs.Length; i++) + { + _assembly.SetCustomAttribute(attribs[i]); + } + } + + if (resourceFile != null) + { + // unmanaged resources are not supported + throw new ArgumentOutOfRangeException("resourceFile"); + } + } + finally + { + CodeAccessPermission.RevertAssert(); + } + } + + static RegexDynamicModule() + { + + new ReflectionPermission(PermissionState.Unrestricted).Assert(); + try + { + // note some fields + _textbegF = RegexRunnerField("runtextbeg"); + _textendF = RegexRunnerField("runtextend"); + _textstartF = RegexRunnerField("runtextstart"); + _textposF = RegexRunnerField("runtextpos"); + _textF = RegexRunnerField("runtext"); + _trackposF = RegexRunnerField("runtrackpos"); + _trackF = RegexRunnerField("runtrack"); + _stackposF = RegexRunnerField("runstackpos"); + _stackF = RegexRunnerField("runstack"); + _crawlposF = RegexRunnerField("runcrawlpos"); + _crawlF = RegexRunnerField("runcrawl"); + _matchF = RegexRunnerField("runmatch"); + _trackcountF = RegexRunnerField("runtrackcount"); + + // note some methods + _ensurestorageM = RegexRunnerMethod("EnsureStorage"); + _captureM = RegexRunnerMethod("Capture"); + _transferM = RegexRunnerMethod("TransferCapture"); + _uncaptureM = RegexRunnerMethod("Uncapture"); + _ismatchedM = RegexRunnerMethod("IsMatched"); + _matchlengthM = RegexRunnerMethod("MatchLength"); + _matchindexM = RegexRunnerMethod("MatchIndex"); + _isboundaryM = RegexRunnerMethod("IsBoundary"); + _charInSetM = RegexRunnerMethod("CharInSet"); + _isECMABoundaryM = RegexRunnerMethod("IsECMABoundary"); + _crawlposM = RegexRunnerMethod("Crawlpos"); + + _chartolowerM = typeof(Char).GetMethod("ToLower", new Type[] { typeof(Char), typeof(CultureInfo) }); + _getcharM = typeof(String).GetMethod("get_Chars", new Type[] { typeof(int) }); + _getCurrentCulture = typeof(CultureInfo).GetMethod("get_CurrentCulture"); + _getInvariantCulture = typeof(CultureInfo).GetMethod("get_InvariantCulture"); + + +#if DBG + _dumpstateM = RegexRunnerMethod("DumpState"); +#endif + } + finally + { + CodeAccessPermission.RevertAssert(); + } + } + + private static FieldInfo RegexRunnerField(String fieldname) + { + return typeof(RegexRunner).GetField(fieldname, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); + } + + private static MethodInfo RegexRunnerMethod(String methname) + { + return typeof(RegexRunner).GetMethod(methname, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); + } + } + + + internal sealed class RegexCompiler : RegexDynamicModule + { + internal static Object _syncObject = new Object(); + internal static int _typeCount = 0; + internal static int _moduleCount = 0; + internal static LocalDataStoreSlot _moduleSlot = Thread.AllocateDataSlot(); + + // state of the type builder + internal TypeBuilder _typebuilder; + internal MethodBuilder _methbuilder; + internal ILGenerator _ilg; + + // tokens representing local variables + internal LocalBuilder _textstartV; + internal LocalBuilder _textbegV; + internal LocalBuilder _textendV; + internal LocalBuilder _textposV; + internal LocalBuilder _textV; + internal LocalBuilder _trackposV; + internal LocalBuilder _trackV; + internal LocalBuilder _stackposV; + internal LocalBuilder _stackV; + internal LocalBuilder _tempV; + internal LocalBuilder _temp2V; + internal LocalBuilder _temp3V; + + + internal RegexCode _code; // the RegexCode object (used for debugging only) + internal int[] _codes; // the RegexCodes being translated + internal String[] _strings; // the stringtable associated with the RegexCodes + internal RegexPrefix _fcPrefix; // the possible first chars computed by RegexFCD + internal RegexPrefix _scPrefix; // the set of eaten prefix chars + internal RegexBoyerMoore _bmPrefix; // a prefix as a boyer-moore machine + internal int _anchors; // the set of anchors + + internal Label[] _labels; // a label for every operation in _codes + internal BacktrackNote[] _notes; // a list of the backtracking states to be generated + internal int _notecount; // true count of _notes (allocation grows exponentially) + internal int _trackcount; // count of backtracking states (used to reduce allocations) + + internal Label _backtrack; // label for backtracking + + + internal int _regexopcode; // the current opcode being processed + internal int _codepos; // the current code being translated + internal int _backpos; // the current backtrack-note being translated + + internal RegexOptions _options; // options + + internal const int infinite = RegexNode.infinite; // an infinity + + // special code fragments + internal int[] _uniquenote; // _notes indices for code that should be emitted <= once + internal int[] _goto; // indices for forward-jumps-through-switch (for allocations) + + // indices for unique code fragments + internal const int stackpop = 0; // pop one + internal const int stackpop2 = 1; // pop two + internal const int stackpop3 = 2; // pop three + internal const int capback = 3; // uncapture + internal const int capback2 = 4; // uncapture 2 + internal const int branchmarkback2 = 5; // back2 part of branchmark + internal const int lazybranchmarkback2 = 6; // back2 part of lazybranchmark + internal const int branchcountback2 = 7; // back2 part of branchcount + internal const int lazybranchcountback2 = 8; // back2 part of lazybranchcount + internal const int forejumpback = 9; // back part of forejump + internal const int uniquecount = 10; + + + private RegexCompiler(int moduleNum) + : base(moduleNum, null, null, null) + { + } + + private RegexCompiler(int moduleNum, AssemblyName an, CustomAttributeBuilder[] attribs, String resourceFile) + : base(moduleNum, an, attribs, resourceFile) + { + } + + // Entry point to dynamically compile a regular expression. The expression is compiled to + // an in memory assembly. + internal static RegexRunnerFactory Compile(RegexCode code, RegexOptions options) + { + RegexCompiler c; + + c = GetThreadCompiler(); + + Type factory; + RegexRunnerFactory rrf; + + new ReflectionPermission(PermissionState.Unrestricted).Assert(); + try + { + factory = c.FactoryFromCode(code, options, "Regex"); + rrf = (RegexRunnerFactory)(Activator.CreateInstance(factory, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null)); + } + finally + { + CodeAccessPermission.RevertAssert(); + } + return rrf; + } + + // Compile regular expressions into an assembly on disk. + internal static void CompileToAssembly(RegexCompilationInfo[] regexes, AssemblyName an, CustomAttributeBuilder[] attribs, String resourceFile) + { + RegexCompiler c = new RegexCompiler(0, an, attribs, resourceFile); + + for (int i = 0; i < regexes.Length; i++) + { + String pattern = regexes[i].Pattern; + RegexOptions options = regexes[i].Options; + String fullname = regexes[i].Namespace + "." + regexes[i].Name; + + RegexTree tree = RegexParser.Parse(pattern, options); + RegexCode code = RegexWriter.Write(tree); + + Type factory; + + new ReflectionPermission(PermissionState.Unrestricted).Assert(); + try + { + factory = c.FactoryFromCode(code, options, fullname); + c.GenerateRegexType(pattern, options, fullname, regexes[i].IsPublic, code, tree, factory); + } + finally + { + CodeAccessPermission.RevertAssert(); + } + } + + c.Save(); + } + + // The top-level driver. Initializes everything then calls the Generate* methods. + internal Type FactoryFromCode(RegexCode code, RegexOptions options, String typeprefix) + { + String runnertypename; + String runnerfactoryname; + Type runnertype; + Type factory; + + _code = code; + _codes = code._codes; + _strings = code._strings; + _fcPrefix = code._fcPrefix; + _scPrefix = code._scPrefix; + _bmPrefix = code._bmPrefix; + _anchors = code._anchors; + _trackcount = code._trackcount; + _options = options; + + // pick a name for the class + + lock (_syncObject) + { + + // Note: Class names must be unique within assemblies, not just + // within modules. We append the modulename to the runner name + // to make our name unique across the assembly + + runnertypename = typeprefix + "Runner" + _typeCount.ToString(); + runnerfactoryname = typeprefix + "Factory" + _typeCount.ToString(); + _typeCount++; + } + + // Generate a RegexRunner class + // (blocks are simply illustrative) + + DefineType(runnertypename, false, typeof(RegexRunner)); + { + DefineMethod("Go", null); + { + GenerateGo(); + BakeMethod(); + } + + DefineMethod("FindFirstChar", typeof(bool)); + { + GenerateFindFirstChar(); + BakeMethod(); + } + + DefineMethod("InitTrackCount", null); + { + GenerateInitTrackCount(); + BakeMethod(); + } + + runnertype = BakeType(); + } + + // Generate a RegexRunnerFactory class + + DefineType(runnerfactoryname, false, typeof(RegexRunnerFactory)); + { + DefineMethod("CreateInstance", typeof(RegexRunner)); + { + GenerateCreateInstance(runnertype); + BakeMethod(); + } + + factory = BakeType(); + } + + return factory; + } + + + internal void GenerateRegexType(String pattern, RegexOptions opts, String name, bool ispublic, RegexCode code, RegexTree tree, Type factory) + { + FieldInfo patternF = RegexField("pattern"); + FieldInfo optionsF = RegexField("roptions"); + FieldInfo factoryF = RegexField("factory"); + FieldInfo capsF = RegexField("caps"); + FieldInfo capnamesF = RegexField("capnames"); + FieldInfo capslistF = RegexField("capslist"); + FieldInfo capsizeF = RegexField("capsize"); + Type[] noTypeArray = new Type[0]; + ConstructorBuilder cbuilder; + + DefineType(name, ispublic, typeof(Regex)); + { + // define constructor + _methbuilder = null; + MethodAttributes ma = System.Reflection.MethodAttributes.Public; + cbuilder = _typebuilder.DefineConstructor(ma, CallingConventions.Standard, noTypeArray); + _ilg = cbuilder.GetILGenerator(); + { + // call base constructor + Ldthis(); + _ilg.Emit(OpCodes.Call, typeof(Regex).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, + null, new Type[0], new ParameterModifier[0])); + // set pattern + Ldthis(); + Ldstr(pattern); + Stfld(patternF); + + // set options + Ldthis(); + Ldc((int)opts); + Stfld(optionsF); + + // set factory + Ldthis(); + Newobj(factory.GetConstructor(noTypeArray)); + Stfld(factoryF); + + // set caps + if (code._caps != null) + GenerateCreateHashtable(capsF, code._caps); + + // set capnames + if (tree._capnames != null) + GenerateCreateHashtable(capnamesF, tree._capnames); + + // set capslist + if (tree._capslist != null) + { + Ldthis(); + Ldc(tree._capslist.Length); + _ilg.Emit(OpCodes.Newarr, typeof(String)); // create new string array + Stfld(capslistF); + + for (int i = 0; i < tree._capslist.Length; i++) + { + Ldthisfld(capslistF); + + Ldc(i); + Ldstr(tree._capslist[i]); + _ilg.Emit(OpCodes.Stelem_Ref); + } + } + + // set capsize + Ldthis(); + Ldc(code._capsize); + Stfld(capsizeF); + + // set runnerref and replref by calling InitializeReferences() + Ldthis(); + Call(typeof(Regex).GetMethod("InitializeReferences", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); + + + Ret(); + } + } + + // bake the constructor and type, then save the assembly + cbuilder = null; + _typebuilder.CreateType(); + _ilg = null; + _typebuilder = null; + } + + internal void GenerateCreateHashtable(FieldInfo field, Hashtable ht) + { + MethodInfo addMethod = typeof(Hashtable).GetMethod("Add", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + + Ldthis(); + Newobj(typeof(Hashtable).GetConstructor(new Type[0])); + Stfld(field); + + IDictionaryEnumerator en = ht.GetEnumerator(); + while (en.MoveNext()) + { + Ldthisfld(field); + + if (en.Key is int) + { + Ldc((int)en.Key); + _ilg.Emit(OpCodes.Box, typeof(Int32)); + } + else + Ldstr((String)en.Key); + + Ldc((int)en.Value); + _ilg.Emit(OpCodes.Box, typeof(Int32)); + Callvirt(addMethod); + } + } + + private FieldInfo RegexField(String fieldname) + { + return typeof(Regex).GetField(fieldname, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + } + + internal void Save() + { + _assembly.Save(_assembly.GetName().Name + ".dll"); + } + + // Keeps track of an operation that needs to be referenced in the backtrack-jump + // switch table, and that needs backtracking code to be emitted (if flags != 0) + internal sealed class BacktrackNote + { + internal BacktrackNote(int flags, Label label, int codepos) + { + _codepos = codepos; + _flags = flags; + _label = label; + } + + internal int _codepos; + internal int _flags; + internal Label _label; + } + + // Adds a backtrack note to the list of them, and returns the index of the new + // note (which is also the index for the jump used by the switch table) + internal int AddBacktrackNote(int flags, Label l, int codepos) + { + if (_notes == null || _notecount >= _notes.Length) + { + BacktrackNote[] newnotes = new BacktrackNote[_notes == null ? 16 : _notes.Length * 2]; + if (_notes != null) + System.Array.Copy(_notes, 0, newnotes, 0, _notecount); + _notes = newnotes; + } + + _notes[_notecount] = new BacktrackNote(flags, l, codepos); + + return _notecount++; + } + + // Adds a backtrack note for the current operation; creates a new label for + // where the code will be, and returns the switch index. + internal int AddTrack() + { + return AddTrack(RegexCode.Back); + } + + // Adds a backtrack note for the current operation; creates a new label for + // where the code will be, and returns the switch index. + internal int AddTrack(int flags) + { + return AddBacktrackNote(flags, DefineLabel(), _codepos); + } + + // Adds a switchtable entry for the specified position (for the forward + // logic; does not cause backtracking logic to be generated) + internal int AddGoto(int destpos) + { + if (_goto[destpos] == -1) + _goto[destpos] = AddBacktrackNote(0, _labels[destpos], destpos); + + return _goto[destpos]; + } + + // Adds a note for backtracking code that only needs to be generated once; + // if it's already marked to be generated, returns the switch index + // for the unique piece of code. + internal int AddUniqueTrack(int i) + { + return AddUniqueTrack(i, RegexCode.Back); + } + + // Adds a note for backtracking code that only needs to be generated once; + // if it's already marked to be generated, returns the switch index + // for the unique piece of code. + internal int AddUniqueTrack(int i, int flags) + { + if (_uniquenote[i] == -1) + _uniquenote[i] = AddTrack(flags); + + return _uniquenote[i]; + } + + // A macro for _ilg.DefineLabel + internal Label DefineLabel() + { + return _ilg.DefineLabel(); + } + + // A macro for _ilg.MarkLabel + internal void MarkLabel(Label l) + { + _ilg.MarkLabel(l); + } + + // Returns the ith operand of the current operation + internal int Operand(int i) + { + return _codes[_codepos + i + 1]; + } + + // True if the current operation is marked for the leftward direction + internal bool IsRtl() + { + return (_regexopcode & RegexCode.Rtl) != 0; + } + + // True if the current operation is marked for the leftward direction + internal bool IsCi() + { + return (_regexopcode & RegexCode.Ci) != 0; + } + +#if DBG + // True if we need to do the backtrack logic for the current operation + internal bool IsBack() { + return(_regexopcode & RegexCode.Back) != 0; + } + + // True if we need to do the second-backtrack logic for the current operation + internal bool IsBack2() { + return(_regexopcode & RegexCode.Back2) != 0; + } +#endif + + // Returns the raw regex opcode (masking out Back and Rtl) + internal int Code() + { + return _regexopcode & RegexCode.Mask; + } + + internal void Ldstr(string str) + { + _ilg.Emit(OpCodes.Ldstr, str); + } + + // A macro for the various forms of Ldc + internal void Ldc(int i) + { + if (i <= 127 && i >= -128) + _ilg.Emit(OpCodes.Ldc_I4_S, (byte)i); + else + _ilg.Emit(OpCodes.Ldc_I4, i); + } + + // A macro for _ilg.Emit(OpCodes.Dup) + internal void Dup() + { + _ilg.Emit(OpCodes.Dup); + } + + // A macro for _ilg.Emit(OpCodes.Ret) + internal void Ret() + { + _ilg.Emit(OpCodes.Ret); + } + + // A macro for _ilg.Emit(OpCodes.Pop) + internal void Pop() + { + _ilg.Emit(OpCodes.Pop); + } + + // A macro for _ilg.Emit(OpCodes.Add) + internal void Add() + { + _ilg.Emit(OpCodes.Add); + } + + // A macro for _ilg.Emit(OpCodes.Add); a true flag can turn it into a Sub + internal void Add(bool negate) + { + if (negate) + _ilg.Emit(OpCodes.Sub); + else + _ilg.Emit(OpCodes.Add); + } + + // A macro for _ilg.Emit(OpCodes.Sub) + internal void Sub() + { + _ilg.Emit(OpCodes.Sub); + } + + // A macro for _ilg.Emit(OpCodes.Sub); a true flag can turn it into a Add + internal void Sub(bool negate) + { + if (negate) + _ilg.Emit(OpCodes.Add); + else + _ilg.Emit(OpCodes.Sub); + } + + // A macro for _ilg.Emit(OpCodes.Ldloc); + internal void Ldloc(LocalBuilder lt) + { + _ilg.Emit(OpCodes.Ldloc_S, lt); + } + + // A macro for _ilg.Emit(OpCodes.Stloc); + internal void Stloc(LocalBuilder lt) + { + _ilg.Emit(OpCodes.Stloc_S, lt); + } + + // A macro for _ilg.Emit(OpCodes.Ldarg_0); + internal void Ldthis() + { + _ilg.Emit(OpCodes.Ldarg_0); + } + + // A macro for Ldthis(); Ldfld(); + internal void Ldthisfld(FieldInfo ft) + { + Ldthis(); + _ilg.Emit(OpCodes.Ldfld, ft); + } + + // A macro for Ldthis(); Ldfld(); Stloc(); + internal void Mvfldloc(FieldInfo ft, LocalBuilder lt) + { + Ldthisfld(ft); + Stloc(lt); + } + + // A macro for Ldthis(); Ldthisfld(); Stloc(); + internal void Mvlocfld(LocalBuilder lt, FieldInfo ft) + { + Ldthis(); + Ldloc(lt); + Stfld(ft); + } + + // A macro for _ilg.Emit(OpCodes.Stfld); + internal void Stfld(FieldInfo ft) + { + _ilg.Emit(OpCodes.Stfld, ft); + } + + // A macro for _ilg.Emit(OpCodes.Callvirt); + internal void Callvirt(MethodInfo mt) + { + _ilg.Emit(OpCodes.Callvirt, mt); + } + + // A macro for _ilg.Emit(OpCodes.Call); + internal void Call(MethodInfo mt) + { + _ilg.Emit(OpCodes.Call, mt); + } + + // A macro for _ilg.Emit(OpCodes.Newobj); + internal void Newobj(ConstructorInfo ct) + { + _ilg.Emit(OpCodes.Newobj, ct); + } + + // A macro for _ilg.Emit(OpCodes.Brfalse) (long form) + internal void BrfalseFar(Label l) + { + _ilg.Emit(OpCodes.Brfalse, l); + } + + // A macro for _ilg.Emit(OpCodes.Brtrue) (long form) + internal void BrtrueFar(Label l) + { + _ilg.Emit(OpCodes.Brtrue, l); + } + + // A macro for _ilg.Emit(OpCodes.Br) (long form) + internal void BrFar(Label l) + { + _ilg.Emit(OpCodes.Br, l); + } + + // A macro for _ilg.Emit(OpCodes.Ble) (long form) + internal void BleFar(Label l) + { + _ilg.Emit(OpCodes.Ble, l); + } + + // A macro for _ilg.Emit(OpCodes.Blt) (long form) + internal void BltFar(Label l) + { + _ilg.Emit(OpCodes.Blt, l); + } + + // A macro for _ilg.Emit(OpCodes.Bge) (long form) + internal void BgeFar(Label l) + { + _ilg.Emit(OpCodes.Bge, l); + } + + // A macro for _ilg.Emit(OpCodes.Bgt) (long form) + internal void BgtFar(Label l) + { + _ilg.Emit(OpCodes.Bgt, l); + } + + // A macro for _ilg.Emit(OpCodes.Bne) (long form) + internal void BneFar(Label l) + { + _ilg.Emit(OpCodes.Bne_Un, l); + } + + // A macro for _ilg.Emit(OpCodes.Beq) (long form) + internal void BeqFar(Label l) + { + _ilg.Emit(OpCodes.Beq, l); + } + + // A macro for _ilg.Emit(OpCodes.Brfalse_S) (short jump) + internal void Brfalse(Label l) + { + _ilg.Emit(OpCodes.Brfalse_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Br_S) (short jump) + internal void Br(Label l) + { + _ilg.Emit(OpCodes.Br_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Ble_S) (short jump) + internal void Ble(Label l) + { + _ilg.Emit(OpCodes.Ble_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Blt_S) (short jump) + internal void Blt(Label l) + { + _ilg.Emit(OpCodes.Blt_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Bge_S) (short jump) + internal void Bge(Label l) + { + _ilg.Emit(OpCodes.Bge_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Bgt_S) (short jump) + internal void Bgt(Label l) + { + _ilg.Emit(OpCodes.Bgt_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Bleun_S) (short jump) + internal void Bgtun(Label l) + { + _ilg.Emit(OpCodes.Bgt_Un_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Bne_S) (short jump) + internal void Bne(Label l) + { + _ilg.Emit(OpCodes.Bne_Un_S, l); + } + + // A macro for _ilg.Emit(OpCodes.Beq_S) (short jump) + internal void Beq(Label l) + { + _ilg.Emit(OpCodes.Beq_S, l); + } + + // A macro for the Ldlen instruction + internal void Ldlen() + { + _ilg.Emit(OpCodes.Ldlen); + } + + // Loads the char to the right of the current position + internal void Rightchar() + { + Ldloc(_textV); + Ldloc(_textposV); + Callvirt(_getcharM); + } + + // Loads the char to the right of the current position and advances the current position + internal void Rightcharnext() + { + Ldloc(_textV); + Ldloc(_textposV); + Dup(); + Ldc(1); + Add(); + Stloc(_textposV); + Callvirt(_getcharM); + } + + // Loads the char to the left of the current position + internal void Leftchar() + { + Ldloc(_textV); + Ldloc(_textposV); + Ldc(1); + Sub(); + Callvirt(_getcharM); + } + + // Loads the char to the left of the current position and advances (leftward) + internal void Leftcharnext() + { + Ldloc(_textV); + Ldloc(_textposV); + Ldc(1); + Sub(); + Dup(); + Stloc(_textposV); + Callvirt(_getcharM); + } + + // Creates a backtrack note and pushes the switch index it on the tracking stack + internal void Track() + { + ReadyPushTrack(); + Ldc(AddTrack()); + DoPush(); + } + + // Pushes the current switch index on the tracking stack so the backtracking + // logic will be repeated again next time we backtrack here. + // + internal void Trackagain() + { + ReadyPushTrack(); + Ldc(_backpos); + DoPush(); + } + + // Saves the value of a local variable on the tracking stack + internal void PushTrack(LocalBuilder lt) + { + ReadyPushTrack(); + Ldloc(lt); + DoPush(); + } + + // Creates a backtrack note for a piece of code that should only be generated once, + // and emits code that pushes the switch index on the backtracking stack. + internal void TrackUnique(int i) + { + ReadyPushTrack(); + Ldc(AddUniqueTrack(i)); + DoPush(); + } + + // Creates a second-backtrack note for a piece of code that should only be + // generated once, and emits code that pushes the switch index on the + // backtracking stack. + internal void TrackUnique2(int i) + { + ReadyPushTrack(); + Ldc(AddUniqueTrack(i, RegexCode.Back2)); + DoPush(); + } + + // Prologue to code that will push an element on the tracking stack + internal void ReadyPushTrack() + { + _ilg.Emit(OpCodes.Ldloc_S, _trackV); + _ilg.Emit(OpCodes.Ldloc_S, _trackposV); + _ilg.Emit(OpCodes.Ldc_I4_1); + _ilg.Emit(OpCodes.Sub); + _ilg.Emit(OpCodes.Dup); + _ilg.Emit(OpCodes.Stloc_S, _trackposV); + } + + // Pops an element off the tracking stack (leave it on the operand stack) + internal void PopTrack() + { + _ilg.Emit(OpCodes.Ldloc_S, _trackV); + _ilg.Emit(OpCodes.Ldloc_S, _trackposV); + _ilg.Emit(OpCodes.Dup); + _ilg.Emit(OpCodes.Ldc_I4_1); + _ilg.Emit(OpCodes.Add); + _ilg.Emit(OpCodes.Stloc_S, _trackposV); + _ilg.Emit(OpCodes.Ldelem_I4); + } + + // Retrieves the top entry on the tracking stack without popping + internal void TopTrack() + { + _ilg.Emit(OpCodes.Ldloc_S, _trackV); + _ilg.Emit(OpCodes.Ldloc_S, _trackposV); + _ilg.Emit(OpCodes.Ldelem_I4); + } + + // Saves the value of a local variable on the grouping stack + internal void PushStack(LocalBuilder lt) + { + ReadyPushStack(); + _ilg.Emit(OpCodes.Ldloc_S, lt); + DoPush(); + } + + // Prologue to code that will replace the ith element on the grouping stack + internal void ReadyReplaceStack(int i) + { + _ilg.Emit(OpCodes.Ldloc_S, _stackV); + _ilg.Emit(OpCodes.Ldloc_S, _stackposV); + if (i != 0) + { + Ldc(i); + _ilg.Emit(OpCodes.Add); + } + } + + // Prologue to code that will push an element on the grouping stack + internal void ReadyPushStack() + { + _ilg.Emit(OpCodes.Ldloc_S, _stackV); + _ilg.Emit(OpCodes.Ldloc_S, _stackposV); + _ilg.Emit(OpCodes.Ldc_I4_1); + _ilg.Emit(OpCodes.Sub); + _ilg.Emit(OpCodes.Dup); + _ilg.Emit(OpCodes.Stloc_S, _stackposV); + } + + // Retrieves the top entry on the stack without popping + internal void TopStack() + { + _ilg.Emit(OpCodes.Ldloc_S, _stackV); + _ilg.Emit(OpCodes.Ldloc_S, _stackposV); + _ilg.Emit(OpCodes.Ldelem_I4); + } + + // Pops an element off the grouping stack (leave it on the operand stack) + internal void PopStack() + { + _ilg.Emit(OpCodes.Ldloc_S, _stackV); + _ilg.Emit(OpCodes.Ldloc_S, _stackposV); + _ilg.Emit(OpCodes.Dup); + _ilg.Emit(OpCodes.Ldc_I4_1); + _ilg.Emit(OpCodes.Add); + _ilg.Emit(OpCodes.Stloc_S, _stackposV); + _ilg.Emit(OpCodes.Ldelem_I4); + } + + // Pops 1 element off the grouping stack and discards it + internal void PopDiscardStack() + { + PopDiscardStack(1); + } + + // Pops i elements off the grouping stack and discards them + internal void PopDiscardStack(int i) + { + _ilg.Emit(OpCodes.Ldloc_S, _stackposV); + Ldc(i); + _ilg.Emit(OpCodes.Add); + _ilg.Emit(OpCodes.Stloc_S, _stackposV); + } + + // Epilogue to code that will replace an element on a stack (use Ld* in between) + internal void DoReplace() + { + _ilg.Emit(OpCodes.Stelem_I4); + } + + // Epilogue to code that will push an element on a stack (use Ld* in between) + internal void DoPush() + { + _ilg.Emit(OpCodes.Stelem_I4); + } + + // Jump to the backtracking switch + internal void Back() + { + _ilg.Emit(OpCodes.Br, _backtrack); + } + + // Branch to the MSIL corresponding to the regex code at i + // + // A trick: since track and stack space is gobbled up unboundedly + // only as a result of branching backwards, this is where we check + // for sufficient space and trigger reallocations. + // + // If the "goto" is backwards, we generate code that checks + // available space against the amount of space that would be needed + // in the worst case by code that will only go forward; if there's + // not enough, we push the destination on the tracking stack, then + // we jump to the place where we invoke the allocator. + // + // Since forward gotos pose no threat, they just turn into a Br. + internal void Goto(int i) + { + if (i < _codepos) + { + Label l1 = DefineLabel(); + + // When going backwards, ensure enough space. + Ldloc(_trackposV); + Ldc(_trackcount * 4); + Ble(l1); + Ldloc(_stackposV); + Ldc(_trackcount * 3); + BgtFar(_labels[i]); + MarkLabel(l1); + ReadyPushTrack(); + Ldc(AddGoto(i)); + DoPush(); + BrFar(_backtrack); + } + else + { + BrFar(_labels[i]); + } + } + + // Returns the position of the next operation in the regex code, taking + // into account the different numbers of arguments taken by operations + internal int NextCodepos() + { + return _codepos + RegexCode.OpcodeSize(_codes[_codepos]); + } + + // The label for the next (forward) operation + internal Label AdvanceLabel() + { + return _labels[NextCodepos()]; + } + + // Goto the next (forward) operation + internal void Advance() + { + _ilg.Emit(OpCodes.Br, AdvanceLabel()); + } + + internal void CallToLower() + { + if ((_options & RegexOptions.CultureInvariant) != 0) + Call(_getInvariantCulture); + else + Call(_getCurrentCulture); + + Call(_chartolowerM); + } + + // Generates the first section of the MSIL. This section contains all + // the forward logic, and corresponds directly to the regex codes. + // + // In the absence of backtracking, this is all we would need. + internal void GenerateForwardSection() + { + int codepos; + + _labels = new Label[_codes.Length]; + _goto = new int[_codes.Length]; + + // initialize + + for (codepos = 0; codepos < _codes.Length; codepos += RegexCode.OpcodeSize(_codes[codepos])) + { + _goto[codepos] = -1; + _labels[codepos] = _ilg.DefineLabel(); + } + + _uniquenote = new int[uniquecount]; + for (int i = 0; i < uniquecount; i++) + _uniquenote[i] = -1; + + // emit variable initializers + + Mvfldloc(_textF, _textV); + Mvfldloc(_textstartF, _textstartV); + Mvfldloc(_textbegF, _textbegV); + Mvfldloc(_textendF, _textendV); + Mvfldloc(_textposF, _textposV); + Mvfldloc(_trackF, _trackV); + Mvfldloc(_trackposF, _trackposV); + Mvfldloc(_stackF, _stackV); + Mvfldloc(_stackposF, _stackposV); + + _backpos = -1; + + for (codepos = 0; codepos < _codes.Length; codepos += RegexCode.OpcodeSize(_codes[codepos])) + { + MarkLabel(_labels[codepos]); + _codepos = codepos; + _regexopcode = _codes[codepos]; + GenerateOneCode(); + } + } + + // Generates the middle section of the MSIL. This section contains the + // big switch jump that allows us to simulate a stack of addresses, + // and it also contains the calls that expand the tracking and the + // grouping stack when they get too full. + internal void GenerateMiddleSection() + { + Label l1 = DefineLabel(); + Label[] table; + int i; + + // Backtrack switch + MarkLabel(_backtrack); + + // first call EnsureStorage + Mvlocfld(_trackposV, _trackposF); + Mvlocfld(_stackposV, _stackposF); + Ldthis(); + Callvirt(_ensurestorageM); + Mvfldloc(_trackposF, _trackposV); + Mvfldloc(_stackposF, _stackposV); + Mvfldloc(_trackF, _trackV); + Mvfldloc(_stackF, _stackV); + + + PopTrack(); + + table = new Label[_notecount]; + for (i = 0; i < _notecount; i++) + table[i] = _notes[i]._label; + + _ilg.Emit(OpCodes.Switch, table); + + } + + // Generates the last section of the MSIL. This section contains all of + // the backtracking logic. + internal void GenerateBacktrackSection() + { + int i; + + for (i = 0; i < _notecount; i++) + { + BacktrackNote n = _notes[i]; + if (n._flags != 0) + { + _ilg.MarkLabel(n._label); + _codepos = n._codepos; + _backpos = i; + _regexopcode = _codes[n._codepos] | n._flags; + GenerateOneCode(); + } + } + } + + // Generates FindFirstChar + internal void GenerateFindFirstChar() + { + _textposV = DeclareInt(); + _textV = DeclareString(); + _tempV = DeclareInt(); + _temp2V = DeclareInt(); + + if (0 != (_anchors & (RegexFCD.Beginning | RegexFCD.Start | RegexFCD.EndZ | RegexFCD.End))) + { + if (!_code._rightToLeft) + { + if (0 != (_anchors & RegexFCD.Beginning)) + { + Label l1 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textbegF); + Ble(l1); + Ldthis(); + Ldthisfld(_textendF); + Stfld(_textposF); + Ldc(0); + Ret(); + MarkLabel(l1); + } + + if (0 != (_anchors & RegexFCD.Start)) + { + Label l1 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textstartF); + Ble(l1); + Ldthis(); + Ldthisfld(_textendF); + Stfld(_textposF); + Ldc(0); + Ret(); + MarkLabel(l1); + } + + if (0 != (_anchors & RegexFCD.EndZ)) + { + Label l1 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textendF); + Ldc(1); + Sub(); + Bge(l1); + Ldthis(); + Ldthisfld(_textendF); + Ldc(1); + Sub(); + Stfld(_textposF); + MarkLabel(l1); + } + + if (0 != (_anchors & RegexFCD.End)) + { + Label l1 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textendF); + Bge(l1); + Ldthis(); + Ldthisfld(_textendF); + Stfld(_textposF); + MarkLabel(l1); + } + } + else + { + if (0 != (_anchors & RegexFCD.End)) + { + Label l1 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textendF); + Bge(l1); + Ldthis(); + Ldthisfld(_textbegF); + Stfld(_textposF); + Ldc(0); + Ret(); + MarkLabel(l1); + } + + if (0 != (_anchors & RegexFCD.EndZ)) + { + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textendF); + Ldc(1); + Sub(); + Blt(l1); + Ldthisfld(_textposF); + Ldthisfld(_textendF); + Beq(l2); + Ldthisfld(_textF); + Ldthisfld(_textposF); + Callvirt(_getcharM); + Ldc((int)'\n'); + Beq(l2); + MarkLabel(l1); + Ldthis(); + Ldthisfld(_textbegF); + Stfld(_textposF); + Ldc(0); + Ret(); + MarkLabel(l2); + } + + if (0 != (_anchors & RegexFCD.Start)) + { + Label l1 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textstartF); + Bge(l1); + Ldthis(); + Ldthisfld(_textbegF); + Stfld(_textposF); + Ldc(0); + Ret(); + MarkLabel(l1); + } + + if (0 != (_anchors & RegexFCD.Beginning)) + { + Label l1 = DefineLabel(); + Ldthisfld(_textposF); + Ldthisfld(_textbegF); + Ble(l1); + Ldthis(); + Ldthisfld(_textbegF); + Stfld(_textposF); + MarkLabel(l1); + } + } + + + Ldc(1); + Ret(); + } + else if (_bmPrefix != null && _bmPrefix._negativeUnicode == null) + { + // Compiled Boyer-Moore string matching + + LocalBuilder chV = _tempV; + LocalBuilder testV = _tempV; + LocalBuilder limitV = _temp2V; + Label lDefaultAdvance = DefineLabel(); + Label lAdvance = DefineLabel(); + Label lFail = DefineLabel(); + Label lStart = DefineLabel(); + Label lOutOfRange = DefineLabel(); + Label lPartialMatch = DefineLabel(); + + + int chLast; + int i; + int beforefirst; + int last; + Label[] table; + + if (!_code._rightToLeft) + { + beforefirst = -1; + last = _bmPrefix._pattern.Length - 1; + } + else + { + beforefirst = _bmPrefix._pattern.Length; + last = 0; + } + + chLast = _bmPrefix._pattern[last]; + + Mvfldloc(_textF, _textV); + if (!_code._rightToLeft) + Ldthisfld(_textendF); + else + Ldthisfld(_textbegF); + Stloc(limitV); + + Ldthisfld(_textposF); + if (!_code._rightToLeft) + { + Ldc(_bmPrefix._pattern.Length - 1); + Add(); + } + else + { + Ldc(_bmPrefix._pattern.Length); + Sub(); + } + Stloc(_textposV); + Br(lStart); + + MarkLabel(lDefaultAdvance); + + if (!_code._rightToLeft) + Ldc(_bmPrefix._pattern.Length); + else + Ldc(-_bmPrefix._pattern.Length); + + MarkLabel(lAdvance); + + Ldloc(_textposV); + Add(); + Stloc(_textposV); + + MarkLabel(lStart); + + Ldloc(_textposV); + Ldloc(limitV); + if (!_code._rightToLeft) + BgeFar(lFail); + else + BltFar(lFail); + + Rightchar(); + if (_bmPrefix._caseInsensitive) + CallToLower(); + + Dup(); + Stloc(chV); + Ldc(chLast); + BeqFar(lPartialMatch); + + Ldloc(chV); + Ldc(_bmPrefix._lowASCII); + Sub(); + Dup(); + Stloc(chV); + Ldc(_bmPrefix._highASCII - _bmPrefix._lowASCII); + Bgtun(lDefaultAdvance); + + table = new Label[_bmPrefix._highASCII - _bmPrefix._lowASCII + 1]; + + for (i = _bmPrefix._lowASCII; i <= _bmPrefix._highASCII; i++) + { + if (_bmPrefix._negativeASCII[i] == beforefirst) + table[i - _bmPrefix._lowASCII] = lDefaultAdvance; + else + table[i - _bmPrefix._lowASCII] = DefineLabel(); + } + + Ldloc(chV); + _ilg.Emit(OpCodes.Switch, table); + + for (i = _bmPrefix._lowASCII; i <= _bmPrefix._highASCII; i++) + { + if (_bmPrefix._negativeASCII[i] == beforefirst) + continue; + + MarkLabel(table[i - _bmPrefix._lowASCII]); + + Ldc(_bmPrefix._negativeASCII[i]); + BrFar(lAdvance); + } + + MarkLabel(lPartialMatch); + + Ldloc(_textposV); + Stloc(testV); + + for (i = _bmPrefix._pattern.Length - 2; i >= 0; i--) + { + Label lNext = DefineLabel(); + int charindex; + + if (!_code._rightToLeft) + charindex = i; + else + charindex = _bmPrefix._pattern.Length - 1 - i; + + Ldloc(_textV); + Ldloc(testV); + Ldc(1); + Sub(_code._rightToLeft); + Dup(); + Stloc(testV); + Callvirt(_getcharM); + if (_bmPrefix._caseInsensitive) + CallToLower(); + + Ldc(_bmPrefix._pattern[charindex]); + Beq(lNext); + Ldc(_bmPrefix._positive[charindex]); + BrFar(lAdvance); + + MarkLabel(lNext); + + } + + Ldthis(); + Ldloc(testV); + if (_code._rightToLeft) + { + Ldc(1); + Add(); + } + Stfld(_textposF); + Ldc(1); + Ret(); + + MarkLabel(lFail); + + Ldthis(); + if (!_code._rightToLeft) + Ldthisfld(_textendF); + else + Ldthisfld(_textbegF); + Stfld(_textposF); + Ldc(0); + Ret(); + } + else if (_fcPrefix == null) + { + Ldc(1); + Ret(); + } + else + { + LocalBuilder cV = _temp2V; + LocalBuilder chV = _tempV; + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + Label l3 = DefineLabel(); + Label l4 = DefineLabel(); + Label l5 = DefineLabel(); + + Mvfldloc(_textposF, _textposV); + Mvfldloc(_textF, _textV); + + if (!_code._rightToLeft) + { + Ldthisfld(_textendF); + Ldloc(_textposV); + } + else + { + Ldloc(_textposV); + Ldthisfld(_textbegF); + } + Sub(); + Stloc(cV); + + Ldloc(cV); + Ldc(0); + BleFar(l4); + + MarkLabel(l1); + + Ldloc(cV); + Ldc(1); + Sub(); + Stloc(cV); + + if (_code._rightToLeft) + Leftcharnext(); + else + Rightcharnext(); + + if (_fcPrefix.CaseInsensitive) + CallToLower(); + + if (!RegexCharClass.IsSingleton(_fcPrefix.Prefix)) + { + Ldstr(_fcPrefix.Prefix); + Ldstr(String.Empty); + Call(_charInSetM); + + BrtrueFar(l2); + } + else + { + Ldc(RegexCharClass.SingletonChar(_fcPrefix.Prefix)); + Beq(l2); + } + + MarkLabel(l5); + + Ldloc(cV); + Ldc(0); + if (!RegexCharClass.IsSingleton(_fcPrefix.Prefix)) + BgtFar(l1); + else + Bgt(l1); + + Ldc(0); + BrFar(l3); + + MarkLabel(l2); + + /* // CURRENTLY DISABLED + // If for some reason we have a prefix we didn't use, use it now. + + if (_bmPrefix != null) { + if (!_code._rightToLeft) { + Ldthisfld(_textendF); + Ldloc(_textposV); + } + else { + Ldloc(_textposV); + Ldthisfld(_textbegF); + } + Sub(); + Ldc(_bmPrefix._pattern.Length - 1); + BltFar(l5); + + for (int i = 1; i < _bmPrefix._pattern.Length; i++) { + Ldloc(_textV); + Ldloc(_textposV); + if (!_code._rightToLeft) { + Ldc(i - 1); + Add(); + } + else { + Ldc(i); + Sub(); + } + Callvirt(_getcharM); + if (!_code._rightToLeft) + Ldc(_bmPrefix._pattern[i]); + else + Ldc(_bmPrefix._pattern[_bmPrefix._pattern.Length - 1 - i]); + BneFar(l5); + } + } + */ + + Ldloc(_textposV); + Ldc(1); + Sub(_code._rightToLeft); + Stloc(_textposV); + Ldc(1); + + MarkLabel(l3); + + Mvlocfld(_textposV, _textposF); + Ret(); + + MarkLabel(l4); + Ldc(0); + Ret(); + } + + } + + // Generates a very simple method that sets the _trackcount field. + internal void GenerateInitTrackCount() + { + Ldthis(); + Ldc(_trackcount); + Stfld(_trackcountF); + Ret(); + } + + // Generates a very simple factory method. + internal void GenerateCreateInstance(Type newtype) + { + Newobj(newtype.GetConstructor(new Type[0])); + Ret(); + } + + // Gets the unique-for-regex dynamic module for this thread + internal static RegexCompiler GetThreadCompiler() + { + RegexCompiler compiler = (RegexCompiler)Thread.GetData(_moduleSlot); + + if (compiler == null) + { + int moduleNum; + + lock (_syncObject) + { + moduleNum = _moduleCount++; + } + + compiler = new RegexCompiler(moduleNum); + Thread.SetData(_moduleSlot, compiler); + } + + return compiler; + } + + // Begins the definition of a new type with a specified base class + internal void DefineType(String typename, bool ispublic, Type inheritfromclass) + { + if (ispublic) + _typebuilder = _module.DefineType(typename, TypeAttributes.Class | TypeAttributes.Public, inheritfromclass); + else + _typebuilder = _module.DefineType(typename, TypeAttributes.Class | TypeAttributes.NotPublic, inheritfromclass); + + } + + // Begins the definition of a new method (no args) with a specified return value + internal void DefineMethod(String methname, Type returntype) + { + MethodAttributes ma = System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Virtual; + + _methbuilder = _typebuilder.DefineMethod(methname, ma, returntype, null); + _ilg = _methbuilder.GetILGenerator(); + } + + // Ends the definition of a method + internal void BakeMethod() + { + _methbuilder = null; + } + + // Ends the definition of a class and returns the type + internal Type BakeType() + { + Type retval = _typebuilder.CreateType(); + _typebuilder = null; + + return retval; + } + + // Declares a local int + internal LocalBuilder DeclareInt() + { + return _ilg.DeclareLocal(typeof(int)); + } + + // Declares a local int array + internal LocalBuilder DeclareIntArray() + { + return _ilg.DeclareLocal(typeof(int[])); + } + + // Declares a local char array + internal LocalBuilder DeclareCharArray() + { + return _ilg.DeclareLocal(typeof(char[])); + } + + // Declares a local string + internal LocalBuilder DeclareString() + { + return _ilg.DeclareLocal(typeof(string)); + } + + // Generates the code for "RegexRunner.Go" + internal void GenerateGo() + { + // declare some locals + + _textposV = DeclareInt(); + _textV = DeclareString(); + _trackposV = DeclareInt(); + _trackV = DeclareIntArray(); + _stackposV = DeclareInt(); + _stackV = DeclareIntArray(); + _tempV = DeclareInt(); + _temp2V = DeclareInt(); + _temp3V = DeclareInt(); + _textbegV = DeclareInt(); + _textendV = DeclareInt(); + _textstartV = DeclareInt(); + + // clear some tables + + _labels = null; + _notes = null; + _notecount = 0; + + // globally used labels + + _backtrack = DefineLabel(); + + // emit the code! + + GenerateForwardSection(); + GenerateMiddleSection(); + GenerateBacktrackSection(); + } + +#if DBG + // Some simple debugging stuff + internal static char[] Hex = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + internal static MethodInfo _debugWriteLine = typeof(Debug).GetMethod("WriteLine", new Type[] {typeof(string)}); + + internal static String BaDescription(byte[] ba) { + StringBuilder sb = new StringBuilder(); + + sb.Append("Length " + ba.Length.ToString() + "\n"); + + for (int i = 0; i < ba.Length; i++) { + sb.Append(Hex[ba[i] >> 4]); + sb.Append(Hex[ba[i] & 0xF]); + sb.Append(' '); + } + return sb.ToString(); + } + + // Debug only: emit code to print out a message + internal void Message(String str) { + Ldstr(str); + Call(_debugWriteLine); + } + +#endif + + // The main translation function. It translates the logic for a single opcode at + // the current position. The structure of this function exactly mirrors + // the structure of the inner loop of RegexInterpreter.Go(). + // + // The C# code from RegexInterpreter.Go() that corresponds to each case is + // included as a comment. + // + // Note that since we're generating code, we can collapse many cases that are + // dealt with one-at-a-time in RegexIntepreter. We can also unroll loops that + // iterate over constant strings or sets. + internal void GenerateOneCode() + { +#if DBG + if ((_options & RegexOptions.Debug) != 0) { + Mvlocfld(_textposV, _textposF); + Mvlocfld(_trackposV, _trackposF); + Mvlocfld(_stackposV, _stackposF); + Ldthis(); + Callvirt(_dumpstateM); + StringBuilder sb = new StringBuilder(); + if (_backpos > 0) + sb.AppendFormat("{0:D6} ", _backpos); + else + sb.Append(" "); + sb.Append(_code.OpcodeDescription(_codepos)); + if (IsBack()) + sb.Append(" Back"); + if (IsBack2()) + sb.Append(" Back2"); + Message(sb.ToString()); + } +#endif + + switch (_regexopcode) + { + case RegexCode.Stop: + //: return; + Mvlocfld(_textposV, _textposF); // update _textpos + Ret(); + break; + + case RegexCode.Nothing: + //: break Backward; + Back(); + break; + + case RegexCode.Goto: + //: Goto(Operand(0)); + Goto(Operand(0)); + break; + + case RegexCode.Testref: + //: if (!_match.IsMatched(Operand(0))) + //: break Backward; + Ldthis(); + Ldc(Operand(0)); + Callvirt(_ismatchedM); + BrfalseFar(_backtrack); + break; + + case RegexCode.Lazybranch: + //: Track(Textpos()); + PushTrack(_textposV); + Track(); + break; + + case RegexCode.Lazybranch | RegexCode.Back: + //: Trackframe(1); + //: Textto(Tracked(0)); + //: Goto(Operand(0)); + PopTrack(); + Stloc(_textposV); + Goto(Operand(0)); + break; + + case RegexCode.Nullmark: + //: Stack(-1); + //: Track(); + ReadyPushStack(); + Ldc(-1); + DoPush(); + TrackUnique(stackpop); + break; + + case RegexCode.Setmark: + //: Stack(Textpos()); + //: Track(); + PushStack(_textposV); + TrackUnique(stackpop); + break; + + case RegexCode.Nullmark | RegexCode.Back: + case RegexCode.Setmark | RegexCode.Back: + //: Stackframe(1); + //: break Backward; + PopDiscardStack(); + Back(); + break; + + case RegexCode.Getmark: + //: Stackframe(1); + //: Track(Stacked(0)); + //: Textto(Stacked(0)); + ReadyPushTrack(); + PopStack(); + Dup(); + Stloc(_textposV); + DoPush(); + + Track(); + break; + + case RegexCode.Getmark | RegexCode.Back: + //: Trackframe(1); + //: Stack(Tracked(0)); + //: break Backward; + ReadyPushStack(); + PopTrack(); + DoPush(); + Back(); + break; + + case RegexCode.Capturemark: + //: if (!IsMatched(Operand(1))) + //: break Backward; + //: Stackframe(1); + //: if (Operand(1) != -1) + //: TransferCapture(Operand(0), Operand(1), Stacked(0), Textpos()); + //: else + //: Capture(Operand(0), Stacked(0), Textpos()); + //: Track(Stacked(0)); + + //: Stackframe(1); + //: Capture(Operand(0), Stacked(0), Textpos()); + //: Track(Stacked(0)); + + if (Operand(1) != -1) + { + Ldthis(); + Ldc(Operand(1)); + Callvirt(_ismatchedM); + BrfalseFar(_backtrack); + } + + PopStack(); + Stloc(_tempV); + + if (Operand(1) != -1) + { + Ldthis(); + Ldc(Operand(0)); + Ldc(Operand(1)); + Ldloc(_tempV); + Ldloc(_textposV); + Callvirt(_transferM); + } + else + { + Ldthis(); + Ldc(Operand(0)); + Ldloc(_tempV); + Ldloc(_textposV); + Callvirt(_captureM); + } + + PushTrack(_tempV); + + if (Operand(0) != -1 && Operand(1) != -1) + TrackUnique(capback2); + else + TrackUnique(capback); + + break; + + + case RegexCode.Capturemark | RegexCode.Back: + //: Trackframe(1); + //: Stack(Tracked(0)); + //: Uncapture(); + //: if (Operand(0) != -1 && Operand(1) != -1) + //: Uncapture(); + //: break Backward; + ReadyPushStack(); + PopTrack(); + DoPush(); + Ldthis(); + Callvirt(_uncaptureM); + if (Operand(0) != -1 && Operand(1) != -1) + { + Ldthis(); + Callvirt(_uncaptureM); + } + Back(); + break; + + case RegexCode.Branchmark: + //: Stackframe(1); + //: + //: if (Textpos() != Stacked(0)) + //: { // Nonempty match -> loop now + //: Track(Stacked(0), Textpos()); // Save old mark, textpos + //: Stack(Textpos()); // Make new mark + //: Goto(Operand(0)); // Loop + //: } + //: else + //: { // Empty match -> straight now + //: Track2(Stacked(0)); // Save old mark + //: Advance(1); // Straight + //: } + //: continue Forward; + { + LocalBuilder mark = _tempV; + Label l1 = DefineLabel(); + + PopStack(); + Dup(); + Stloc(mark); // Stacked(0) -> temp + PushTrack(mark); + Ldloc(_textposV); + Beq(l1); // mark == textpos -> branch + + // (matched != 0) + + PushTrack(_textposV); + PushStack(_textposV); + Track(); + Goto(Operand(0)); // Goto(Operand(0)) + + // else + + MarkLabel(l1); + TrackUnique2(branchmarkback2); + break; + } + + case RegexCode.Branchmark | RegexCode.Back: + //: Trackframe(2); + //: Stackframe(1); + //: Textto(Tracked(1)); // Recall position + //: Track2(Tracked(0)); // Save old mark + //: Advance(1); + PopTrack(); + Stloc(_textposV); + PopStack(); + Pop(); + // track spot 0 is already in place + TrackUnique2(branchmarkback2); + Advance(); + break; + + case RegexCode.Branchmark | RegexCode.Back2: + //: Trackframe(1); + //: Stack(Tracked(0)); // Recall old mark + //: break Backward; // Backtrack + ReadyPushStack(); + PopTrack(); + DoPush(); + Back(); + break; + + + case RegexCode.Lazybranchmark: + //: Stackframe(1); + //: + //: if (Textpos() != Stacked(0)) + //: { // Nonempty match -> next loop + //: Track(Stacked(0), Textpos()); // Save old mark, textpos + //: } + //: else + //: { // Empty match -> no loop + //: Track2(Stacked(0)); // Save old mark + //: } + //: Advance(1); + //: continue Forward; + { + LocalBuilder mark = _tempV; + Label l1 = DefineLabel(); + + PopStack(); + Dup(); + Stloc(mark); // Stacked(0) -> temp + PushTrack(mark); + Ldloc(_textposV); + Beq(l1); // mark == textpos -> branch + + // (matched != 0) + + PushTrack(_textposV); + Track(); + Br(AdvanceLabel()); // Advance (near) + + // else + + MarkLabel(l1); + TrackUnique2(lazybranchmarkback2); + break; + } + + case RegexCode.Lazybranchmark | RegexCode.Back: + //: Trackframe(2); + //: Track2(Tracked(0)); // Save old mark + //: Stack(Textpos()); // Make new mark + //: Textto(Tracked(1)); // Recall position + //: Goto(Operand(0)); // Loop + + PopTrack(); + Stloc(_textposV); + PushStack(_textposV); + TrackUnique2(lazybranchmarkback2); + Goto(Operand(0)); + break; + + case RegexCode.Lazybranchmark | RegexCode.Back2: + //: Stackframe(1); + //: Trackframe(1); + //: Stack(Tracked(0)); // Recall old mark + //: break Backward; + ReadyReplaceStack(0); + PopTrack(); + DoReplace(); + Back(); + break; + + case RegexCode.Nullcount: + //: Stack(-1, Operand(0)); + //: Track(); + ReadyPushStack(); + Ldc(-1); + DoPush(); + ReadyPushStack(); + Ldc(Operand(0)); + DoPush(); + TrackUnique(stackpop2); + break; + + case RegexCode.Setcount: + //: Stack(Textpos(), Operand(0)); + //: Track(); + PushStack(_textposV); + ReadyPushStack(); + Ldc(Operand(0)); + DoPush(); + TrackUnique(stackpop2); + break; + + + case RegexCode.Nullcount | RegexCode.Back: + case RegexCode.Setcount | RegexCode.Back: + //: Stackframe(2); + //: break Backward; + PopDiscardStack(2); + Back(); + break; + + + case RegexCode.Branchcount: + //: Stackframe(2); + //: int mark = Stacked(0); + //: int count = Stacked(1); + //: + //: if (count >= Operand(1) || Textpos() == mark && count >= 0) + //: { // Max loops or empty match -> straight now + //: Track2(mark, count); // Save old mark, count + //: Advance(2); // Straight + //: } + //: else + //: { // Nonempty match -> count+loop now + //: Track(mark); // remember mark + //: Stack(Textpos(), count + 1); // Make new mark, incr count + //: Goto(Operand(0)); // Loop + //: } + //: continue Forward; + { + LocalBuilder count = _tempV; + LocalBuilder mark = _temp2V; + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + + PopStack(); + Stloc(count); // count -> temp + PopStack(); + Dup(); + Stloc(mark); // mark -> temp2 + PushTrack(mark); + + Ldloc(_textposV); + Bne(l1); // mark != textpos -> l1 + Ldloc(count); + Ldc(0); + Bge(l2); // count >= 0 && mark == textpos -> l2 + + MarkLabel(l1); + Ldloc(count); + Ldc(Operand(1)); + Bge(l2); // count >= Operand(1) -> l2 + + // else + PushStack(_textposV); + ReadyPushStack(); + Ldloc(count); // mark already on track + Ldc(1); + Add(); + DoPush(); + Track(); + Goto(Operand(0)); + + // if (count >= Operand(1) || Textpos() == mark) + MarkLabel(l2); + PushTrack(count); // mark already on track + TrackUnique2(branchcountback2); + break; + } + + case RegexCode.Branchcount | RegexCode.Back: + //: Trackframe(1); + //: Stackframe(2); + //: if (Stacked(1) > 0) // Positive -> can go straight + //: { + //: Textto(Stacked(0)); // Zap to mark + //: Track2(Tracked(0), Stacked(1) - 1); // Save old mark, old count + //: Advance(2); // Straight + //: continue Forward; + //: } + //: Stack(Tracked(0), Stacked(1) - 1); // recall old mark, old count + //: break Backward; + { + + LocalBuilder count = _tempV; + Label l1 = DefineLabel(); + PopStack(); + Ldc(1); + Sub(); + Dup(); + Stloc(count); + Ldc(0); + Blt(l1); + + // if (count >= 0) + PopStack(); + Stloc(_textposV); + PushTrack(count); // Tracked(0) is alredy on the track + TrackUnique2(branchcountback2); + Advance(); + + // else + MarkLabel(l1); + ReadyReplaceStack(0); + PopTrack(); + DoReplace(); + PushStack(count); + Back(); + break; + } + + case RegexCode.Branchcount | RegexCode.Back2: + //: Trackframe(2); + //: Stack(Tracked(0), Tracked(1)); // Recall old mark, old count + //: break Backward; // Backtrack + + PopTrack(); + Stloc(_tempV); + ReadyPushStack(); + PopTrack(); + DoPush(); + PushStack(_tempV); + Back(); + break; + + case RegexCode.Lazybranchcount: + //: Stackframe(2); + //: int mark = Stacked(0); + //: int count = Stacked(1); + //: + //: if (count < 0) + //: { // Negative count -> loop now + //: Track2(mark); // Save old mark + //: Stack(Textpos(), count + 1); // Make new mark, incr count + //: Goto(Operand(0)); // Loop + //: } + //: else + //: { // Nonneg count or empty match -> straight now + //: Track(mark, count, Textpos()); // Save mark, count, position + //: } + { + LocalBuilder count = _tempV; + LocalBuilder mark = _temp2V; + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + Label l3 = _labels[NextCodepos()]; + + PopStack(); + Stloc(count); // count -> temp + PopStack(); + Stloc(mark); // mark -> temp2 + + Ldloc(count); + Ldc(0); + Bge(l1); // count >= 0 -> l1 + + // if (count < 0) + PushTrack(mark); + PushStack(_textposV); + ReadyPushStack(); + Ldloc(count); + Ldc(1); + Add(); + DoPush(); + TrackUnique2(lazybranchcountback2); + Goto(Operand(0)); + + // else + MarkLabel(l1); + PushTrack(mark); + PushTrack(count); + PushTrack(_textposV); + Track(); + break; + } + + case RegexCode.Lazybranchcount | RegexCode.Back: + //: Trackframe(3); + //: int mark = Tracked(0); + //: int textpos = Tracked(2); + //: if (Tracked(1) <= Operand(1) && textpos != mark) + //: { + //: Textto(Tracked(2)); // Recall position + //: Stack(Textpos(), Tracked(1) + 1); // Make new mark, incr count + //: Track2(Tracked(0)); // Save old mark + //: Goto(Operand(0)); // Loop + //: continue Forward; + //: } + //: else + //: { + //: Stack(Tracked(0), Tracked(1)); // Recall old mark, count + //: break Backward; // backtrack + //: } + { + Label l1 = DefineLabel(); + LocalBuilder cV = _tempV; + PopTrack(); + Stloc(_textposV); + PopTrack(); + Dup(); + Stloc(cV); + Ldc(Operand(1)); + Bgt(l1); // Tracked(1) > Operand(1) -> l1 + + Ldloc(_textposV); + TopTrack(); + Beq(l1); // textpos == mark -> l1 + + PushStack(_textposV); + ReadyPushStack(); + Ldloc(cV); + Ldc(1); + Add(); + DoPush(); + TrackUnique2(lazybranchcountback2); + Goto(Operand(0)); + + MarkLabel(l1); + ReadyPushStack(); + PopTrack(); + DoPush(); + PushStack(cV); + Back(); + break; + } + + case RegexCode.Lazybranchcount | RegexCode.Back2: + //: Trackframe(1); + //: Stackframe(2); + //: Stack(Tracked(0), Stacked(1) - 1); // Recall old mark, count + //: break Backward; // Backtrack + + ReadyReplaceStack(1); + PopTrack(); + DoReplace(); + ReadyReplaceStack(0); + TopStack(); + Ldc(1); + Sub(); + DoReplace(); + Back(); + break; + + + case RegexCode.Setjump: + //: Stack(Trackpos(), Crawlpos()); + //: Track(); + ReadyPushStack(); + Ldthisfld(_trackF); + Ldlen(); + Ldloc(_trackposV); + Sub(); + DoPush(); + ReadyPushStack(); + Ldthis(); + Callvirt(_crawlposM); + DoPush(); + TrackUnique(stackpop2); + break; + + case RegexCode.Setjump | RegexCode.Back: + //: Stackframe(2); + PopDiscardStack(2); + Back(); + break; + + + case RegexCode.Backjump: + //: Stackframe(2); + //: Trackto(Stacked(0)); + //: while (Crawlpos() != Stacked(1)) + //: Uncapture(); + //: break Backward; + { + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + + PopStack(); + Ldthisfld(_trackF); + Ldlen(); + PopStack(); + Sub(); + Stloc(_trackposV); + Dup(); + Ldthis(); + Callvirt(_crawlposM); + Beq(l2); + + MarkLabel(l1); + Ldthis(); + Callvirt(_uncaptureM); + Dup(); + Ldthis(); + Callvirt(_crawlposM); + Bne(l1); + + MarkLabel(l2); + Pop(); + Back(); + break; + } + + case RegexCode.Forejump: + //: Stackframe(2); + //: Trackto(Stacked(0)); + //: Track(Stacked(1)); + PopStack(); + Stloc(_tempV); + Ldthisfld(_trackF); + Ldlen(); + PopStack(); + Sub(); + Stloc(_trackposV); + PushTrack(_tempV); + TrackUnique(forejumpback); + break; + + case RegexCode.Forejump | RegexCode.Back: + //: Trackframe(1); + //: while (Crawlpos() != Tracked(0)) + //: Uncapture(); + //: break Backward; + { + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + + PopTrack(); + + Dup(); + Ldthis(); + Callvirt(_crawlposM); + Beq(l2); + + MarkLabel(l1); + Ldthis(); + Callvirt(_uncaptureM); + Dup(); + Ldthis(); + Callvirt(_crawlposM); + Bne(l1); + + MarkLabel(l2); + Pop(); + Back(); + break; + } + + case RegexCode.Bol: + //: if (Leftchars() > 0 && CharAt(Textpos() - 1) != '\n') + //: break Backward; + { + Label l1 = _labels[NextCodepos()]; + Ldloc(_textposV); + Ldloc(_textbegV); + Ble(l1); + Leftchar(); + Ldc((int)'\n'); + BneFar(_backtrack); + break; + } + + case RegexCode.Eol: + //: if (Rightchars() > 0 && CharAt(Textpos()) != '\n') + //: break Backward; + { + Label l1 = _labels[NextCodepos()]; + Ldloc(_textposV); + Ldloc(_textendV); + Bge(l1); + Rightchar(); + Ldc((int)'\n'); + BneFar(_backtrack); + break; + } + + case RegexCode.Boundary: + case RegexCode.Nonboundary: + //: if (!IsBoundary(Textpos(), _textbeg, _textend)) + //: break Backward; + Ldthis(); + Ldloc(_textposV); + Ldloc(_textbegV); + Ldloc(_textendV); + Callvirt(_isboundaryM); + if (Code() == RegexCode.Boundary) + BrfalseFar(_backtrack); + else + BrtrueFar(_backtrack); + break; + + case RegexCode.ECMABoundary: + case RegexCode.NonECMABoundary: + //: if (!IsECMABoundary(Textpos(), _textbeg, _textend)) + //: break Backward; + Ldthis(); + Ldloc(_textposV); + Ldloc(_textbegV); + Ldloc(_textendV); + Callvirt(_isECMABoundaryM); + if (Code() == RegexCode.ECMABoundary) + BrfalseFar(_backtrack); + else + BrtrueFar(_backtrack); + break; + + case RegexCode.Beginning: + //: if (Leftchars() > 0) + //: break Backward; + Ldloc(_textposV); + Ldloc(_textbegV); + BgtFar(_backtrack); + break; + + case RegexCode.Start: + //: if (Textpos() != Textstart()) + //: break Backward; + Ldloc(_textposV); + Ldthisfld(_textstartF); + BneFar(_backtrack); + break; + + case RegexCode.EndZ: + //: if (Rightchars() > 1 || Rightchars() == 1 && CharAt(Textpos()) != '\n') + //: break Backward; + Ldloc(_textposV); + Ldloc(_textendV); + Ldc(1); + Sub(); + BltFar(_backtrack); + Ldloc(_textposV); + Ldloc(_textendV); + Bge(_labels[NextCodepos()]); + Rightchar(); + Ldc((int)'\n'); + BneFar(_backtrack); + break; + + case RegexCode.End: + //: if (Rightchars() > 0) + //: break Backward; + Ldloc(_textposV); + Ldloc(_textendV); + BltFar(_backtrack); + break; + + case RegexCode.One: + case RegexCode.Notone: + case RegexCode.Set: + case RegexCode.One | RegexCode.Rtl: + case RegexCode.Notone | RegexCode.Rtl: + case RegexCode.Set | RegexCode.Rtl: + case RegexCode.One | RegexCode.Ci: + case RegexCode.Notone | RegexCode.Ci: + case RegexCode.Set | RegexCode.Ci: + case RegexCode.One | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Notone | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Set | RegexCode.Ci | RegexCode.Rtl: + + //: if (Rightchars() < 1 || Rightcharnext() != (char)Operand(0)) + //: break Backward; + Ldloc(_textposV); + + if (!IsRtl()) + { + Ldloc(_textendV); + BgeFar(_backtrack); + Rightcharnext(); + } + else + { + Ldloc(_textbegV); + BleFar(_backtrack); + Leftcharnext(); + } + + if (IsCi()) + CallToLower(); + + if (Code() == RegexCode.Set) + { + + Ldstr(_strings[Operand(0)]); + Ldstr(_strings[Operand(1)]); + Call(_charInSetM); + + BrfalseFar(_backtrack); + } + else + { + Ldc(Operand(0)); + if (Code() == RegexCode.One) + BneFar(_backtrack); + else + BeqFar(_backtrack); + } + break; + + case RegexCode.Multi: + case RegexCode.Multi | RegexCode.Ci: + // + // + + //: String Str = _strings[Operand(0)]; + //: int i, c; + //: if (Rightchars() < (c = Str.Length)) + //: break Backward; + //: for (i = 0; c > 0; i++, c--) + //: if (Str[i] != Rightcharnext()) + //: break Backward; + { + int i; + String str; + + str = _strings[Operand(0)]; + + Ldc(str.Length); + Ldloc(_textendV); + Ldloc(_textposV); + Sub(); + BgtFar(_backtrack); + + // unroll the string + for (i = 0; i < str.Length; i++) + { + Ldloc(_textV); + Ldloc(_textposV); + if (i != 0) + { + Ldc(i); + Add(); + } + Callvirt(_getcharM); + if (IsCi()) + CallToLower(); + + Ldc((int)str[i]); + BneFar(_backtrack); + } + + Ldloc(_textposV); + Ldc(str.Length); + Add(); + Stloc(_textposV); + break; + } + + + case RegexCode.Multi | RegexCode.Rtl: + case RegexCode.Multi | RegexCode.Ci | RegexCode.Rtl: + //: String Str = _strings[Operand(0)]; + //: int c; + //: if (Leftchars() < (c = Str.Length)) + //: break Backward; + //: while (c > 0) + //: if (Str[--c] != Leftcharnext()) + //: break Backward; + { + int i; + String str; + + str = _strings[Operand(0)]; + + Ldc(str.Length); + Ldloc(_textposV); + Ldloc(_textbegV); + Sub(); + BgtFar(_backtrack); + + // unroll the string + for (i = str.Length; i > 0; ) + { + i--; + Ldloc(_textV); + Ldloc(_textposV); + Ldc(str.Length - i); + Sub(); + Callvirt(_getcharM); + if (IsCi()) + { + CallToLower(); + } + Ldc((int)str[i]); + BneFar(_backtrack); + } + + Ldloc(_textposV); + Ldc(str.Length); + Sub(); + Stloc(_textposV); + + break; + } + + case RegexCode.Ref: + case RegexCode.Ref | RegexCode.Rtl: + case RegexCode.Ref | RegexCode.Ci: + case RegexCode.Ref | RegexCode.Ci | RegexCode.Rtl: + //: int capnum = Operand(0); + //: int j, c; + //: if (!_match.IsMatched(capnum)) { + //: #if ECMA + //: if (!RegexOptions.ECMAScript) + //: #endif + //: break Backward; + //: } else { + //: if (Rightchars() < (c = _match.MatchLength(capnum))) + //: break Backward; + //: for (j = _match.MatchIndex(capnum); c > 0; j++, c--) + //: if (CharAt(j) != Rightcharnext()) + //: break Backward; + //: } + { + LocalBuilder lenV = _tempV; + LocalBuilder indexV = _temp2V; + Label l1 = DefineLabel(); + + Ldthis(); + Ldc(Operand(0)); + Callvirt(_ismatchedM); + if ((_options & RegexOptions.ECMAScript) != 0) + Brfalse(AdvanceLabel()); + else + BrfalseFar(_backtrack); // !IsMatched() -> back + + Ldthis(); + Ldc(Operand(0)); + Callvirt(_matchlengthM); + Dup(); + Stloc(lenV); + if (!IsRtl()) + { + Ldloc(_textendV); + Ldloc(_textposV); + } + else + { + Ldloc(_textposV); + Ldloc(_textbegV); + } + Sub(); + BgtFar(_backtrack); // Matchlength() > Rightchars() -> back + + Ldthis(); + Ldc(Operand(0)); + Callvirt(_matchindexM); + if (!IsRtl()) + { + Ldloc(lenV); + Add(IsRtl()); + } + Stloc(indexV); // index += len + + Ldloc(_textposV); + Ldloc(lenV); + Add(IsRtl()); + Stloc(_textposV); // texpos += len + + MarkLabel(l1); + Ldloc(lenV); + Ldc(0); + Ble(AdvanceLabel()); + Ldloc(_textV); + Ldloc(indexV); + Ldloc(lenV); + if (IsRtl()) + { + Ldc(1); + Sub(); + Dup(); + Stloc(lenV); + } + Sub(IsRtl()); + Callvirt(_getcharM); + if (IsCi()) + CallToLower(); + + Ldloc(_textV); + Ldloc(_textposV); + Ldloc(lenV); + if (!IsRtl()) + { + Dup(); + Ldc(1); + Sub(); + Stloc(lenV); + } + Sub(IsRtl()); + Callvirt(_getcharM); + if (IsCi()) + CallToLower(); + + Beq(l1); + Back(); + break; + } + + + case RegexCode.Onerep: + case RegexCode.Notonerep: + case RegexCode.Setrep: + case RegexCode.Onerep | RegexCode.Rtl: + case RegexCode.Notonerep | RegexCode.Rtl: + case RegexCode.Setrep | RegexCode.Rtl: + case RegexCode.Onerep | RegexCode.Ci: + case RegexCode.Notonerep | RegexCode.Ci: + case RegexCode.Setrep | RegexCode.Ci: + case RegexCode.Onerep | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Notonerep | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Setrep | RegexCode.Ci | RegexCode.Rtl: + //: int c = Operand(1); + //: if (Rightchars() < c) + //: break Backward; + //: char ch = (char)Operand(0); + //: while (c-- > 0) + //: if (Rightcharnext() != ch) + //: break Backward; + { + LocalBuilder lenV = _tempV; + Label l1 = DefineLabel(); + + int c = (Code() == RegexCode.Setrep) ? Operand(2) : Operand(1); + + if (c == 0) + break; + + Ldc(c); + if (!IsRtl()) + { + Ldloc(_textendV); + Ldloc(_textposV); + } + else + { + Ldloc(_textposV); + Ldloc(_textbegV); + } + Sub(); + BgtFar(_backtrack); // Matchlength() > Rightchars() -> back + + Ldloc(_textposV); + Ldc(c); + Add(IsRtl()); + Stloc(_textposV); // texpos += len + + Ldc(c); + Stloc(lenV); + + MarkLabel(l1); + Ldloc(_textV); + Ldloc(_textposV); + Ldloc(lenV); + if (IsRtl()) + { + Ldc(1); + Sub(); + Dup(); + Stloc(lenV); + Add(); + } + else + { + Dup(); + Ldc(1); + Sub(); + Stloc(lenV); + Sub(); + } + Callvirt(_getcharM); + if (IsCi()) + CallToLower(); + + if (Code() == RegexCode.Setrep) + { + Ldstr(_strings[Operand(0)]); + Ldstr(_strings[Operand(1)]); + Call(_charInSetM); + + BrfalseFar(_backtrack); + } + else + { + Ldc(Operand(0)); + if (Code() == RegexCode.Onerep) + BneFar(_backtrack); + else + BeqFar(_backtrack); + } + Ldloc(lenV); + Ldc(0); + if (Code() == RegexCode.Setrep) + BgtFar(l1); + else + Bgt(l1); + break; + } + + + case RegexCode.Oneloop: + case RegexCode.Notoneloop: + case RegexCode.Setloop: + case RegexCode.Oneloop | RegexCode.Rtl: + case RegexCode.Notoneloop | RegexCode.Rtl: + case RegexCode.Setloop | RegexCode.Rtl: + case RegexCode.Oneloop | RegexCode.Ci: + case RegexCode.Notoneloop | RegexCode.Ci: + case RegexCode.Setloop | RegexCode.Ci: + case RegexCode.Oneloop | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Notoneloop | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Setloop | RegexCode.Ci | RegexCode.Rtl: + //: int c = Operand(1); + //: if (c > Rightchars()) + //: c = Rightchars(); + //: char ch = (char)Operand(0); + //: int i; + //: for (i = c; i > 0; i--) + //: { + //: if (Rightcharnext() != ch) + //: { + //: Leftnext(); + //: break; + //: } + //: } + //: if (c > i) + //: Track(c - i - 1, Textpos() - 1); + { + LocalBuilder cV = _tempV; + LocalBuilder lenV = _temp2V; + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + + int c = (Code() == RegexCode.Setloop) ? Operand(2) : Operand(1); + + if (c == 0) + break; + if (!IsRtl()) + { + Ldloc(_textendV); + Ldloc(_textposV); + } + else + { + Ldloc(_textposV); + Ldloc(_textbegV); + } + Sub(); + if (c != infinite) + { + Label l4 = DefineLabel(); + Dup(); + Ldc(c); + Blt(l4); + Pop(); + Ldc(c); + MarkLabel(l4); + } + Dup(); + Stloc(lenV); + Ldc(1); + Add(); + Stloc(cV); + + MarkLabel(l1); + Ldloc(cV); + Ldc(1); + Sub(); + Dup(); + Stloc(cV); + Ldc(0); + if (Code() == RegexCode.Setloop) + BleFar(l2); + else + Ble(l2); + + if (IsRtl()) + Leftcharnext(); + else + Rightcharnext(); + if (IsCi()) + CallToLower(); + + if (Code() == RegexCode.Setloop) + { + Ldstr(_strings[Operand(0)]); + Ldstr(_strings[Operand(1)]); + Call(_charInSetM); + + BrtrueFar(l1); + } + else + { + Ldc(Operand(0)); + if (Code() == RegexCode.Oneloop) + Beq(l1); + else + Bne(l1); + } + + Ldloc(_textposV); + Ldc(1); + Sub(IsRtl()); + Stloc(_textposV); + + MarkLabel(l2); + Ldloc(lenV); + Ldloc(cV); + Ble(AdvanceLabel()); + + ReadyPushTrack(); + Ldloc(lenV); + Ldloc(cV); + Sub(); + Ldc(1); + Sub(); + DoPush(); + + ReadyPushTrack(); + Ldloc(_textposV); + Ldc(1); + Sub(IsRtl()); + DoPush(); + + Track(); + break; + } + + case RegexCode.Oneloop | RegexCode.Back: + case RegexCode.Notoneloop | RegexCode.Back: + case RegexCode.Setloop | RegexCode.Back: + case RegexCode.Oneloop | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Notoneloop | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Setloop | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Oneloop | RegexCode.Ci | RegexCode.Back: + case RegexCode.Notoneloop | RegexCode.Ci | RegexCode.Back: + case RegexCode.Setloop | RegexCode.Ci | RegexCode.Back: + case RegexCode.Oneloop | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Notoneloop | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Setloop | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back: + //: Trackframe(2); + //: int i = Tracked(0); + //: int pos = Tracked(1); + //: Textto(pos); + //: if (i > 0) + //: Track(i - 1, pos - 1); + //: Advance(2); + PopTrack(); + Stloc(_textposV); + PopTrack(); + Stloc(_tempV); + Ldloc(_tempV); + Ldc(0); + BleFar(AdvanceLabel()); + ReadyPushTrack(); + Ldloc(_tempV); + Ldc(1); + Sub(); + DoPush(); + ReadyPushTrack(); + Ldloc(_textposV); + Ldc(1); + Sub(IsRtl()); + DoPush(); + Trackagain(); + Advance(); + break; + + case RegexCode.Onelazy: + case RegexCode.Notonelazy: + case RegexCode.Setlazy: + case RegexCode.Onelazy | RegexCode.Rtl: + case RegexCode.Notonelazy | RegexCode.Rtl: + case RegexCode.Setlazy | RegexCode.Rtl: + case RegexCode.Onelazy | RegexCode.Ci: + case RegexCode.Notonelazy | RegexCode.Ci: + case RegexCode.Setlazy | RegexCode.Ci: + case RegexCode.Onelazy | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Notonelazy | RegexCode.Ci | RegexCode.Rtl: + case RegexCode.Setlazy | RegexCode.Ci | RegexCode.Rtl: + //: int c = Operand(1); + //: if (c > Rightchars()) + //: c = Rightchars(); + //: if (c > 0) + //: Track(c - 1, Textpos()); + { + LocalBuilder cV = _tempV; + + int c = (Code() == RegexCode.Setlazy) ? Operand(2) : Operand(1); + + if (c == 0) + break; + + if (!IsRtl()) + { + Ldloc(_textendV); + Ldloc(_textposV); + } + else + { + Ldloc(_textposV); + Ldloc(_textbegV); + } + Sub(); + if (c != infinite) + { + Label l4 = DefineLabel(); + Dup(); + Ldc(c); + Blt(l4); + Pop(); + Ldc(c); + MarkLabel(l4); + } + Dup(); + Stloc(cV); + Ldc(0); + Ble(AdvanceLabel()); + ReadyPushTrack(); + Ldloc(cV); + Ldc(1); + Sub(); + DoPush(); + PushTrack(_textposV); + Track(); + break; + } + + case RegexCode.Onelazy | RegexCode.Back: + case RegexCode.Notonelazy | RegexCode.Back: + case RegexCode.Setlazy | RegexCode.Back: + case RegexCode.Onelazy | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Notonelazy | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Setlazy | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Onelazy | RegexCode.Ci | RegexCode.Back: + case RegexCode.Notonelazy | RegexCode.Ci | RegexCode.Back: + case RegexCode.Setlazy | RegexCode.Ci | RegexCode.Back: + case RegexCode.Onelazy | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Notonelazy | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back: + case RegexCode.Setlazy | RegexCode.Ci | RegexCode.Rtl | RegexCode.Back: + //: Trackframe(2); + //: int pos = Tracked(1); + //: Textto(pos); + //: if (Rightcharnext() != (char)Operand(0)) + //: break Backward; + //: int i = Tracked(0); + //: if (i > 0) + //: Track(i - 1, pos + 1); + + PopTrack(); + Stloc(_textposV); + PopTrack(); + Stloc(_temp2V); + + if (!IsRtl()) + Rightcharnext(); + else + Leftcharnext(); + + if (IsCi()) + CallToLower(); + + if (Code() == RegexCode.Setlazy) + { + Ldstr(_strings[Operand(0)]); + Ldstr(_strings[Operand(1)]); + Call(_charInSetM); + + BrfalseFar(_backtrack); + } + else + { + Ldc(Operand(0)); + if (Code() == RegexCode.Onelazy) + BneFar(_backtrack); + else + BeqFar(_backtrack); + } + + Ldloc(_temp2V); + Ldc(0); + BleFar(AdvanceLabel()); + ReadyPushTrack(); + Ldloc(_temp2V); + Ldc(1); + Sub(); + DoPush(); + PushTrack(_textposV); + Trackagain(); + Advance(); + break; + + default: + throw new NotImplementedException(SR.GetString(SR.UnimplementedState)); + } + } + } + +} + -- cgit v1.1