Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement regex sticky support #1181

Merged
merged 1 commit into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 62 additions & 19 deletions src/org/mozilla/javascript/regexp/NativeRegExp.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ 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

// type of match to perform
public static final int TEST = 0;
Expand Down Expand Up @@ -187,10 +188,15 @@ public String toString() {
buf.append("(?:)");
}
buf.append('/');
appendFlags(buf);
return buf.toString();
}

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');
return buf.toString();
if ((re.flags & JSREG_STICKY) != 0) buf.append('y');
}

NativeRegExp() {}
Expand Down Expand Up @@ -234,24 +240,25 @@ Object execSub(Context cx, Scriptable scopeObj, Object[] args, int matchType) {
} else {
str = ScriptRuntime.toString(args[0]);
}

boolean globalOrSticky = (re.flags & JSREG_GLOB) != 0 || (re.flags & JSREG_STICKY) != 0;
double d = 0;
if ((re.flags & JSREG_GLOB) != 0) {
if (globalOrSticky) {
d = ScriptRuntime.toInteger(lastIndex);

if (d < 0 || str.length() < d) {
setLastIndex(ScriptRuntime.zeroObj);
return null;
}
}

Object rval;
if (d < 0 || str.length() < d) {
setLastIndex(ScriptRuntime.zeroObj);
rval = null;
} else {
int indexp[] = {(int) d};
rval = executeRegExp(cx, scopeObj, reImpl, str, indexp, matchType);
if ((re.flags & JSREG_GLOB) != 0) {
if (rval == null || rval == Undefined.instance) {
setLastIndex(ScriptRuntime.zeroObj);
} else {
setLastIndex(Double.valueOf(indexp[0]));
}
int indexp[] = {(int) d};
Object rval = executeRegExp(cx, scopeObj, reImpl, str, indexp, matchType);
if (globalOrSticky) {
if (rval == null || rval == Undefined.instance) {
setLastIndex(ScriptRuntime.zeroObj);
} else {
setLastIndex(Double.valueOf(indexp[0]));
}
}
return rval;
Expand All @@ -271,6 +278,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 == 'y') {
f = JSREG_STICKY;
} else {
reportError("msg.invalid.re.flag", String.valueOf(c));
}
Expand Down Expand Up @@ -2334,6 +2343,11 @@ private static boolean matchRegExp(
&& upcase(matchCh) == upcase((char) anchorCh))) {
break;
}

if ((gData.regexp.flags & JSREG_STICKY) != 0) {
return false;
}

++i;
}
}
Expand All @@ -2353,6 +2367,11 @@ && upcase(matchCh) == upcase((char) anchorCh))) {
gData.skipped = end;
return false;
}

if ((gData.regexp.flags & JSREG_STICKY) != 0) {
return false;
}

i = start + gData.skipped;
}
return false;
Expand Down Expand Up @@ -2495,10 +2514,12 @@ private static void reportError(String messageId, String arg) {

private static final int Id_lastIndex = 1,
Id_source = 2,
Id_global = 3,
Id_ignoreCase = 4,
Id_multiline = 5,
MAX_INSTANCE_ID = 5;
Id_flags = 3,
Id_global = 4,
Id_ignoreCase = 5,
Id_multiline = 6,
Id_sticky = 7,
MAX_INSTANCE_ID = 7;

@Override
protected int getMaxInstanceId() {
Expand All @@ -2515,6 +2536,9 @@ protected int findInstanceIdInfo(String s) {
case "source":
id = Id_source;
break;
case "flags":
id = Id_flags;
break;
case "global":
id = Id_global;
break;
Expand All @@ -2524,6 +2548,9 @@ protected int findInstanceIdInfo(String s) {
case "multiline":
id = Id_multiline;
break;
case "sticky":
id = Id_sticky;
break;
default:
id = 0;
break;
Expand All @@ -2537,9 +2564,11 @@ protected int findInstanceIdInfo(String s) {
attr = lastIndexAttr;
break;
case Id_source:
case Id_flags:
case Id_global:
case Id_ignoreCase:
case Id_multiline:
case Id_sticky:
attr = PERMANENT | READONLY | DONTENUM;
break;
default:
Expand All @@ -2555,12 +2584,16 @@ protected String getInstanceIdName(int id) {
return "lastIndex";
case Id_source:
return "source";
case Id_flags:
return "flags";
case Id_global:
return "global";
case Id_ignoreCase:
return "ignoreCase";
case Id_multiline:
return "multiline";
case Id_sticky:
return "sticky";
}
return super.getInstanceIdName(id);
}
Expand All @@ -2572,12 +2605,20 @@ protected Object getInstanceIdValue(int id) {
return lastIndex;
case Id_source:
return new String(re.source);
case Id_flags:
{
StringBuilder buf = new StringBuilder();
appendFlags(buf);
return buf.toString();
}
case Id_global:
return ScriptRuntime.wrapBoolean((re.flags & JSREG_GLOB) != 0);
case Id_ignoreCase:
return ScriptRuntime.wrapBoolean((re.flags & JSREG_FOLD) != 0);
case Id_multiline:
return ScriptRuntime.wrapBoolean((re.flags & JSREG_MULTILINE) != 0);
case Id_sticky:
return ScriptRuntime.wrapBoolean((re.flags & JSREG_STICKY) != 0);
}
return super.getInstanceIdValue(id);
}
Expand All @@ -2596,9 +2637,11 @@ protected void setInstanceIdValue(int id, Object value) {
setLastIndex(value);
return;
case Id_source:
case Id_flags:
case Id_global:
case Id_ignoreCase:
case Id_multiline:
case Id_sticky:
return;
}
super.setInstanceIdValue(id, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
*/
package org.mozilla.javascript.tests;

import static org.junit.Assert.*;

import java.math.BigInteger;
import junit.framework.TestCase;
import org.junit.Test;
Expand Down
Loading