From a592f61f36e18ffcafeb186ee133cd37b7f5295c Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sat, 18 Jan 2014 22:04:37 +0100 Subject: [PATCH] Implement Number and Object classes. Split built-in functions into one file per class. --- js.h | 8 ++++ jsbarray.c | 15 +++++++ jsbboolean.c | 15 +++++++ jsbfunction.c | 15 +++++++ jsbnumber.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ jsbobject.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ jsbstring.c | 15 +++++++ jsbuiltin.c | 79 +----------------------------------- jsobject.c | 23 ++++------- jsrun.h | 2 +- 10 files changed, 291 insertions(+), 95 deletions(-) create mode 100644 jsbarray.c create mode 100644 jsbboolean.c create mode 100644 jsbfunction.c create mode 100644 jsbnumber.c create mode 100644 jsbobject.c create mode 100644 jsbstring.c diff --git a/js.h b/js.h index 2756f4b..be48937 100644 --- a/js.h +++ b/js.h @@ -8,6 +8,7 @@ #include #include #include +#include /* noreturn is a GCC extension */ #ifdef __GNUC__ @@ -64,4 +65,11 @@ const char *js_intern(js_State *J, const char *s); void js_printstrings(js_State *J); void js_freestrings(js_State *J); +void jsB_initobject(js_State *J); +void jsB_initarray(js_State *J); +void jsB_initfunction(js_State *J); +void jsB_initboolean(js_State *J); +void jsB_initnumber(js_State *J); +void jsB_initstring(js_State *J); + #endif diff --git a/jsbarray.c b/jsbarray.c new file mode 100644 index 0000000..82b4f19 --- /dev/null +++ b/jsbarray.c @@ -0,0 +1,15 @@ +#include "js.h" +#include "jsobject.h" +#include "jsrun.h" +#include "jsstate.h" + +static int jsB_Array(js_State *J, int n) { 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_setglobal(J, "Array"); +} diff --git a/jsbboolean.c b/jsbboolean.c new file mode 100644 index 0000000..1eea887 --- /dev/null +++ b/jsbboolean.c @@ -0,0 +1,15 @@ +#include "js.h" +#include "jsobject.h" +#include "jsrun.h" +#include "jsstate.h" + +static int jsB_Boolean(js_State *J, int n) { return 0; } + +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"); + js_setglobal(J, "Boolean"); +} diff --git a/jsbfunction.c b/jsbfunction.c new file mode 100644 index 0000000..1c6a284 --- /dev/null +++ b/jsbfunction.c @@ -0,0 +1,15 @@ +#include "js.h" +#include "jsobject.h" +#include "jsrun.h" +#include "jsstate.h" + +static int jsB_Function(js_State *J, int n) { return 0; } + +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"); + js_setglobal(J, "Function"); +} diff --git a/jsbnumber.c b/jsbnumber.c new file mode 100644 index 0000000..43f181e --- /dev/null +++ b/jsbnumber.c @@ -0,0 +1,105 @@ +#include "js.h" +#include "jsobject.h" +#include "jsrun.h" +#include "jsstate.h" + +static int jsB_new_Number(js_State *J, int n) +{ + js_pushobject(J, jsR_newnumber(J, n > 0 ? js_tonumber(J, 0) : 0)); + return 1; +} + +static int jsB_Number(js_State *J, int n) +{ + js_pushnumber(J, n > 0 ? js_tonumber(J, 1) : 0); + return 1; +} + +static int jsB_Number_p_valueOf(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + if (T->type != JS_CNUMBER) jsR_error(J, "TypeError"); + js_pushnumber(J, T->primitive.number); + return 1; +} + +static int jsB_Number_p_toString(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + if (T->type != JS_CNUMBER) jsR_error(J, "TypeError"); + js_pushliteral(J, jsR_numbertostring(J, T->primitive.number)); + return 1; +} + +static int jsB_Number_p_toFixed(js_State *J, int n) +{ + char buf[40]; + js_Object *T = js_toobject(J, 0); + int width = js_tonumber(J, 1); + if (T->type != JS_CNUMBER) jsR_error(J, "TypeError"); + sprintf(buf, "%*f", width, T->primitive.number); + js_pushstring(J, buf); + return 1; +} + +static int jsB_Number_p_toExponential(js_State *J, int n) +{ + char buf[40]; + js_Object *T = js_toobject(J, 0); + int width = js_tonumber(J, 1); + if (T->type != JS_CNUMBER) jsR_error(J, "TypeError"); + sprintf(buf, "%*e", width, T->primitive.number); + js_pushstring(J, buf); + return 1; +} + +static int jsB_Number_p_toPrecision(js_State *J, int n) +{ + char buf[40]; + js_Object *T = js_toobject(J, 0); + int width = js_tonumber(J, 1); + if (T->type != JS_CNUMBER) jsR_error(J, "TypeError"); + sprintf(buf, "%*g", width, T->primitive.number); + js_pushstring(J, buf); + return 1; +} + +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)); + { + 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"); + } + 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"); + } + js_setglobal(J, "Number"); +} diff --git a/jsbobject.c b/jsbobject.c new file mode 100644 index 0000000..3c2d433 --- /dev/null +++ b/jsbobject.c @@ -0,0 +1,109 @@ +#include "js.h" +#include "jsobject.h" +#include "jsrun.h" +#include "jsstate.h" + +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_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_Object_p_toString(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + switch (T->type) { + case JS_COBJECT: js_pushliteral(J, "[object Object]"); break; + case JS_CARRAY: js_pushliteral(J, "[object Array]"); break; + case JS_CFUNCTION: js_pushliteral(J, "[object Function]"); break; + case JS_CSCRIPT: js_pushliteral(J, "[object Function]"); break; + case JS_CCFUNCTION: js_pushliteral(J, "[object Function]"); break; + case JS_CERROR: js_pushliteral(J, "[object Error]"); break; + case JS_CBOOLEAN: js_pushliteral(J, "[object Boolean]"); break; + case JS_CNUMBER: js_pushliteral(J, "[object Number]"); break; + case JS_CSTRING: js_pushliteral(J, "[object String]"); break; + case JS_CREGEXP: js_pushliteral(J, "[object RegExp]"); break; + case JS_CDATE: js_pushliteral(J, "[object Date]"); break; + case JS_CMATH: js_pushliteral(J, "[object Math]"); break; + default: return 0; + } + return 1; +} + +static int jsB_Object_p_valueOf(js_State *J, int n) +{ + /* return the 'this' object */ + return 1; +} + +static int jsB_Object_p_hasOwnProperty(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + const char *name = js_tostring(J, 1); + js_Property *ref = jsR_getownproperty(J, T, name); + js_pushboolean(J, ref != NULL); + return 1; +} + +static int jsB_Object_p_isPrototypeOf(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + if (js_isobject(J, 1)) { + js_Object *V = js_toobject(J, 1); + do { + V = V->prototype; + if (V == T) { + js_pushboolean(J, 1); + return 1; + } + } while (V); + } + js_pushboolean(J, 0); + return 1; +} + +static int jsB_Object_p_propertyIsEnumerable(js_State *J, int n) +{ + js_Object *T = js_toobject(J, 0); + const char *name = js_tostring(J, 1); + js_Property *ref = jsR_getownproperty(J, T, name); + js_pushboolean(J, ref && (ref->flags & JS_PENUMERABLE)); + return 1; +} + +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)); + { + 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"); + } + js_setproperty(J, -2, "prototype"); + } + js_setglobal(J, "Object"); +} diff --git a/jsbstring.c b/jsbstring.c new file mode 100644 index 0000000..df98043 --- /dev/null +++ b/jsbstring.c @@ -0,0 +1,15 @@ +#include "js.h" +#include "jsobject.h" +#include "jsrun.h" +#include "jsstate.h" + +static int jsB_String(js_State *J, int n) { return 0; } + +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"); + js_setglobal(J, "String"); +} diff --git a/jsbuiltin.c b/jsbuiltin.c index 3bd367f..3a0e3e7 100644 --- a/jsbuiltin.c +++ b/jsbuiltin.c @@ -29,8 +29,6 @@ static int jsB_eval(js_State *J, int argc) if (!js_isstring(J, -1)) return 1; - // FIXME: return value if eval string is an expression - s = js_tostring(J, -1); if (jsR_loadscript(J, "(eval)", s)) jsR_error(J, "SyntaxError (eval)"); @@ -40,81 +38,6 @@ static int jsB_eval(js_State *J, int argc) return 1; } -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; } -static int jsB_Number(js_State *J, int n) { return 0; } -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_newcconstructor(J, jsB_Object, jsB_new_Object); - js_pushobject(J, J->Object_prototype); - js_setproperty(J, -2, "prototype"); - js_setglobal(J, "Object"); -} - -static 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_setglobal(J, "Array"); -} - -static 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"); - js_setglobal(J, "Function"); -} - -static 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"); - js_setglobal(J, "Boolean"); -} - -static void jsB_initnumber(js_State *J) -{ - J->Number_prototype = jsR_newobject(J, JS_COBJECT, NULL); - js_newcfunction(J, jsB_Number); - js_pushobject(J, J->Number_prototype); - js_setproperty(J, -2, "prototype"); - js_setglobal(J, "Number"); -} - -static 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"); - js_setglobal(J, "String"); -} - static int jsB_parseInt(js_State *J, int argc) { const char *s = js_tostring(J, 1); @@ -126,7 +49,7 @@ static int jsB_parseInt(js_State *J, int argc) static int jsB_parseFloat(js_State *J, int argc) { const char *s = js_tostring(J, 1); - js_pushnumber(J, strtod(s, NULL)); + js_pushnumber(J, jsR_stringtonumber(J, s)); return 1; } diff --git a/jsobject.c b/jsobject.c index a7b7689..db2019a 100644 --- a/jsobject.c +++ b/jsobject.c @@ -21,15 +21,15 @@ static js_Object *jsR_newscript(js_State *J, js_Function *function) static 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, J->Function_prototype); obj->cfunction = cfunction; obj->cconstructor = NULL; return obj; } -static js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor) +js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor) { - js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, NULL); + js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, J->Function_prototype); obj->cfunction = cfunction; obj->cconstructor = cconstructor; return obj; @@ -85,19 +85,10 @@ void js_newscript(js_State *J, js_Function *F) void js_newcfunction(js_State *J, js_CFunction fun) { 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_newcconstructor(js_State *J, js_CFunction fun, js_CFunction con) -{ - js_pushobject(J, jsR_newcconstructor(J, fun, con)); - // TODO: length property? - js_newobject(J); - js_copy(J, -2); - js_setproperty(J, -2, "constructor"); + { + js_copy(J, -2); + js_setproperty(J, -2, "constructor"); + } js_setproperty(J, -2, "prototype"); } diff --git a/jsrun.h b/jsrun.h index 35ae963..d43e214 100644 --- a/jsrun.h +++ b/jsrun.h @@ -13,6 +13,7 @@ struct js_Environment /* private */ void jsB_init(js_State *J); 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); void jsR_error(js_State *J, const char *fmt, ...); void js_pushobject(js_State *J, js_Object *v); @@ -52,7 +53,6 @@ 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_newcconstructor(js_State *J, js_CFunction fun, js_CFunction con); const char *js_typeof(js_State *J, int idx); int js_isundefined(js_State *J, int idx);