ref: 1237388b8e825ef032e81694a983b1eac2c6954a
parent: a592f61f36e18ffcafeb186ee133cd37b7f5295c
author: Tor Andersson <tor@ccxvii.net>
date: Sat Jan 18 20:50:41 EST 2014
More builtins. Fix prototype chains for builtin classes and prototypes.
--- 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");
}
--- 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");
}
--- 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");
}
--- a/jsbnumber.c
+++ b/jsbnumber.c
@@ -15,7 +15,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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");
}
--- 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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");
}
--- 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");
}
--- a/jsbuiltin.c
+++ b/jsbuiltin.c
@@ -67,14 +67,35 @@
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 @@
jsB_initnumber(J);
jsB_initstring(J);
+ /* Initialize the global object */
js_pushnumber(J, NAN);
js_setglobal(J, "NaN");
@@ -91,12 +113,12 @@
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);
}
--- a/jsobject.c
+++ b/jsobject.c
@@ -69,12 +69,16 @@
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 @@
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");
}
--- a/jsrun.h
+++ b/jsrun.h
@@ -12,6 +12,9 @@
/* 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_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);