public virtual object Action(Context cx, Scriptable scope, Scriptable thisObj, object[] args, int actionType) { GlobData data = new GlobData(); data.mode = actionType; switch (actionType) { case RegExpProxyConstants.RA_MATCH: { object rval; data.optarg = 1; rval = MatchOrReplace(cx, scope, thisObj, args, this, data, false); return data.arrayobj == null ? rval : data.arrayobj; } case RegExpProxyConstants.RA_SEARCH: { data.optarg = 1; return MatchOrReplace(cx, scope, thisObj, args, this, data, false); } case RegExpProxyConstants.RA_REPLACE: { object arg1 = args.Length < 2 ? Undefined.instance : args[1]; string repstr = null; Function lambda = null; if (arg1 is Function) { lambda = (Function)arg1; } else { repstr = ScriptRuntime.ToString(arg1); } data.optarg = 2; data.lambda = lambda; data.repstr = repstr; data.dollar = repstr == null ? -1 : repstr.IndexOf('$'); data.charBuf = null; data.leftIndex = 0; object val = MatchOrReplace(cx, scope, thisObj, args, this, data, true); if (data.charBuf == null) { if (data.global || val == null || !val.Equals(true)) { return data.str; } SubString lc = this.leftContext; Replace_glob(data, cx, scope, this, lc.index, lc.length); } SubString rc = this.rightContext; data.charBuf.AppendRange(rc.str, rc.index, rc.index + rc.length); return data.charBuf.ToString(); } default: { throw Kit.CodeBug(); } } }
/// <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 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); }