From ae78dbfbbc50e205e71b19f1d44613ed462879b5 Mon Sep 17 00:00:00 2001 From: Ronald Brill Date: Tue, 15 Feb 2022 09:18:38 +0100 Subject: [PATCH 1/2] convert RegEx properties --- .../javascript/regexp/NativeRegExp.java | 174 ++++++++++++------ .../javascript/tests/NativeRegExpTest.java | 43 ++++- testsrc/test262.properties | 27 +-- 3 files changed, 156 insertions(+), 88 deletions(-) diff --git a/src/org/mozilla/javascript/regexp/NativeRegExp.java b/src/org/mozilla/javascript/regexp/NativeRegExp.java index 222e159cc0..5f835d79d4 100644 --- a/src/org/mozilla/javascript/regexp/NativeRegExp.java +++ b/src/org/mozilla/javascript/regexp/NativeRegExp.java @@ -109,6 +109,12 @@ public class NativeRegExp extends IdScriptableObject { private static final int ANCHOR_BOL = -2; + private static final SymbolKey GET_FLAGS = new SymbolKey("[Symbol.getFlags]"); + 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]"); + public static void init(Context cx, Scriptable scope, boolean sealed) { NativeRegExp proto = NativeRegExpInstantiator.withLanguageVersion(cx.getLanguageVersion()); @@ -126,6 +132,36 @@ public static void init(Context cx, Scriptable scope, boolean sealed) { ctor.setImmunePrototypeProperty(proto); + ScriptableObject desc = (ScriptableObject) cx.newObject(scope); + 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); + if (sealed) { proto.sealObject(); ctor.sealObject(); @@ -2512,14 +2548,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; @Override protected int getMaxInstanceId() { @@ -2536,21 +2565,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; @@ -2564,11 +2578,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: @@ -2584,16 +2593,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); } @@ -2605,20 +2604,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); } @@ -2637,11 +2622,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); @@ -2667,6 +2647,26 @@ 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; + } String s; int arity; @@ -2728,6 +2728,21 @@ 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_match: return realThis(thisObj, f).execSub(cx, scope, args, MATCH); @@ -2751,6 +2766,22 @@ 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; + } return 0; } @@ -2783,6 +2814,28 @@ protected int findPrototypeId(String s) { return id; } + private Object js_getFlags() { + 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, @@ -2791,7 +2844,12 @@ 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, + MAX_PROTOTYPE_ID = SymbolId_getSticky; private RECompiled re; Object lastIndex = ScriptRuntime.zeroObj; /* index after last match, for //g iterator */ diff --git a/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java b/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java index 944629438d..7888ead69e 100644 --- a/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java +++ b/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java @@ -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; @@ -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" @@ -315,17 +317,48 @@ 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"); + } + + 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) { diff --git a/testsrc/test262.properties b/testsrc/test262.properties index 38f0e44f4a..fa95e9a317 100644 --- a/testsrc/test262.properties +++ b/testsrc/test262.properties @@ -812,7 +812,7 @@ built-ins/Number 9/283 (3.18%) S9.3.1_A3_T1_U180E.js {unsupported: [u180e]} S9.3.1_A3_T2_U180E.js {unsupported: [u180e]} -built-ins/Object 153/3150 (4.86%) +built-ins/Object 150/3150 (4.76%) assign/source-own-prop-desc-missing.js {unsupported: [Proxy]} assign/source-own-prop-error.js {unsupported: [Proxy]} assign/source-own-prop-keys-error.js {unsupported: [Proxy]} @@ -894,9 +894,6 @@ built-ins/Object 153/3150 (4.86%) getOwnPropertyDescriptors/tamper-with-object-keys.js getOwnPropertyDescriptor/15.2.3.3-4-187.js getOwnPropertyDescriptor/15.2.3.3-4-212.js - getOwnPropertyDescriptor/15.2.3.3-4-213.js - getOwnPropertyDescriptor/15.2.3.3-4-214.js - getOwnPropertyDescriptor/15.2.3.3-4-215.js getOwnPropertyDescriptor/15.2.3.3-4-249.js getOwnPropertyDescriptor/15.2.3.3-4-250.js getOwnPropertyNames/15.2.3.4-4-44.js @@ -1385,7 +1382,7 @@ built-ins/Promise 406/599 (67.78%) ~built-ins/Reflect -built-ins/RegExp 897/1464 (61.27%) +built-ins/RegExp 877/1464 (59.9%) CharacterClassEscapes 24/24 (100.0%) dotall 4/4 (100.0%) lookBehind 17/17 (100.0%) @@ -1407,30 +1404,14 @@ built-ins/RegExp 897/1464 (61.27%) prototype/flags/coercion-sticky.js prototype/flags/coercion-unicode.js prototype/flags/get-order.js {unsupported: [regexp-dotall]} - prototype/flags/length.js - prototype/flags/name.js - prototype/flags/prop-desc.js prototype/flags/rethrow.js {unsupported: [regexp-dotall]} prototype/flags/return-order.js {unsupported: [regexp-dotall]} prototype/flags/this-val-regexp.js {unsupported: [regexp-dotall]} - prototype/flags/this-val-regexp-prototype.js - prototype/global/15.10.7.2-2.js prototype/global/cross-realm.js {unsupported: [cross-realm]} - prototype/global/length.js - prototype/global/name.js - prototype/global/S15.10.7.2_A9.js prototype/global/this-val-regexp-prototype.js - prototype/ignoreCase/15.10.7.3-2.js prototype/ignoreCase/cross-realm.js {unsupported: [cross-realm]} - prototype/ignoreCase/length.js - prototype/ignoreCase/name.js - prototype/ignoreCase/S15.10.7.3_A9.js prototype/ignoreCase/this-val-regexp-prototype.js - prototype/multiline/15.10.7.4-2.js prototype/multiline/cross-realm.js {unsupported: [cross-realm]} - prototype/multiline/length.js - prototype/multiline/name.js - prototype/multiline/S15.10.7.4_A9.js prototype/multiline/this-val-regexp-prototype.js prototype/source/cross-realm.js {unsupported: [cross-realm]} prototype/source/length.js @@ -1441,13 +1422,9 @@ built-ins/RegExp 897/1464 (61.27%) prototype/source/value-line-terminator.js prototype/source/value-u.js prototype/sticky/cross-realm.js {unsupported: [cross-realm]} - prototype/sticky/length.js - prototype/sticky/name.js - prototype/sticky/prop-desc.js prototype/sticky/this-val-regexp-prototype.js prototype/Symbol.matchAll 25/25 (100.0%) prototype/Symbol.match/builtin-infer-unicode.js - prototype/Symbol.match/builtin-success-g-set-lastindex.js prototype/Symbol.match/builtin-success-g-set-lastindex-err.js prototype/Symbol.match/builtin-success-u-return-val-groups.js prototype/Symbol.match/coerce-global.js From fe010383a64fb4700acf7cd127717d85b4ea768f Mon Sep 17 00:00:00 2001 From: Ronald Brill Date: Tue, 15 Feb 2022 12:19:25 +0100 Subject: [PATCH 2/2] add souce getter --- .../javascript/regexp/NativeRegExp.java | 20 ++++++++++++++++++- .../javascript/tests/NativeRegExpTest.java | 6 ++++++ testsrc/test262.properties | 7 ++----- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/org/mozilla/javascript/regexp/NativeRegExp.java b/src/org/mozilla/javascript/regexp/NativeRegExp.java index 5f835d79d4..5ffc2c3f96 100644 --- a/src/org/mozilla/javascript/regexp/NativeRegExp.java +++ b/src/org/mozilla/javascript/regexp/NativeRegExp.java @@ -114,6 +114,7 @@ public class NativeRegExp extends IdScriptableObject { 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) { @@ -162,6 +163,12 @@ public static void init(Context cx, Scriptable scope, boolean sealed) { 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(); @@ -2667,6 +2674,10 @@ protected void initPrototypeId(int id) { 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; @@ -2743,6 +2754,9 @@ public Object execIdCall( 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); @@ -2782,6 +2796,9 @@ protected int findPrototypeId(Symbol k) { if (GET_STICKY.equals(k)) { return SymbolId_getSticky; } + if (GET_SOURCE.equals(k)) { + return SymbolId_getSource; + } return 0; } @@ -2849,7 +2866,8 @@ private Object js_getSticky() { SymbolId_getIgnoreCase = 11, SymbolId_getMultiline = 12, SymbolId_getSticky = 13, - MAX_PROTOTYPE_ID = SymbolId_getSticky; + SymbolId_getSource = 14, + MAX_PROTOTYPE_ID = SymbolId_getSource; private RECompiled re; Object lastIndex = ScriptRuntime.zeroObj; /* index after last match, for //g iterator */ diff --git a/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java b/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java index 7888ead69e..e102faed1f 100644 --- a/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java +++ b/testsrc/org/mozilla/javascript/tests/NativeRegExpTest.java @@ -346,6 +346,12 @@ 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, '" diff --git a/testsrc/test262.properties b/testsrc/test262.properties index fa95e9a317..4a8ab99c91 100644 --- a/testsrc/test262.properties +++ b/testsrc/test262.properties @@ -812,7 +812,7 @@ built-ins/Number 9/283 (3.18%) S9.3.1_A3_T1_U180E.js {unsupported: [u180e]} S9.3.1_A3_T2_U180E.js {unsupported: [u180e]} -built-ins/Object 150/3150 (4.76%) +built-ins/Object 149/3150 (4.73%) assign/source-own-prop-desc-missing.js {unsupported: [Proxy]} assign/source-own-prop-error.js {unsupported: [Proxy]} assign/source-own-prop-keys-error.js {unsupported: [Proxy]} @@ -893,7 +893,6 @@ built-ins/Object 150/3150 (4.76%) getOwnPropertyDescriptors/tamper-with-global-object.js getOwnPropertyDescriptors/tamper-with-object-keys.js getOwnPropertyDescriptor/15.2.3.3-4-187.js - getOwnPropertyDescriptor/15.2.3.3-4-212.js getOwnPropertyDescriptor/15.2.3.3-4-249.js getOwnPropertyDescriptor/15.2.3.3-4-250.js getOwnPropertyNames/15.2.3.4-4-44.js @@ -1382,7 +1381,7 @@ built-ins/Promise 406/599 (67.78%) ~built-ins/Reflect -built-ins/RegExp 877/1464 (59.9%) +built-ins/RegExp 875/1464 (59.77%) CharacterClassEscapes 24/24 (100.0%) dotall 4/4 (100.0%) lookBehind 17/17 (100.0%) @@ -1414,8 +1413,6 @@ built-ins/RegExp 877/1464 (59.9%) prototype/multiline/cross-realm.js {unsupported: [cross-realm]} prototype/multiline/this-val-regexp-prototype.js prototype/source/cross-realm.js {unsupported: [cross-realm]} - prototype/source/length.js - prototype/source/name.js prototype/source/prop-desc.js prototype/source/this-val-regexp-prototype.js prototype/source/value-empty.js