ref: a592f61f36e18ffcafeb186ee133cd37b7f5295c
parent: 07610bd0ac03c3c3473cb1965aed6db08d6120c5
author: Tor Andersson <[email protected]>
date: Sat Jan 18 17:04:37 EST 2014
Implement Number and Object classes. Split built-in functions into one file per class.
--- a/js.h
+++ b/js.h
@@ -8,6 +8,7 @@
#include <string.h>
#include <setjmp.h>
#include <math.h>
+#include <float.h>
/* noreturn is a GCC extension */
#ifdef __GNUC__
@@ -63,5 +64,12 @@
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
--- /dev/null
+++ b/jsbarray.c
@@ -1,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");
+}
--- /dev/null
+++ b/jsbboolean.c
@@ -1,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");
+}
--- /dev/null
+++ b/jsbfunction.c
@@ -1,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");
+}
--- /dev/null
+++ b/jsbnumber.c
@@ -1,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");
+}
--- /dev/null
+++ b/jsbobject.c
@@ -1,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");
+}
--- /dev/null
+++ b/jsbstring.c
@@ -1,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");
+}
--- a/jsbuiltin.c
+++ b/jsbuiltin.c
@@ -29,8 +29,6 @@
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 @@
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_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;
}
--- a/jsobject.c
+++ b/jsobject.c
@@ -21,15 +21,15 @@
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_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");
}
--- a/jsrun.h
+++ b/jsrun.h
@@ -13,6 +13,7 @@
/* 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_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);