public override IScriptable Construct(Context cx, IScriptable scope, object [] args) { BuiltinRegExp re = new BuiltinRegExp(); re.compile(cx, scope, args); ScriptRuntime.setObjectProtoAndParent(re, scope); return(re); }
private static SubString interpretDollar(Context cx, RegExpImpl res, string da, int dp, int [] skip) { char dc; int num, tmp; if (da [dp] != '$') { Context.CodeBug(); } /* Allow a real backslash (literal "\\") to escape "$1" etc. */ Context.Versions version = cx.Version; if (version != Context.Versions.Default && version <= Context.Versions.JS1_4) { if (dp > 0 && da [dp - 1] == '\\') { return(null); } } int daL = da.Length; if (dp + 1 >= daL) { return(null); } /* Interpret all Perl match-induced dollar variables. */ dc = da [dp + 1]; if (BuiltinRegExp.isDigit(dc)) { int cp; if (version != Context.Versions.Default && version <= Context.Versions.JS1_4) { if (dc == '0') { return(null); } /* Check for overflow to avoid gobbling arbitrary decimal digits. */ num = 0; cp = dp; while (++cp < daL && BuiltinRegExp.isDigit(dc = da [cp])) { tmp = 10 * num + (dc - '0'); if (tmp < num) { break; } num = tmp; } } else { /* ECMA 3, 1-9 or 01-99 */ 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 (BuiltinRegExp.isDigit(dc)) { tmp = 10 * num + (dc - '0'); if (tmp <= parenCount) { cp++; num = tmp; } } } if (num == 0) { return(null); /* $0 or $00 is not valid */ } } /* Adjust num from 1 $n-origin to 0 array-index-origin. */ 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.Versions.JS1_2) { /* * JS1.2 imitated the Perl4 bug where left context at each step * in an iterative use of a global regexp started from last match, * not from the start of the target string. But Perl4 does start * $` at the beginning of the target string when it is used in a * substitution, so we emulate that special case here. */ res.leftContext.index = 0; res.leftContext.length = res.lastMatch.index; } return(res.leftContext); case '\'': return(res.rightContext); } return(null); }
public virtual int FindSplit(Context cx, IScriptable scope, string target, string separator, IScriptable reObj, int [] ip, int [] matchlen, bool [] matched, string [] [] parensp) { int i = ip [0]; int length = target.Length; int result; Context.Versions version = cx.Version; BuiltinRegExp re = (BuiltinRegExp)reObj; while (true) { // imitating C label /* JS1.2 deviated from Perl by never matching at end of string. */ int ipsave = ip [0]; // reuse ip to save object creation ip [0] = i; object ret = re.executeRegExp(cx, scope, this, target, ip, BuiltinRegExp.TEST); if (ret == null || !ret.Equals(true)) { // Mismatch: ensure our caller advances i past end of string. ip [0] = ipsave; matchlen [0] = 1; matched [0] = false; return(length); } i = ip [0]; ip [0] = ipsave; matched [0] = true; SubString sep = this.lastMatch; matchlen [0] = sep.length; if (matchlen [0] == 0) { /* * Empty string match: never split on an empty * match at the start of a find_split cycle. Same * rule as for an empty global match in * match_or_replace. */ if (i == ip [0]) { /* * "Bump-along" to avoid sticking at an empty * match, but don't bump past end of string -- * our caller must do that by adding * sep->length to our return value. */ if (i == length) { if (version == Context.Versions.JS1_2) { matchlen [0] = 1; result = i; } else { result = -1; } break; } i++; goto again; // imitating C goto } } // PR_ASSERT((size_t)i >= sep->length); result = i - matchlen [0]; break; again: ; } int size = (parens == null) ? 0 : parens.Length; parensp [0] = new string [size]; for (int num = 0; num < size; num++) { SubString parsub = getParenSubString(num); parensp [0] [num] = parsub.ToString(); } return(result); }
public virtual object Compile(Context cx, string source, string flags) { return(BuiltinRegExp.compileRE(source, flags, false)); }
/// <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); }