Skip to content

Commit

Permalink
Pull Request mozilla#1434: Various fixes and implementations to Nativ…
Browse files Browse the repository at this point in the history
…eRegExp
  • Loading branch information
rbri committed Jan 5, 2024
2 parents ef18cb9 + c61b21c commit f73614e
Show file tree
Hide file tree
Showing 8 changed files with 493 additions and 397 deletions.
65 changes: 42 additions & 23 deletions src/org/mozilla/javascript/NativeString.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ protected void fillConstructorProperties(IdFunctionObject ctor) {
addIdFunctionProperty(ctor, STRING_TAG, ConstructorId_match, "match", 2);
addIdFunctionProperty(ctor, STRING_TAG, ConstructorId_search, "search", 2);
addIdFunctionProperty(ctor, STRING_TAG, ConstructorId_replace, "replace", 2);
addIdFunctionProperty(ctor, STRING_TAG, ConstructorId_replaceAll, "replaceAll", 2);
addIdFunctionProperty(ctor, STRING_TAG, ConstructorId_localeCompare, "localeCompare", 2);
addIdFunctionProperty(
ctor, STRING_TAG, ConstructorId_toLocaleLowerCase, "toLocaleLowerCase", 1);
Expand Down Expand Up @@ -246,6 +247,10 @@ protected void initPrototypeId(int id) {
arity = 2;
s = "replace";
break;
case Id_replaceAll:
arity = 2;
s = "replaceAll";
break;
case Id_at:
arity = 1;
s = "at";
Expand Down Expand Up @@ -345,6 +350,7 @@ public Object execIdCall(
case ConstructorId_match:
case ConstructorId_search:
case ConstructorId_replace:
case ConstructorId_replaceAll:
case ConstructorId_localeCompare:
case ConstructorId_toLocaleLowerCase:
{
Expand Down Expand Up @@ -463,10 +469,15 @@ public Object execIdCall(
String thisString =
ScriptRuntime.toString(requireObjectCoercible(cx, thisObj, f));
if (args.length > 0 && args[0] instanceof NativeRegExp) {
throw ScriptRuntime.typeErrorById(
"msg.first.arg.not.regexp",
String.class.getSimpleName(),
f.getFunctionName());
if (ScriptableObject.isTrue(
ScriptableObject.getProperty(
ScriptableObject.ensureScriptable(args[0]),
SymbolKey.MATCH))) {
throw ScriptRuntime.typeErrorById(
"msg.first.arg.not.regexp",
String.class.getSimpleName(),
f.getFunctionName());
}
}

int idx = js_indexOf(id, thisString, args);
Expand Down Expand Up @@ -599,14 +610,17 @@ public Object execIdCall(
case Id_match:
case Id_search:
case Id_replace:
case Id_replaceAll:
{
int actionType;
if (id == Id_match) {
actionType = RegExpProxy.RA_MATCH;
} else if (id == Id_search) {
actionType = RegExpProxy.RA_SEARCH;
} else {
} else if (id == Id_replace) {
actionType = RegExpProxy.RA_REPLACE;
} else {
actionType = RegExpProxy.RA_REPLACE_ALL;
}

requireObjectCoercible(cx, thisObj, f);
Expand Down Expand Up @@ -1286,6 +1300,9 @@ protected int findPrototypeId(String s) {
case "replace":
id = Id_replace;
break;
case "replaceAll":
id = Id_replaceAll;
break;
case "localeCompare":
id = Id_localeCompare;
break;
Expand Down Expand Up @@ -1380,24 +1397,25 @@ protected int findPrototypeId(String s) {
Id_match = 31,
Id_search = 32,
Id_replace = 33,
Id_localeCompare = 34,
Id_toLocaleLowerCase = 35,
Id_toLocaleUpperCase = 36,
Id_trim = 37,
Id_trimLeft = 38,
Id_trimRight = 39,
Id_includes = 40,
Id_startsWith = 41,
Id_endsWith = 42,
Id_normalize = 43,
Id_repeat = 44,
Id_codePointAt = 45,
Id_padStart = 46,
Id_padEnd = 47,
SymbolId_iterator = 48,
Id_trimStart = 49,
Id_trimEnd = 50,
Id_at = 51,
Id_replaceAll = 34,
Id_localeCompare = 35,
Id_toLocaleLowerCase = 36,
Id_toLocaleUpperCase = 37,
Id_trim = 38,
Id_trimLeft = 39,
Id_trimRight = 40,
Id_includes = 41,
Id_startsWith = 42,
Id_endsWith = 43,
Id_normalize = 44,
Id_repeat = 45,
Id_codePointAt = 46,
Id_padStart = 47,
Id_padEnd = 48,
SymbolId_iterator = 49,
Id_trimStart = 50,
Id_trimEnd = 51,
Id_at = 52,
MAX_PROTOTYPE_ID = Id_at;
private static final int ConstructorId_charAt = -Id_charAt,
ConstructorId_charCodeAt = -Id_charCodeAt,
Expand All @@ -1414,6 +1432,7 @@ protected int findPrototypeId(String s) {
ConstructorId_match = -Id_match,
ConstructorId_search = -Id_search,
ConstructorId_replace = -Id_replace,
ConstructorId_replaceAll = -Id_replaceAll,
ConstructorId_localeCompare = -Id_localeCompare,
ConstructorId_toLocaleLowerCase = -Id_toLocaleLowerCase;

Expand Down
3 changes: 2 additions & 1 deletion src/org/mozilla/javascript/RegExpProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public interface RegExpProxy {
// Types of regexp actions
public static final int RA_MATCH = 1;
public static final int RA_REPLACE = 2;
public static final int RA_SEARCH = 3;
public static final int RA_REPLACE_ALL = 3;
public static final int RA_SEARCH = 4;

public boolean isRegExp(Scriptable obj);

Expand Down
4 changes: 2 additions & 2 deletions src/org/mozilla/javascript/TokenStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -1496,8 +1496,8 @@ void readRegExp(int startToken) throws IOException {
if (matchChar('g')) addToString('g');
else if (matchChar('i')) addToString('i');
else if (matchChar('m')) addToString('m');
else if (matchChar('y')) // FireFox 3
addToString('y');
else if (matchChar('s')) addToString('s');
else if (matchChar('y')) addToString('y');
else break;
}
tokenEnd = start + stringBufferTop + 2; // include slashes
Expand Down
37 changes: 33 additions & 4 deletions src/org/mozilla/javascript/regexp/NativeRegExp.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.mozilla.javascript.IdFunctionObject;
import org.mozilla.javascript.IdScriptableObject;
import org.mozilla.javascript.Kit;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
Expand All @@ -37,7 +38,8 @@ public class NativeRegExp extends IdScriptableObject {
public static final int JSREG_GLOB = 0x1; // 'g' flag: global
public static final int JSREG_FOLD = 0x2; // 'i' flag: fold
public static final int JSREG_MULTILINE = 0x4; // 'm' flag: multiline
public static final int JSREG_STICKY = 0x8; // 'y' flag: sticky
public static final int JSREG_DOTALL = 0x8; // 's' flag: dotAll
public static final int JSREG_STICKY = 0x10; // 'y' flag: sticky

// type of match to perform
public static final int TEST = 0;
Expand Down Expand Up @@ -196,6 +198,7 @@ private void appendFlags(StringBuilder buf) {
if ((re.flags & JSREG_GLOB) != 0) buf.append('g');
if ((re.flags & JSREG_FOLD) != 0) buf.append('i');
if ((re.flags & JSREG_MULTILINE) != 0) buf.append('m');
if ((re.flags & JSREG_DOTALL) != 0) buf.append('s');
if ((re.flags & JSREG_STICKY) != 0) buf.append('y');
}

Expand Down Expand Up @@ -278,6 +281,8 @@ static RECompiled compileRE(Context cx, String str, String global, boolean flat)
f = JSREG_FOLD;
} else if (c == 'm') {
f = JSREG_MULTILINE;
} else if (c == 's') {
f = JSREG_DOTALL;
} else if (c == 'y') {
f = JSREG_STICKY;
} else {
Expand Down Expand Up @@ -1709,7 +1714,9 @@ private static int simpleMatch(
^ ((gData.cp < end) && isWord(input.charAt(gData.cp))));
break;
case REOP_DOT:
if (gData.cp != end && !isLineTerm(input.charAt(gData.cp))) {
if (gData.cp != end
&& ((gData.regexp.flags & JSREG_DOTALL) != 0
|| !isLineTerm(input.charAt(gData.cp)))) {
result = true;
gData.cp++;
}
Expand Down Expand Up @@ -2521,8 +2528,9 @@ private static void reportError(String messageId, String arg) {
Id_global = 4,
Id_ignoreCase = 5,
Id_multiline = 6,
Id_sticky = 7,
MAX_INSTANCE_ID = 7;
Id_dotAll = 7,
Id_sticky = 8,
MAX_INSTANCE_ID = 8;

@Override
protected int getMaxInstanceId() {
Expand Down Expand Up @@ -2551,6 +2559,9 @@ protected int findInstanceIdInfo(String s) {
case "multiline":
id = Id_multiline;
break;
case "dotAll":
id = Id_dotAll;
break;
case "sticky":
id = Id_sticky;
break;
Expand All @@ -2571,6 +2582,7 @@ protected int findInstanceIdInfo(String s) {
case Id_global:
case Id_ignoreCase:
case Id_multiline:
case Id_dotAll:
case Id_sticky:
attr = PERMANENT | READONLY | DONTENUM;
break;
Expand All @@ -2595,6 +2607,8 @@ protected String getInstanceIdName(int id) {
return "ignoreCase";
case Id_multiline:
return "multiline";
case Id_dotAll:
return "dotAll";
case Id_sticky:
return "sticky";
}
Expand All @@ -2620,6 +2634,8 @@ protected Object getInstanceIdValue(int id) {
return ScriptRuntime.wrapBoolean((re.flags & JSREG_FOLD) != 0);
case Id_multiline:
return ScriptRuntime.wrapBoolean((re.flags & JSREG_MULTILINE) != 0);
case Id_dotAll:
return ScriptRuntime.wrapBoolean((re.flags & JSREG_DOTALL) != 0);
case Id_sticky:
return ScriptRuntime.wrapBoolean((re.flags & JSREG_STICKY) != 0);
}
Expand All @@ -2644,6 +2660,7 @@ protected void setInstanceIdValue(int id, Object value) {
case Id_global:
case Id_ignoreCase:
case Id_multiline:
case Id_dotAll:
case Id_sticky:
return;
}
Expand Down Expand Up @@ -2716,6 +2733,18 @@ public Object execIdCall(
return realThis(thisObj, f).compile(cx, scope, args);

case Id_toString:
// thisObj != scope is a strange hack but i had no better idea for the moment
if (thisObj != scope && thisObj instanceof NativeObject) {
Object sourceObj = thisObj.get("source", thisObj);
String source =
sourceObj.equals(NOT_FOUND) ? "undefined" : escapeRegExp(sourceObj);
Object flagsObj = thisObj.get("flags", thisObj);
String flags = flagsObj.equals(NOT_FOUND) ? "undefined" : flagsObj.toString();

return "/" + source + "/" + flags;
}
return realThis(thisObj, f).toString();

case Id_toSource:
return realThis(thisObj, f).toString();

Expand Down
66 changes: 47 additions & 19 deletions src/org/mozilla/javascript/regexp/RegExpImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public Object action(
}

case RA_REPLACE:
case RA_REPLACE_ALL:
{
boolean useRE = args.length > 0 && args[0] instanceof NativeRegExp;

Expand All @@ -78,6 +79,11 @@ public Object action(
String search = null;
if (useRE) {
re = createRegExp(cx, scope, args, 2, true);
if (RA_REPLACE_ALL == actionType
&& (re.getFlags() & NativeRegExp.JSREG_GLOB) == 0) {
throw ScriptRuntime.typeError(
"replaceAll must be called with a global RegExp");
}
} else {
Object arg0 = args.length < 1 ? Undefined.instance : args[0];
search = ScriptRuntime.toString(arg0);
Expand All @@ -102,32 +108,54 @@ public Object action(

Object val;
if (useRE) {
val = matchOrReplace(cx, scope, thisObj, args, this, data, re);
Object result = matchOrReplace(cx, scope, thisObj, args, this, data, re);
if (data.charBuf == null) {
if (data.global || result == null || !Boolean.TRUE.equals(result)) {
/* Didn't match even once. */
return data.str;
}
SubString lc = this.leftContext;
replace_glob(data, cx, scope, this, lc.index, lc.length);
}
} else {
String str = data.str;
int index = str.indexOf(search);
if (index >= 0) {
int slen = search.length();
final String str = data.str;
final int strLen = str.length(), searchLen = search.length();
int index = -1, lastIndex = 0;
for (; ; ) {
if (search.isEmpty()) {
if (index == -1) {
index = 0;
} else {
index = (lastIndex < strLen) ? lastIndex + 1 : -1;
}
} else {
index = str.indexOf(search, lastIndex);
}

if (index == -1) {
if (data.charBuf == null) {
return str;
}
break;
}

this.parens = null;
this.lastParen = null;
this.leftContext = new SubString(str, 0, index);
this.lastMatch = new SubString(str, index, slen);
this.lastMatch = new SubString(str, index, searchLen);
this.rightContext =
new SubString(str, index + slen, str.length() - index - slen);
val = Boolean.TRUE;
} else {
val = Boolean.FALSE;
}
}
new SubString(
str, index + searchLen, strLen - index - searchLen);

replace_glob(data, cx, scope, this, lastIndex, index - lastIndex);
lastIndex = index + searchLen;

if (data.charBuf == null) {
if (data.global || val == null || !val.equals(Boolean.TRUE)) {
/* Didn't match even once. */
return data.str;
if (actionType != RA_REPLACE_ALL) {
break;
}
}
SubString lc = this.leftContext;
replace_glob(data, cx, scope, this, lc.index, lc.length);
}

SubString rc = this.rightContext;
data.charBuf.append(rc.str, rc.index, rc.index + rc.length);
return data.charBuf.toString();
Expand Down Expand Up @@ -192,7 +220,7 @@ private static Object matchOrReplace(
if (data.mode == RA_MATCH) {
match_glob(data, cx, scope, count, reImpl);
} else {
if (data.mode != RA_REPLACE) Kit.codeBug();
if (data.mode != RA_REPLACE && data.mode != RA_REPLACE_ALL) Kit.codeBug();
SubString lastMatch = reImpl.lastMatch;
int leftIndex = data.leftIndex;
int leftlen = lastMatch.index - leftIndex;
Expand Down
Loading

0 comments on commit f73614e

Please sign in to comment.