[es6] Partially implement Reflect.set.
Proxies are not properly supported yet. R=rossberg BUG=v8:3931 LOG=n Review URL: https://codereview.chromium.org/1415883007 Cr-Commit-Position: refs/heads/master@{#31685}
This commit is contained in:
parent
08ca3f240c
commit
5820adf276
@ -2207,6 +2207,8 @@ void Genesis::InitializeGlobal_harmony_reflect() {
|
|||||||
Builtins::kReflectIsExtensible, 1, true);
|
Builtins::kReflectIsExtensible, 1, true);
|
||||||
SimpleInstallFunction(reflect, "preventExtensions",
|
SimpleInstallFunction(reflect, "preventExtensions",
|
||||||
Builtins::kReflectPreventExtensions, 1, true);
|
Builtins::kReflectPreventExtensions, 1, true);
|
||||||
|
SimpleInstallFunction(reflect, "set",
|
||||||
|
Builtins::kReflectSet, 3, false);
|
||||||
SimpleInstallFunction(reflect, "setPrototypeOf",
|
SimpleInstallFunction(reflect, "setPrototypeOf",
|
||||||
Builtins::kReflectSetPrototypeOf, 2, true);
|
Builtins::kReflectSetPrototypeOf, 2, true);
|
||||||
}
|
}
|
||||||
|
@ -1652,6 +1652,35 @@ BUILTIN(ReflectPreventExtensions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ES6 section 26.1.13 Reflect.set
|
||||||
|
BUILTIN(ReflectSet) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
Handle<Object> undef = isolate->factory()->undefined_value();
|
||||||
|
Handle<Object> target = args.length() > 1 ? args.at<Object>(1) : undef;
|
||||||
|
Handle<Object> key = args.length() > 2 ? args.at<Object>(2) : undef;
|
||||||
|
Handle<Object> value = args.length() > 3 ? args.at<Object>(3) : undef;
|
||||||
|
Handle<Object> receiver = args.length() > 4 ? args.at<Object>(4) : target;
|
||||||
|
|
||||||
|
if (!target->IsJSReceiver()) {
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
|
isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
|
||||||
|
isolate->factory()->NewStringFromAsciiChecked(
|
||||||
|
"Reflect.set")));
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<Name> name;
|
||||||
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
||||||
|
Object::ToName(isolate, key));
|
||||||
|
|
||||||
|
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||||
|
isolate, receiver, name, Handle<JSReceiver>::cast(target));
|
||||||
|
Maybe<bool> result = Object::SetSuperProperty(
|
||||||
|
&it, value, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED);
|
||||||
|
MAYBE_RETURN(result, isolate->heap()->exception());
|
||||||
|
return *isolate->factory()->ToBoolean(result.FromJust());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ES6 section 26.1.14 Reflect.setPrototypeOf
|
// ES6 section 26.1.14 Reflect.setPrototypeOf
|
||||||
BUILTIN(ReflectSetPrototypeOf) {
|
BUILTIN(ReflectSetPrototypeOf) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
@ -67,6 +67,7 @@ enum BuiltinExtraArguments {
|
|||||||
V(ReflectHas, NO_EXTRA_ARGUMENTS) \
|
V(ReflectHas, NO_EXTRA_ARGUMENTS) \
|
||||||
V(ReflectIsExtensible, NO_EXTRA_ARGUMENTS) \
|
V(ReflectIsExtensible, NO_EXTRA_ARGUMENTS) \
|
||||||
V(ReflectPreventExtensions, NO_EXTRA_ARGUMENTS) \
|
V(ReflectPreventExtensions, NO_EXTRA_ARGUMENTS) \
|
||||||
|
V(ReflectSet, NO_EXTRA_ARGUMENTS) \
|
||||||
V(ReflectSetPrototypeOf, NO_EXTRA_ARGUMENTS) \
|
V(ReflectSetPrototypeOf, NO_EXTRA_ARGUMENTS) \
|
||||||
\
|
\
|
||||||
V(SymbolConstructor, NO_EXTRA_ARGUMENTS) \
|
V(SymbolConstructor, NO_EXTRA_ARGUMENTS) \
|
||||||
|
@ -52,11 +52,16 @@ function prepare(target) {
|
|||||||
target[4] = 42;
|
target[4] = 42;
|
||||||
target[sym] = "foo";
|
target[sym] = "foo";
|
||||||
target["noconf"] = 43;
|
target["noconf"] = 43;
|
||||||
Object.defineProperty(target, "noconf", {configurable: false});
|
Object.defineProperty(target, "noconf",
|
||||||
|
{ configurable: false });
|
||||||
|
Object.defineProperty(target, "nowrite",
|
||||||
|
{ writable: false, configurable: true, value: 44 });
|
||||||
Object.defineProperty(target, "getter",
|
Object.defineProperty(target, "getter",
|
||||||
{ get: function () {return this.bla}, configurable: true });
|
{ get: function () {return this.bla}, configurable: true });
|
||||||
Object.defineProperty(target, "setter",
|
Object.defineProperty(target, "setter",
|
||||||
{ set: function () {}, configurable: true });
|
{ set: function (x) {this.gaga = x}, configurable: true });
|
||||||
|
Object.defineProperty(target, "setter2",
|
||||||
|
{ set: function (x) {}, configurable: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -129,6 +134,142 @@ function prepare(target) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Reflect.set
|
||||||
|
|
||||||
|
|
||||||
|
(function testReflectSetArity() {
|
||||||
|
assertEquals(3, Reflect.set.length);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function testReflectSetOnNonObject() {
|
||||||
|
assertThrows(function() { Reflect.set(); }, TypeError);
|
||||||
|
assertThrows(function() { Reflect.set(42, "bla"); }, TypeError);
|
||||||
|
assertThrows(function() { Reflect.set(null, "bla"); }, TypeError);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function testReflectSetKeyConversion() {
|
||||||
|
var target = {};
|
||||||
|
var a = { [Symbol.toPrimitive]: function() { return "bla" } };
|
||||||
|
var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
|
||||||
|
assertTrue(Reflect.set(target, a, 42));
|
||||||
|
assertEquals(42, target.bla);
|
||||||
|
assertThrows(function() { Reflect.set(target, b, 42); }, "gaga");
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function testReflectSetOnObject() {
|
||||||
|
var receiver = {bla: false};
|
||||||
|
var value = 34234;
|
||||||
|
for (let target of objects) {
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, "bla", value));
|
||||||
|
assertEquals(value, target.bla);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, "bla", value, target));
|
||||||
|
assertEquals(value, target.bla);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, "bla", value, receiver));
|
||||||
|
assertEquals(true, target.bla);
|
||||||
|
assertEquals(value, receiver.bla);
|
||||||
|
receiver.bla = false;
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, 4, value));
|
||||||
|
assertEquals(value, target[4]);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, 4, value, target));
|
||||||
|
assertEquals(value, target[4]);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, 4, value, receiver));
|
||||||
|
assertEquals(42, target[4]);
|
||||||
|
assertEquals(value, receiver[4]);
|
||||||
|
delete receiver[4];
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, sym, value));
|
||||||
|
assertEquals(value, target[sym]);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, sym, value, target));
|
||||||
|
assertEquals(value, target[sym]);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, sym, value, receiver));
|
||||||
|
assertEquals("foo", target[sym]);
|
||||||
|
assertEquals(value, receiver[sym]);
|
||||||
|
delete receiver[sym];
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, "noconf", value));
|
||||||
|
assertEquals(value, target.noconf);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, "noconf", value, target));
|
||||||
|
assertEquals(value, target.noconf);
|
||||||
|
|
||||||
|
prepare(target);
|
||||||
|
assertTrue(Reflect.set(target, "noconf", value, receiver));
|
||||||
|
assertEquals(43, target.noconf);
|
||||||
|
assertEquals(value, receiver.noconf);
|
||||||
|
delete receiver.noconf;
|
||||||
|
|
||||||
|
assertTrue(Reflect.set(target, "setter", value));
|
||||||
|
assertEquals(value, target.gaga)
|
||||||
|
delete target.gaga;
|
||||||
|
|
||||||
|
assertTrue(Reflect.set(target, "setter", value, target));
|
||||||
|
assertEquals(value, target.gaga)
|
||||||
|
delete target.gaga;
|
||||||
|
|
||||||
|
assertTrue(Reflect.set(target, "setter", value, receiver));
|
||||||
|
assertFalse("gaga" in target);
|
||||||
|
assertEquals(value, receiver.gaga);
|
||||||
|
delete receiver.gaga;
|
||||||
|
|
||||||
|
assertFalse(Reflect.set(target, "nowrite", value));
|
||||||
|
assertEquals(44, target.nowrite);
|
||||||
|
|
||||||
|
assertFalse(Reflect.set(target, "nowrite", value, target));
|
||||||
|
assertEquals(44, target.nowrite);
|
||||||
|
|
||||||
|
assertFalse(Reflect.set(target, "nowrite", value, receiver));
|
||||||
|
assertEquals(44, target.nowrite);
|
||||||
|
assertFalse("nowrite" in receiver);
|
||||||
|
|
||||||
|
// Data vs Non-Writable
|
||||||
|
// TODO(neis): This must return false but currently doesn't.
|
||||||
|
// assertFalse(Reflect.set({}, "nowrite", value, target));
|
||||||
|
|
||||||
|
// Data vs Accessor
|
||||||
|
// TODO(neis): These must return false but currently don't.
|
||||||
|
// assertFalse(Reflect.set(target, "unknown", value, {set bla(x) {}}));
|
||||||
|
// assertFalse(Reflect.set(target, "unknown", value, {get bla() {}}));
|
||||||
|
// assertFalse(Reflect.set(target, "bla", value, {set bla(x) {}}));
|
||||||
|
// assertFalse(Reflect.set(target, "bla", value, {get bla() {}}));
|
||||||
|
|
||||||
|
// Accessor vs Data
|
||||||
|
assertTrue(Reflect.set({set bla(x) {}}), "bla", value, target);
|
||||||
|
assertFalse(Reflect.set({get bla() {}}, "bla", value, target));
|
||||||
|
|
||||||
|
// Data vs Non-Object
|
||||||
|
assertFalse(Reflect.set({}, "bla", value, null));
|
||||||
|
assertFalse(Reflect.set({bla: 42}, "bla", value, null));
|
||||||
|
|
||||||
|
// Accessor vs Non-Object
|
||||||
|
assertTrue(Reflect.set(target, "setter2", value, null));
|
||||||
|
assertFalse(Reflect.set(target, "getter", value, null));
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Reflect.has
|
// Reflect.has
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user