shithub: libmujs

Download patch

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);