/// <summary>Analog of C match_or_replace.</summary> /// <remarks>Analog of C match_or_replace.</remarks> private static object MatchOrReplace(Context cx, Scriptable scope, Scriptable thisObj, object[] args, RegExpImpl reImpl, GlobData data, bool forceFlat) { NativeRegExp re; string str = ScriptRuntime.ToString(thisObj); data.str = str; Scriptable topScope = ScriptableObject.GetTopLevelScope(scope); if (args.Length == 0) { RECompiled compiled = NativeRegExp.CompileRE(cx, string.Empty, string.Empty, false); re = new NativeRegExp(topScope, compiled); } else { if (args[0] is NativeRegExp) { re = (NativeRegExp)args[0]; } else { string src = ScriptRuntime.ToString(args[0]); string opt; if (data.optarg < args.Length) { args[0] = src; opt = ScriptRuntime.ToString(args[data.optarg]); } else { opt = null; } RECompiled compiled = NativeRegExp.CompileRE(cx, src, opt, forceFlat); re = new NativeRegExp(topScope, compiled); } } data.global = (re.GetFlags() & NativeRegExp.JSREG_GLOB) != 0; int[] indexp = new int[] { 0 }; object result = null; if (data.mode == RegExpProxyConstants.RA_SEARCH) { result = re.ExecuteRegExp(cx, scope, reImpl, str, indexp, NativeRegExp.TEST); if (result != null && result.Equals(true)) { result = Sharpen.Extensions.ValueOf(reImpl.leftContext.length); } else { result = Sharpen.Extensions.ValueOf(-1); } } else { if (data.global) { re.lastIndex = 0; for (int count = 0; indexp[0] <= str.Length; count++) { result = re.ExecuteRegExp(cx, scope, reImpl, str, indexp, NativeRegExp.TEST); if (result == null || !result.Equals(true)) { break; } if (data.mode == RegExpProxyConstants.RA_MATCH) { Match_glob(data, cx, scope, count, reImpl); } else { if (data.mode != RegExpProxyConstants.RA_REPLACE) { Kit.CodeBug(); } SubString lastMatch = reImpl.lastMatch; int leftIndex = data.leftIndex; int leftlen = lastMatch.index - leftIndex; data.leftIndex = lastMatch.index + lastMatch.length; Replace_glob(data, cx, scope, reImpl, leftIndex, leftlen); } if (reImpl.lastMatch.length == 0) { if (indexp[0] == str.Length) { break; } indexp[0]++; } } } else { result = re.ExecuteRegExp(cx, scope, reImpl, str, indexp, ((data.mode == RegExpProxyConstants.RA_REPLACE) ? NativeRegExp.TEST : NativeRegExp.MATCH)); } } return result; }
/// <summary>Analog of do_replace in jsstr.c</summary> private static void Do_replace(GlobData rdata, Context cx, RegExpImpl regExpImpl) { StringBuilder charBuf = rdata.charBuf; int cp = 0; string da = rdata.repstr; int dp = rdata.dollar; if (dp != -1) { int[] skip = new int[1]; do { int len = dp - cp; charBuf.Append(Sharpen.Runtime.Substring(da, cp, dp)); cp = dp; SubString sub = InterpretDollar(cx, regExpImpl, da, dp, skip); if (sub != null) { len = sub.length; if (len > 0) { charBuf.AppendRange(sub.str, sub.index, sub.index + len); } cp += skip[0]; dp += skip[0]; } else { ++dp; } dp = da.IndexOf('$', dp); } while (dp >= 0); } int daL = da.Length; if (daL > cp) { charBuf.Append(Sharpen.Runtime.Substring(da, cp, daL)); } }
private static SubString InterpretDollar(Context cx, RegExpImpl res, string da, int dp, int[] skip) { char dc; int num; int tmp; if (da[dp] != '$') { Kit.CodeBug(); } int version = cx.GetLanguageVersion(); if (version != Context.VERSION_DEFAULT && version <= Context.VERSION_1_4) { if (dp > 0 && da[dp - 1] == '\\') { return null; } } int daL = da.Length; if (dp + 1 >= daL) { return null; } dc = da[dp + 1]; if (NativeRegExp.IsDigit(dc)) { int cp; if (version != Context.VERSION_DEFAULT && version <= Context.VERSION_1_4) { if (dc == '0') { return null; } num = 0; cp = dp; while (++cp < daL && NativeRegExp.IsDigit(dc = da[cp])) { tmp = 10 * num + (dc - '0'); if (tmp < num) { break; } num = tmp; } } else { int parenCount = (res.parens == null) ? 0 : res.parens.Length; num = dc - '0'; if (num > parenCount) { return null; } cp = dp + 2; if ((dp + 2) < daL) { dc = da[dp + 2]; if (NativeRegExp.IsDigit(dc)) { tmp = 10 * num + (dc - '0'); if (tmp <= parenCount) { cp++; num = tmp; } } } if (num == 0) { return null; } } num--; skip[0] = cp - dp; return res.GetParenSubString(num); } skip[0] = 2; switch (dc) { case '$': { return new SubString("$"); } case '&': { return res.lastMatch; } case '+': { return res.lastParen; } case '`': { if (version == Context.VERSION_1_2) { res.leftContext.index = 0; res.leftContext.length = res.lastMatch.index; } return res.leftContext; } case '\'': { return res.rightContext; } } return null; }
private static void Replace_glob(GlobData rdata, Context cx, Scriptable scope, RegExpImpl reImpl, int leftIndex, int leftlen) { int replen; string lambdaStr; if (rdata.lambda != null) { // invoke lambda function with args lastMatch, $1, $2, ... $n, // leftContext.length, whole string. SubString[] parens = reImpl.parens; int parenCount = (parens == null) ? 0 : parens.Length; object[] args = new object[parenCount + 3]; args[0] = reImpl.lastMatch.ToString(); for (int i = 0; i < parenCount; i++) { SubString sub = parens[i]; if (sub != null) { args[i + 1] = sub.ToString(); } else { args[i + 1] = Undefined.instance; } } args[parenCount + 1] = Sharpen.Extensions.ValueOf(reImpl.leftContext.length); args[parenCount + 2] = rdata.str; // This is a hack to prevent expose of reImpl data to // JS function which can run new regexps modifing // regexp that are used later by the engine. // TODO: redesign is necessary if (reImpl != ScriptRuntime.GetRegExpProxy(cx)) { Kit.CodeBug(); } RegExpImpl re2 = new RegExpImpl(); re2.multiline = reImpl.multiline; re2.input = reImpl.input; ScriptRuntime.SetRegExpProxy(cx, re2); try { Scriptable parent = ScriptableObject.GetTopLevelScope(scope); object result = rdata.lambda.Call(cx, parent, parent, args); lambdaStr = ScriptRuntime.ToString(result); } finally { ScriptRuntime.SetRegExpProxy(cx, reImpl); } replen = lambdaStr.Length; } else { lambdaStr = null; replen = rdata.repstr.Length; if (rdata.dollar >= 0) { int[] skip = new int[1]; int dp = rdata.dollar; do { SubString sub = InterpretDollar(cx, reImpl, rdata.repstr, dp, skip); if (sub != null) { replen += sub.length - skip[0]; dp += skip[0]; } else { ++dp; } dp = rdata.repstr.IndexOf('$', dp); } while (dp >= 0); } } int growth = leftlen + replen + reImpl.rightContext.length; StringBuilder charBuf = rdata.charBuf; if (charBuf == null) { charBuf = new StringBuilder(growth); rdata.charBuf = charBuf; } else { charBuf.EnsureCapacity(rdata.charBuf.Length + growth); } charBuf.AppendRange(reImpl.leftContext.str, leftIndex, leftIndex + leftlen); if (rdata.lambda != null) { charBuf.Append(lambdaStr); } else { Do_replace(rdata, cx, reImpl); } }
private static void Match_glob(GlobData mdata, Context cx, Scriptable scope, int count, RegExpImpl reImpl) { if (mdata.arrayobj == null) { mdata.arrayobj = cx.NewArray(scope, 0); } SubString matchsub = reImpl.lastMatch; string matchstr = matchsub.ToString(); mdata.arrayobj.Put(count, mdata.arrayobj, matchstr); }
internal virtual object ExecuteRegExp(Context cx, Scriptable scope, RegExpImpl res, string str, int[] indexp, int matchType) { REGlobalData gData = new REGlobalData(); int start = indexp[0]; int end = str.Length; if (start > end) { start = end; } // // Call the recursive matcher to do the real work. // bool matches = MatchRegExp(gData, re, str, start, end, res.multiline); if (!matches) { if (matchType != PREFIX) { return null; } return Undefined.instance; } int index = gData.cp; int ep = indexp[0] = index; int matchlen = ep - (start + gData.skipped); index -= matchlen; object result; Scriptable obj; if (matchType == TEST) { result = true; obj = null; } else { result = cx.NewArray(scope, 0); obj = (Scriptable)result; string matchstr = Sharpen.Runtime.Substring(str, index, 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.ParensIndex(num); string parstr; if (cap_index != -1) { int cap_length = gData.ParensLength(num); parsub = new SubString(str, cap_index, cap_length); res.parens[num] = parsub; if (matchType != TEST) { obj.Put(num + 1, obj, parsub.ToString()); } } else { if (matchType != TEST) { obj.Put(num + 1, obj, Undefined.instance); } } } res.lastParen = parsub; } if (!(matchType == TEST)) { obj.Put("index", obj, Sharpen.Extensions.ValueOf(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.str = str; res.lastMatch.index = index; res.lastMatch.length = matchlen; res.leftContext.str = str; if (cx.GetLanguageVersion() == Context.VERSION_1_2) { res.leftContext.index = start; res.leftContext.length = gData.skipped; } else { res.leftContext.index = 0; res.leftContext.length = start + gData.skipped; } res.rightContext.str = str; res.rightContext.index = ep; res.rightContext.length = end - ep; return result; }