/* 1. Evaluate DecimalEscape to obtain an EscapeValue E. 2. If E is not a character then go to step 6. 3. Let ch be E's character. 4. Let A be a one-element RECharSet containing the character ch. 5. Call CharacterSetMatcher(A, false) and return its Matcher result. 6. E must be an integer. Let n be that integer. 7. If n=0 or n>NCapturingParens then throw a SyntaxError exception. 8. Return an internal Matcher closure that takes two arguments, a State x and a Continuation c, and performs the following: 1. Let cap be x's captures internal array. 2. Let s be cap[n]. 3. If s is undefined, then call c(x) and return its result. 4. Let e be x's endIndex. 5. Let len be s's length. 6. Let f be e+len. 7. If f>InputLength, return failure. 8. If there exists an integer i between 0 (inclusive) and len (exclusive) such that Canonicalize(s[i]) is not the same character as Canonicalize(Input [e+i]), then return failure. 9. Let y be the State (f, cap). 10. Call c(y) and return its result. */ private static bool backrefMatcher(REGlobalData gData, int parenIndex, char [] chars, int end) { int len; int i; int parenContent = gData.parens_index (parenIndex); if (parenContent == -1) return true; len = gData.parens_length (parenIndex); if ((gData.cp + len) > end) return false; if ((gData.regexp.flags & JSREG_FOLD) != 0) { for (i = 0; i < len; i++) { if (upcase (chars [parenContent + i]) != upcase (chars [gData.cp + i])) return false; } } else { for (i = 0; i < len; i++) { if (chars [parenContent + i] != chars [gData.cp + i]) return false; } } gData.cp += len; return true; }
/* * indexp is assumed to be an array of length 1 */ internal virtual object executeRegExp(Context cx, IScriptable scopeObj, RegExpImpl res, string str, int [] indexp, int matchType) { REGlobalData gData = new REGlobalData (); int start = indexp [0]; char [] charArray = str.ToCharArray (); int end = charArray.Length; if (start > end) start = end; // // Call the recursive matcher to do the real work. // bool matches = matchRegExp (gData, re, charArray, start, end, res.multiline); if (!matches) { if (matchType != PREFIX) return null; return Undefined.Value; } int index = gData.cp; int i = index; indexp [0] = i; int matchlen = i - (start + gData.skipped); int ep = index; index -= matchlen; object result; IScriptable obj; if (matchType == TEST) { /* * Testing for a match and updating cx.regExpImpl: don't allocate * an array object, do return true. */ result = true; obj = null; } else { /* * The array returned on match has element 0 bound to the matched * string, elements 1 through re.parenCount bound to the paren * matches, an index property telling the length of the left context, * and an input property referring to the input string. */ IScriptable scope = GetTopLevelScope (scopeObj); result = ScriptRuntime.NewObject (cx, scope, "Array", null); obj = (IScriptable)result; string matchstr = new string (charArray, index, matchlen); obj.Put (0, obj, matchstr); } if (re.parenCount == 0) { res.parens = null; res.lastParen = SubString.EmptySubString; } else { SubString parsub = null; int num; res.parens = new SubString [re.parenCount]; for (num = 0; num < re.parenCount; num++) { int cap_index = gData.parens_index (num); string parstr; if (cap_index != -1) { int cap_length = gData.parens_length (num); parsub = new SubString (charArray, cap_index, cap_length); res.parens [num] = parsub; if (matchType == TEST) continue; parstr = parsub.ToString (); obj.Put (num + 1, obj, parstr); } else { if (matchType != TEST) obj.Put (num + 1, obj, Undefined.Value); } } res.lastParen = parsub; } if (!(matchType == TEST)) { /* * Define the index and input properties last for better for/in loop * order (so they come after the elements). */ obj.Put ("index", obj, (object)(start + gData.skipped)); obj.Put ("input", obj, str); } if (res.lastMatch == null) { res.lastMatch = new SubString (); res.leftContext = new SubString (); res.rightContext = new SubString (); } res.lastMatch.charArray = charArray; res.lastMatch.index = index; res.lastMatch.length = matchlen; res.leftContext.charArray = charArray; if (cx.Version == Context.Versions.JS1_2) { /* * JS1.2 emulated Perl4.0.1.8 (patch level 36) for global regexps used * in scalar contexts, and unintentionally for the string.match "list" * psuedo-context. On "hi there bye", the following would result: * * Language while(/ /g){print("$`");} s/ /$`/g * perl4.036 "hi", "there" "hihitherehi therebye" * perl5 "hi", "hi there" "hihitherehi therebye" * js1.2 "hi", "there" "hihitheretherebye" * * Insofar as JS1.2 always defined $` as "left context from the last * match" for global regexps, it was more consistent than perl4. */ res.leftContext.index = start; res.leftContext.length = gData.skipped; } else { /* * For JS1.3 and ECMAv2, emulate Perl5 exactly: * * js1.3 "hi", "hi there" "hihitherehi therebye" */ res.leftContext.index = 0; res.leftContext.length = start + gData.skipped; } res.rightContext.charArray = charArray; res.rightContext.index = ep; res.rightContext.length = end - ep; return result; }