mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-27 13:23:38 +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;
|
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_Array(js_State *J, int n) { return 0; }
|
||||||
static int jsB_Function(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; }
|
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)
|
static void jsB_initobject(js_State *J)
|
||||||
{
|
{
|
||||||
J->Object_prototype = jsR_newobject(J, JS_COBJECT, NULL);
|
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_pushobject(J, J->Object_prototype);
|
||||||
js_setproperty(J, -2, "prototype");
|
js_setproperty(J, -2, "prototype");
|
||||||
js_setglobal(J, "Object");
|
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);
|
js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, NULL);
|
||||||
obj->cfunction = cfunction;
|
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;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ struct js_Object
|
|||||||
js_Environment *scope;
|
js_Environment *scope;
|
||||||
js_Function *function;
|
js_Function *function;
|
||||||
js_CFunction cfunction;
|
js_CFunction cfunction;
|
||||||
|
js_CFunction cconstructor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct js_Property
|
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_newfunction(js_State *J, js_Function *function, js_Environment *scope);
|
||||||
js_Object *jsR_newscript(js_State *J, js_Function *function);
|
js_Object *jsR_newscript(js_State *J, js_Function *function);
|
||||||
js_Object *jsR_newcfunction(js_State *J, js_CFunction cfunction);
|
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_newboolean(js_State *J, int v);
|
||||||
js_Object *jsR_newnumber(js_State *J, double v);
|
js_Object *jsR_newnumber(js_State *J, double v);
|
||||||
js_Object *jsR_newstring(js_State *J, const char *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");
|
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 */
|
/* Read values from stack */
|
||||||
@@ -137,15 +151,13 @@ static const js_Value *stackidx(js_State *J, int idx)
|
|||||||
return stack + idx;
|
return stack + idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int js_isundefined(js_State *J, int idx)
|
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; }
|
||||||
return stackidx(J, idx)->type == JS_TUNDEFINED;
|
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_isstring(js_State *J, int idx)
|
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; }
|
||||||
return stackidx(J, idx)->type == JS_TSTRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
js_Value js_tovalue(js_State *J, int idx)
|
js_Value js_tovalue(js_State *J, int idx)
|
||||||
{
|
{
|
||||||
@@ -237,6 +249,15 @@ void js_dup1rot4(js_State *J)
|
|||||||
++top;
|
++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 */
|
/* Global and object property accessors */
|
||||||
|
|
||||||
void js_getglobal(js_State *J, const char *name)
|
void js_getglobal(js_State *J, const char *name)
|
||||||
@@ -396,6 +417,37 @@ void js_call(js_State *J, int n)
|
|||||||
bot = savebot;
|
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 */
|
/* Main interpreter loop */
|
||||||
|
|
||||||
void jsR_dumpstack(js_State *J)
|
void jsR_dumpstack(js_State *J)
|
||||||
@@ -559,6 +611,10 @@ static void jsR_run(js_State *J, js_Function *F)
|
|||||||
js_call(J, *pc++);
|
js_call(J, *pc++);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_NEW:
|
||||||
|
js_construct(J, *pc++);
|
||||||
|
break;
|
||||||
|
|
||||||
/* Unary expressions */
|
/* Unary expressions */
|
||||||
|
|
||||||
case OP_POS:
|
case OP_POS:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ void js_pushobject(js_State *J, js_Object *v);
|
|||||||
/* public */
|
/* public */
|
||||||
|
|
||||||
void js_call(js_State *J, int n);
|
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_getglobal(js_State *J, const char *name);
|
||||||
void js_setglobal(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_pushstring(js_State *J, const char *v);
|
||||||
void js_newobject(js_State *J);
|
void js_newobject(js_State *J);
|
||||||
void js_newarray(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_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_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);
|
int js_toboolean(js_State *J, int idx);
|
||||||
double js_tonumber(js_State *J, int idx);
|
double js_tonumber(js_State *J, int idx);
|
||||||
|
|||||||
Reference in New Issue
Block a user