shithub: libmujs

Download patch

ref: c87898e63b24d89de26f68e70df00a73cc64554d
parent: 35cc749225516c14183ffc5e8bbde35ee6a560b0
author: Tor Andersson <tor@ccxvii.net>
date: Thu Mar 6 11:48:42 EST 2014

Implement Function.prototype.bind().

--- a/jsfunction.c
+++ b/jsfunction.c
@@ -120,6 +120,85 @@
 	js_call(J, argc - 1);
 }
 
+static void callbound(js_State *J, unsigned int argc)
+{
+	unsigned int i, fun, args, n;
+
+	fun = js_gettop(J);
+	js_currentfunction(J);
+	js_getproperty(J, fun, "__TargetFunction__");
+	js_getproperty(J, fun, "__BoundThis__");
+
+	args = js_gettop(J);
+	js_getproperty(J, fun, "__BoundArguments__");
+	n = js_getlength(J, args);
+	for (i = 0; i < n; ++i)
+		js_getindex(J, args, i);
+	js_remove(J, args);
+
+	for (i = 1; i <= argc; ++i)
+		js_copy(J, i);
+
+	js_call(J, n + argc);
+}
+
+static void constructbound(js_State *J, unsigned int argc)
+{
+	unsigned int i, fun, args, n;
+
+	fun = js_gettop(J);
+	js_currentfunction(J);
+	js_getproperty(J, fun, "__TargetFunction__");
+
+	args = js_gettop(J);
+	js_getproperty(J, fun, "__BoundArguments__");
+	n = js_getlength(J, args);
+	for (i = 0; i < n; ++i)
+		js_getindex(J, args, i);
+	js_remove(J, args);
+
+	for (i = 1; i <= argc; ++i)
+		js_copy(J, i);
+
+	js_construct(J, n + argc);
+}
+
+static void Fp_bind(js_State *J, unsigned int argc)
+{
+	unsigned int i, n;
+
+	if (!js_iscallable(J, 0))
+		js_typeerror(J, "not a function");
+
+	n = js_getlength(J, 0);
+	if (argc - 1 < n)
+		n -= argc - 1;
+	else
+		n = 0;
+
+	js_newcconstructor(J, callbound, constructbound, n);
+
+	/* Reuse target function's prototype for HasInstance check. */
+	js_getproperty(J, 0, "prototype");
+	js_defproperty(J, -2, "prototype", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
+
+	/* target function */
+	js_copy(J, 0);
+	js_defproperty(J, -2, "__TargetFunction__", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
+
+	/* bound this */
+	js_copy(J, 1);
+	js_defproperty(J, -2, "__BoundThis__", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
+
+	/* bound arguments */
+	js_newarray(J);
+	for (i = 2; i <= argc; ++i) {
+		js_copy(J, i);
+		js_setindex(J, -2, i-2);
+	}
+	js_defproperty(J, -2, "__BoundArguments__", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
+}
+
 void jsB_initfunction(js_State *J)
 {
 	J->Function_prototype->u.c.function = jsB_Function_prototype;
@@ -130,6 +209,7 @@
 		jsB_propf(J, "toString", Fp_toString, 2);
 		jsB_propf(J, "apply", Fp_apply, 2);
 		jsB_propf(J, "call", Fp_call, 1);
+		jsB_propf(J, "bind", Fp_bind, 1);
 	}
 	js_newcconstructor(J, jsB_Function, jsB_Function, 1);
 	js_defglobal(J, "Function", JS_DONTENUM);
--- a/jsrun.c
+++ b/jsrun.c
@@ -307,6 +307,16 @@
 	}
 }
 
+void js_remove(js_State *J, int idx)
+{
+	idx = idx < 0 ? TOP + idx : BOT + idx;
+	if (idx < BOT || idx >= TOP)
+		js_error(J, "stack error!");
+	for (;idx < TOP - 1; ++idx)
+		STACK[idx] = STACK[idx+1];
+	--TOP;
+}
+
 void js_copy(js_State *J, int idx)
 {
 	CHECKSTACK(1);