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

convert RegEx properties #1183

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
192 changes: 134 additions & 58 deletions src/org/mozilla/javascript/regexp/NativeRegExp.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ public class NativeRegExp extends IdScriptableObject {

private static final int ANCHOR_BOL = -2;

private static final SymbolKey GET_FLAGS = new SymbolKey("[Symbol.getFlags]");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a Symbol? Symbol is written as [ @@match ].
https://262.ecma-international.org/12.0/#sec-get-regexp.prototype.flags

private static final SymbolKey GET_GLOBAL = new SymbolKey("[Symbol.getGlobal]");
private static final SymbolKey GET_IGNORE_CASE = new SymbolKey("[Symbol.getIgnoreCase]");
private static final SymbolKey GET_MULTILINE = new SymbolKey("[Symbol.getMultiline]");
private static final SymbolKey GET_STICKY = new SymbolKey("[Symbol.getSticky]");
private static final SymbolKey GET_SOURCE = new SymbolKey("[Symbol.getSource]");

public static void init(Context cx, Scriptable scope, boolean sealed) {

NativeRegExp proto = NativeRegExpInstantiator.withLanguageVersion(cx.getLanguageVersion());
Expand All @@ -126,6 +133,42 @@ public static void init(Context cx, Scriptable scope, boolean sealed) {

ctor.setImmunePrototypeProperty(proto);

ScriptableObject desc = (ScriptableObject) cx.newObject(scope);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I don't know much about this area, but...) Could you write simply using Lambda?

constructor.defineConstructorMethod(
scope, "resolve", 1, NativePromise::resolve, DONTENUM, DONTENUM | READONLY);
constructor.defineConstructorMethod(
scope, "reject", 1, NativePromise::reject, DONTENUM, DONTENUM | READONLY);
constructor.defineConstructorMethod(
scope, "all", 1, NativePromise::all, DONTENUM, DONTENUM | READONLY);
constructor.defineConstructorMethod(
scope, "allSettled", 1, NativePromise::allSettled, DONTENUM, DONTENUM | READONLY);
constructor.defineConstructorMethod(
scope, "race", 1, NativePromise::race, DONTENUM, DONTENUM | READONLY);
ScriptableObject speciesDescriptor = (ScriptableObject) cx.newObject(scope);
ScriptableObject.putProperty(speciesDescriptor, "enumerable", false);
ScriptableObject.putProperty(speciesDescriptor, "configurable", true);
ScriptableObject.putProperty(
speciesDescriptor,
"get",
new LambdaFunction(
scope,
"get [Symbol.species]",
0,
(Context lcx, Scriptable lscope, Scriptable thisObj, Object[] args) ->
constructor));
constructor.defineOwnProperty(cx, SymbolKey.SPECIES, speciesDescriptor, false);
constructor.definePrototypeMethod(
scope,
"then",
2,
(Context lcx, Scriptable lscope, Scriptable thisObj, Object[] args) -> {
NativePromise self =
LambdaConstructor.convertThisObject(thisObj, NativePromise.class);
return self.then(lcx, lscope, constructor, args);
},
DONTENUM,
DONTENUM | READONLY);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will check.....

desc.put("enumerable", desc, Boolean.FALSE);
desc.put("configurable", desc, Boolean.TRUE);
desc.put("get", desc, proto.get(GET_FLAGS, proto));
proto.defineOwnProperty(cx, "flags", desc);

desc = (ScriptableObject) cx.newObject(scope);
desc.put("enumerable", desc, Boolean.FALSE);
desc.put("configurable", desc, Boolean.TRUE);
desc.put("get", desc, proto.get(GET_GLOBAL, proto));
proto.defineOwnProperty(cx, "global", desc);

desc = (ScriptableObject) cx.newObject(scope);
desc.put("enumerable", desc, Boolean.FALSE);
desc.put("configurable", desc, Boolean.TRUE);
desc.put("get", desc, proto.get(GET_IGNORE_CASE, proto));
proto.defineOwnProperty(cx, "ignoreCase", desc);

desc = (ScriptableObject) cx.newObject(scope);
desc.put("enumerable", desc, Boolean.FALSE);
desc.put("configurable", desc, Boolean.TRUE);
desc.put("get", desc, proto.get(GET_MULTILINE, proto));
proto.defineOwnProperty(cx, "multiline", desc);

desc = (ScriptableObject) cx.newObject(scope);
desc.put("enumerable", desc, Boolean.FALSE);
desc.put("configurable", desc, Boolean.TRUE);
desc.put("get", desc, proto.get(GET_STICKY, proto));
proto.defineOwnProperty(cx, "sticky", desc);

desc = (ScriptableObject) cx.newObject(scope);
desc.put("enumerable", desc, Boolean.FALSE);
desc.put("configurable", desc, Boolean.TRUE);
desc.put("get", desc, proto.get(GET_SOURCE, proto));
proto.defineOwnProperty(cx, "source", desc);

if (sealed) {
proto.sealObject();
ctor.sealObject();
Expand Down Expand Up @@ -2512,14 +2555,7 @@ private static void reportError(String messageId, String arg) {
throw ScriptRuntime.constructError("SyntaxError", msg);
}

private static final int Id_lastIndex = 1,
Id_source = 2,
Id_flags = 3,
Id_global = 4,
Id_ignoreCase = 5,
Id_multiline = 6,
Id_sticky = 7,
MAX_INSTANCE_ID = 7;
private static final int Id_lastIndex = 1, Id_source = 2, MAX_INSTANCE_ID = Id_source;
p-bakker marked this conversation as resolved.
Show resolved Hide resolved

@Override
protected int getMaxInstanceId() {
Expand All @@ -2536,21 +2572,6 @@ protected int findInstanceIdInfo(String s) {
case "source":
id = Id_source;
break;
case "flags":
id = Id_flags;
break;
case "global":
id = Id_global;
break;
case "ignoreCase":
id = Id_ignoreCase;
break;
case "multiline":
id = Id_multiline;
break;
case "sticky":
id = Id_sticky;
break;
default:
id = 0;
break;
Expand All @@ -2564,11 +2585,6 @@ 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 @@ -2584,16 +2600,6 @@ 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 @@ -2605,20 +2611,6 @@ 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 @@ -2637,11 +2629,6 @@ 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 All @@ -2667,6 +2654,30 @@ protected void initPrototypeId(int id) {
initPrototypeMethod(REGEXP_TAG, id, SymbolKey.SEARCH, "[Symbol.search]", 1);
return;
}
if (id == SymbolId_getFlags) {
initPrototypeMethod(REGEXP_TAG, id, GET_FLAGS, "get flags", 0);
return;
}
if (id == SymbolId_getGlobal) {
initPrototypeMethod(REGEXP_TAG, id, GET_GLOBAL, "get global", 0);
return;
}
if (id == SymbolId_getIgnoreCase) {
initPrototypeMethod(REGEXP_TAG, id, GET_IGNORE_CASE, "get ignoreCase", 0);
return;
}
if (id == SymbolId_getMultiline) {
initPrototypeMethod(REGEXP_TAG, id, GET_MULTILINE, "get multiline", 0);
return;
}
if (id == SymbolId_getSticky) {
initPrototypeMethod(REGEXP_TAG, id, GET_STICKY, "get sticky", 0);
return;
}
if (id == SymbolId_getSource) {
initPrototypeMethod(REGEXP_TAG, id, GET_SOURCE, "get source", 0);
return;
}

String s;
int arity;
Expand Down Expand Up @@ -2728,6 +2739,24 @@ public Object execIdCall(
case Id_prefix:
return realThis(thisObj, f).execSub(cx, scope, args, PREFIX);

case SymbolId_getFlags:
return realThis(thisObj, f).js_getFlags();

case SymbolId_getGlobal:
return realThis(thisObj, f).js_getGlobal();

case SymbolId_getIgnoreCase:
return realThis(thisObj, f).js_getIgnoreCase();

case SymbolId_getMultiline:
return realThis(thisObj, f).js_getMultiline();

case SymbolId_getSticky:
return realThis(thisObj, f).js_getSticky();

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

case SymbolId_match:
return realThis(thisObj, f).execSub(cx, scope, args, MATCH);

Expand All @@ -2751,6 +2780,25 @@ protected int findPrototypeId(Symbol k) {
if (SymbolKey.SEARCH.equals(k)) {
return SymbolId_search;
}

if (GET_FLAGS.equals(k)) {
return SymbolId_getFlags;
}
if (GET_GLOBAL.equals(k)) {
return SymbolId_getGlobal;
}
if (GET_IGNORE_CASE.equals(k)) {
return SymbolId_getIgnoreCase;
}
if (GET_MULTILINE.equals(k)) {
return SymbolId_getMultiline;
}
if (GET_STICKY.equals(k)) {
return SymbolId_getSticky;
}
if (GET_SOURCE.equals(k)) {
return SymbolId_getSource;
}
return 0;
}

Expand Down Expand Up @@ -2783,6 +2831,28 @@ protected int findPrototypeId(String s) {
return id;
}

private Object js_getFlags() {
p-bakker marked this conversation as resolved.
Show resolved Hide resolved
StringBuilder buf = new StringBuilder();
appendFlags(buf);
return buf.toString();
}

private Object js_getGlobal() {
return ScriptRuntime.wrapBoolean((re.flags & JSREG_GLOB) != 0);
}

private Object js_getIgnoreCase() {
return ScriptRuntime.wrapBoolean((re.flags & JSREG_FOLD) != 0);
}

private Object js_getMultiline() {
return ScriptRuntime.wrapBoolean((re.flags & JSREG_MULTILINE) != 0);
}

private Object js_getSticky() {
return ScriptRuntime.wrapBoolean((re.flags & JSREG_STICKY) != 0);
}

private static final int Id_compile = 1,
Id_toString = 2,
Id_toSource = 3,
Expand All @@ -2791,7 +2861,13 @@ protected int findPrototypeId(String s) {
Id_prefix = 6,
SymbolId_match = 7,
SymbolId_search = 8,
MAX_PROTOTYPE_ID = SymbolId_search;
SymbolId_getFlags = 9,
SymbolId_getGlobal = 10,
SymbolId_getIgnoreCase = 11,
SymbolId_getMultiline = 12,
SymbolId_getSticky = 13,
SymbolId_getSource = 14,
MAX_PROTOTYPE_ID = SymbolId_getSource;

private RECompiled re;
Object lastIndex = ScriptRuntime.zeroObj; /* index after last match, for //g iterator */
Expand Down
49 changes: 44 additions & 5 deletions testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import static org.junit.Assert.assertEquals;

import org.junit.Ignore;
import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
Expand Down Expand Up @@ -303,7 +304,8 @@ public void matchStickyAndGlobal() throws Exception {
}

/** @throws Exception if an error occurs */
// TODO @Test
@Ignore
@Test
public void matchStickyAndGlobalSymbol() throws Exception {
final String script =
"var result = /a/yg[Symbol.match]('aaba');\n"
Expand All @@ -315,17 +317,54 @@ public void matchStickyAndGlobalSymbol() throws Exception {
}

/** @throws Exception if an error occurs */
// TODO @Test
@Test
public void flagsPropery() throws Exception {
testPropery("0-function-undefined-true-false-undefined", "flags");
}

/** @throws Exception if an error occurs */
@Test
public void globalPropery() throws Exception {
testPropery("0-function-undefined-true-false-undefined", "global");
}

/** @throws Exception if an error occurs */
@Test
public void ignoreCasePropery() throws Exception {
testPropery("0-function-undefined-true-false-undefined", "ignoreCase");
}

/** @throws Exception if an error occurs */
@Test
public void multilinePropery() throws Exception {
testPropery("0-function-undefined-true-false-undefined", "multiline");
}

/** @throws Exception if an error occurs */
@Test
public void stickyPropery() throws Exception {
testPropery("0-function-undefined-true-false-undefined", "sticky");
}

/** @throws Exception if an error occurs */
@Test
public void sourcePropery() throws Exception {
testPropery("0-function-undefined-true-false-undefined", "source");
}

private static void testPropery(String expected, String property) throws Exception {
final String script =
"var get = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags');\n"
+ "var res = '';" // + get.get.length;\n"
"var get = Object.getOwnPropertyDescriptor(RegExp.prototype, '"
+ property
+ "');\n"
+ "var res = '' + get.get.length;\n"
+ "var res = res + '-' + typeof get.get;\n"
+ "res = res + '-' + get.value;\n"
+ "res = res + '-' + get.configurable;\n"
+ "res = res + '-' + get.enumerable;\n"
+ "res = res + '-' + get.writable;\n"
+ "res;";
test("0-undefined-true-false-undefined", script);
test(expected, script);
}

private static void test(final String expected, final String script) {
Expand Down
Loading