mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-25 19:23:34 +08:00
Add constructors called with 'new' keyword.
Support built-in constructors that create their own objects. They get called without a this object, which they should create and push on the stack.
This commit is contained in:
+16
-2
@@ -33,7 +33,21 @@ static int jsB_eval(js_State *J, int argc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int jsB_Object(js_State *J, int n) { return 0; }
|
||||
static int jsB_Object(js_State *J, int n) {
|
||||
if (n == 0 || js_isundefined(J, 1) || js_isnull(J, 1))
|
||||
js_newobject(J);
|
||||
else
|
||||
js_pushobject(J, js_toobject(J, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int jsB_new_Object(js_State *J, int n) {
|
||||
if (n == 0 || js_isundefined(J, 0) || js_isnull(J, 0))
|
||||
js_newobject(J);
|
||||
else
|
||||
js_pushobject(J, js_toobject(J, 0));
|
||||
return 1;
|
||||
}
|
||||
static int jsB_Array(js_State *J, int n) { return 0; }
|
||||
static int jsB_Function(js_State *J, int n) { return 0; }
|
||||
static int jsB_Boolean(js_State *J, int n) { return 0; }
|
||||
@@ -43,7 +57,7 @@ static int jsB_String(js_State *J, int n) { return 0; }
|
||||
static void jsB_initobject(js_State *J)
|
||||
{
|
||||
J->Object_prototype = jsR_newobject(J, JS_COBJECT, NULL);
|
||||
js_pushcfunction(J, jsB_Object);
|
||||
js_pushcconstructor(J, jsB_Object, jsB_new_Object);
|
||||
js_pushobject(J, J->Object_prototype);
|
||||
js_setproperty(J, -2, "prototype");
|
||||
js_setglobal(J, "Object");
|
||||
|
||||
@@ -21,6 +21,15 @@ js_Object *jsR_newcfunction(js_State *J, js_CFunction cfunction)
|
||||
{
|
||||
js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, NULL);
|
||||
obj->cfunction = cfunction;
|
||||
obj->cconstructor = NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor)
|
||||
{
|
||||
js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, NULL);
|
||||
obj->cfunction = cfunction;
|
||||
obj->cconstructor = cconstructor;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ struct js_Object
|
||||
js_Environment *scope;
|
||||
js_Function *function;
|
||||
js_CFunction cfunction;
|
||||
js_CFunction cconstructor;
|
||||
};
|
||||
|
||||
struct js_Property
|
||||
@@ -96,6 +97,7 @@ js_Property *jsR_nextproperty(js_State *J, js_Object *obj, const char *name);
|
||||
js_Object *jsR_newfunction(js_State *J, js_Function *function, js_Environment *scope);
|
||||
js_Object *jsR_newscript(js_State *J, js_Function *function);
|
||||
js_Object *jsR_newcfunction(js_State *J, js_CFunction cfunction);
|
||||
js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor);
|
||||
js_Object *jsR_newboolean(js_State *J, int v);
|
||||
js_Object *jsR_newnumber(js_State *J, double v);
|
||||
js_Object *jsR_newstring(js_State *J, const char *v);
|
||||
|
||||
@@ -121,9 +121,23 @@ void js_newfunction(js_State *J, js_Function *F, js_Environment *scope)
|
||||
js_setproperty(J, -2, "prototype");
|
||||
}
|
||||
|
||||
void js_pushcfunction(js_State *J, js_CFunction v)
|
||||
void js_pushcfunction(js_State *J, js_CFunction fun)
|
||||
{
|
||||
js_pushobject(J, jsR_newcfunction(J, v));
|
||||
js_pushobject(J, jsR_newcfunction(J, fun));
|
||||
// TODO: length property?
|
||||
js_newobject(J);
|
||||
js_copy(J, -2);
|
||||
js_setproperty(J, -2, "constructor");
|
||||
js_setproperty(J, -2, "prototype");
|
||||
}
|
||||
|
||||
void js_pushcconstructor(js_State *J, js_CFunction fun, js_CFunction con)
|
||||
{
|
||||
js_pushobject(J, jsR_newcconstructor(J, fun, con));
|
||||
js_newobject(J);
|
||||
js_copy(J, -2);
|
||||
js_setproperty(J, -2, "constructor");
|
||||
js_setproperty(J, -2, "prototype");
|
||||
}
|
||||
|
||||
/* Read values from stack */
|
||||
@@ -137,15 +151,13 @@ static const js_Value *stackidx(js_State *J, int idx)
|
||||
return stack + idx;
|
||||
}
|
||||
|
||||
int js_isundefined(js_State *J, int idx)
|
||||
{
|
||||
return stackidx(J, idx)->type == JS_TUNDEFINED;
|
||||
}
|
||||
|
||||
int js_isstring(js_State *J, int idx)
|
||||
{
|
||||
return stackidx(J, idx)->type == JS_TSTRING;
|
||||
}
|
||||
int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TUNDEFINED; }
|
||||
int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNULL; }
|
||||
int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TBOOLEAN; }
|
||||
int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNUMBER; }
|
||||
int js_isstring(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TSTRING; }
|
||||
int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; }
|
||||
int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; }
|
||||
|
||||
js_Value js_tovalue(js_State *J, int idx)
|
||||
{
|
||||
@@ -237,6 +249,15 @@ void js_dup1rot4(js_State *J)
|
||||
++top;
|
||||
}
|
||||
|
||||
void js_rot(js_State *J, int n)
|
||||
{
|
||||
int i;
|
||||
js_Value tmp = stack[top-1];
|
||||
for (i = 1; i <= n; i++)
|
||||
stack[top-i] = stack[top-i-1];
|
||||
stack[top-i] = tmp;
|
||||
}
|
||||
|
||||
/* Global and object property accessors */
|
||||
|
||||
void js_getglobal(js_State *J, const char *name)
|
||||
@@ -396,6 +417,37 @@ void js_call(js_State *J, int n)
|
||||
bot = savebot;
|
||||
}
|
||||
|
||||
void js_construct(js_State *J, int n)
|
||||
{
|
||||
js_Object *obj = js_toobject(J, -n - 1);
|
||||
js_Object *prototype;
|
||||
|
||||
/* built-in constructors create their own objects */
|
||||
if (obj->type == JS_CCFUNCTION && obj->cconstructor) {
|
||||
int savebot = bot;
|
||||
bot = top - n;
|
||||
jsR_callcfunction(J, n, obj->cconstructor);
|
||||
bot = savebot;
|
||||
return;
|
||||
}
|
||||
|
||||
/* extract the function object's prototype property */
|
||||
js_getproperty(J, -n - 1, "prototype");
|
||||
if (js_isobject(J, -1))
|
||||
prototype = js_toobject(J, -1);
|
||||
else
|
||||
prototype = J->Object_prototype;
|
||||
js_pop(J, 1);
|
||||
|
||||
/* create a new object with above prototype, and shift it into the 'this' slot */
|
||||
js_pushobject(J, jsR_newobject(J, JS_COBJECT, prototype));
|
||||
if (n > 0)
|
||||
js_rot(J, n + 1);
|
||||
|
||||
/* call the function */
|
||||
js_call(J, n);
|
||||
}
|
||||
|
||||
/* Main interpreter loop */
|
||||
|
||||
void jsR_dumpstack(js_State *J)
|
||||
@@ -559,6 +611,10 @@ static void jsR_run(js_State *J, js_Function *F)
|
||||
js_call(J, *pc++);
|
||||
break;
|
||||
|
||||
case OP_NEW:
|
||||
js_construct(J, *pc++);
|
||||
break;
|
||||
|
||||
/* Unary expressions */
|
||||
|
||||
case OP_POS:
|
||||
|
||||
@@ -17,6 +17,7 @@ void js_pushobject(js_State *J, js_Object *v);
|
||||
/* public */
|
||||
|
||||
void js_call(js_State *J, int n);
|
||||
void js_construct(js_State *J, int n);
|
||||
|
||||
void js_getglobal(js_State *J, const char *name);
|
||||
void js_setglobal(js_State *J, const char *name);
|
||||
@@ -33,10 +34,16 @@ void js_pushnumber(js_State *J, double v);
|
||||
void js_pushstring(js_State *J, const char *v);
|
||||
void js_newobject(js_State *J);
|
||||
void js_newarray(js_State *J);
|
||||
void js_pushcfunction(js_State *J, js_CFunction v);
|
||||
void js_pushcfunction(js_State *J, js_CFunction fun);
|
||||
void js_pushcconstructor(js_State *J, js_CFunction fun, js_CFunction con);
|
||||
|
||||
int js_isundefined(js_State *J, int idx);
|
||||
int js_isnull(js_State *J, int idx);
|
||||
int js_isboolean(js_State *J, int idx);
|
||||
int js_isnumber(js_State *J, int idx);
|
||||
int js_isstring(js_State *J, int idx);
|
||||
int js_isprimitive(js_State *J, int idx);
|
||||
int js_isobject(js_State *J, int idx);
|
||||
|
||||
int js_toboolean(js_State *J, int idx);
|
||||
double js_tonumber(js_State *J, int idx);
|
||||
|
||||
Reference in New Issue
Block a user