diff --git a/jsbarray.c b/jsbarray.c index 82b4f19..367ae8b 100644 --- a/jsbarray.c +++ b/jsbarray.c @@ -4,12 +4,35 @@ #include "jsstate.h" static int jsB_Array(js_State *J, int n) { return 0; } +static int jsB_new_Array(js_State *J, int n) { return 0; } + +static int A_isArray(js_State *J, int n) +{ + if (js_isobject(J, 1)) { + js_Object *T = js_toobject(J, 1); + js_pushboolean(J, T->type == JS_CARRAY); + return 1; + } + js_pushboolean(J, 0); + return 0; +} void jsB_initarray(js_State *J) { - J->Array_prototype = jsR_newobject(J, JS_COBJECT, NULL); - js_newcfunction(J, jsB_Array); - js_pushobject(J, J->Array_prototype); - js_setproperty(J, -2, "prototype"); + js_pushobject(J, jsR_newcconstructor(J, jsB_Array, jsB_new_Array)); + { + jsB_propn(J, "length", 1); + + js_pushobject(J, J->Array_prototype); + { + js_copy(J, -2); + js_setproperty(J, -2, "constructor"); + jsB_propn(J, "length", 0); + } + js_setproperty(J, -2, "prototype"); + + /* ECMA-262-5 */ + jsB_propf(J, "isArray", A_isArray, 1); + } js_setglobal(J, "Array"); } diff --git a/jsbboolean.c b/jsbboolean.c index 1eea887..ee43517 100644 --- a/jsbboolean.c +++ b/jsbboolean.c @@ -3,13 +3,49 @@ #include "jsrun.h" #include "jsstate.h" -static int jsB_Boolean(js_State *J, int n) { return 0; } +static int jsB_new_Boolean(js_State *J, int n) +{ + js_pushobject(J, jsR_newboolean(J, js_toboolean(J, 0))); + return 1; +} + +static int jsB_Boolean(js_State *J, int n) +{ + js_pushboolean(J, js_toboolean(J, 1)); + return 1; +} + +static int Bp_toString(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + if (T->type != JS_CBOOLEAN) jsR_error(J, "TypeError"); + js_pushliteral(J, T->primitive.boolean ? "true" : "false"); + return 1; +} + +static int Bp_valueOf(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + if (T->type != JS_CBOOLEAN) jsR_error(J, "TypeError"); + js_pushboolean(J, T->primitive.boolean); + return 1; +} void jsB_initboolean(js_State *J) { - J->Boolean_prototype = jsR_newobject(J, JS_COBJECT, NULL); - js_newcfunction(J, jsB_Boolean); - js_pushobject(J, J->Boolean_prototype); - js_setproperty(J, -2, "prototype"); + J->Boolean_prototype->primitive.boolean = 0; + + js_pushobject(J, jsR_newcconstructor(J, jsB_Boolean, jsB_new_Boolean)); + { + jsB_propn(J, "length", 1); + js_pushobject(J, J->Boolean_prototype); + { + js_copy(J, -2); + js_setproperty(J, -2, "constructor"); + jsB_propf(J, "toString", Bp_toString, 0); + jsB_propf(J, "valueOf", Bp_valueOf, 0); + } + js_setproperty(J, -2, "prototype"); + } js_setglobal(J, "Boolean"); } diff --git a/jsbfunction.c b/jsbfunction.c index 1c6a284..ca98c5c 100644 --- a/jsbfunction.c +++ b/jsbfunction.c @@ -3,13 +3,53 @@ #include "jsrun.h" #include "jsstate.h" +static int jsB_new_Function(js_State *J, int n) { return 0; } static int jsB_Function(js_State *J, int n) { return 0; } +static int jsB_Function_prototype(js_State *J, int n) +{ + js_pushundefined(J); + return 1; +} + +static int Fp_call(js_State *J, int n) +{ + int i; + + if (!js_iscallable(J, 0)) + jsR_error(J, "TypeError"); + js_copy(J, 0); + + if (js_isundefined(J, 1) || js_isnull(J, 1)) + js_pushglobal(J); + else + js_copy(J, 1); + + for (i = 1; i < n; ++i) + js_copy(J, i + 1); + + js_call(J, n - 1); + return 1; +} + void jsB_initfunction(js_State *J) { - J->Function_prototype = jsR_newobject(J, JS_COBJECT, NULL); - js_newcfunction(J, jsB_Function); - js_pushobject(J, J->Function_prototype); - js_setproperty(J, -2, "prototype"); + J->Function_prototype->cfunction = jsB_Function_prototype; + J->Function_prototype->cconstructor = NULL; + + js_pushobject(J, jsR_newcconstructor(J, jsB_Function, jsB_new_Function)); + { + jsB_propn(J, "length", 1); + + js_pushobject(J, J->Function_prototype); + { + js_copy(J, -2); + js_setproperty(J, -2, "constructor"); + // jsB_propf(J, "toString", Fp_toString, 2); + // jsB_propf(J, "apply", Fp_apply, 2); + jsB_propf(J, "call", Fp_call, 1); + } + js_setproperty(J, -2, "prototype"); + } js_setglobal(J, "Function"); } diff --git a/jsbnumber.c b/jsbnumber.c index 43f181e..9ce4902 100644 --- a/jsbnumber.c +++ b/jsbnumber.c @@ -15,7 +15,7 @@ static int jsB_Number(js_State *J, int n) return 1; } -static int jsB_Number_p_valueOf(js_State *J, int n) +static int Np_valueOf(js_State *J, int n) { js_Object *T = js_toobject(J, 0); if (T->type != JS_CNUMBER) jsR_error(J, "TypeError"); @@ -23,7 +23,7 @@ static int jsB_Number_p_valueOf(js_State *J, int n) return 1; } -static int jsB_Number_p_toString(js_State *J, int n) +static int Np_toString(js_State *J, int n) { js_Object *T = js_toobject(J, 0); if (T->type != JS_CNUMBER) jsR_error(J, "TypeError"); @@ -31,7 +31,7 @@ static int jsB_Number_p_toString(js_State *J, int n) return 1; } -static int jsB_Number_p_toFixed(js_State *J, int n) +static int Np_toFixed(js_State *J, int n) { char buf[40]; js_Object *T = js_toobject(J, 0); @@ -42,7 +42,7 @@ static int jsB_Number_p_toFixed(js_State *J, int n) return 1; } -static int jsB_Number_p_toExponential(js_State *J, int n) +static int Np_toExponential(js_State *J, int n) { char buf[40]; js_Object *T = js_toobject(J, 0); @@ -53,7 +53,7 @@ static int jsB_Number_p_toExponential(js_State *J, int n) return 1; } -static int jsB_Number_p_toPrecision(js_State *J, int n) +static int Np_toPrecision(js_State *J, int n) { char buf[40]; js_Object *T = js_toobject(J, 0); @@ -66,40 +66,30 @@ static int jsB_Number_p_toPrecision(js_State *J, int n) void jsB_initnumber(js_State *J) { - J->Number_prototype = jsR_newobject(J, JS_CNUMBER, J->Object_prototype); J->Number_prototype->primitive.number = 0; js_pushobject(J, jsR_newcconstructor(J, jsB_Number, jsB_new_Number)); { + jsB_propn(J, "length", 1); + js_pushobject(J, J->Number_prototype); { js_copy(J, -2); js_setproperty(J, -2, "constructor"); - js_newcfunction(J, jsB_Number_p_valueOf); - js_setproperty(J, -2, "valueOf"); - js_newcfunction(J, jsB_Number_p_toString); - js_dup(J); - js_setproperty(J, -3, "toString"); - js_setproperty(J, -2, "toLocaleString"); - js_newcfunction(J, jsB_Number_p_toFixed); - js_setproperty(J, -2, "toFixed"); - js_newcfunction(J, jsB_Number_p_toExponential); - js_setproperty(J, -2, "toExponential"); - js_newcfunction(J, jsB_Number_p_toPrecision); - js_setproperty(J, -2, "toPrecision"); + jsB_propf(J, "valueOf", Np_valueOf, 0); + jsB_propf(J, "toString", Np_toString, 0); + jsB_propf(J, "toLocaleString", Np_toString, 0); + jsB_propf(J, "toFixed", Np_toFixed, 1); + jsB_propf(J, "toExponential", Np_toExponential, 1); + jsB_propf(J, "toPrecision", Np_toPrecision, 1); } js_setproperty(J, -2, "prototype"); - js_pushnumber(J, DBL_MAX); - js_setproperty(J, -2, "MAX_VALUE"); - js_pushnumber(J, DBL_MIN); - js_setproperty(J, -2, "MIN_VALUE"); - js_pushnumber(J, NAN); - js_setproperty(J, -2, "NaN"); - js_pushnumber(J, -INFINITY); - js_setproperty(J, -2, "NEGATIVE_INFINITY"); - js_pushnumber(J, INFINITY); - js_setproperty(J, -2, "POSITIVE_INFINITY"); + jsB_propn(J, "MAX_VALUE", DBL_MAX); + jsB_propn(J, "MIN_VALUE", DBL_MIN); + jsB_propn(J, "NaN", NAN); + jsB_propn(J, "NEGATIVE_INFINITY", -INFINITY); + jsB_propn(J, "POSITIVE_INFINITY", INFINITY); } js_setglobal(J, "Number"); } diff --git a/jsbobject.c b/jsbobject.c index 3c2d433..a56cf23 100644 --- a/jsbobject.c +++ b/jsbobject.c @@ -3,7 +3,8 @@ #include "jsrun.h" #include "jsstate.h" -static int jsB_new_Object(js_State *J, int n) { +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 @@ -11,7 +12,8 @@ static int jsB_new_Object(js_State *J, int n) { return 1; } -static int jsB_Object(js_State *J, int n) { +static int jsB_Object(js_State *J, int n) +{ if (n == 0 || js_isundefined(J, 1) || js_isnull(J, 1)) js_newobject(J); else @@ -19,7 +21,7 @@ static int jsB_Object(js_State *J, int n) { return 1; } -static int jsB_Object_p_toString(js_State *J, int n) +static int Op_toString(js_State *J, int n) { js_Object *T = js_toobject(J, 0); switch (T->type) { @@ -40,13 +42,13 @@ static int jsB_Object_p_toString(js_State *J, int n) return 1; } -static int jsB_Object_p_valueOf(js_State *J, int n) +static int Op_valueOf(js_State *J, int n) { /* return the 'this' object */ return 1; } -static int jsB_Object_p_hasOwnProperty(js_State *J, int n) +static int Op_hasOwnProperty(js_State *J, int n) { js_Object *T = js_toobject(J, 0); const char *name = js_tostring(J, 1); @@ -55,7 +57,7 @@ static int jsB_Object_p_hasOwnProperty(js_State *J, int n) return 1; } -static int jsB_Object_p_isPrototypeOf(js_State *J, int n) +static int Op_isPrototypeOf(js_State *J, int n) { js_Object *T = js_toobject(J, 0); if (js_isobject(J, 1)) { @@ -72,7 +74,7 @@ static int jsB_Object_p_isPrototypeOf(js_State *J, int n) return 1; } -static int jsB_Object_p_propertyIsEnumerable(js_State *J, int n) +static int Op_propertyIsEnumerable(js_State *J, int n) { js_Object *T = js_toobject(J, 0); const char *name = js_tostring(J, 1); @@ -83,25 +85,19 @@ static int jsB_Object_p_propertyIsEnumerable(js_State *J, int n) void jsB_initobject(js_State *J) { - J->Object_prototype = jsR_newobject(J, JS_COBJECT, NULL); js_pushobject(J, jsR_newcconstructor(J, jsB_Object, jsB_new_Object)); { + jsB_propn(J, "length", 1); js_pushobject(J, J->Object_prototype); { js_copy(J, -2); js_setproperty(J, -2, "constructor"); - js_newcfunction(J, jsB_Object_p_toString); - js_dup(J); - js_setproperty(J, -3, "toString"); - js_setproperty(J, -2, "toLocaleString"); - js_newcfunction(J, jsB_Object_p_valueOf); - js_setproperty(J, -2, "valueOf"); - js_newcfunction(J, jsB_Object_p_hasOwnProperty); - js_setproperty(J, -2, "hasOwnProperty"); - js_newcfunction(J, jsB_Object_p_isPrototypeOf); - js_setproperty(J, -2, "isPrototypeOf"); - js_newcfunction(J, jsB_Object_p_propertyIsEnumerable); - js_setproperty(J, -2, "propertyIsEnumerable"); + jsB_propf(J, "toString", Op_toString, 0); + jsB_propf(J, "toLocaleString", Op_toString, 0); + jsB_propf(J, "valueOf", Op_valueOf, 0); + jsB_propf(J, "hasOwnProperty", Op_hasOwnProperty, 1); + jsB_propf(J, "isPrototypeOf", Op_isPrototypeOf, 1); + jsB_propf(J, "propertyIsEnumerable", Op_propertyIsEnumerable, 1); } js_setproperty(J, -2, "prototype"); } diff --git a/jsbstring.c b/jsbstring.c index df98043..53bbefa 100644 --- a/jsbstring.c +++ b/jsbstring.c @@ -2,14 +2,70 @@ #include "jsobject.h" #include "jsrun.h" #include "jsstate.h" +#include "jsutf.h" -static int jsB_String(js_State *J, int n) { return 0; } +static int jsB_new_String(js_State *J, int n) +{ + js_pushobject(J, jsR_newstring(J, n > 0 ? js_tostring(J, 0) : "")); + return 1; +} + +static int jsB_String(js_State *J, int n) +{ + js_pushliteral(J, n > 0 ? js_tostring(J, 1) : ""); + return 1; +} + +static int Sp_toString(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + if (T->type != JS_CSTRING) jsR_error(J, "TypeError"); + js_pushliteral(J, T->primitive.string); + return 1; +} + +static int Sp_valueOf(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + if (T->type != JS_CSTRING) jsR_error(J, "TypeError"); + js_pushliteral(J, T->primitive.string); + return 1; +} + +static int S_fromCharCode(js_State *J, int n) +{ + int i; + Rune c; + char *s = malloc(n * UTFmax + 1), *p = s; + // TODO: guard malloc with try/catch + for (i = 0; i < n; i++) { + c = js_tonumber(J, i + 1); // TODO: ToUInt16() + p += runetochar(p, &c); + } + *p = 0; + js_pushstring(J, s); + free(s); + return 1; +} void jsB_initstring(js_State *J) { - J->String_prototype = jsR_newobject(J, JS_COBJECT, NULL); - js_newcfunction(J, jsB_String); - js_pushobject(J, J->String_prototype); - js_setproperty(J, -2, "prototype"); + J->String_prototype->primitive.string = ""; + + js_pushobject(J, jsR_newcconstructor(J, jsB_String, jsB_new_String)); + { + jsB_propn(J, "length", 1); + + js_pushobject(J, J->String_prototype); + { + js_copy(J, -2); + js_setproperty(J, -2, "constructor"); + jsB_propf(J, "toString", Sp_toString, 0); + jsB_propf(J, "valueOf", Sp_valueOf, 0); + } + js_setproperty(J, -2, "prototype"); + + jsB_propf(J, "fromCharCode", S_fromCharCode, 1); + } js_setglobal(J, "String"); } diff --git a/jsbuiltin.c b/jsbuiltin.c index 3a0e3e7..38d51e5 100644 --- a/jsbuiltin.c +++ b/jsbuiltin.c @@ -67,14 +67,35 @@ static int jsB_isFinite(js_State *J, int argc) return 1; } -static void jsB_register(js_State *J, const char *name, js_CFunction cfun) +static void jsB_globalf(js_State *J, const char *name, js_CFunction cfun, int n) { - js_newcfunction(J, cfun); + js_newcfunction(J, cfun, n); js_setglobal(J, name); } +void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n) +{ + js_newcfunction(J, cfun, n); + js_setproperty(J, -2, name); +} + +void jsB_propn(js_State *J, const char *name, double number) +{ + js_pushnumber(J, number); + js_setproperty(J, -2, name); +} + void jsB_init(js_State *J) { + /* Create the prototype objects here, before the constructors */ + J->Object_prototype = jsR_newobject(J, JS_COBJECT, NULL); + J->Array_prototype = jsR_newobject(J, JS_CARRAY, J->Object_prototype); + J->Function_prototype = jsR_newobject(J, JS_CCFUNCTION, J->Object_prototype); + J->Boolean_prototype = jsR_newobject(J, JS_CBOOLEAN, J->Object_prototype); + J->Number_prototype = jsR_newobject(J, JS_CNUMBER, J->Object_prototype); + J->String_prototype = jsR_newobject(J, JS_CSTRING, J->Object_prototype); + + /* Create the constructors and fill out the prototype objects */ jsB_initobject(J); jsB_initarray(J); jsB_initfunction(J); @@ -82,6 +103,7 @@ void jsB_init(js_State *J) jsB_initnumber(J); jsB_initstring(J); + /* Initialize the global object */ js_pushnumber(J, NAN); js_setglobal(J, "NaN"); @@ -91,12 +113,12 @@ void jsB_init(js_State *J) js_pushundefined(J); js_setglobal(J, "undefined"); - jsB_register(J, "eval", jsB_eval); - jsB_register(J, "parseInt", jsB_parseInt); - jsB_register(J, "parseFloat", jsB_parseFloat); - jsB_register(J, "isNaN", jsB_isNaN); - jsB_register(J, "isFinite", jsB_isFinite); + jsB_globalf(J, "eval", jsB_eval, 1); + jsB_globalf(J, "parseInt", jsB_parseInt, 1); + jsB_globalf(J, "parseFloat", jsB_parseFloat, 1); + jsB_globalf(J, "isNaN", jsB_isNaN, 1); + jsB_globalf(J, "isFinite", jsB_isFinite, 1); - jsB_register(J, "collectGarbage", jsB_collectGarbage); - jsB_register(J, "print", jsB_print); + jsB_globalf(J, "collectGarbage", jsB_collectGarbage, 0); + jsB_globalf(J, "print", jsB_print, 0); } diff --git a/jsobject.c b/jsobject.c index db2019a..1652581 100644 --- a/jsobject.c +++ b/jsobject.c @@ -69,12 +69,16 @@ void js_newarray(js_State *J) void js_newfunction(js_State *J, js_Function *F, js_Environment *scope) { js_pushobject(J, jsR_newfunction(J, F, scope)); - js_pushnumber(J, F->numparams); - js_setproperty(J, -2, "length"); - js_newobject(J); - js_copy(J, -2); - js_setproperty(J, -2, "constructor"); - js_setproperty(J, -2, "prototype"); + { + js_pushnumber(J, F->numparams); + js_setproperty(J, -2, "length"); + js_newobject(J); + { + js_copy(J, -2); + js_setproperty(J, -2, "constructor"); + } + js_setproperty(J, -2, "prototype"); + } } void js_newscript(js_State *J, js_Function *F) @@ -82,13 +86,17 @@ void js_newscript(js_State *J, js_Function *F) js_pushobject(J, jsR_newscript(J, F)); } -void js_newcfunction(js_State *J, js_CFunction fun) +void js_newcfunction(js_State *J, js_CFunction fun, int length) { js_pushobject(J, jsR_newcfunction(J, fun)); - js_newobject(J); { - js_copy(J, -2); - js_setproperty(J, -2, "constructor"); + js_pushnumber(J, length); + js_setproperty(J, -2, "length"); + js_newobject(J); + { + js_copy(J, -2); + js_setproperty(J, -2, "constructor"); + } + js_setproperty(J, -2, "prototype"); } - js_setproperty(J, -2, "prototype"); } diff --git a/jsrun.h b/jsrun.h index d43e214..e018652 100644 --- a/jsrun.h +++ b/jsrun.h @@ -12,6 +12,9 @@ struct js_Environment /* private */ void jsB_init(js_State *J); +void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n); +void jsB_propn(js_State *J, const char *name, double number); + js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer); js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor); int jsR_loadscript(js_State *J, const char *filename, const char *source); @@ -52,7 +55,7 @@ void js_newobject(js_State *J); void js_newarray(js_State *J); void js_newfunction(js_State *J, js_Function *function, js_Environment *scope); void js_newscript(js_State *J, js_Function *function); -void js_newcfunction(js_State *J, js_CFunction fun); +void js_newcfunction(js_State *J, js_CFunction fun, int length); const char *js_typeof(js_State *J, int idx); int js_isundefined(js_State *J, int idx);