-
Notifications
You must be signed in to change notification settings - Fork 921
ADD: ES6 Object.values / Object.entries / Object.fromEntries #902
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
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
ae236ba
ADD: ES6 Object.values / Object.entries / Object.fromEntries
rPraml 6a913ed
enabled some tests
rPraml b4817f0
spotless
rPraml 0fed865
enabled test262 for entries/vaules
rPraml d3c13ea
spotless
rPraml afe2274
Merge remote-tracking branch 'upstream/master' into object.values-obj…
rPraml 2fb4633
FIX: fromEntries/evaluation-order.js
rPraml 5cdf431
FIX: fromEntries/to-property-key.js
rPraml 88d40c6
FIX: Support for symbols
rPraml 3b2e52f
Merge remote-tracking branch 'upstream/master' into object.values-obj…
rPraml 265f5ca
used common "loadFromIterable" code
rPraml 8fa46fa
spotless NativeMap
rPraml f0e20c9
Merge remote-tracking branch 'upstream/master' into object.values-obj…
rPraml c915eea
Spotless NativeMap
rPraml 37b6fee
FIX: lastStoredScriptable got lost during merge resolve
rPraml File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,9 +9,11 @@ | |
| import java.util.AbstractCollection; | ||
| import java.util.AbstractSet; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.Collection; | ||
| import java.util.Iterator; | ||
| import java.util.Map; | ||
| import java.util.Map.Entry; | ||
| import java.util.NoSuchElementException; | ||
| import java.util.Set; | ||
| import org.mozilla.javascript.ScriptRuntime.StringIdOrIndex; | ||
|
|
@@ -47,6 +49,9 @@ protected void fillConstructorProperties(IdFunctionObject ctor) { | |
| if (Context.getCurrentContext().version >= Context.VERSION_ES6) { | ||
| addIdFunctionProperty( | ||
| ctor, OBJECT_TAG, ConstructorId_setPrototypeOf, "setPrototypeOf", 2); | ||
| addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_entries, "entries", 1); | ||
| addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_fromEntries, "fromEntries", 1); | ||
| addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_values, "values", 1); | ||
| } | ||
| addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_keys, "keys", 1); | ||
| addIdFunctionProperty( | ||
|
|
@@ -224,11 +229,7 @@ public Object execIdCall( | |
|
|
||
| if (arg instanceof Symbol) { | ||
| result = ((SymbolScriptable) thisObj).has((Symbol) arg, thisObj); | ||
| if (result && thisObj instanceof ScriptableObject) { | ||
| ScriptableObject so = (ScriptableObject) thisObj; | ||
| int attrs = so.getAttributes((Symbol) arg); | ||
| result = ((attrs & ScriptableObject.DONTENUM) == 0); | ||
| } | ||
| result = result && isEnumerable((Symbol) arg, thisObj); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved code to "isEnumerable" method |
||
| } else { | ||
| StringIdOrIndex s = ScriptRuntime.toStringIdOrIndex(cx, arg); | ||
| // When checking if a property is enumerable, a missing property should | ||
|
|
@@ -237,18 +238,10 @@ public Object execIdCall( | |
| try { | ||
| if (s.stringId == null) { | ||
| result = thisObj.has(s.index, thisObj); | ||
| if (result && thisObj instanceof ScriptableObject) { | ||
| ScriptableObject so = (ScriptableObject) thisObj; | ||
| int attrs = so.getAttributes(s.index); | ||
| result = ((attrs & ScriptableObject.DONTENUM) == 0); | ||
| } | ||
| result = result && isEnumerable(s.index, thisObj); | ||
| } else { | ||
| result = thisObj.has(s.stringId, thisObj); | ||
| if (result && thisObj instanceof ScriptableObject) { | ||
| ScriptableObject so = (ScriptableObject) thisObj; | ||
| int attrs = so.getAttributes(s.stringId); | ||
| result = ((attrs & ScriptableObject.DONTENUM) == 0); | ||
| } | ||
| result = result && isEnumerable(s.stringId, thisObj); | ||
| } | ||
| } catch (EvaluatorException ee) { | ||
| if (ee.getMessage() | ||
|
|
@@ -403,6 +396,80 @@ public Object execIdCall( | |
| } | ||
| return cx.newArray(scope, ids); | ||
| } | ||
|
|
||
| case ConstructorId_entries: | ||
| { | ||
| Object arg = args.length < 1 ? Undefined.instance : args[0]; | ||
| Scriptable obj = getCompatibleObject(cx, scope, arg); | ||
| Object[] ids = obj.getIds(); | ||
| int j = 0; | ||
| for (int i = 0; i < ids.length; i++) { | ||
| if (ids[i] instanceof Integer) { | ||
| int intId = (Integer) ids[i]; | ||
| if (obj.has(intId, obj) && isEnumerable(intId, obj)) { | ||
| String stringId = ScriptRuntime.toString(ids[i]); | ||
| Object[] entry = new Object[] {stringId, obj.get(intId, obj)}; | ||
| ids[j++] = cx.newArray(scope, entry); | ||
| } | ||
| } else { | ||
| String stringId = ScriptRuntime.toString(ids[i]); | ||
| if (obj.has(stringId, obj) && isEnumerable(stringId, obj)) { | ||
| Object[] entry = new Object[] {stringId, obj.get(stringId, obj)}; | ||
| ids[j++] = cx.newArray(scope, entry); | ||
| } | ||
| } | ||
| } | ||
| if (j != ids.length) { | ||
| ids = Arrays.copyOf(ids, j); | ||
| } | ||
| return cx.newArray(scope, ids); | ||
| } | ||
| case ConstructorId_fromEntries: | ||
| { | ||
| Object arg = args.length < 1 ? Undefined.instance : args[0]; | ||
| arg = getCompatibleObject(cx, scope, arg); | ||
| Scriptable obj = cx.newObject(scope); | ||
| ScriptRuntime.loadFromIterable( | ||
| cx, | ||
| scope, | ||
| arg, | ||
| (key, value) -> { | ||
| if (key instanceof Integer) { | ||
| obj.put((Integer) key, obj, value); | ||
| } else if (key instanceof Symbol | ||
| && obj instanceof SymbolScriptable) { | ||
| ((SymbolScriptable) obj).put((Symbol) key, obj, value); | ||
| } else { | ||
| obj.put(ScriptRuntime.toString(key), obj, value); | ||
| } | ||
| }); | ||
| return obj; | ||
| } | ||
| case ConstructorId_values: | ||
| { | ||
| Object arg = args.length < 1 ? Undefined.instance : args[0]; | ||
| Scriptable obj = getCompatibleObject(cx, scope, arg); | ||
| Object[] ids = obj.getIds(); | ||
| int j = 0; | ||
| for (int i = 0; i < ids.length; i++) { | ||
| if (ids[i] instanceof Integer) { | ||
| int intId = (Integer) ids[i]; | ||
| if (obj.has(intId, obj) && isEnumerable(intId, obj)) { | ||
| ids[j++] = obj.get(intId, obj); | ||
| } | ||
| } else { | ||
| String stringId = ScriptRuntime.toString(ids[i]); | ||
| // getter may remove keys | ||
| if (obj.has(stringId, obj) && isEnumerable(stringId, obj)) { | ||
| ids[j++] = obj.get(stringId, obj); | ||
| } | ||
| } | ||
| } | ||
| if (j != ids.length) { | ||
| ids = Arrays.copyOf(ids, j); | ||
| } | ||
| return cx.newArray(scope, ids); | ||
| } | ||
| case ConstructorId_getOwnPropertyNames: | ||
| { | ||
| Object arg = args.length < 1 ? Undefined.instance : args[0]; | ||
|
|
@@ -640,6 +707,36 @@ && isFalse(desc.get("writable"))) { | |
| } | ||
| } | ||
|
|
||
| private boolean isEnumerable(int index, Object obj) { | ||
| if (obj instanceof ScriptableObject) { | ||
| ScriptableObject so = (ScriptableObject) obj; | ||
| int attrs = so.getAttributes(index); | ||
| return (attrs & ScriptableObject.DONTENUM) == 0; | ||
| } else { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| private boolean isEnumerable(String key, Object obj) { | ||
| if (obj instanceof ScriptableObject) { | ||
| ScriptableObject so = (ScriptableObject) obj; | ||
| int attrs = so.getAttributes(key); | ||
| return (attrs & ScriptableObject.DONTENUM) == 0; | ||
| } else { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| private boolean isEnumerable(Symbol sym, Object obj) { | ||
| if (obj instanceof ScriptableObject) { | ||
| ScriptableObject so = (ScriptableObject) obj; | ||
| int attrs = so.getAttributes(sym); | ||
| return (attrs & ScriptableObject.DONTENUM) == 0; | ||
| } else { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| private static Scriptable getCompatibleObject(Context cx, Scriptable scope, Object arg) { | ||
| if (cx.getLanguageVersion() >= Context.VERSION_ES6) { | ||
| Scriptable s = ScriptRuntime.toObject(cx, scope, arg); | ||
|
|
@@ -931,7 +1028,12 @@ protected int findPrototypeId(String s) { | |
| ConstructorId_getOwnPropertySymbols = -14, | ||
| ConstructorId_assign = -15, | ||
| ConstructorId_is = -16, | ||
|
|
||
| // ES6 | ||
| ConstructorId_setPrototypeOf = -17, | ||
| ConstructorId_entries = -18, | ||
| ConstructorId_fromEntries = -19, | ||
| ConstructorId_values = -20, | ||
| Id_constructor = 1, | ||
| Id_toString = 2, | ||
| Id_toLocaleString = 3, | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| import java.util.Arrays; | ||
| import java.util.Locale; | ||
| import java.util.ResourceBundle; | ||
| import java.util.function.BiConsumer; | ||
| import org.mozilla.javascript.ast.FunctionNode; | ||
| import org.mozilla.javascript.v8dtoa.DoubleConversion; | ||
| import org.mozilla.javascript.v8dtoa.FastDtoa; | ||
|
|
@@ -2417,6 +2418,50 @@ private static void enumChangeObject(IdEnumeration x) { | |
| x.index = 0; | ||
| } | ||
|
|
||
| /** | ||
| * This is used to handle all the special cases that are required when invoking | ||
| * Object.fromEntries or constructing a NativeMap or NativeWeakMap from an iterable. | ||
| * | ||
| * @param cx the current context | ||
| * @param scope the current scope | ||
| * @param arg1 the iterable object. | ||
| * @param setter the setter to set the value | ||
| * @return true, if arg1 was iterable. | ||
| */ | ||
| public static boolean loadFromIterable( | ||
| Context cx, Scriptable scope, Object arg1, BiConsumer<Object, Object> setter) { | ||
| if ((arg1 == null) || Undefined.instance.equals(arg1)) { | ||
| return false; | ||
| } | ||
|
|
||
| // Call the "[Symbol.iterator]" property as a function. | ||
| final Object ito = ScriptRuntime.callIterator(arg1, cx, scope); | ||
| if (Undefined.instance.equals(ito)) { | ||
| // Per spec, ignore if the iterator is undefined | ||
| return false; | ||
| } | ||
|
|
||
| // Finally, run through all the iterated values and add them! | ||
| try (IteratorLikeIterable it = new IteratorLikeIterable(cx, scope, ito)) { | ||
| for (Object val : it) { | ||
| Scriptable sVal = ScriptableObject.ensureScriptable(val); | ||
| if (sVal instanceof Symbol) { | ||
| throw ScriptRuntime.typeErrorById( | ||
| "msg.arg.not.object", ScriptRuntime.typeof(sVal)); | ||
| } | ||
| Object finalKey = sVal.get(0, sVal); | ||
| if (finalKey == Scriptable.NOT_FOUND) { | ||
| finalKey = Undefined.instance; | ||
| } | ||
| Object finalVal = sVal.get(1, sVal); | ||
| if (finalVal == Scriptable.NOT_FOUND) { | ||
| finalVal = Undefined.instance; | ||
| } | ||
| setter.accept(finalKey, finalVal); | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| /** | ||
| * Prepare for calling name(...): return function corresponding to name and make current top | ||
| * scope available as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. The | ||
|
|
@@ -4293,22 +4338,30 @@ public static Scriptable newObjectLiteral( | |
| // -1 for property getter, 1 for property setter, 0 for a regular value property | ||
| int getterSetter = getterSetters == null ? 0 : getterSetters[i]; | ||
| Object value = propertyValues[i]; | ||
|
|
||
| if (getterSetter == 0) { | ||
| if (id instanceof String) { | ||
| if (isSpecialProperty((String) id)) { | ||
| Ref ref = specialRef(object, (String) id, cx, scope); | ||
| if (id instanceof Symbol) { | ||
| Symbol sym = (Symbol) id; | ||
| SymbolScriptable so = (SymbolScriptable) object; | ||
| so.put(sym, object, value); | ||
| } else if (id instanceof Integer) { | ||
| int index = ((Integer) id).intValue(); | ||
| object.put(index, object, value); | ||
| } else { | ||
| String stringId = ScriptRuntime.toString(id); | ||
| if (isSpecialProperty(stringId)) { | ||
| Ref ref = specialRef(object, stringId, cx, scope); | ||
| ref.set(cx, scope, value); | ||
| } else { | ||
| object.put((String) id, object, value); | ||
| object.put(stringId, object, value); | ||
| } | ||
| } else { | ||
| int index = ((Integer) id).intValue(); | ||
| object.put(index, object, value); | ||
| } | ||
| } else { | ||
| ScriptableObject so = (ScriptableObject) object; | ||
| Callable getterOrSetter = (Callable) value; | ||
| boolean isSetter = getterSetter == 1; | ||
| // XXX: Do we have to handle Symbol here. | ||
| // This will be required, when conputedprops are supported. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we need to check this. See FOCONIS@6d2a459 |
||
| String key = id instanceof String ? (String) id : null; | ||
| int index = key == null ? ((Integer) id).intValue() : 0; | ||
| so.setGetterOrSetter(key, index, getterOrSetter, isSetter); | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are the only code change in this class.
I have changed this to
getClassPrototypeinstead of creating a dummy object and I reuse the code inScriptRuntime.loadFromIterable