ref: 4e6c74b5512dbc53300fbb4c119ea75bfeab0916
parent: d800b59f0f0fabc15f3eb572ab85baefc0a7edef
author: Tor Andersson <tor.andersson@artifex.com>
date: Mon Jan 11 12:02:43 EST 2016
Add userdata has/put callbacks for custom properties. This goes beyond defining accessors, and allows capturing all property accesses. With these callbacks, things like typed arrays can be implemented.
--- a/jsrun.c
+++ b/jsrun.c
@@ -499,6 +499,11 @@
}
}
+ if (obj->type == JS_CUSERDATA) {
+ if (obj->u.user.has && obj->u.user.has(J, obj->u.user.data, name))
+ return 1;
+ }
+
ref = jsV_getproperty(J, obj, name);
if (ref) {
if (ref->getter) {
@@ -520,8 +525,9 @@
js_pushundefined(J);
}
-static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, js_Value *value)
+static void jsR_setproperty(js_State *J, js_Object *obj, const char *name)
{
+ js_Value *value = stackidx(J, -1);
js_Property *ref;
unsigned int k;
int own;
@@ -559,6 +565,11 @@
}
}
+ if (obj->type == JS_CUSERDATA) {
+ if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name))
+ return;
+ }
+
/* First try to find a setter in prototype chain */
ref = jsV_getpropertyx(J, obj, name, &own);
if (ref && ref->setter) {
@@ -614,6 +625,11 @@
if (!strcmp(name, "lastIndex")) goto readonly;
}
+ if (obj->type == JS_CUSERDATA) {
+ if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name))
+ return;
+ }
+
ref = jsV_setproperty(J, obj, name);
if (ref) {
if (value) {
@@ -721,7 +737,7 @@
void js_setregistry(js_State *J, const char *name)
{
- jsR_setproperty(J, J->R, name, stackidx(J, -1));
+ jsR_setproperty(J, J->R, name);
js_pop(J, 1);
}
@@ -737,7 +753,7 @@
void js_setglobal(js_State *J, const char *name)
{
- jsR_setproperty(J, J->G, name, stackidx(J, -1));
+ jsR_setproperty(J, J->G, name);
js_pop(J, 1);
}
@@ -754,7 +770,7 @@
void js_setproperty(js_State *J, int idx, const char *name)
{
- jsR_setproperty(J, js_toobject(J, idx), name, stackidx(J, -1));
+ jsR_setproperty(J, js_toobject(J, idx), name);
js_pop(J, 1);
}
@@ -861,7 +877,7 @@
} while (E);
if (J->strict)
js_referenceerror(J, "assignment to undeclared variable '%s'", name);
- jsR_setproperty(J, J->G, name, stackidx(J, -1));
+ jsR_setproperty(J, J->G, name);
}
static int js_delvar(js_State *J, const char *name)
@@ -1320,7 +1336,7 @@
case OP_INITPROP:
obj = js_toobject(J, -3);
str = js_tostring(J, -2);
- jsR_setproperty(J, obj, str, stackidx(J, -1));
+ jsR_setproperty(J, obj, str);
js_pop(J, 2);
break;
@@ -1355,7 +1371,7 @@
case OP_SETPROP:
str = js_tostring(J, -2);
obj = js_toobject(J, -3);
- jsR_setproperty(J, obj, str, stackidx(J, -1));
+ jsR_setproperty(J, obj, str);
js_rot3pop2(J);
break;
@@ -1362,7 +1378,7 @@
case OP_SETPROP_S:
str = ST[*pc++];
obj = js_toobject(J, -2);
- jsR_setproperty(J, obj, str, stackidx(J, -1));
+ jsR_setproperty(J, obj, str);
js_rot2pop1(J);
break;
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -432,7 +432,7 @@
}
}
-void js_newuserdata(js_State *J, const char *tag, void *data, js_Finalize finalize)
+void js_newuserdatax(js_State *J, const char *tag, void *data, js_HasProperty has, js_Put put, js_Finalize finalize)
{
js_Object *prototype = NULL;
js_Object *obj;
@@ -444,8 +444,15 @@
obj = jsV_newobject(J, JS_CUSERDATA, prototype);
obj->u.user.tag = tag;
obj->u.user.data = data;
+ obj->u.user.has = has;
+ obj->u.user.put = put;
obj->u.user.finalize = finalize;
js_pushobject(J, obj);
+}
+
+void js_newuserdata(js_State *J, const char *tag, void *data, js_Finalize finalize)
+{
+ js_newuserdatax(J, tag, data, NULL, NULL, finalize);
}
/* Non-trivial operations on values. These are implemented using the stack. */
--- a/jsvalue.h
+++ b/jsvalue.h
@@ -112,6 +112,8 @@
struct {
const char *tag;
void *data;
+ js_HasProperty has;
+ js_Put put;
js_Finalize finalize;
} user;
} u;
--- a/mujs.h
+++ b/mujs.h
@@ -30,6 +30,8 @@
typedef void (*js_Panic)(js_State *J);
typedef void (*js_CFunction)(js_State *J);
typedef void (*js_Finalize)(js_State *J, void *p);
+typedef int (*js_HasProperty)(js_State *J, void *p, const char *name);
+typedef int (*js_Put)(js_State *J, void *p, const char *name);
/* Basic functions */
js_State *js_newstate(js_Alloc alloc, void *actx, int flags);
@@ -132,6 +134,7 @@
void js_newcfunction(js_State *J, js_CFunction fun, const char *name, unsigned int length);
void js_newcconstructor(js_State *J, js_CFunction fun, js_CFunction con, const char *name, unsigned int length);
void js_newuserdata(js_State *J, const char *tag, void *data, js_Finalize finalize);
+void js_newuserdatax(js_State *J, const char *tag, void *data, js_HasProperty has, js_Put put, js_Finalize finalize);
void js_newregexp(js_State *J, const char *pattern, int flags);
void js_pushiterator(js_State *J, int idx, int own);