public virtual object Perform (Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpActions actionType) { GlobData data = new GlobData (); data.mode = actionType; switch ( (RegExpActions)actionType) { case EcmaScript.NET.RegExpActions.Match: { object rval; data.optarg = 1; rval = matchOrReplace (cx, scope, thisObj, args, this, data, false); return data.arrayobj == null ? rval : data.arrayobj; } case EcmaScript.NET.RegExpActions.Search: data.optarg = 1; return matchOrReplace (cx, scope, thisObj, args, this, data, false); case EcmaScript.NET.RegExpActions.Replace: { object arg1 = args.Length < 2 ? Undefined.Value : args [1]; string repstr = null; IFunction lambda = null; if (arg1 is IFunction) { lambda = (IFunction)arg1; } else { repstr = ScriptConvert.ToString (arg1); } data.optarg = 2; data.lambda = lambda; data.repstr = repstr; data.dollar = repstr == null ? -1 : repstr.IndexOf ((char)'$'); data.charBuf = null; data.leftIndex = 0; object val = matchOrReplace (cx, scope, thisObj, args, this, data, true); SubString rc = this.rightContext; if (data.charBuf == null) { if (data.global || val == null || !val.Equals (true)) { /* Didn't match even once. */ return data.str; } SubString lc = this.leftContext; replace_glob (data, cx, scope, this, lc.index, lc.length); } data.charBuf.Append (rc.charArray, rc.index, rc.length); return data.charBuf.ToString (); } default: throw Context.CodeBug (); } }
/* * Analog of match_glob() in jsstr.c */ private static void match_glob(GlobData mdata, Context cx, IScriptable scope, int count, RegExpImpl reImpl) { if (mdata.arrayobj == null) { IScriptable s = ScriptableObject.GetTopLevelScope(scope); mdata.arrayobj = ScriptRuntime.NewObject(cx, s, "Array", null); } SubString matchsub = reImpl.lastMatch; string matchstr = matchsub.ToString(); mdata.arrayobj.Put(count, mdata.arrayobj, matchstr); }
/// <summary> Analog of do_replace in jsstr.c</summary> private static void do_replace(GlobData rdata, Context cx, RegExpImpl regExpImpl) { System.Text.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(da.Substring(cp, (dp) - (cp))); cp = dp; SubString sub = interpretDollar(cx, regExpImpl, da, dp, skip); if (sub != null) { len = sub.length; if (len > 0) { charBuf.Append(sub.charArray, sub.index, len); } cp += skip [0]; dp += skip [0]; } else { ++dp; } dp = da.IndexOf((char)'$', dp); }while (dp >= 0); } int daL = da.Length; if (daL > cp) { charBuf.Append(da.Substring(cp, (daL) - (cp))); } }
/// <summary> Analog of C match_or_replace.</summary> private static object matchOrReplace (Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpImpl reImpl, GlobData data, bool forceFlat) { BuiltinRegExp re; string str = ScriptConvert.ToString (thisObj); data.str = str; IScriptable topScope = ScriptableObject.GetTopLevelScope (scope); if (args.Length == 0) { object compiled = BuiltinRegExp.compileRE ("", "", false); re = new BuiltinRegExp (topScope, compiled); } else if (args [0] is BuiltinRegExp) { re = (BuiltinRegExp)args [0]; } else { string src = ScriptConvert.ToString (args [0]); string opt; if (data.optarg < args.Length) { args [0] = src; opt = ScriptConvert.ToString (args [data.optarg]); } else { opt = null; } object compiled = BuiltinRegExp.compileRE (src, opt, forceFlat); re = new BuiltinRegExp (topScope, compiled); } data.regexp = re; data.global = (re.Flags & BuiltinRegExp.JSREG_GLOB) != 0; int [] indexp = new int [] { 0 }; object result = null; if (data.mode == EcmaScript.NET.RegExpActions.Search) { result = re.executeRegExp (cx, scope, reImpl, str, indexp, BuiltinRegExp.TEST); if (result != null && result.Equals (true)) result = (int)reImpl.leftContext.length; else result = -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, BuiltinRegExp.TEST); if (result == null || !result.Equals (true)) break; if (data.mode == EcmaScript.NET.RegExpActions.Match) { match_glob (data, cx, scope, count, reImpl); } else { if (data.mode != EcmaScript.NET.RegExpActions.Replace) Context.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 == EcmaScript.NET.RegExpActions.Replace) ? BuiltinRegExp.TEST : BuiltinRegExp.MATCH)); } return result; }
/// <summary> Analog of do_replace in jsstr.c</summary> private static void do_replace (GlobData rdata, Context cx, RegExpImpl regExpImpl) { System.Text.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 (da.Substring (cp, (dp) - (cp))); cp = dp; SubString sub = interpretDollar (cx, regExpImpl, da, dp, skip); if (sub != null) { len = sub.length; if (len > 0) { charBuf.Append (sub.charArray, sub.index, len); } cp += skip [0]; dp += skip [0]; } else { ++dp; } dp = da.IndexOf ((char)'$', dp); } while (dp >= 0); } int daL = da.Length; if (daL > cp) { charBuf.Append (da.Substring (cp, (daL) - (cp))); } }
/* * Analog of replace_glob() in jsstr.c */ private static void replace_glob (GlobData rdata, Context cx, IScriptable 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.Value; } } args [parenCount + 1] = (int)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 != cx.RegExpProxy) Context.CodeBug (); RegExpImpl re2 = new RegExpImpl (); re2.multiline = reImpl.multiline; re2.input = reImpl.input; cx.RegExpProxy = re2; try { IScriptable parent = ScriptableObject.GetTopLevelScope (scope); object result = rdata.lambda.Call (cx, parent, parent, args); lambdaStr = ScriptConvert.ToString (result); } finally { cx.RegExpProxy = 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 ((char)'$', dp); } while (dp >= 0); } } int growth = leftlen + replen + reImpl.rightContext.length; System.Text.StringBuilder charBuf = rdata.charBuf; if (charBuf == null) { charBuf = new System.Text.StringBuilder (growth); rdata.charBuf = charBuf; } else { charBuf.EnsureCapacity (rdata.charBuf.Length + growth); } charBuf.Append (reImpl.leftContext.charArray, leftIndex, leftlen); if (rdata.lambda != null) { charBuf.Append (lambdaStr); } else { do_replace (rdata, cx, reImpl); } }
/* * Analog of match_glob() in jsstr.c */ private static void match_glob (GlobData mdata, Context cx, IScriptable scope, int count, RegExpImpl reImpl) { if (mdata.arrayobj == null) { IScriptable s = ScriptableObject.GetTopLevelScope (scope); mdata.arrayobj = ScriptRuntime.NewObject (cx, s, "Array", null); } SubString matchsub = reImpl.lastMatch; string matchstr = matchsub.ToString (); mdata.arrayobj.Put (count, mdata.arrayobj, matchstr); }
public virtual object Perform(Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpActions actionType) { GlobData data = new GlobData(); data.mode = actionType; switch ((RegExpActions)actionType) { case EcmaScript.NET.RegExpActions.Match: { object rval; data.optarg = 1; rval = matchOrReplace(cx, scope, thisObj, args, this, data, false); return(data.arrayobj == null ? rval : data.arrayobj); } case EcmaScript.NET.RegExpActions.Search: data.optarg = 1; return(matchOrReplace(cx, scope, thisObj, args, this, data, false)); case EcmaScript.NET.RegExpActions.Replace: { object arg1 = args.Length < 2 ? Undefined.Value : args [1]; string repstr = null; IFunction lambda = null; if (arg1 is IFunction) { lambda = (IFunction)arg1; } else { repstr = ScriptConvert.ToString(arg1); } data.optarg = 2; data.lambda = lambda; data.repstr = repstr; data.dollar = repstr == null ? -1 : repstr.IndexOf((char)'$'); data.charBuf = null; data.leftIndex = 0; object val = matchOrReplace(cx, scope, thisObj, args, this, data, true); SubString rc = this.rightContext; if (data.charBuf == null) { if (data.global || val == null || !val.Equals(true)) { /* Didn't match even once. */ return(data.str); } SubString lc = this.leftContext; replace_glob(data, cx, scope, this, lc.index, lc.length); } data.charBuf.Append(rc.charArray, rc.index, rc.length); return(data.charBuf.ToString()); } default: throw Context.CodeBug(); } }
/* * Analog of replace_glob() in jsstr.c */ private static void replace_glob(GlobData rdata, Context cx, IScriptable 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.Value; } } args [parenCount + 1] = (int)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 != cx.RegExpProxy) { Context.CodeBug(); } RegExpImpl re2 = new RegExpImpl(); re2.multiline = reImpl.multiline; re2.input = reImpl.input; cx.RegExpProxy = re2; try { IScriptable parent = ScriptableObject.GetTopLevelScope(scope); object result = rdata.lambda.Call(cx, parent, parent, args); lambdaStr = ScriptConvert.ToString(result); } finally { cx.RegExpProxy = 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((char)'$', dp); }while (dp >= 0); } } int growth = leftlen + replen + reImpl.rightContext.length; System.Text.StringBuilder charBuf = rdata.charBuf; if (charBuf == null) { charBuf = new System.Text.StringBuilder(growth); rdata.charBuf = charBuf; } else { charBuf.EnsureCapacity(rdata.charBuf.Length + growth); } charBuf.Append(reImpl.leftContext.charArray, leftIndex, leftlen); if (rdata.lambda != null) { charBuf.Append(lambdaStr); } else { do_replace(rdata, cx, reImpl); } }
/// <summary> Analog of C match_or_replace.</summary> private static object matchOrReplace(Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpImpl reImpl, GlobData data, bool forceFlat) { BuiltinRegExp re; string str = ScriptConvert.ToString(thisObj); data.str = str; IScriptable topScope = ScriptableObject.GetTopLevelScope(scope); if (args.Length == 0) { object compiled = BuiltinRegExp.compileRE("", "", false); re = new BuiltinRegExp(topScope, compiled); } else if (args [0] is BuiltinRegExp) { re = (BuiltinRegExp)args [0]; } else { string src = ScriptConvert.ToString(args [0]); string opt; if (data.optarg < args.Length) { args [0] = src; opt = ScriptConvert.ToString(args [data.optarg]); } else { opt = null; } object compiled = BuiltinRegExp.compileRE(src, opt, forceFlat); re = new BuiltinRegExp(topScope, compiled); } data.regexp = re; data.global = (re.Flags & BuiltinRegExp.JSREG_GLOB) != 0; int [] indexp = new int [] { 0 }; object result = null; if (data.mode == EcmaScript.NET.RegExpActions.Search) { result = re.executeRegExp(cx, scope, reImpl, str, indexp, BuiltinRegExp.TEST); if (result != null && result.Equals(true)) { result = (int)reImpl.leftContext.length; } else { result = -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, BuiltinRegExp.TEST); if (result == null || !result.Equals(true)) { break; } if (data.mode == EcmaScript.NET.RegExpActions.Match) { match_glob(data, cx, scope, count, reImpl); } else { if (data.mode != EcmaScript.NET.RegExpActions.Replace) { Context.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 == EcmaScript.NET.RegExpActions.Replace) ? BuiltinRegExp.TEST : BuiltinRegExp.MATCH)); } return(result); }