зеркало из https://github.com/mozilla/gecko-dev.git
Bug 987514, part 4 - Implement most of the standard Reflect methods. r=Waldo.
Reflect.construct will be added in bug 1178932. Reflect.enumerate is not implemented because we do not implement the underlying internal method to spec yet. --HG-- extra : rebase_source : 47f533df6e2b4f38b3812c1ce955fa90ce055a75
This commit is contained in:
Родитель
3a5f570d6f
Коммит
b99588d3e5
|
@ -312,6 +312,7 @@ selfhosting_srcs := \
|
||||||
$(srcdir)/builtin/Map.js \
|
$(srcdir)/builtin/Map.js \
|
||||||
$(srcdir)/builtin/Number.js \
|
$(srcdir)/builtin/Number.js \
|
||||||
$(srcdir)/builtin/Object.js \
|
$(srcdir)/builtin/Object.js \
|
||||||
|
$(srcdir)/builtin/Reflect.js \
|
||||||
$(srcdir)/builtin/RegExp.js \
|
$(srcdir)/builtin/RegExp.js \
|
||||||
$(srcdir)/builtin/String.js \
|
$(srcdir)/builtin/String.js \
|
||||||
$(srcdir)/builtin/Set.js \
|
$(srcdir)/builtin/Set.js \
|
||||||
|
|
|
@ -390,25 +390,6 @@ js::obj_valueOf(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES6 draft rev27 (2014/08/24) 19.1.2.9 Object.getPrototypeOf(O)
|
|
||||||
bool
|
|
||||||
js::obj_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
|
|
||||||
/* Steps 1-2. */
|
|
||||||
RootedObject obj(cx, ToObject(cx, args.get(0)));
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Step 3. */
|
|
||||||
RootedObject proto(cx);
|
|
||||||
if (!GetPrototype(cx, obj, &proto))
|
|
||||||
return false;
|
|
||||||
args.rval().setObjectOrNull(proto);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
|
obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
@ -711,7 +692,7 @@ js::obj_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
|
||||||
// Steps 3-4.
|
// Steps 3-4.
|
||||||
RootedId id(cx);
|
RootedId id(cx);
|
||||||
if (!ValueToId<CanGC>(cx, args.get(1), &id))
|
if (!ToPropertyKey(cx, args.get(1), &id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Steps 5-7.
|
// Steps 5-7.
|
||||||
|
@ -758,11 +739,9 @@ js::IdToStringOrSymbol(JSContext* cx, HandleId id, MutableHandleValue result)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
/* ES6 draft rev 25 (2014 May 22) 19.1.2.8.1 */
|
/* ES6 draft rev 25 (2014 May 22) 19.1.2.8.1 */
|
||||||
bool
|
bool
|
||||||
GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
|
js::GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
|
||||||
{
|
{
|
||||||
// Steps 1-2.
|
// Steps 1-2.
|
||||||
RootedObject obj(cx, ToObject(cx, args.get(0)));
|
RootedObject obj(cx, ToObject(cx, args.get(0)));
|
||||||
|
@ -794,8 +773,6 @@ GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace js
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::obj_getOwnPropertyNames(JSContext* cx, unsigned argc, Value* vp)
|
js::obj_getOwnPropertyNames(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
@ -865,25 +842,6 @@ obj_defineProperties(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return DefineProperties(cx, obj, props);
|
return DefineProperties(cx, obj, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES6 draft rev27 (2014/08/24) 19.1.2.11 Object.isExtensible(O)
|
|
||||||
static bool
|
|
||||||
obj_isExtensible(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
|
|
||||||
// Step 1.
|
|
||||||
bool extensible = false;
|
|
||||||
|
|
||||||
// Step 2.
|
|
||||||
if (args.get(0).isObject()) {
|
|
||||||
RootedObject obj(cx, &args.get(0).toObject());
|
|
||||||
if (!IsExtensible(cx, obj, &extensible))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
args.rval().setBoolean(extensible);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ES6 20141014 draft 19.1.2.15 Object.preventExtensions(O)
|
// ES6 20141014 draft 19.1.2.15 Object.preventExtensions(O)
|
||||||
static bool
|
static bool
|
||||||
obj_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
|
obj_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
@ -1067,23 +1025,23 @@ static const JSPropertySpec object_properties[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JSFunctionSpec object_static_methods[] = {
|
static const JSFunctionSpec object_static_methods[] = {
|
||||||
JS_SELF_HOSTED_FN("assign", "ObjectStaticAssign", 2,JSPROP_DEFINE_LATE),
|
JS_SELF_HOSTED_FN("assign", "ObjectStaticAssign", 2, JSPROP_DEFINE_LATE),
|
||||||
JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0),
|
JS_SELF_HOSTED_FN("getPrototypeOf", "ObjectGetPrototypeOf", 1, JSPROP_DEFINE_LATE),
|
||||||
JS_FN("setPrototypeOf", obj_setPrototypeOf, 2,0),
|
JS_FN("setPrototypeOf", obj_setPrototypeOf, 2, 0),
|
||||||
JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2,0),
|
JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2, 0),
|
||||||
JS_FN("keys", obj_keys, 1,0),
|
JS_FN("keys", obj_keys, 1, 0),
|
||||||
JS_FN("is", obj_is, 2,0),
|
JS_FN("is", obj_is, 2, 0),
|
||||||
JS_FN("defineProperty", obj_defineProperty, 3,0),
|
JS_FN("defineProperty", obj_defineProperty, 3, 0),
|
||||||
JS_FN("defineProperties", obj_defineProperties, 2,0),
|
JS_FN("defineProperties", obj_defineProperties, 2, 0),
|
||||||
JS_FN("create", obj_create, 2,0),
|
JS_FN("create", obj_create, 2, 0),
|
||||||
JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
|
JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1, 0),
|
||||||
JS_FN("getOwnPropertySymbols", obj_getOwnPropertySymbols, 1,0),
|
JS_FN("getOwnPropertySymbols", obj_getOwnPropertySymbols, 1, 0),
|
||||||
JS_FN("isExtensible", obj_isExtensible, 1,0),
|
JS_SELF_HOSTED_FN("isExtensible", "ObjectIsExtensible", 1, JSPROP_DEFINE_LATE),
|
||||||
JS_FN("preventExtensions", obj_preventExtensions, 1,0),
|
JS_FN("preventExtensions", obj_preventExtensions, 1, 0),
|
||||||
JS_FN("freeze", obj_freeze, 1,0),
|
JS_FN("freeze", obj_freeze, 1, 0),
|
||||||
JS_FN("isFrozen", obj_isFrozen, 1,0),
|
JS_FN("isFrozen", obj_isFrozen, 1, 0),
|
||||||
JS_FN("seal", obj_seal, 1,0),
|
JS_FN("seal", obj_seal, 1, 0),
|
||||||
JS_FN("isSealed", obj_isSealed, 1,0),
|
JS_FN("isSealed", obj_isSealed, 1, 0),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,9 @@ obj_getPrototypeOf(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
bool
|
bool
|
||||||
obj_hasOwnProperty(JSContext* cx, unsigned argc, JS::Value* vp);
|
obj_hasOwnProperty(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
|
||||||
|
bool
|
||||||
|
obj_isExtensible(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
|
||||||
// Exposed so SelfHosting.cpp can use it in the OwnPropertyKeys intrinsic
|
// Exposed so SelfHosting.cpp can use it in the OwnPropertyKeys intrinsic
|
||||||
bool
|
bool
|
||||||
GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags);
|
GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags);
|
||||||
|
|
|
@ -41,6 +41,16 @@ function ObjectStaticAssign(target, firstSource) {
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.9. */
|
||||||
|
function ObjectGetPrototypeOf(obj) {
|
||||||
|
return std_Reflect_getPrototypeOf(ToObject(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.11. */
|
||||||
|
function ObjectIsExtensible(obj) {
|
||||||
|
return IsObject(obj) && std_Reflect_isExtensible(obj);
|
||||||
|
}
|
||||||
|
|
||||||
function ObjectDefineSetter(name, setter) {
|
function ObjectDefineSetter(name, setter) {
|
||||||
var object;
|
var object;
|
||||||
if (this === null || this === undefined)
|
if (this === null || this === undefined)
|
||||||
|
@ -96,7 +106,7 @@ function ObjectLookupSetter(name) {
|
||||||
return desc.set;
|
return desc.set;
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
object = std_Object_getPrototypeOf(object);
|
object = std_Reflect_getPrototypeOf(object);
|
||||||
} while (object !== null);
|
} while (object !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +121,7 @@ function ObjectLookupGetter(name) {
|
||||||
return desc.get;
|
return desc.get;
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
object = std_Object_getPrototypeOf(object);
|
object = std_Reflect_getPrototypeOf(object);
|
||||||
} while (object !== null);
|
} while (object !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,366 @@
|
||||||
|
|
||||||
#include "builtin/Reflect.h"
|
#include "builtin/Reflect.h"
|
||||||
|
|
||||||
|
#include "jscntxt.h"
|
||||||
|
|
||||||
|
#include "vm/Stack.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
||||||
|
|
||||||
|
/*** Reflect methods *****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ES draft rev 32 (2015 Feb 2) 7.3.17 CreateListFromArrayLike.
|
||||||
|
* The elementTypes argument is not supported. The result list is
|
||||||
|
* pushed to *args.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
InitArgsFromArrayLike(JSContext* cx, HandleValue v, InvokeArgs* args, bool construct)
|
||||||
|
{
|
||||||
|
// Step 3.
|
||||||
|
RootedObject obj(cx, NonNullObject(cx, v));
|
||||||
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 4-5.
|
||||||
|
uint32_t len;
|
||||||
|
if (!GetLengthProperty(cx, obj, &len))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Allocate space for the arguments.
|
||||||
|
if (len > ARGS_LENGTH_MAX) {
|
||||||
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!args->init(len, construct))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 6-8.
|
||||||
|
for (uint32_t index = 0; index < len; index++) {
|
||||||
|
if (!GetElement(cx, obj, obj, index, (*args)[index]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.1 Reflect.apply(target, thisArgument, argumentsList) */
|
||||||
|
static bool
|
||||||
|
Reflect_apply(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
if (!IsCallable(args.get(0))) {
|
||||||
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION,
|
||||||
|
"Reflect.apply argument");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
FastInvokeGuard fig(cx, args.get(0));
|
||||||
|
InvokeArgs& invokeArgs = fig.args();
|
||||||
|
if (!InitArgsFromArrayLike(cx, args.get(2), &invokeArgs, false))
|
||||||
|
return false;
|
||||||
|
invokeArgs.setCallee(args.get(0));
|
||||||
|
invokeArgs.setThis(args.get(1));
|
||||||
|
|
||||||
|
// Steps 4-5. This is specified to be a tail call, but isn't.
|
||||||
|
if (!fig.invoke(cx))
|
||||||
|
return false;
|
||||||
|
args.rval().set(invokeArgs.rval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.3 Reflect.defineProperty(target, propertyKey, attributes) */
|
||||||
|
static bool
|
||||||
|
Reflect_defineProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
RootedValue propertyKey(cx, args.get(1));
|
||||||
|
RootedId key(cx);
|
||||||
|
if (!ToPropertyKey(cx, propertyKey, &key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 4-5.
|
||||||
|
Rooted<JSPropertyDescriptor> desc(cx);
|
||||||
|
if (!ToPropertyDescriptor(cx, args.get(2), true, &desc))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
ObjectOpResult result;
|
||||||
|
if (!DefineProperty(cx, obj, key, desc, result))
|
||||||
|
return false;
|
||||||
|
args.rval().setBoolean(bool(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.4 Reflect.deleteProperty (target, propertyKey) */
|
||||||
|
static bool
|
||||||
|
Reflect_deleteProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject target(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
RootedValue propertyKey(cx, args.get(1));
|
||||||
|
RootedId key(cx);
|
||||||
|
if (!ToPropertyKey(cx, propertyKey, &key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
ObjectOpResult result;
|
||||||
|
if (!DeleteProperty(cx, target, key, result))
|
||||||
|
return false;
|
||||||
|
args.rval().setBoolean(bool(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* ES6 26.1.5 Reflect.enumerate(target)
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* - redefine enumeration in terms of iterators without losing performance
|
||||||
|
* - support iterators in Proxies
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
Reflect_enumerate(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
RootedObject iterator(cx);
|
||||||
|
if (!Enumerate(cx, obj, &iterator))
|
||||||
|
return false;
|
||||||
|
args.rval().setObject(*iterator);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ES6 26.1.6 Reflect.get(target, propertyKey [, receiver])
|
||||||
|
*
|
||||||
|
* Primitive receivers are not supported yet (see bug 603201).
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
Reflect_get(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
RootedValue propertyKey(cx, args.get(1));
|
||||||
|
RootedId key(cx);
|
||||||
|
if (!ToPropertyKey(cx, propertyKey, &key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
RootedValue receiver(cx, argc > 2 ? args[2] : args.get(0));
|
||||||
|
|
||||||
|
// Non-standard hack: Throw a TypeError if the receiver isn't an object.
|
||||||
|
// See bug 603201.
|
||||||
|
RootedObject receiverObj(cx, NonNullObject(cx, receiver));
|
||||||
|
if (!receiverObj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
return GetProperty(cx, obj, receiverObj, key, args.rval());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.7 Reflect.getOwnPropertyDescriptor(target, propertyKey) */
|
||||||
|
static bool
|
||||||
|
Reflect_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
// Step 1.
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
if (!NonNullObject(cx, args.get(0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The other steps are identical to ES6 draft rev 32 (2015 Feb 2) 19.1.2.6
|
||||||
|
// Object.getOwnPropertyDescriptor.
|
||||||
|
return js::obj_getOwnPropertyDescriptor(cx, argc, vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.8 Reflect.getPrototypeOf(target) */
|
||||||
|
bool
|
||||||
|
js::Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject target(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
RootedObject proto(cx);
|
||||||
|
if (!GetPrototype(cx, target, &proto))
|
||||||
|
return false;
|
||||||
|
args.rval().setObjectOrNull(proto);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 draft 26.1.10 Reflect.isExtensible(target) */
|
||||||
|
bool
|
||||||
|
js::Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject target(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
bool extensible;
|
||||||
|
if (!IsExtensible(cx, target, &extensible))
|
||||||
|
return false;
|
||||||
|
args.rval().setBoolean(extensible);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.11 Reflect.ownKeys(target) */
|
||||||
|
static bool
|
||||||
|
Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
if (!NonNullObject(cx, args.get(0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 2-4.
|
||||||
|
return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.12 Reflect.preventExtensions(target) */
|
||||||
|
static bool
|
||||||
|
Reflect_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject target(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
ObjectOpResult result;
|
||||||
|
if (!PreventExtensions(cx, target, result))
|
||||||
|
return false;
|
||||||
|
args.rval().setBoolean(bool(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES6 26.1.13 Reflect.set(target, propertyKey, V [, receiver]) */
|
||||||
|
static bool
|
||||||
|
Reflect_set(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject target(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
RootedValue propertyKey(cx, args.get(1));
|
||||||
|
RootedId key(cx);
|
||||||
|
if (!ToPropertyKey(cx, propertyKey, &key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
RootedValue receiver(cx, argc > 3 ? args[3] : args.get(0));
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
ObjectOpResult result;
|
||||||
|
RootedValue value(cx, args.get(2));
|
||||||
|
if (!SetProperty(cx, target, key, value, receiver, result))
|
||||||
|
return false;
|
||||||
|
args.rval().setBoolean(bool(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ES6 26.1.3 Reflect.setPrototypeOf(target, proto)
|
||||||
|
*
|
||||||
|
* The specification is not quite similar enough to Object.setPrototypeOf to
|
||||||
|
* share code.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
Reflect_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
|
||||||
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
if (!args.get(1).isObjectOrNull()) {
|
||||||
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
|
||||||
|
"Reflect.setPrototypeOf", "an object or null",
|
||||||
|
InformalValueTypeName(args.get(1)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RootedObject proto(cx, args.get(1).toObjectOrNull());
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
ObjectOpResult result;
|
||||||
|
if (!SetPrototype(cx, obj, proto, result))
|
||||||
|
return false;
|
||||||
|
args.rval().setBoolean(bool(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JSFunctionSpec methods[] = {
|
||||||
|
JS_FN("apply", Reflect_apply, 3, 0),
|
||||||
|
// JS_FN("construct", Reflect_construct, 2, 0),
|
||||||
|
JS_FN("defineProperty", Reflect_defineProperty, 3, 0),
|
||||||
|
JS_FN("deleteProperty", Reflect_deleteProperty, 2, 0),
|
||||||
|
// JS_FN("enumerate", Reflect_enumerate, 1, 0),
|
||||||
|
JS_FN("get", Reflect_get, 2, 0),
|
||||||
|
JS_FN("getOwnPropertyDescriptor", Reflect_getOwnPropertyDescriptor, 2, 0),
|
||||||
|
JS_FN("getPrototypeOf", Reflect_getPrototypeOf, 1, 0),
|
||||||
|
JS_SELF_HOSTED_FN("has", "Reflect_has", 2, 0),
|
||||||
|
JS_FN("isExtensible", Reflect_isExtensible, 1, 0),
|
||||||
|
JS_FN("ownKeys", Reflect_ownKeys, 1, 0),
|
||||||
|
JS_FN("preventExtensions", Reflect_preventExtensions, 1, 0),
|
||||||
|
JS_FN("set", Reflect_set, 3, 0),
|
||||||
|
JS_FN("setPrototypeOf", Reflect_setPrototypeOf, 2, 0),
|
||||||
|
JS_FS_END
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*** Setup **************************************************************************************/
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
js::InitReflect(JSContext* cx, HandleObject obj)
|
js::InitReflect(JSContext* cx, HandleObject obj)
|
||||||
{
|
{
|
||||||
static const JSFunctionSpec static_methods[] = {
|
|
||||||
JS_FS_END
|
|
||||||
};
|
|
||||||
|
|
||||||
RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
|
RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
|
||||||
if (!proto)
|
if (!proto)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -22,7 +373,7 @@ js::InitReflect(JSContext* cx, HandleObject obj)
|
||||||
RootedObject reflect(cx, NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject));
|
RootedObject reflect(cx, NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject));
|
||||||
if (!reflect)
|
if (!reflect)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!JS_DefineFunctions(cx, reflect, static_methods))
|
if (!JS_DefineFunctions(cx, reflect, methods))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
RootedValue value(cx, ObjectValue(*reflect));
|
RootedValue value(cx, ObjectValue(*reflect));
|
||||||
|
|
|
@ -16,4 +16,14 @@ InitReflect(JSContext* cx, js::HandleObject obj);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
extern bool
|
||||||
|
Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
|
extern bool
|
||||||
|
Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* builtin_Reflect_h */
|
#endif /* builtin_Reflect_h */
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// ES6 draft rev 32 (2015 Feb 2) 26.1.9
|
||||||
|
function Reflect_has(target, propertyKey) {
|
||||||
|
// Step 1.
|
||||||
|
if (!IsObject(target))
|
||||||
|
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, target));
|
||||||
|
|
||||||
|
// Steps 2-4 are identical to the runtime semantics of the "in" operator.
|
||||||
|
return propertyKey in target;
|
||||||
|
}
|
|
@ -1,10 +1,8 @@
|
||||||
"use strict";
|
// Direct proxies pass through the receiver argument to [[Set]] to their targets.
|
||||||
|
// This also tests that an ordinary object's [[Set]] method can change the length
|
||||||
|
// of an array passed as the receiver.
|
||||||
|
|
||||||
if (this.Reflect && Reflect.set)
|
load(libdir + "asserts.js");
|
||||||
throw new Error("Congrats on implementing Reflect.set! Uncomment this test for 1 karma point.");
|
|
||||||
|
|
||||||
/*
|
|
||||||
load("asserts.js");
|
|
||||||
|
|
||||||
var a = [0, 1, 2, 3];
|
var a = [0, 1, 2, 3];
|
||||||
var p = new Proxy({}, {});
|
var p = new Proxy({}, {});
|
||||||
|
@ -12,4 +10,3 @@ Reflect.set(p, "length", 2, a);
|
||||||
assertEq("length" in p, false);
|
assertEq("length" in p, false);
|
||||||
assertEq(a.length, 2);
|
assertEq(a.length, 2);
|
||||||
assertDeepEq(a, [0, 1]);
|
assertDeepEq(a, [0, 1]);
|
||||||
*/
|
|
||||||
|
|
|
@ -595,6 +595,19 @@ ToPrimitive(JSContext* cx, JSType preferredType, MutableHandleValue vp)
|
||||||
return ToPrimitive(cx, obj, preferredType, vp);
|
return ToPrimitive(cx, obj, preferredType, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */
|
||||||
|
inline bool
|
||||||
|
ToPropertyKey(JSContext* cx, Value argument, MutableHandleId result)
|
||||||
|
{
|
||||||
|
// Steps 1-2.
|
||||||
|
RootedValue key(cx, argument);
|
||||||
|
if (!ToPrimitive(cx, JSTYPE_STRING, &key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 3-4.
|
||||||
|
return ValueToId<CanGC>(cx, key, result);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return true if this is a compiler-created internal function accessed by
|
* Return true if this is a compiler-created internal function accessed by
|
||||||
* its own object. Such a function object must not be accessible to script
|
* its own object. Such a function object must not be accessible to script
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.apply calls functions.
|
||||||
|
assertEq(Reflect.apply(Math.floor, undefined, [1.75]), 1);
|
||||||
|
|
||||||
|
// Reflect.apply requires a target object that's callable.
|
||||||
|
class clsX { constructor() {} } // classes are not callable
|
||||||
|
var nonCallable = [{}, [], clsX];
|
||||||
|
for (var value of nonCallable) {
|
||||||
|
assertThrowsInstanceOf(() => Reflect.apply(nonCallable), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When target is not callable, Reflect.apply does not try to get argumentList.length before throwing.
|
||||||
|
var hits = 0;
|
||||||
|
var bogusArgumentList = {get length() { hit++; throw "FAIL";}};
|
||||||
|
assertThrowsInstanceOf(() => Reflect.apply({callable: false}, null, bogusArgumentList),
|
||||||
|
TypeError);
|
||||||
|
assertEq(hits, 0);
|
||||||
|
|
||||||
|
// Reflect.apply works on a range of different callable objects.
|
||||||
|
// Builtin functions (we also tested Math.floor above):
|
||||||
|
assertEq(Reflect.apply(String.fromCharCode,
|
||||||
|
undefined,
|
||||||
|
[104, 101, 108, 108, 111]),
|
||||||
|
"hello");
|
||||||
|
|
||||||
|
// Builtin methods:
|
||||||
|
assertEq(Reflect.apply(RegExp.prototype.exec,
|
||||||
|
/ab/,
|
||||||
|
["confabulation"]).index,
|
||||||
|
4);
|
||||||
|
|
||||||
|
// Builtin methods of primitive objects:
|
||||||
|
assertEq(Reflect.apply("".charAt,
|
||||||
|
"ponies",
|
||||||
|
[3]),
|
||||||
|
"i");
|
||||||
|
|
||||||
|
// Bound functions:
|
||||||
|
assertEq(Reflect.apply(function () { return this; }.bind(Math),
|
||||||
|
Function,
|
||||||
|
[]),
|
||||||
|
Math);
|
||||||
|
assertEq(Reflect.apply(Array.prototype.concat.bind([1, 2], [3]),
|
||||||
|
[4, 5],
|
||||||
|
[[6, 7, 8]]).join(),
|
||||||
|
"1,2,3,6,7,8");
|
||||||
|
|
||||||
|
// Generator functions:
|
||||||
|
function* g(arg) { yield "pass" + arg; }
|
||||||
|
assertEq(Reflect.apply(g,
|
||||||
|
undefined,
|
||||||
|
["word"]).next().value,
|
||||||
|
"password");
|
||||||
|
|
||||||
|
// Proxies:
|
||||||
|
function f() { return 13; }
|
||||||
|
assertEq(Reflect.apply(new Proxy(f, {}),
|
||||||
|
undefined,
|
||||||
|
[]),
|
||||||
|
13);
|
||||||
|
|
||||||
|
// Cross-compartment wrappers:
|
||||||
|
var gw = newGlobal();
|
||||||
|
assertEq(Reflect.apply(gw.parseInt,
|
||||||
|
undefined,
|
||||||
|
["45"]),
|
||||||
|
45);
|
||||||
|
assertEq(Reflect.apply(gw.Symbol.for,
|
||||||
|
undefined,
|
||||||
|
["moon"]),
|
||||||
|
Symbol.for("moon"));
|
||||||
|
|
||||||
|
gw.eval("function q() { return q; }");
|
||||||
|
assertEq(Reflect.apply(gw.q,
|
||||||
|
undefined,
|
||||||
|
[]),
|
||||||
|
gw.q);
|
||||||
|
|
||||||
|
|
||||||
|
// Exceptions are propagated.
|
||||||
|
var nope = new Error("nope");
|
||||||
|
function fail() {
|
||||||
|
throw nope;
|
||||||
|
}
|
||||||
|
assertThrowsValue(() => Reflect.apply(fail, undefined, []),
|
||||||
|
nope);
|
||||||
|
|
||||||
|
// Exceptions thrown by cross-compartment wrappers are re-wrapped for the
|
||||||
|
// calling compartment.
|
||||||
|
var gxw = gw.eval("var x = new Error('x'); x");
|
||||||
|
gw.eval("function fail() { throw x; }");
|
||||||
|
assertThrowsValue(() => Reflect.apply(gw.fail, undefined, []),
|
||||||
|
gxw);
|
||||||
|
|
||||||
|
// The thisArgument is passed to the target function as the 'this' value.
|
||||||
|
var obj = {};
|
||||||
|
hits = 0;
|
||||||
|
assertEq(Reflect.apply(function () { hits++; assertEq(this, obj); },
|
||||||
|
obj,
|
||||||
|
[]),
|
||||||
|
undefined);
|
||||||
|
assertEq(hits, 1);
|
||||||
|
|
||||||
|
// Primitive values can be thisArgument.
|
||||||
|
function strictThis() { "use strict"; return this; }
|
||||||
|
for (var value of [null, undefined, 0, -0, NaN, Symbol("moon")]) {
|
||||||
|
assertEq(Reflect.apply(strictThis, value, []),
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the target is a non-strict function and thisArgument is a primitive value
|
||||||
|
// other than null or undefined, then thisArgument is converted to a wrapper
|
||||||
|
// object.
|
||||||
|
var testValues = [true, 1e9, "ok", Symbol("ok")];
|
||||||
|
function nonStrictThis(expected) {
|
||||||
|
assertEq(typeof this, "object");
|
||||||
|
assertEq(Reflect.apply(Object.prototype.toString, this, []).toLowerCase(), expected);
|
||||||
|
return "ok";
|
||||||
|
}
|
||||||
|
for (var value of testValues) {
|
||||||
|
assertEq(Reflect.apply(nonStrictThis,
|
||||||
|
value,
|
||||||
|
["[object " + typeof value + "]"]),
|
||||||
|
"ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
// For more Reflect.apply tests, see target.js and argumentsList.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,168 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Tests for the argumentList argument to Reflect.apply and Reflect.construct.
|
||||||
|
|
||||||
|
if (Reflect.construct) {
|
||||||
|
throw new Error("Congratulations on implementing Reflect.construct! " +
|
||||||
|
"Please uncomment the Reflect.construct tests below.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reflect.apply and Reflect.construct require an argumentList argument that must be an object.
|
||||||
|
assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined), // missing
|
||||||
|
TypeError);
|
||||||
|
//assertThrowsInstanceOf(() => Reflect.construct(Object), // missing
|
||||||
|
// TypeError);
|
||||||
|
for (var primitive of SOME_PRIMITIVE_VALUES) {
|
||||||
|
assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined, primitive),
|
||||||
|
TypeError);
|
||||||
|
//assertThrowsInstanceOf(() => Reflect.construct(Object, primitive),
|
||||||
|
// TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array used by several tests below.
|
||||||
|
var BOTH = [
|
||||||
|
Reflect.apply,
|
||||||
|
// Adapt Reflect.construct to accept the same arguments as Reflect.apply.
|
||||||
|
//(target, thisArgument, argumentList) => Reflect.construct(target, argumentList)
|
||||||
|
];
|
||||||
|
|
||||||
|
// The argumentList is copied and becomes the list of arguments passed to the function.
|
||||||
|
function getRest(...x) { return x; }
|
||||||
|
var args = [1, 2, 3];
|
||||||
|
for (var method of BOTH) {
|
||||||
|
var result = method(getRest, undefined, args);
|
||||||
|
assertEq(result.join(), args.join());
|
||||||
|
assertEq(result !== args, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// argumentList.length can be less than func.length.
|
||||||
|
function testLess(a, b, c, d, e) {
|
||||||
|
assertEq(a, 1);
|
||||||
|
assertEq(b, true);
|
||||||
|
assertEq(c, "three");
|
||||||
|
assertEq(d, Symbol.for);
|
||||||
|
assertEq(e, undefined);
|
||||||
|
|
||||||
|
assertEq(arguments.length, 4);
|
||||||
|
assertEq(arguments !== args, true);
|
||||||
|
return "ok";
|
||||||
|
}
|
||||||
|
args = [1, true, "three", Symbol.for];
|
||||||
|
assertEq(Reflect.apply(testLess, undefined, args), "ok");
|
||||||
|
//assertEq(Reflect.construct(testLess, args) instanceof testLess, true);
|
||||||
|
|
||||||
|
// argumentList.length can be more than func.length.
|
||||||
|
function testMoar(a) {
|
||||||
|
assertEq(a, args[0]);
|
||||||
|
return "good";
|
||||||
|
}
|
||||||
|
assertEq(Reflect.apply(testMoar, undefined, args), "good");
|
||||||
|
//assertEq(Reflect.construct(testMoar, args) instanceof testMoar, true);
|
||||||
|
|
||||||
|
// argumentList can be any object with a .length property.
|
||||||
|
function getArgs(...args) {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
for (var method of BOTH) {
|
||||||
|
assertDeepEq(method(getArgs, undefined, {length: 0}),
|
||||||
|
[]);
|
||||||
|
assertDeepEq(method(getArgs, undefined, {length: 1, "0": "zero"}),
|
||||||
|
["zero"]);
|
||||||
|
assertDeepEq(method(getArgs, undefined, {length: 2}),
|
||||||
|
[undefined, undefined]);
|
||||||
|
assertDeepEq(method(getArgs, undefined, function (a, b, c) {}),
|
||||||
|
[undefined, undefined, undefined]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Iterable/Iterator interfaces are not used.
|
||||||
|
var funnyArgs = {
|
||||||
|
0: "zero",
|
||||||
|
1: "one",
|
||||||
|
length: 2,
|
||||||
|
[Symbol.iterator]() { throw "FAIL 1"; },
|
||||||
|
next() { throw "FAIL 2"; }
|
||||||
|
};
|
||||||
|
for (var method of BOTH) {
|
||||||
|
assertDeepEq(method(getArgs, undefined, funnyArgs),
|
||||||
|
["zero", "one"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If argumentList has no .length property, no arguments are passed.
|
||||||
|
function count() { return {numArgsReceived: arguments.length}; }
|
||||||
|
for (var method of BOTH) {
|
||||||
|
assertEq(method(count, undefined, {"0": 0, "1": 1}).numArgsReceived,
|
||||||
|
0);
|
||||||
|
function* g() { yield 1; yield 2; }
|
||||||
|
assertEq(method(count, undefined, g()).numArgsReceived,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If argumentsList.length has a getter, it is called.
|
||||||
|
var log;
|
||||||
|
args = {
|
||||||
|
get length() { log += "L"; return 1; },
|
||||||
|
get "0"() { log += "0"; return "zero"; },
|
||||||
|
get "1"() { log += "1"; return "one"; }
|
||||||
|
};
|
||||||
|
for (var method of BOTH) {
|
||||||
|
log = "";
|
||||||
|
assertDeepEq(method(getArgs, undefined, args),
|
||||||
|
["zero"]);
|
||||||
|
assertEq(log, "L0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The argumentsList.length getter can throw; the exception is propagated.
|
||||||
|
var exc = {status: "bad"};
|
||||||
|
args = {
|
||||||
|
get length() { throw exc; }
|
||||||
|
};
|
||||||
|
for (var method of BOTH) {
|
||||||
|
assertThrowsValue(() => method(count, undefined, args), exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If argumentsList.length is unreasonably huge, we get an error.
|
||||||
|
// (This is an implementation limit.)
|
||||||
|
for (var method of BOTH) {
|
||||||
|
for (var value of [1e12, 1e240, Infinity]) {
|
||||||
|
assertThrowsInstanceOf(() => method(count, undefined, {length: value}),
|
||||||
|
Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// argumentsList.length is converted to an integer.
|
||||||
|
for (var value of [1.7, "1", {valueOf() { return "1"; }}]) {
|
||||||
|
args = {
|
||||||
|
length: value,
|
||||||
|
"0": "ponies"
|
||||||
|
};
|
||||||
|
for (var method of BOTH) {
|
||||||
|
var result = method(getArgs, undefined, args);
|
||||||
|
assertEq(result.length, 1);
|
||||||
|
assertEq(result[0], "ponies");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If argumentsList.length is negative or NaN, no arguments are passed.
|
||||||
|
for (var method of BOTH) {
|
||||||
|
for (var num of [-1, -0.1, -0, -1e99, -Infinity, NaN]) {
|
||||||
|
assertEq(method(count, undefined, {length: num}).numArgsReceived,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Many arguments can be passed.
|
||||||
|
var many = 65537;
|
||||||
|
var args = {length: many, 0: "zero", [many - 1]: "last"};
|
||||||
|
function testMany(...args) {
|
||||||
|
"use strict";
|
||||||
|
for (var i = 0; i < many; i++) {
|
||||||
|
assertEq(i in args, true);
|
||||||
|
assertEq(args[i], i === 0 ? "zero" : i === many - 1 ? "last" : undefined);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
assertEq(Reflect.apply(testMany, "pass", args), "pass");
|
||||||
|
//assertEq(Reflect.construct(testMany, args) instanceof testMany, true);
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,164 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.defineProperty defines properties.
|
||||||
|
var obj = {};
|
||||||
|
assertEq(Reflect.defineProperty(obj, "x", {value: 7}), true);
|
||||||
|
assertEq(obj.x, 7);
|
||||||
|
var desc = Reflect.getOwnPropertyDescriptor(obj, "x");
|
||||||
|
assertDeepEq(desc, {value: 7,
|
||||||
|
writable: false,
|
||||||
|
enumerable: false,
|
||||||
|
configurable: false});
|
||||||
|
|
||||||
|
// Reflect.defineProperty can define a symbol-keyed property.
|
||||||
|
var key = Symbol(":o)");
|
||||||
|
assertEq(Reflect.defineProperty(obj, key, {value: 8}), true);
|
||||||
|
assertEq(obj[key], 8);
|
||||||
|
|
||||||
|
// array .length property
|
||||||
|
obj = [1, 2, 3, 4, 5];
|
||||||
|
assertEq(Reflect.defineProperty(obj, "length", {value: 4}), true);
|
||||||
|
assertDeepEq(obj, [1, 2, 3, 4]);
|
||||||
|
|
||||||
|
// The target can be a proxy.
|
||||||
|
obj = {};
|
||||||
|
var proxy = new Proxy(obj, {
|
||||||
|
defineProperty(t, id, desc) {
|
||||||
|
t[id] = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertEq(Reflect.defineProperty(proxy, "prop", {value: 7}), true);
|
||||||
|
assertEq(obj.prop, 1);
|
||||||
|
assertEq(delete obj.prop, true);
|
||||||
|
assertEq("prop" in obj, false);
|
||||||
|
|
||||||
|
// The attributes object is re-parsed, not passed through to the
|
||||||
|
// handler.defineProperty method.
|
||||||
|
obj = {};
|
||||||
|
var attributes = {
|
||||||
|
configurable: 17,
|
||||||
|
enumerable: undefined,
|
||||||
|
value: null
|
||||||
|
};
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
defineProperty(t, id, desc) {
|
||||||
|
assertEq(desc !== attributes, true);
|
||||||
|
assertEq(desc.configurable, true);
|
||||||
|
assertEq(desc.enumerable, false);
|
||||||
|
assertEq(desc.value, null);
|
||||||
|
assertEq("writable" in desc, false);
|
||||||
|
return 15; // and the return value here is coerced to boolean
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertEq(Reflect.defineProperty(proxy, "prop", attributes), true);
|
||||||
|
|
||||||
|
|
||||||
|
// === Failure and error cases
|
||||||
|
//
|
||||||
|
// Reflect.defineProperty behaves much like Object.defineProperty, which has
|
||||||
|
// extremely thorough tests elsewhere, and the implementation is largely
|
||||||
|
// shared. Duplicating those tests with Reflect.defineProperty would be a
|
||||||
|
// big waste.
|
||||||
|
//
|
||||||
|
// However, certain failures cause Reflect.defineProperty to return false
|
||||||
|
// without throwing a TypeError (unlike Object.defineProperty). So here we test
|
||||||
|
// many error cases to check that behavior.
|
||||||
|
|
||||||
|
// missing attributes argument
|
||||||
|
assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y"),
|
||||||
|
TypeError);
|
||||||
|
|
||||||
|
// non-object attributes argument
|
||||||
|
for (var attributes of SOME_PRIMITIVE_VALUES) {
|
||||||
|
assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y", attributes),
|
||||||
|
TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inextensible object
|
||||||
|
obj = Object.preventExtensions({});
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false);
|
||||||
|
|
||||||
|
// inextensible object with irrelevant inherited property
|
||||||
|
obj = Object.preventExtensions(Object.create({"prop": 3}));
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false);
|
||||||
|
|
||||||
|
// redefine nonconfigurable to configurable
|
||||||
|
obj = Object.freeze({prop: 1});
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {configurable: true}), false);
|
||||||
|
|
||||||
|
// redefine enumerability of nonconfigurable property
|
||||||
|
obj = Object.freeze(Object.defineProperties({}, {
|
||||||
|
x: {enumerable: true, configurable: false, value: 0},
|
||||||
|
y: {enumerable: false, configurable: false, value: 0},
|
||||||
|
}));
|
||||||
|
assertEq(Reflect.defineProperty(obj, "x", {enumerable: false}), false);
|
||||||
|
assertEq(Reflect.defineProperty(obj, "y", {enumerable: true}), false);
|
||||||
|
|
||||||
|
// redefine nonconfigurable data to accessor property, or vice versa
|
||||||
|
obj = Object.seal({x: 1, get y() { return 2; }});
|
||||||
|
assertEq(Reflect.defineProperty(obj, "x", {get() { return 2; }}), false);
|
||||||
|
assertEq(Reflect.defineProperty(obj, "y", {value: 1}), false);
|
||||||
|
|
||||||
|
// redefine nonwritable, nonconfigurable property as writable
|
||||||
|
obj = Object.freeze({prop: 0});
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {writable: true}), false);
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {writable: false}), true); // no-op
|
||||||
|
|
||||||
|
// change value of nonconfigurable nonwritable property
|
||||||
|
obj = Object.freeze({prop: 0});
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {value: -0}), false);
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {value: +0}), true); // no-op
|
||||||
|
|
||||||
|
// change getter or setter
|
||||||
|
function g() {}
|
||||||
|
function s(x) {}
|
||||||
|
obj = {};
|
||||||
|
Object.defineProperty(obj, "prop", {get: g, set: s, configurable: false});
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {get: s}), false);
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {get: g}), true); // no-op
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {set: g}), false);
|
||||||
|
assertEq(Reflect.defineProperty(obj, "prop", {set: s}), true); // no-op
|
||||||
|
|
||||||
|
// Proxy defineProperty handler method that returns false
|
||||||
|
var falseValues = [false, 0, -0, "", NaN, null, undefined];
|
||||||
|
if (typeof objectEmulatingUndefined === "function")
|
||||||
|
falseValues.push(objectEmulatingUndefined());
|
||||||
|
var value;
|
||||||
|
proxy = new Proxy({}, {
|
||||||
|
defineProperty(t, id, desc) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (value of falseValues) {
|
||||||
|
assertEq(Reflect.defineProperty(proxy, "prop", {value: 1}), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy defineProperty handler method returns true, in violation of invariants.
|
||||||
|
// Per spec, this is a TypeError, not a false return.
|
||||||
|
obj = Object.freeze({x: 1});
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
defineProperty(t, id, desc) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "x", {value: 2}), TypeError);
|
||||||
|
assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "y", {value: 0}), TypeError);
|
||||||
|
assertEq(Reflect.defineProperty(proxy, "x", {value: 1}), true);
|
||||||
|
|
||||||
|
// The second argument is converted ToPropertyKey before any internal methods
|
||||||
|
// are called on the first argument.
|
||||||
|
var poison =
|
||||||
|
(counter => new Proxy({}, new Proxy({}, { get() { throw counter++; } })))(42);
|
||||||
|
assertThrowsValue(() => {
|
||||||
|
Reflect.defineProperty(poison, {
|
||||||
|
toString() { throw 17; },
|
||||||
|
valueOf() { throw 8675309; }
|
||||||
|
}, poison);
|
||||||
|
}, 17);
|
||||||
|
|
||||||
|
|
||||||
|
// For more Reflect.defineProperty tests, see target.js and propertyKeys.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,80 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.deleteProperty deletes properties.
|
||||||
|
var obj = {x: 1, y: 2};
|
||||||
|
assertEq(Reflect.deleteProperty(obj, "x"), true);
|
||||||
|
assertDeepEq(obj, {y: 2});
|
||||||
|
|
||||||
|
var arr = [1, 1, 2, 3, 5];
|
||||||
|
assertEq(Reflect.deleteProperty(arr, "3"), true);
|
||||||
|
assertDeepEq(arr, [1, 1, 2, , 5]);
|
||||||
|
|
||||||
|
|
||||||
|
// === Failure and error cases
|
||||||
|
// Since Reflect.deleteProperty is almost exactly identical to the non-strict
|
||||||
|
// `delete` operator, there is not much to test that would not be redundant.
|
||||||
|
|
||||||
|
// Returns true if no such property exists.
|
||||||
|
assertEq(Reflect.deleteProperty({}, "q"), true);
|
||||||
|
|
||||||
|
// Or if it's inherited.
|
||||||
|
var proto = {x: 1};
|
||||||
|
assertEq(Reflect.deleteProperty(Object.create(proto), "x"), true);
|
||||||
|
assertEq(proto.x, 1);
|
||||||
|
|
||||||
|
// Return false if asked to delete a non-configurable property.
|
||||||
|
var arr = [];
|
||||||
|
assertEq(Reflect.deleteProperty(arr, "length"), false);
|
||||||
|
assertEq(arr.hasOwnProperty("length"), true);
|
||||||
|
assertEq(Reflect.deleteProperty(this, "undefined"), false);
|
||||||
|
assertEq(this.undefined, void 0);
|
||||||
|
|
||||||
|
// Return false if a Proxy's deleteProperty handler returns a false-y value.
|
||||||
|
var value;
|
||||||
|
var proxy = new Proxy({}, {
|
||||||
|
deleteProperty(t, k) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (value of [true, false, 0, "something", {}]) {
|
||||||
|
assertEq(Reflect.deleteProperty(proxy, "q"), !!value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a Proxy's handler method throws, the error is propagated.
|
||||||
|
proxy = new Proxy({}, {
|
||||||
|
deleteProperty(t, k) { throw "vase"; }
|
||||||
|
});
|
||||||
|
assertThrowsValue(() => Reflect.deleteProperty(proxy, "prop"), "vase");
|
||||||
|
|
||||||
|
// Throw a TypeError if a Proxy's handler method returns true in violation of
|
||||||
|
// the object invariants.
|
||||||
|
proxy = new Proxy(Object.freeze({prop: 1}), {
|
||||||
|
deleteProperty(t, k) { return true; }
|
||||||
|
});
|
||||||
|
assertThrowsInstanceOf(() => Reflect.deleteProperty(proxy, "prop"), TypeError);
|
||||||
|
|
||||||
|
|
||||||
|
// === Deleting elements from `arguments`
|
||||||
|
|
||||||
|
// Non-strict arguments element becomes unmapped
|
||||||
|
function f(x, y, z) {
|
||||||
|
assertEq(Reflect.deleteProperty(arguments, "0"), true);
|
||||||
|
arguments.x = 33;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
assertEq(f(17, 19, 23), 17);
|
||||||
|
|
||||||
|
// Frozen non-strict arguments element
|
||||||
|
function testFrozenArguments() {
|
||||||
|
Object.freeze(arguments);
|
||||||
|
assertEq(Reflect.deleteProperty(arguments, "0"), false);
|
||||||
|
assertEq(arguments[0], "zero");
|
||||||
|
assertEq(arguments[1], "one");
|
||||||
|
}
|
||||||
|
testFrozenArguments("zero", "one");
|
||||||
|
|
||||||
|
|
||||||
|
// For more Reflect.deleteProperty tests, see target.js and propertyKeys.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.get gets the value of a property.
|
||||||
|
|
||||||
|
var x = {p: 1};
|
||||||
|
assertEq(Reflect.get(x, "p"), 1);
|
||||||
|
assertEq(Reflect.get(x, "toString"), Object.prototype.toString);
|
||||||
|
assertEq(Reflect.get(x, "missing"), undefined);
|
||||||
|
|
||||||
|
|
||||||
|
// === Various targets
|
||||||
|
|
||||||
|
// Array
|
||||||
|
assertEq(Reflect.get([], 700), undefined);
|
||||||
|
assertEq(Reflect.get(["zero", "one"], 1), "one");
|
||||||
|
|
||||||
|
// TypedArray
|
||||||
|
assertEq(Reflect.get(new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]), 7), 7);
|
||||||
|
|
||||||
|
// Treatment of NaN
|
||||||
|
var f = new Float64Array([NaN]);
|
||||||
|
var u = new Uint32Array(f.buffer);
|
||||||
|
u[0]++;
|
||||||
|
u[1]++;
|
||||||
|
assertEq(f[0], NaN);
|
||||||
|
assertEq(Reflect.get(f, 0), NaN);
|
||||||
|
|
||||||
|
// Proxy with no get handler
|
||||||
|
assertEq(Reflect.get(new Proxy(x, {}), "p"), 1);
|
||||||
|
|
||||||
|
// Proxy with a get handler
|
||||||
|
var obj = new Proxy(x, {
|
||||||
|
get(t, k, r) { return k + "ful"; }
|
||||||
|
});
|
||||||
|
assertEq(Reflect.get(obj, "mood"), "moodful");
|
||||||
|
|
||||||
|
// Exceptions thrown by a proxy's get handler are propagated.
|
||||||
|
assertThrowsInstanceOf(() => Reflect.get(obj, Symbol()), TypeError);
|
||||||
|
|
||||||
|
// Ordinary object, property has a setter and no getter
|
||||||
|
obj = {set name(x) {}};
|
||||||
|
assertEq(Reflect.get(obj, "name"), undefined);
|
||||||
|
|
||||||
|
|
||||||
|
// === Receiver
|
||||||
|
|
||||||
|
// Receiver argument is passed to getters as the this-value.
|
||||||
|
obj = { get x() { return this; }};
|
||||||
|
assertEq(Reflect.get(obj, "x", Math), Math);
|
||||||
|
assertEq(Reflect.get(Object.create(obj), "x", JSON), JSON);
|
||||||
|
|
||||||
|
// If missing, target is passed instead.
|
||||||
|
assertEq(Reflect.get(obj, "x"), obj);
|
||||||
|
|
||||||
|
// Receiver argument is passed to the proxy get handler.
|
||||||
|
obj = new Proxy({}, {
|
||||||
|
get(t, k, r) {
|
||||||
|
assertEq(k, "itself");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertEq(Reflect.get(obj, "itself"), obj);
|
||||||
|
assertEq(Reflect.get(obj, "itself", Math), Math);
|
||||||
|
assertEq(Reflect.get(Object.create(obj), "itself", Math), Math);
|
||||||
|
|
||||||
|
// The receiver shouldn't have to be an object---but we do not implement that
|
||||||
|
// correctly yet (bug 603201). For now, test the wrong behavior just to make
|
||||||
|
// sure we don't crash.
|
||||||
|
var result;
|
||||||
|
try {
|
||||||
|
result = Reflect.get(obj, "x", 37.2);
|
||||||
|
} catch (exc) {
|
||||||
|
result = exc;
|
||||||
|
}
|
||||||
|
if (result === 37.2) {
|
||||||
|
throw new Error("Congratulations on fixing bug 603201! " +
|
||||||
|
"Please update this test for 1 karma point.");
|
||||||
|
}
|
||||||
|
assertEq(result instanceof TypeError, true);
|
||||||
|
|
||||||
|
|
||||||
|
// For more Reflect.get tests, see target.js and propertyKeys.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.getOwnPropertyDescriptor inspects object properties.
|
||||||
|
assertDeepEq(
|
||||||
|
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x"),
|
||||||
|
{value: "hello", writable: true, enumerable: true, configurable: true});
|
||||||
|
assertEq(
|
||||||
|
Reflect.getOwnPropertyDescriptor({x: "hello"}, "y"),
|
||||||
|
undefined);
|
||||||
|
assertDeepEq(
|
||||||
|
Reflect.getOwnPropertyDescriptor([], "length"),
|
||||||
|
{value: 0, writable: true, enumerable: false, configurable: false});
|
||||||
|
|
||||||
|
// Reflect.getOwnPropertyDescriptor shares its implementation with
|
||||||
|
// Object.getOwnPropertyDescriptor. The only difference is how non-object
|
||||||
|
// targets are handled.
|
||||||
|
//
|
||||||
|
// For more Reflect.getOwnPropertyDescriptor tests, see target.js and propertyKeys.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.getPrototypeOf returns an object's prototype.
|
||||||
|
assertEq(Reflect.getPrototypeOf({}), Object.prototype);
|
||||||
|
assertEq(Reflect.getPrototypeOf(Object.prototype), null);
|
||||||
|
assertEq(Reflect.getPrototypeOf(Object.create(null)), null);
|
||||||
|
|
||||||
|
// Sleeper test for when scripted proxies support the getPrototypeOf handler
|
||||||
|
// method (bug 888969).
|
||||||
|
var proxy = new Proxy({}, {
|
||||||
|
getPrototypeOf(t) { return Math; }
|
||||||
|
});
|
||||||
|
var result = Reflect.getPrototypeOf(proxy);
|
||||||
|
if (result === Math) {
|
||||||
|
throw new Error("Congratulations on fixing bug 888969! " +
|
||||||
|
"Please update this test to cover scripted proxies.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// For more Reflect.getPrototypeOf tests, see target.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.has is identical to the `in` operator.
|
||||||
|
assertEq(Reflect.has({x: 0}, "x"), true);
|
||||||
|
assertEq(Reflect.has({x: 0}, "y"), false);
|
||||||
|
assertEq(Reflect.has({x: 0}, "toString"), true);
|
||||||
|
|
||||||
|
// The target can be an array; Reflect.has works on array elements.
|
||||||
|
var arr = ["zero"];
|
||||||
|
arr[10000] = 0;
|
||||||
|
assertEq(Reflect.has(arr, "10000"), true);
|
||||||
|
assertEq(Reflect.has(arr, 10000), true);
|
||||||
|
assertEq(Reflect.has(arr, "-0"), false);
|
||||||
|
assertEq(Reflect.has(arr, -0), true);
|
||||||
|
|
||||||
|
// And string objects (though not string primitives; see target.js).
|
||||||
|
var str = new String("hello");
|
||||||
|
assertEq(Reflect.has(str, "4"), true);
|
||||||
|
assertEq(Reflect.has(str, "-0"), false);
|
||||||
|
assertEq(Reflect.has(str, -0), true);
|
||||||
|
|
||||||
|
// Proxy without .has() handler method
|
||||||
|
var obj = {get prop() {}};
|
||||||
|
for (var i = 0; i < 2; i++) {
|
||||||
|
obj = new Proxy(obj, {});
|
||||||
|
assertEq(Reflect.has(obj, "prop"), true);
|
||||||
|
assertEq(Reflect.has(obj, "nope"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy with .has() handler method
|
||||||
|
obj = new Proxy({}, {
|
||||||
|
has(t, k) { return k.startsWith("door"); }
|
||||||
|
});
|
||||||
|
assertEq(Reflect.has(obj, "doorbell"), true);
|
||||||
|
assertEq(Reflect.has(obj, "dormitory"), false);
|
||||||
|
|
||||||
|
|
||||||
|
// For more Reflect.has tests, see target.js and propertyKeys.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,54 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.isExtensible behaves just like Object.extensible except when the
|
||||||
|
// target argument is missing or is not an object (and that behavior is tested
|
||||||
|
// in target.js).
|
||||||
|
|
||||||
|
// Test basic functionality.
|
||||||
|
var someObjects = [
|
||||||
|
{},
|
||||||
|
{a: "a"},
|
||||||
|
[0, 1],
|
||||||
|
new Uint8Array(64),
|
||||||
|
Object(Symbol("table")),
|
||||||
|
new Proxy({}, {})
|
||||||
|
];
|
||||||
|
for (var obj of someObjects) {
|
||||||
|
assertEq(Reflect.isExtensible(obj), true);
|
||||||
|
assertEq(Reflect.preventExtensions(obj), true);
|
||||||
|
assertEq(Reflect.isExtensible(obj), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array with nonwritable length.
|
||||||
|
var arr = [0, 1, 2, 3];
|
||||||
|
Object.defineProperty(arr, "length", {writable: false});
|
||||||
|
assertEq(Reflect.isExtensible(arr), true);
|
||||||
|
|
||||||
|
// Proxy case.
|
||||||
|
for (var ext of [true, false]) {
|
||||||
|
var obj = {};
|
||||||
|
if (!ext)
|
||||||
|
Object.preventExtensions(obj);
|
||||||
|
var proxy = new Proxy(obj, {
|
||||||
|
isExtensible() { return ext; }
|
||||||
|
});
|
||||||
|
assertEq(Reflect.isExtensible(proxy), ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a Proxy's isExtensible method throws, the exception is propagated.
|
||||||
|
proxy = new Proxy({}, {
|
||||||
|
isExtensible() { throw "oops"; }
|
||||||
|
});
|
||||||
|
assertThrowsValue(() => Reflect.isExtensible(proxy), "oops");
|
||||||
|
|
||||||
|
// If an invariant is broken, [[IsExtensible]] does not return false. It throws
|
||||||
|
// a TypeError.
|
||||||
|
proxy = new Proxy({}, {
|
||||||
|
isExtensible() { return false; }
|
||||||
|
});
|
||||||
|
assertThrowsInstanceOf(() => Reflect.isExtensible(proxy), TypeError);
|
||||||
|
|
||||||
|
// For more Reflect.isExtensible tests, see target.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.ownKeys(obj) returns an array of an object's own property keys.
|
||||||
|
|
||||||
|
// Test that Reflect.ownKeys gets the expected result when applied to various
|
||||||
|
// objects. (These tests also check the basics: that the result is an array,
|
||||||
|
// that its prototype is correct, etc.)
|
||||||
|
var sym = Symbol.for("comet");
|
||||||
|
var sym2 = Symbol.for("meteor");
|
||||||
|
var cases = [
|
||||||
|
{object: {z: 3, y: 2, x: 1},
|
||||||
|
keys: ["z", "y", "x"]},
|
||||||
|
{object: [],
|
||||||
|
keys: ["length"]},
|
||||||
|
{object: new Int8Array(4),
|
||||||
|
keys: ["0", "1", "2", "3"]},
|
||||||
|
{object: new Proxy({a: 7}, {}),
|
||||||
|
keys: ["a"]},
|
||||||
|
{object: {[sym]: "ok"},
|
||||||
|
keys: [sym]},
|
||||||
|
{object: {[sym]: 0, // test 9.1.12 ordering
|
||||||
|
"str": 0,
|
||||||
|
"773": 0,
|
||||||
|
"0": 0,
|
||||||
|
[sym2]: 0,
|
||||||
|
"-1": 0,
|
||||||
|
"8": 0,
|
||||||
|
"second str": 0},
|
||||||
|
keys: ["0", "8", "773", // indexes in numeric order
|
||||||
|
"str", "-1", "second str", // strings in insertion order
|
||||||
|
sym, sym2]}, // symbols in insertion order
|
||||||
|
{object: newGlobal().Math, // cross-compartment wrapper
|
||||||
|
keys: Reflect.ownKeys(Math)}
|
||||||
|
];
|
||||||
|
for (var {object, keys} of cases)
|
||||||
|
assertDeepEq(Reflect.ownKeys(object), keys);
|
||||||
|
|
||||||
|
// Reflect.ownKeys() creates a new array each time it is called.
|
||||||
|
var object = {}, keys = [];
|
||||||
|
for (var i = 0; i < 3; i++) {
|
||||||
|
var newKeys = Reflect.ownKeys(object);
|
||||||
|
assertEq(newKeys !== keys, true);
|
||||||
|
keys = newKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy behavior with successful ownKeys() handler
|
||||||
|
keys = ["str", "0"];
|
||||||
|
obj = {};
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
ownKeys() { return keys; }
|
||||||
|
});
|
||||||
|
var actual = Reflect.ownKeys(proxy);
|
||||||
|
assertDeepEq(actual, keys); // we get correct answers
|
||||||
|
assertEq(actual !== keys, true); // but not the same object
|
||||||
|
|
||||||
|
// If a proxy breaks invariants, a TypeError is thrown.
|
||||||
|
var obj = Object.preventExtensions({});
|
||||||
|
var proxy = new Proxy(obj, {
|
||||||
|
ownKeys() { return ["something"]; }
|
||||||
|
});
|
||||||
|
assertThrowsInstanceOf(() => Reflect.ownKeys(proxy), TypeError);
|
||||||
|
|
||||||
|
// For more Reflect.ownKeys tests, see target.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.preventExtensions is the same as Object.preventExtensions, except
|
||||||
|
// for the return value and the behavior in error cases.
|
||||||
|
|
||||||
|
var someObjects = [
|
||||||
|
{},
|
||||||
|
new Int32Array(7),
|
||||||
|
Object(Symbol("table")),
|
||||||
|
new Proxy({}, {})
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var obj of someObjects) {
|
||||||
|
assertEq(Reflect.preventExtensions(obj), true);
|
||||||
|
// [[PreventExtensions]] on an already-inextensible object is a no-op.
|
||||||
|
assertEq(Reflect.preventExtensions(obj), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error cases.
|
||||||
|
assertThrowsInstanceOf(() => Reflect.isExtensible(), TypeError);
|
||||||
|
for (var value of [undefined, null, true, 1, NaN, "Phaedo", Symbol("good")]) {
|
||||||
|
assertThrowsInstanceOf(() => Reflect.isExtensible(value), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A proxy's preventExtensions handler can return false without doing anything.
|
||||||
|
obj = {};
|
||||||
|
var proxy = new Proxy(obj, {
|
||||||
|
preventExtensions() { return false; }
|
||||||
|
});
|
||||||
|
assertEq(Reflect.preventExtensions(proxy), false);
|
||||||
|
assertEq(Reflect.isExtensible(obj), true);
|
||||||
|
assertEq(Reflect.isExtensible(proxy), true);
|
||||||
|
|
||||||
|
// If a proxy's preventExtensions handler throws, the exception is propagated.
|
||||||
|
obj = {};
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
preventExtensions() { throw "fit"; }
|
||||||
|
});
|
||||||
|
assertThrowsValue(() => Reflect.preventExtensions(proxy), "fit");
|
||||||
|
assertEq(Reflect.isExtensible(obj), true);
|
||||||
|
assertEq(Reflect.isExtensible(proxy), true);
|
||||||
|
|
||||||
|
// If a proxy's preventExtensions handler returns true while leaving the target
|
||||||
|
// extensible, that's a TypeError.
|
||||||
|
obj = {};
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
preventExtensions() { return true; }
|
||||||
|
});
|
||||||
|
assertThrowsInstanceOf(() => Reflect.preventExtensions(proxy), TypeError);
|
||||||
|
assertEq(Reflect.isExtensible(obj), true);
|
||||||
|
assertEq(Reflect.isExtensible(proxy), true);
|
||||||
|
|
||||||
|
// For more Reflect.preventExtensions tests, see target.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Test corner cases involving Reflect methods' propertyKey arguments.
|
||||||
|
|
||||||
|
// keys - Array of propertyKey values to be tested.
|
||||||
|
//
|
||||||
|
// Each element of this array is a record with these properties:
|
||||||
|
//
|
||||||
|
// * value: a value that will be passed as a property key
|
||||||
|
// to the various Reflect methods;
|
||||||
|
//
|
||||||
|
// * expected: (optional) the string or symbol that ToPropertyKey(value)
|
||||||
|
// should return. If this is omitted, ToPropertyKey(value) === value.
|
||||||
|
//
|
||||||
|
var keys = [
|
||||||
|
{value: null, expected: "null"},
|
||||||
|
{value: undefined, expected: "undefined"},
|
||||||
|
{value: true, expected: "true"},
|
||||||
|
{value: 42, expected: "42"},
|
||||||
|
{value: "string"},
|
||||||
|
{value: ""},
|
||||||
|
{value: "string with \0"},
|
||||||
|
{value: new String("ok"), expected: "ok"},
|
||||||
|
{value: Symbol("sym")},
|
||||||
|
{value: Symbol.iterator},
|
||||||
|
{value: Object(Symbol.for("comet")), expected: Symbol.for("comet")},
|
||||||
|
{
|
||||||
|
value: {
|
||||||
|
toString() { return "key"; },
|
||||||
|
valueOf() { return "bad"; }
|
||||||
|
},
|
||||||
|
expected: "key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: {
|
||||||
|
toString: undefined,
|
||||||
|
valueOf() { return "fallback"; }
|
||||||
|
},
|
||||||
|
expected: "fallback"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if ("toPrimitive" in Symbol) {
|
||||||
|
throw new Error("Congratulations on implementing Symbol.toPrimitive! " +
|
||||||
|
"Please add an object with an @@toPrimitive method in the list above.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var {value, expected} of keys) {
|
||||||
|
if (expected === undefined)
|
||||||
|
expected = value;
|
||||||
|
|
||||||
|
var obj = {};
|
||||||
|
assertEq(Reflect.defineProperty(obj, value, {value: 1, configurable: true}), true);
|
||||||
|
assertDeepEq(Reflect.ownKeys(obj), [expected]);
|
||||||
|
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, value),
|
||||||
|
{value: 1,
|
||||||
|
writable: false,
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true});
|
||||||
|
assertEq(Reflect.deleteProperty(obj, value), true);
|
||||||
|
assertEq(Reflect.has(obj, value), false);
|
||||||
|
assertEq(Reflect.set(obj, value, 113), true);
|
||||||
|
assertEq(obj[expected], 113);
|
||||||
|
assertEq(Reflect.has(obj, value), true);
|
||||||
|
assertEq(Reflect.get(obj, value), 113);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPropertyKey can throw.
|
||||||
|
var exc = {};
|
||||||
|
var badKey = {toString() { throw exc; }};
|
||||||
|
var methodNames = ["defineProperty", "deleteProperty", "has", "get", "getOwnPropertyDescriptor", "set"];
|
||||||
|
for (var name of methodNames) {
|
||||||
|
assertThrowsValue(() => Reflect[name]({}, badKey), exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -1,16 +1,280 @@
|
||||||
if (this.Reflect && Reflect.set)
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
throw new Error("Congrats on implementing Reflect.set! Uncomment this test for 1 karma point.");
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.set does property assignment.
|
||||||
|
// With three arguments, this is pretty straightforward.
|
||||||
|
var obj = {};
|
||||||
|
assertEq(Reflect.set(obj, "prop", "value"), true);
|
||||||
|
assertEq(obj.prop, "value");
|
||||||
|
|
||||||
|
|
||||||
|
// === Various targets
|
||||||
|
|
||||||
|
// It can assign array elements.
|
||||||
|
var arr = ["duck", "duck", "duck"];
|
||||||
|
assertEq(Reflect.set(arr, 2, "goose"), true);
|
||||||
|
assertEq(arr[2], "goose");
|
||||||
|
|
||||||
|
// It can extend an array.
|
||||||
|
assertEq(Reflect.set(arr, 3, "Model T"), true);
|
||||||
|
assertEq(arr.length, 4);
|
||||||
|
|
||||||
|
// It can truncate an array.
|
||||||
|
assertEq(Reflect.set(arr, "length", 1), true);
|
||||||
|
assertDeepEq(arr, ["duck"]);
|
||||||
|
|
||||||
|
// It won't assign to non-writable properties of String objects.
|
||||||
|
var str = new String("hello");
|
||||||
|
assertEq(Reflect.set(str, "0", "y"), false);
|
||||||
|
assertEq(str[0], "h");
|
||||||
|
assertEq(Reflect.set(str, "length", 700), false);
|
||||||
|
assertEq(str.length, 5);
|
||||||
|
|
||||||
|
|
||||||
|
// === Receivers
|
||||||
|
// The optional fourth argument is the receiver, which [[Set]] methods use for
|
||||||
|
// various things.
|
||||||
|
|
||||||
|
// On ordinary objects, if the property has a setter, the receiver is passed as
|
||||||
|
// the this-value to the setter.
|
||||||
|
var expected;
|
||||||
|
var obj = {
|
||||||
|
set prop(v) {
|
||||||
|
"use strict";
|
||||||
|
assertEq(v, 32);
|
||||||
|
assertEq(this, expected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (expected of [obj, {}, [], 37.3]) {
|
||||||
|
assertEq(Reflect.set(obj, "prop", 32, expected), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the property doesn't already exist, it is defined on the receiver.
|
||||||
|
obj = {};
|
||||||
|
var obj2 = {};
|
||||||
|
assertEq(Reflect.set(obj, "prop", 47, obj2), true);
|
||||||
|
assertDeepEq(obj, {});
|
||||||
|
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj2, "prop"),
|
||||||
|
{value: 47, writable: true, enumerable: true, configurable: true});
|
||||||
|
|
||||||
|
// If the property doesn't already exist, and the receiver isn't an object, return false.
|
||||||
|
for (var v of SOME_PRIMITIVE_VALUES) {
|
||||||
|
assertEq(Reflect.set({}, "x", 0, v), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receiver defaults to the target.
|
||||||
|
obj = {};
|
||||||
|
var hits;
|
||||||
|
var expectedReceiver;
|
||||||
|
var proxy = new Proxy(obj, {
|
||||||
|
set(t, k, v, r) {
|
||||||
|
assertEq(t, obj);
|
||||||
|
assertEq(k, "key");
|
||||||
|
assertEq(v, "value");
|
||||||
|
assertEq(r, expectedReceiver); // not obj
|
||||||
|
hits++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hits = 0;
|
||||||
|
expectedReceiver = proxy;
|
||||||
|
assertEq(Reflect.set(proxy, "key", "value"), true);
|
||||||
|
assertEq(hits, 1);
|
||||||
|
|
||||||
|
// But not if explicitly present and undefined.
|
||||||
|
hits = 0;
|
||||||
|
expectedReceiver = undefined;
|
||||||
|
assertEq(Reflect.set(proxy, "key", "value", undefined), true);
|
||||||
|
assertEq(hits, 1);
|
||||||
|
|
||||||
|
// Reflect.set can be used as fallback behavior in a proxy handler .set()
|
||||||
|
// method.
|
||||||
|
var log;
|
||||||
|
obj = {
|
||||||
|
set prop(v) {
|
||||||
|
log += "p";
|
||||||
|
assertEq(v, "value");
|
||||||
|
assertEq(this, proxy); // not obj!
|
||||||
|
}
|
||||||
|
};
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
set(t, k, v, r) {
|
||||||
|
assertEq(t, obj);
|
||||||
|
assertEq(r, proxy);
|
||||||
|
log += "s";
|
||||||
|
return Reflect.set(t, k, v, r);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log = "";
|
||||||
|
assertEq(Reflect.set(proxy, "prop", "value"), true);
|
||||||
|
assertEq(log, "sp");
|
||||||
|
|
||||||
|
|
||||||
|
// === Cross-compartment wrapper behavior.
|
||||||
|
|
||||||
|
// When calling a cross-compartment wrapper, receiver is rewrapped for the
|
||||||
|
// target compartment.
|
||||||
|
var g = newGlobal();
|
||||||
|
if (!("assertEq" in g))
|
||||||
|
g.assertEq = assertEq; // necessary in the browser
|
||||||
|
g.eval(`
|
||||||
|
var hits;
|
||||||
|
var obj = {
|
||||||
|
set x(v) {
|
||||||
|
"use strict";
|
||||||
|
assertEq(this, receiver);
|
||||||
|
assertEq(v, "xyzzy");
|
||||||
|
hits++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var receiver = {};
|
||||||
|
`);
|
||||||
|
g.hits = 0;
|
||||||
|
assertEq(Reflect.set(g.obj, "x", "xyzzy", g.receiver), true);
|
||||||
|
assertEq(g.hits, 1);
|
||||||
|
|
||||||
|
// ...even when receiver is from a different compartment than target.
|
||||||
|
var receiver = {};
|
||||||
|
g.receiver = receiver;
|
||||||
|
g.hits = 0;
|
||||||
|
assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
|
||||||
|
assertEq(g.hits, 1);
|
||||||
|
|
||||||
|
// ...even when receiver is a primtive value, even undefined.
|
||||||
|
for (receiver of SOME_PRIMITIVE_VALUES) {
|
||||||
|
g.receiver = receiver;
|
||||||
|
g.hits = 0;
|
||||||
|
assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
|
||||||
|
assertEq(g.hits, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Less than 3 arguments
|
||||||
|
|
||||||
|
// With two arguments, the value is assumed to be undefined.
|
||||||
|
obj = {};
|
||||||
|
assertEq(Reflect.set(obj, "size"), true);
|
||||||
|
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "size"),
|
||||||
|
{value: undefined, writable: true, enumerable: true, configurable: true});
|
||||||
|
|
||||||
|
// With just one argument, the key is "undefined".
|
||||||
|
obj = {};
|
||||||
|
assertEq(Reflect.set(obj), true);
|
||||||
|
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "undefined"),
|
||||||
|
{value: undefined, writable: true, enumerable: true, configurable: true});
|
||||||
|
|
||||||
|
// For the no argument-case, see target.js.
|
||||||
|
|
||||||
|
|
||||||
|
// === Failure cases
|
||||||
|
|
||||||
|
// Non-writable data property
|
||||||
|
obj = {};
|
||||||
|
Reflect.defineProperty(obj, "x", {value: 0, writable: false});
|
||||||
|
assertEq(Reflect.set(obj, "x", 1), false);
|
||||||
|
assertEq(obj.x, 0);
|
||||||
|
|
||||||
|
// The same, but inherited from a prototype
|
||||||
|
var obj2 = Object.create(obj);
|
||||||
|
assertEq(Reflect.set(obj2, "x", 1), false);
|
||||||
|
assertEq(obj2.hasOwnProperty("x"), false);
|
||||||
|
assertEq(obj2.x, 0);
|
||||||
|
|
||||||
|
// Getter, no setter
|
||||||
|
obj = {};
|
||||||
|
var desc = {get: () => 12, set: undefined, enumerable: false, configurable: true};
|
||||||
|
Reflect.defineProperty(obj, "y", desc);
|
||||||
|
assertEq(Reflect.set(obj, "y", 13), false);
|
||||||
|
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
|
||||||
|
|
||||||
|
// The same, but inherited from a prototype
|
||||||
|
obj2 = Object.create(obj);
|
||||||
|
assertEq(Reflect.set(obj2, "y", 1), false);
|
||||||
|
assertEq(obj2.hasOwnProperty("y"), false);
|
||||||
|
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
|
||||||
|
|
||||||
|
// Proxy set handler returns a false value
|
||||||
|
for (var no of [false, ""]) {
|
||||||
|
var hits = 0;
|
||||||
|
obj = {};
|
||||||
|
var proxy = new Proxy(obj, {
|
||||||
|
set(t, k, v, r) {
|
||||||
|
assertEq(t, obj);
|
||||||
|
assertEq(k, "x");
|
||||||
|
assertEq(v, 33);
|
||||||
|
assertEq(r, proxy);
|
||||||
|
hits++;
|
||||||
|
return no;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertEq(Reflect.set(proxy, "x", 33), false);
|
||||||
|
assertEq(hits, 1);
|
||||||
|
assertEq("x" in obj, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy handler method throws
|
||||||
|
obj = {};
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
set(t, k, v, r) { throw "i don't like " + v; }
|
||||||
|
});
|
||||||
|
assertThrowsValue(() => Reflect.set(proxy, "food", "cheese"), "i don't like cheese");
|
||||||
|
|
||||||
|
// If a Proxy set handler breaks the object invariants, it's a TypeError.
|
||||||
|
for (obj of [{a: 0}, {get a() { return 0; }}]) {
|
||||||
|
Object.freeze(obj);
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
set(t, k, v, r) { return true; }
|
||||||
|
});
|
||||||
|
assertThrowsInstanceOf(() => Reflect.set(proxy, "a", "b"), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Per spec, this should first call p.[[Set]]("0", 42, a) and
|
// Per spec, this should first call p.[[Set]]("0", 42, a) and
|
||||||
// then (since p has no own properties) a.[[Set]]("0", 42, a).
|
// then (since p has no own properties) a.[[Set]]("0", 42, a).
|
||||||
// Obviously the latter should not define a property on p.
|
// The latter should not define a property on p.
|
||||||
|
|
||||||
var a = [0, 1, 2, 3];
|
var a = [0, 1, 2, 3];
|
||||||
var p = Object.create(a);
|
var p = Object.create(a);
|
||||||
Reflect.set(p, "0", 42, a);
|
Reflect.set(p, "0", 42, a);
|
||||||
assertEq(p.hasOwnProperty("0"), false);
|
assertEq(p.hasOwnProperty("0"), false);
|
||||||
assertEq(a[0], 42);
|
assertDeepEq(Reflect.getOwnPropertyDescriptor(a, "0"),
|
||||||
*/
|
{value: 42, writable: true, enumerable: true, configurable: true});
|
||||||
|
|
||||||
reportCompare(0, 0, 'ok');
|
// Test behavior of ordinary objects' [[Set]] method (ES6 9.1.9).
|
||||||
|
// On an ordinary object, if the property key isn't present, [[Set]] calls
|
||||||
|
// receiver.[[GetOwnProperty]]() and then receiver.[[DefineProperty]]().
|
||||||
|
var log;
|
||||||
|
obj = {};
|
||||||
|
var proxyTarget = {};
|
||||||
|
var existingDescriptor, expected, defineResult;
|
||||||
|
var receiver = new Proxy(proxyTarget, {
|
||||||
|
getOwnPropertyDescriptor(t, k) {
|
||||||
|
log += "g";
|
||||||
|
return existingDescriptor;
|
||||||
|
},
|
||||||
|
defineProperty(t, k, desc) {
|
||||||
|
log += "d";
|
||||||
|
assertEq(t, proxyTarget);
|
||||||
|
assertEq(k, "prop");
|
||||||
|
assertDeepEq(desc, expected);
|
||||||
|
return defineResult;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
existingDescriptor = undefined;
|
||||||
|
expected = {value: 5, writable: true, enumerable: true, configurable: true};
|
||||||
|
for (var defineResult of [true, false]) {
|
||||||
|
log = "";
|
||||||
|
assertEq(Reflect.set(obj, "prop", 5, receiver), defineResult);
|
||||||
|
assertEq(log, "gd");
|
||||||
|
}
|
||||||
|
|
||||||
|
existingDescriptor = {value: 7, writable: true, enumerable: false, configurable: true};
|
||||||
|
expected = {value: 4};
|
||||||
|
for (var defineResult of [true, false]) {
|
||||||
|
log = "";
|
||||||
|
assertEq(Reflect.set(obj, "prop", 4, receiver), defineResult);
|
||||||
|
assertEq(log, "gd");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// For more Reflect.set tests, see target.js and propertyKeys.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Reflect.setPrototypeOf changes an object's [[Prototype]].
|
||||||
|
var obj = {};
|
||||||
|
assertEq(Object.getPrototypeOf(obj), Object.prototype);
|
||||||
|
var proto = {};
|
||||||
|
assertEq(Reflect.setPrototypeOf(obj, proto), true);
|
||||||
|
assertEq(Object.getPrototypeOf(obj), proto);
|
||||||
|
|
||||||
|
// It can change an object's [[Prototype]] to null.
|
||||||
|
obj = {};
|
||||||
|
assertEq(Reflect.setPrototypeOf(obj, null), true);
|
||||||
|
assertEq(Object.getPrototypeOf(obj), null);
|
||||||
|
|
||||||
|
// The proto argument is required too.
|
||||||
|
obj = {};
|
||||||
|
assertThrowsInstanceOf(() => Reflect.setPrototypeOf(obj), TypeError);
|
||||||
|
|
||||||
|
// The proto argument must be either null or an object.
|
||||||
|
for (proto of [undefined, false, 0, 1.6, "that", Symbol.iterator]) {
|
||||||
|
assertThrowsInstanceOf(() => Reflect.setPrototypeOf(obj, proto), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return false if the target is inextensible.
|
||||||
|
proto = {};
|
||||||
|
obj = Object.preventExtensions(Object.create(proto));
|
||||||
|
assertEq(Reflect.setPrototypeOf(obj, {}), false);
|
||||||
|
assertEq(Reflect.setPrototypeOf(obj, null), false);
|
||||||
|
assertEq(Reflect.setPrototypeOf(obj, proto), false); // even if not changing anything
|
||||||
|
|
||||||
|
// Return false rather than create a [[Prototype]] cycle.
|
||||||
|
obj = {};
|
||||||
|
assertEq(Reflect.setPrototypeOf(obj, obj), false);
|
||||||
|
|
||||||
|
// Don't create a [[Prototype]] cycle involving 2 objects.
|
||||||
|
obj = Object.create(proto);
|
||||||
|
assertEq(Reflect.setPrototypeOf(proto, obj), false);
|
||||||
|
|
||||||
|
// Don't create a longish [[Prototype]] cycle.
|
||||||
|
for (var i = 0; i < 256; i++)
|
||||||
|
obj = Object.create(obj);
|
||||||
|
assertEq(Reflect.setPrototypeOf(proto, obj), false);
|
||||||
|
|
||||||
|
// The spec claims we should allow creating cycles involving proxies. (The
|
||||||
|
// cycle check quietly exits on encountering the proxy.)
|
||||||
|
obj = {};
|
||||||
|
var proxy = new Proxy(Object.create(obj), {});
|
||||||
|
if (Reflect.setPrototypeOf(obj, proxy) !== false) {
|
||||||
|
throw new Error("Congratulations on implementing ES6 [[SetPrototype]]! " +
|
||||||
|
"Update this test for 1 karma point!");
|
||||||
|
// ...by deleting this if-block and uncommenting the three assertions below.
|
||||||
|
}
|
||||||
|
// assertEq(Reflect.setPrototypeOf(obj, proxy), true);
|
||||||
|
// assertEq(Reflect.getPrototypeOf(obj), proxy);
|
||||||
|
// assertEq(Reflect.getPrototypeOf(proxy), obj);
|
||||||
|
|
||||||
|
// If a proxy handler returns a false-y value, return false.
|
||||||
|
var hits = 0;
|
||||||
|
proto = {name: "proto"};
|
||||||
|
obj = {name: "obj"};
|
||||||
|
proxy = new Proxy(obj, {
|
||||||
|
setPrototypeOf(t, p) {
|
||||||
|
assertEq(t, obj);
|
||||||
|
assertEq(p, proto);
|
||||||
|
hits++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (Reflect.setPrototypeOf(proxy, proto) !== true) {
|
||||||
|
throw new Error("Congratulations on implementing the setPrototypeOf trap for proxies! " +
|
||||||
|
"Please update this test.");
|
||||||
|
// ...by deleting this if-block and uncommenting the two assertions below.
|
||||||
|
// As of this writing, the setPrototypeOf hook is never called; see bug 888969.
|
||||||
|
}
|
||||||
|
// assertEq(Reflect.setPrototypeOf(proxy, proto), false);
|
||||||
|
// assertEq(hits, 1);
|
||||||
|
|
||||||
|
// For more Reflect.setPrototypeOf tests, see target.js.
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,9 @@
|
||||||
|
// List of a few values that are not objects.
|
||||||
|
var SOME_PRIMITIVE_VALUES = [
|
||||||
|
undefined, null,
|
||||||
|
false,
|
||||||
|
-Infinity, -1.6e99, -1, -0, 0, Math.pow(2, -1074), 1, 4294967295,
|
||||||
|
Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER + 1, 1.6e99, Infinity, NaN,
|
||||||
|
"", "Phaedo",
|
||||||
|
Symbol(), Symbol("iterator"), Symbol.for("iterator"), Symbol.iterator
|
||||||
|
];
|
|
@ -1,20 +1,60 @@
|
||||||
/*
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
* Any copyright is dedicated to the Public Domain.
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
* http://creativecommons.org/licenses/publicdomain/
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Check surface features of the Reflect object.
|
||||||
assertEq(typeof Reflect, 'object');
|
assertEq(typeof Reflect, 'object');
|
||||||
assertEq(Object.getPrototypeOf(Reflect), Object.prototype);
|
assertEq(Object.getPrototypeOf(Reflect), Object.prototype);
|
||||||
assertEq(Reflect.toString(), '[object Object]');
|
assertEq(Reflect.toString(), '[object Object]');
|
||||||
|
assertThrowsInstanceOf(() => new Reflect, TypeError);
|
||||||
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(this, "Reflect");
|
var desc = Object.getOwnPropertyDescriptor(this, "Reflect");
|
||||||
assertEq(desc.enumerable, false);
|
assertEq(desc.enumerable, false);
|
||||||
assertEq(desc.configurable, true);
|
assertEq(desc.configurable, true);
|
||||||
assertEq(desc.writable, true);
|
assertEq(desc.writable, true);
|
||||||
|
|
||||||
// Assert that the SpiderMonkey "resolve hook" mechanism does not resurrect the
|
for (var name in Reflect)
|
||||||
|
throw new Error("Reflect should not have any enumerable properties");
|
||||||
|
|
||||||
|
// The name and length of all the standard Reflect methods.
|
||||||
|
var methods = {
|
||||||
|
apply: 3,
|
||||||
|
//construct: 2,
|
||||||
|
defineProperty: 3,
|
||||||
|
deleteProperty: 2,
|
||||||
|
//enumerate: 1,
|
||||||
|
get: 2,
|
||||||
|
getOwnPropertyDescriptor: 2,
|
||||||
|
getPrototypeOf: 1,
|
||||||
|
has: 2,
|
||||||
|
isExtensible: 1,
|
||||||
|
ownKeys: 1,
|
||||||
|
preventExtensions: 1,
|
||||||
|
set: 3,
|
||||||
|
setPrototypeOf: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check that all Reflect properties are listed above.
|
||||||
|
for (var name of Reflect.ownKeys(Reflect)) {
|
||||||
|
// If this assertion fails, congratulations on implementing a new Reflect feature!
|
||||||
|
// Add it to the list of methods above.
|
||||||
|
if (name !== "parse")
|
||||||
|
assertEq(name in methods, true, `unexpected property found: Reflect.${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the .length and property attributes of each Reflect method.
|
||||||
|
for (var name of Object.keys(methods)) {
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(Reflect, name);
|
||||||
|
assertEq(desc.enumerable, false);
|
||||||
|
assertEq(desc.configurable, true);
|
||||||
|
assertEq(desc.writable, true);
|
||||||
|
var f = desc.value;
|
||||||
|
assertEq(typeof f, "function");
|
||||||
|
assertEq(f.length, methods[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the SpiderMonkey "resolve hook" mechanism does not resurrect the
|
||||||
// Reflect property once it is deleted.
|
// Reflect property once it is deleted.
|
||||||
delete this.Reflect;
|
delete this.Reflect;
|
||||||
assertEq("Reflect" in this, false);
|
assertEq("Reflect" in this, false);
|
||||||
|
|
||||||
reportCompare(0, 0, 'ok');
|
reportCompare(0, 0);
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// Check correct handling of the `target` argument shared by every Reflect method.
|
||||||
|
|
||||||
|
// For each standard Reflect method, an array of arguments
|
||||||
|
// that would be OK after a suitable target argument.
|
||||||
|
var methodInfo = {
|
||||||
|
apply: [undefined, []],
|
||||||
|
//construct: [[]],
|
||||||
|
defineProperty: ["x", {}],
|
||||||
|
deleteProperty: ["x"],
|
||||||
|
//enumerate: [],
|
||||||
|
get: ["x", {}],
|
||||||
|
getOwnPropertyDescriptor: ["x"],
|
||||||
|
getPrototypeOf: [],
|
||||||
|
has: ["x"],
|
||||||
|
isExtensible: [],
|
||||||
|
ownKeys: [],
|
||||||
|
preventExtensions: [],
|
||||||
|
set: ["x", 0],
|
||||||
|
setPrototypeOf: [{}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check that all Reflect properties are listed above.
|
||||||
|
for (var name of Reflect.ownKeys(Reflect)) {
|
||||||
|
// If this assertion fails, congratulations on implementing a new Reflect feature!
|
||||||
|
// Add it to methodInfo above.
|
||||||
|
if (name !== "parse")
|
||||||
|
assertEq(name in methodInfo, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var name of Object.keys(methodInfo)) {
|
||||||
|
var args = methodInfo[name];
|
||||||
|
|
||||||
|
// The target argument is required.
|
||||||
|
assertThrowsInstanceOf(Reflect[name], TypeError);
|
||||||
|
|
||||||
|
// Throw if the target argument is not an object.
|
||||||
|
for (var value of SOME_PRIMITIVE_VALUES) {
|
||||||
|
assertThrowsInstanceOf(() => Reflect[name](value, ...args), TypeError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -14,6 +14,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "jsalloc.h"
|
#include "jsalloc.h"
|
||||||
|
#include "jscntxt.h"
|
||||||
#include "jscompartment.h"
|
#include "jscompartment.h"
|
||||||
|
|
||||||
#include "builtin/MapObject.h"
|
#include "builtin/MapObject.h"
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
|
#include "jscntxt.h"
|
||||||
#include "jscompartment.h"
|
#include "jscompartment.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "jshashutil.h"
|
#include "jshashutil.h"
|
||||||
|
@ -398,7 +399,8 @@ SavedFrame::checkThis(JSContext* cx, CallArgs& args, const char* fnName,
|
||||||
const Value& thisValue = args.thisv();
|
const Value& thisValue = args.thisv();
|
||||||
|
|
||||||
if (!thisValue.isObject()) {
|
if (!thisValue.isObject()) {
|
||||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, InformalValueTypeName(thisValue));
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
|
||||||
|
InformalValueTypeName(thisValue));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "builtin/Intl.h"
|
#include "builtin/Intl.h"
|
||||||
#include "builtin/Object.h"
|
#include "builtin/Object.h"
|
||||||
|
#include "builtin/Reflect.h"
|
||||||
#include "builtin/SelfHostingDefines.h"
|
#include "builtin/SelfHostingDefines.h"
|
||||||
#include "builtin/SIMD.h"
|
#include "builtin/SIMD.h"
|
||||||
#include "builtin/TypedObject.h"
|
#include "builtin/TypedObject.h"
|
||||||
|
@ -1270,11 +1271,13 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
JS_FN("std_Object_create", obj_create, 2,0),
|
JS_FN("std_Object_create", obj_create, 2,0),
|
||||||
JS_FN("std_Object_propertyIsEnumerable", obj_propertyIsEnumerable, 1,0),
|
JS_FN("std_Object_propertyIsEnumerable", obj_propertyIsEnumerable, 1,0),
|
||||||
JS_FN("std_Object_defineProperty", obj_defineProperty, 3,0),
|
JS_FN("std_Object_defineProperty", obj_defineProperty, 3,0),
|
||||||
JS_FN("std_Object_getPrototypeOf", obj_getPrototypeOf, 1,0),
|
|
||||||
JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
|
JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
|
||||||
JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0),
|
JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0),
|
||||||
JS_FN("std_Object_hasOwnProperty", obj_hasOwnProperty, 1,0),
|
JS_FN("std_Object_hasOwnProperty", obj_hasOwnProperty, 1,0),
|
||||||
|
|
||||||
|
JS_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0),
|
||||||
|
JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1,0),
|
||||||
|
|
||||||
JS_FN("std_Set_has", SetObject::has, 1,0),
|
JS_FN("std_Set_has", SetObject::has, 1,0),
|
||||||
JS_FN("std_Set_iterator", SetObject::values, 0,0),
|
JS_FN("std_Set_iterator", SetObject::values, 0,0),
|
||||||
|
|
||||||
|
|
|
@ -1066,6 +1066,7 @@ class InvokeArgs : public JS::CallArgs
|
||||||
explicit InvokeArgs(JSContext* cx, bool construct = false) : v_(cx) {}
|
explicit InvokeArgs(JSContext* cx, bool construct = false) : v_(cx) {}
|
||||||
|
|
||||||
bool init(unsigned argc, bool construct = false) {
|
bool init(unsigned argc, bool construct = false) {
|
||||||
|
MOZ_ASSERT(2 + argc + construct > argc); // no overflow
|
||||||
if (!v_.resize(2 + argc + construct))
|
if (!v_.resize(2 + argc + construct))
|
||||||
return false;
|
return false;
|
||||||
ImplicitCast<CallArgs>(*this) = CallArgsFromVp(argc, v_.begin());
|
ImplicitCast<CallArgs>(*this) = CallArgsFromVp(argc, v_.begin());
|
||||||
|
|
|
@ -73,18 +73,14 @@ function test_tamperproof(realObj, accessObj, {method, constant, attribute}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflect.set doesn't work either.
|
// Reflect.set doesn't work either.
|
||||||
if (this.Reflect && this.Reflect.set)
|
if (method) {
|
||||||
throw new Error("Congratulations on implementing Reflect.set! Here are some tests to uncomment.");
|
do_check_false(Reflect.set({}, method, "bad", accessObj));
|
||||||
/*
|
do_check_eq(realObj[method], originalMethod);
|
||||||
if (method) {
|
}
|
||||||
do_check_false(Reflect.set({}, method, "bad", accessObj));
|
if (attribute) {
|
||||||
do_check_eq(realObj[method], originalMethod);
|
do_check_false(Reflect.set({}, attribute, "bad", accessObj));
|
||||||
}
|
do_check_eq(originalAttributeDesc.get, Object.getOwnPropertyDescriptor(realObj, attribute).get);
|
||||||
if (attribute) {
|
}
|
||||||
do_check_false(Reflect.set({}, attribute, "bad", accessObj));
|
|
||||||
do_check_eq(originalAttributeDesc.get, Object.getOwnPropertyDescriptor(realObj, attribute).get);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Object.defineProperty can't do anything either.
|
// Object.defineProperty can't do anything either.
|
||||||
let names = ["expando"];
|
let names = ["expando"];
|
||||||
|
|
Загрузка…
Ссылка в новой задаче