230 lines
4.7 KiB
C
230 lines
4.7 KiB
C
|
#include "jsi.h"
|
||
|
#include "jsparse.h"
|
||
|
#include "jscompile.h"
|
||
|
#include "jsvalue.h"
|
||
|
#include "jsbuiltin.h"
|
||
|
|
||
|
static void jsB_Function(js_State *J)
|
||
|
{
|
||
|
int i, top = js_gettop(J);
|
||
|
js_Buffer *sb = NULL;
|
||
|
const char *body;
|
||
|
js_Ast *parse;
|
||
|
js_Function *fun;
|
||
|
|
||
|
if (js_try(J)) {
|
||
|
js_free(J, sb);
|
||
|
jsP_freeparse(J);
|
||
|
js_throw(J);
|
||
|
}
|
||
|
|
||
|
/* p1, p2, ..., pn */
|
||
|
if (top > 2) {
|
||
|
for (i = 1; i < top - 1; ++i) {
|
||
|
if (i > 1)
|
||
|
js_putc(J, &sb, ',');
|
||
|
js_puts(J, &sb, js_tostring(J, i));
|
||
|
}
|
||
|
js_putc(J, &sb, ')');
|
||
|
js_putc(J, &sb, 0);
|
||
|
}
|
||
|
|
||
|
/* body */
|
||
|
body = js_isdefined(J, top - 1) ? js_tostring(J, top - 1) : "";
|
||
|
|
||
|
parse = jsP_parsefunction(J, "[string]", sb ? sb->s : NULL, body);
|
||
|
fun = jsC_compilefunction(J, parse);
|
||
|
|
||
|
js_endtry(J);
|
||
|
js_free(J, sb);
|
||
|
jsP_freeparse(J);
|
||
|
|
||
|
js_newfunction(J, fun, J->GE);
|
||
|
}
|
||
|
|
||
|
static void jsB_Function_prototype(js_State *J)
|
||
|
{
|
||
|
js_pushundefined(J);
|
||
|
}
|
||
|
|
||
|
static void Fp_toString(js_State *J)
|
||
|
{
|
||
|
js_Object *self = js_toobject(J, 0);
|
||
|
js_Buffer *sb = NULL;
|
||
|
int i;
|
||
|
|
||
|
if (!js_iscallable(J, 0))
|
||
|
js_typeerror(J, "not a function");
|
||
|
|
||
|
if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT) {
|
||
|
js_Function *F = self->u.f.function;
|
||
|
|
||
|
if (js_try(J)) {
|
||
|
js_free(J, sb);
|
||
|
js_throw(J);
|
||
|
}
|
||
|
|
||
|
js_puts(J, &sb, "function ");
|
||
|
js_puts(J, &sb, F->name);
|
||
|
js_putc(J, &sb, '(');
|
||
|
for (i = 0; i < F->numparams; ++i) {
|
||
|
if (i > 0) js_putc(J, &sb, ',');
|
||
|
js_puts(J, &sb, F->vartab[i]);
|
||
|
}
|
||
|
js_puts(J, &sb, ") { [byte code] }");
|
||
|
js_putc(J, &sb, 0);
|
||
|
|
||
|
js_pushstring(J, sb->s);
|
||
|
js_endtry(J);
|
||
|
js_free(J, sb);
|
||
|
} else if (self->type == JS_CCFUNCTION) {
|
||
|
if (js_try(J)) {
|
||
|
js_free(J, sb);
|
||
|
js_throw(J);
|
||
|
}
|
||
|
|
||
|
js_puts(J, &sb, "function ");
|
||
|
js_puts(J, &sb, self->u.c.name);
|
||
|
js_puts(J, &sb, "() { [native code] }");
|
||
|
js_putc(J, &sb, 0);
|
||
|
|
||
|
js_pushstring(J, sb->s);
|
||
|
js_endtry(J);
|
||
|
js_free(J, sb);
|
||
|
} else {
|
||
|
js_pushliteral(J, "function () { }");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Fp_apply(js_State *J)
|
||
|
{
|
||
|
int i, n;
|
||
|
|
||
|
if (!js_iscallable(J, 0))
|
||
|
js_typeerror(J, "not a function");
|
||
|
|
||
|
js_copy(J, 0);
|
||
|
js_copy(J, 1);
|
||
|
|
||
|
if (js_isnull(J, 2) || js_isundefined(J, 2)) {
|
||
|
n = 0;
|
||
|
} else {
|
||
|
n = js_getlength(J, 2);
|
||
|
for (i = 0; i < n; ++i)
|
||
|
js_getindex(J, 2, i);
|
||
|
}
|
||
|
|
||
|
js_call(J, n);
|
||
|
}
|
||
|
|
||
|
static void Fp_call(js_State *J)
|
||
|
{
|
||
|
int i, top = js_gettop(J);
|
||
|
|
||
|
if (!js_iscallable(J, 0))
|
||
|
js_typeerror(J, "not a function");
|
||
|
|
||
|
for (i = 0; i < top; ++i)
|
||
|
js_copy(J, i);
|
||
|
|
||
|
js_call(J, top - 2);
|
||
|
}
|
||
|
|
||
|
static void callbound(js_State *J)
|
||
|
{
|
||
|
int top = js_gettop(J);
|
||
|
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 < top; ++i)
|
||
|
js_copy(J, i);
|
||
|
|
||
|
js_call(J, n + top - 1);
|
||
|
}
|
||
|
|
||
|
static void constructbound(js_State *J)
|
||
|
{
|
||
|
int top = js_gettop(J);
|
||
|
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 < top; ++i)
|
||
|
js_copy(J, i);
|
||
|
|
||
|
js_construct(J, n + top - 1);
|
||
|
}
|
||
|
|
||
|
static void Fp_bind(js_State *J)
|
||
|
{
|
||
|
int i, top = js_gettop(J);
|
||
|
int n;
|
||
|
|
||
|
if (!js_iscallable(J, 0))
|
||
|
js_typeerror(J, "not a function");
|
||
|
|
||
|
n = js_getlength(J, 0);
|
||
|
if (n > top - 2)
|
||
|
n -= top - 2;
|
||
|
else
|
||
|
n = 0;
|
||
|
|
||
|
/* Reuse target function's prototype for HasInstance check. */
|
||
|
js_getproperty(J, 0, "prototype");
|
||
|
js_newcconstructor(J, callbound, constructbound, "[bind]", n);
|
||
|
|
||
|
/* 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 < top; ++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.name = "Function.prototype";
|
||
|
J->Function_prototype->u.c.function = jsB_Function_prototype;
|
||
|
J->Function_prototype->u.c.constructor = NULL;
|
||
|
J->Function_prototype->u.c.length = 0;
|
||
|
|
||
|
js_pushobject(J, J->Function_prototype);
|
||
|
{
|
||
|
jsB_propf(J, "Function.prototype.toString", Fp_toString, 2);
|
||
|
jsB_propf(J, "Function.prototype.apply", Fp_apply, 2);
|
||
|
jsB_propf(J, "Function.prototype.call", Fp_call, 1);
|
||
|
jsB_propf(J, "Function.prototype.bind", Fp_bind, 1);
|
||
|
}
|
||
|
js_newcconstructor(J, jsB_Function, jsB_Function, "Function", 1);
|
||
|
js_defglobal(J, "Function", JS_DONTENUM);
|
||
|
}
|