Skip to content

Commit

Permalink
Merge pull request #397 from Distributive-Network/philippe/396-fix
Browse files Browse the repository at this point in the history
Objects now use prototype defaults
  • Loading branch information
philippedistributive authored Jul 30, 2024
2 parents 8f1ac3c + 3b02465 commit 7a2ffd0
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 66 deletions.
6 changes: 0 additions & 6 deletions include/PyIterableProxyHandler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ public:
JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc
) const override;

/**
* @brief An array of method definitions for Iterable prototype methods
*
*/
static JSMethodDef iterable_methods[];
};

#endif
6 changes: 0 additions & 6 deletions include/PyObjectProxyHandler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,6 @@ public:
JS::ObjectOpResult &result) const override;

bool getBuiltinClass(JSContext *cx, JS::HandleObject proxy, js::ESClass *cls) const override;

/**
* @brief An array of method definitions for Object prototype methods
*
*/
static JSMethodDef object_methods[];
};

#endif
4 changes: 1 addition & 3 deletions src/PyIterableProxyHandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ static bool iterable_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) {
return toPrimitive(cx, argc, vp);
}

JSMethodDef PyIterableProxyHandler::iterable_methods[] = {
static JSMethodDef iterable_methods[] = {
{"next", iterable_next, 0},
{"valueOf", iterable_valueOf, 0},
{NULL, NULL, 0}
Expand Down Expand Up @@ -238,8 +238,6 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
// "constructor" property
bool isConstructorProperty;
if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) {
JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy));

JS::RootedObject rootedObjectPrototype(cx);
if (!JS_GetClassPrototype(cx, JSProto_Object, &rootedObjectPrototype)) {
return false;
Expand Down
2 changes: 0 additions & 2 deletions src/PyListProxyHandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2040,8 +2040,6 @@ bool PyListProxyHandler::getOwnPropertyDescriptor(
// "constructor" property
bool isConstructorProperty;
if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) {
JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy));

JS::RootedObject rootedArrayPrototype(cx);
if (!JS_GetClassPrototype(cx, JSProto_Array, &rootedArrayPrototype)) {
return false;
Expand Down
69 changes: 21 additions & 48 deletions src/PyObjectProxyHandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,6 @@

const char PyObjectProxyHandler::family = 0;

bool PyObjectProxyHandler::object_toString(JSContext *cx, unsigned argc, JS::Value *vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);

args.rval().setString(JS_NewStringCopyZ(cx, "[object Object]"));
return true;
}

bool PyObjectProxyHandler::object_toLocaleString(JSContext *cx, unsigned argc, JS::Value *vp) {
return object_toString(cx, argc, vp);
}

bool PyObjectProxyHandler::object_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);

JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv()));
if (!proxy) {
return false;
}
PyObject *self = JS::GetMaybePtrFromReservedSlot<PyObject>(proxy, PyObjectSlot);

// return ref to self
args.rval().set(jsTypeFactory(cx, self));
return true;
}

JSMethodDef PyObjectProxyHandler::object_methods[] = {
{"toString", PyObjectProxyHandler::object_toString, 0},
{"toLocaleString", PyObjectProxyHandler::object_toLocaleString, 0},
{"valueOf", PyObjectProxyHandler::object_valueOf, 0},
{NULL, NULL, 0}
};

bool PyObjectProxyHandler::handleOwnPropertyKeys(JSContext *cx, PyObject *keys, size_t length, JS::MutableHandleIdVector props) {
if (!props.reserve(length)) {
return false; // out of memory
Expand All @@ -76,24 +44,29 @@ bool PyObjectProxyHandler::handleGetOwnPropertyDescriptor(JSContext *cx, JS::Han
JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc, PyObject *item) {
// see if we're calling a function
if (id.isString()) {
for (size_t index = 0;; index++) {
bool isThatFunction;
const char *methodName = object_methods[index].name;
if (methodName == NULL) {
break;
JS::RootedString idString(cx, id.toString());
const char *methodName = JS_EncodeStringToUTF8(cx, idString).get();
if (!strcmp(methodName, "toString") || !strcmp(methodName, "toLocaleString") || !strcmp(methodName, "valueOf")) {
JS::RootedObject objectPrototype(cx);
if (!JS_GetClassPrototype(cx, JSProto_Object, &objectPrototype)) {
return false;
}
else if (JS_StringEqualsAscii(cx, id.toString(), methodName, &isThatFunction) && isThatFunction) {
JSFunction *newFunction = JS_NewFunction(cx, object_methods[index].call, object_methods[index].nargs, 0, NULL);
if (!newFunction) return false;
JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction));
desc.set(mozilla::Some(
JS::PropertyDescriptor::Data(
JS::ObjectValue(*funObj),
{JS::PropertyAttribute::Enumerable}
)
));
return true;

JS::RootedValue Object_Prototype_Method(cx);
if (!JS_GetProperty(cx, objectPrototype, methodName, &Object_Prototype_Method)) {
return false;
}

JS::RootedObject rootedObjectPrototypeConstructor(cx, Object_Prototype_Method.toObjectOrNull());

desc.set(mozilla::Some(
JS::PropertyDescriptor::Data(
JS::ObjectValue(*rootedObjectPrototypeConstructor),
{JS::PropertyAttribute::Enumerable}
)
));

return true;
}
}

Expand Down
17 changes: 16 additions & 1 deletion tests/python/test_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,19 @@ def test_toPrimitive_stdin():

def test_constructor_stdin():
constructor = pm.eval("(obj) => { return obj.constructor; }")(sys.stdin)
assert repr(constructor).__contains__("<pythonmonkey.JSFunctionProxy object at")
assert repr(constructor).__contains__("<pythonmonkey.JSFunctionProxy object at")


def test_toString_is_prototype_toString():
is_to_string_correct = pm.eval("x => x.toString === Object.prototype.toString")
assert is_to_string_correct({})


def test_toString_is_prototype_toLocaleString():
is_to_locale_string_correct = pm.eval("x => x.toLocaleString === Object.prototype.toLocaleString")
assert is_to_locale_string_correct({})


def test_valueof_is_prototype_valueof():
is_valueof_correct = pm.eval("x => x.valueOf === Object.prototype.valueOf")
assert is_valueof_correct({})

0 comments on commit 7a2ffd0

Please sign in to comment.