shithub: libmujs

Download patch

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);