ref: 3a92e13e47b58c6416a9c5c2738a6ed96032c059
parent: 6c8400d872634c40ca072d94696eadf0d87c9393
author: Tor Andersson <[email protected]>
date: Tue Jan 21 08:58:32 EST 2014
Rename files and move a few functions around.
--- a/js.h
+++ b/js.h
@@ -4,19 +4,29 @@
#include "jsconf.h"
typedef struct js_State js_State;
+
typedef int (*js_CFunction)(js_State *J, int argc);
/* Basic functions */
-
js_State *js_newstate(void);
void js_freestate(js_State *J);
-
int js_dostring(js_State *J, const char *source);
int js_dofile(js_State *J, const char *filename);
-
void js_gc(js_State *J, int report);
-const char *js_intern(js_State *J, const char *s);
+/* RegExp flags */
+enum {
+ JS_REGEXP_G = 1,
+ JS_REGEXP_I = 2,
+ JS_REGEXP_M = 4,
+};
+
+/* Hint to ToPrimitive() */
+enum {
+ JS_HNONE,
+ JS_HNUMBER,
+ JS_HSTRING
+};
/* Property attribute flags */
enum {
--- /dev/null
+++ b/jsarray.c
@@ -1,0 +1,28 @@
+#include "jsi.h"
+#include "jsvalue.h"
+#include "jsbuiltin.h"
+
+static int jsB_Array(js_State *J, int argc) { return 0; }
+static int jsB_new_Array(js_State *J, int argc) { return 0; }
+
+static int A_isArray(js_State *J, int argc)
+{
+ 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 1;
+}
+
+void jsB_initarray(js_State *J)
+{
+ js_pushobject(J, J->Array_prototype);
+ js_newcconstructor(J, jsB_Array, jsB_new_Array);
+ {
+ /* ECMA-262-5 */
+ jsB_propf(J, "isArray", A_isArray, 1);
+ }
+ js_setglobal(J, "Array");
+}
--- a/jsbarray.c
+++ /dev/null
@@ -1,28 +1,0 @@
-#include "jsi.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-
-static int jsB_Array(js_State *J, int argc) { return 0; }
-static int jsB_new_Array(js_State *J, int argc) { return 0; }
-
-static int A_isArray(js_State *J, int argc)
-{
- 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 1;
-}
-
-void jsB_initarray(js_State *J)
-{
- js_pushobject(J, J->Array_prototype);
- js_newcconstructor(J, jsB_Array, jsB_new_Array);
- {
- /* ECMA-262-5 */
- jsB_propf(J, "isArray", A_isArray, 1);
- }
- js_setglobal(J, "Array");
-}
--- a/jsbboolean.c
+++ /dev/null
@@ -1,44 +1,0 @@
-#include "jsi.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-
-static int jsB_new_Boolean(js_State *J, int argc)
-{
- js_newboolean(J, js_toboolean(J, 1));
- return 1;
-}
-
-static int jsB_Boolean(js_State *J, int argc)
-{
- js_pushboolean(J, js_toboolean(J, 1));
- return 1;
-}
-
-static int Bp_toString(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean");
- js_pushliteral(J, self->u.boolean ? "true" : "false");
- return 1;
-}
-
-static int Bp_valueOf(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean");
- js_pushboolean(J, self->u.boolean);
- return 1;
-}
-
-void jsB_initboolean(js_State *J)
-{
- J->Boolean_prototype->u.boolean = 0;
-
- js_pushobject(J, J->Boolean_prototype);
- {
- jsB_propf(J, "toString", Bp_toString, 0);
- jsB_propf(J, "valueOf", Bp_valueOf, 0);
- }
- js_newcconstructor(J, jsB_Boolean, jsB_new_Boolean);
- js_setglobal(J, "Boolean");
-}
--- a/jsberror.c
+++ /dev/null
@@ -1,59 +1,0 @@
-#include "jsi.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-
-#define QQ(X) #X
-#define Q(X) QQ(X)
-
-static int Ep_toString(js_State *J, int argc)
-{
- js_getproperty(J, 0, "name");
- js_pushliteral(J, ": ");
- js_concat(J);
- js_getproperty(J, 0, "message");
- js_concat(J);
- return 1;
-}
-
-#define DECL(NAME) \
- static int jsB_##NAME(js_State *J, int argc) { \
- js_pushobject(J, jsV_newobject(J, JS_CERROR, J->NAME##_prototype)); \
- if (argc > 0) { \
- js_pushstring(J, js_tostring(J, 1)); \
- js_setproperty(J, -2, "message"); \
- } \
- return 1; \
- } \
-
-DECL(Error);
-DECL(EvalError);
-DECL(RangeError);
-DECL(ReferenceError);
-DECL(SyntaxError);
-DECL(TypeError);
-DECL(URIError);
-
-void jsB_initerror(js_State *J)
-{
- js_pushobject(J, J->Error_prototype);
- {
- jsB_props(J, "name", "Error");
- jsB_props(J, "message", "an error has occurred");
- jsB_propf(J, "toString", Ep_toString, 0);
- }
- js_newcconstructor(J, jsB_Error, jsB_Error);
- js_setglobal(J, "Error");
-
- #define INIT(NAME) \
- js_pushobject(J, J->NAME##_prototype); \
- jsB_props(J, "name", Q(NAME)); \
- js_newcconstructor(J, jsB_##NAME, jsB_##NAME); \
- js_setglobal(J, Q(NAME));
-
- INIT(EvalError);
- INIT(RangeError);
- INIT(ReferenceError);
- INIT(SyntaxError);
- INIT(TypeError);
- INIT(URIError);
-}
--- a/jsbfunction.c
+++ /dev/null
@@ -1,101 +1,0 @@
-#include "jsi.h"
-#include "jscompile.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-
-static int jsB_new_Function(js_State *J, int argc) { return 0; }
-static int jsB_Function(js_State *J, int argc) { return 0; }
-
-static int jsB_Function_prototype(js_State *J, int argc)
-{
- js_pushundefined(J);
- return 1;
-}
-
-static int Fp_toString(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- char *s;
- int i, n;
-
- if (!js_iscallable(J, 0))
- js_typeerror(J, "not a function");
-
- if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT) {
- js_Function *F = self->u.f.function;
- n = strlen("function () { ... }");
- n += strlen(F->name);
- for (i = 0; i < F->numparams; i++)
- n += strlen(F->params[i]) + 1;
- s = malloc(n);
- strcpy(s, "function ");
- strcat(s, F->name);
- strcat(s, "(");
- for (i = 0; i < F->numparams; i++) {
- if (i > 0) strcat(s, ",");
- strcat(s, F->params[i]);
- }
- strcat(s, ") { ... }");
- js_pushstring(J, s);
- free(s);
- } else {
- js_pushliteral(J, "function () { ... }");
- }
-
- return 1;
-}
-
-static int Fp_apply(js_State *J, int argc)
-{
- int i, n;
- char name[20];
-
- if (!js_iscallable(J, 0))
- js_typeerror(J, "not a function");
-
- js_copy(J, 0);
- js_copy(J, 1);
-
- js_getproperty(J, 2, "length");
- n = js_tonumber(J, -1);
- js_pop(J, 1);
-
- for (i = 0; i < n; ++i) {
- sprintf(name, "%d", i);
- js_getproperty(J, 2, name);
- }
-
- js_call(J, n);
- return 1;
-}
-
-static int Fp_call(js_State *J, int argc)
-{
- int i;
-
- if (!js_iscallable(J, 0))
- js_typeerror(J, "not a function");
-
- js_copy(J, 0);
- js_copy(J, 1);
- for (i = 2; i <= argc; ++i)
- js_copy(J, i);
-
- js_call(J, argc - 1);
- return 1;
-}
-
-void jsB_initfunction(js_State *J)
-{
- J->Function_prototype->u.c.function = jsB_Function_prototype;
- J->Function_prototype->u.c.constructor = NULL;
-
- js_pushobject(J, J->Function_prototype);
- {
- jsB_propf(J, "toString", Fp_toString, 2);
- jsB_propf(J, "apply", Fp_apply, 2);
- jsB_propf(J, "call", Fp_call, 1);
- }
- js_newcconstructor(J, jsB_Function, jsB_new_Function);
- js_setglobal(J, "Function");
-}
--- a/jsbmath.c
+++ /dev/null
@@ -1,111 +1,0 @@
-#include "jsi.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-
-static int Math_abs(js_State *J, int argc) {
- return js_pushnumber(J, abs(js_tonumber(J, 1))), 1;
-}
-static int Math_acos(js_State *J, int argc) {
- return js_pushnumber(J, acos(js_tonumber(J, 1))), 1;
-}
-static int Math_asin(js_State *J, int argc) {
- return js_pushnumber(J, asin(js_tonumber(J, 1))), 1;
-}
-static int Math_atan(js_State *J, int argc) {
- return js_pushnumber(J, atan(js_tonumber(J, 1))), 1;
-}
-static int Math_atan2(js_State *J, int argc) {
- return js_pushnumber(J, atan2(js_tonumber(J, 1), js_tonumber(J, 2))), 1;
-}
-static int Math_ceil(js_State *J, int argc) {
- return js_pushnumber(J, ceil(js_tonumber(J, 1))), 1;
-}
-static int Math_cos(js_State *J, int argc) {
- return js_pushnumber(J, cos(js_tonumber(J, 1))), 1;
-}
-static int Math_exp(js_State *J, int argc) {
- return js_pushnumber(J, exp(js_tonumber(J, 1))), 1;
-}
-static int Math_floor(js_State *J, int argc) {
- return js_pushnumber(J, floor(js_tonumber(J, 1))), 1;
-}
-static int Math_log(js_State *J, int argc) {
- return js_pushnumber(J, log(js_tonumber(J, 1))), 1;
-}
-static int Math_pow(js_State *J, int argc) {
- return js_pushnumber(J, pow(js_tonumber(J, 1), js_tonumber(J, 2))), 1;
-}
-static int Math_random(js_State *J, int argc) {
- return js_pushnumber(J, (double)rand() / (RAND_MAX - 1)), 1;
-}
-static int Math_round(js_State *J, int argc) {
- return js_pushnumber(J, round(js_tonumber(J, 1))), 1;
-}
-static int Math_sin(js_State *J, int argc) {
- return js_pushnumber(J, sin(js_tonumber(J, 1))), 1;
-}
-static int Math_sqrt(js_State *J, int argc) {
- return js_pushnumber(J, sqrt(js_tonumber(J, 1))), 1;
-}
-static int Math_tan(js_State *J, int argc) {
- return js_pushnumber(J, tan(js_tonumber(J, 1))), 1;
-}
-
-static int Math_max(js_State *J, int argc)
-{
- double n = js_tonumber(J, 1);
- int i;
- for (i = 2; i <= argc; ++i) {
- double m = js_tonumber(J, i);
- n = n > m ? n : m;
- }
- js_pushnumber(J, n);
- return 1;
-}
-
-static int Math_min(js_State *J, int argc)
-{
- double n = js_tonumber(J, 1);
- int i;
- for (i = 2; i <= argc; ++i) {
- double m = js_tonumber(J, i);
- n = n < m ? n : m;
- }
- js_pushnumber(J, n);
- return 1;
-}
-
-void jsB_initmath(js_State *J)
-{
- js_pushobject(J, jsV_newobject(J, JS_CMATH, J->Object_prototype));
- {
- jsB_propn(J, "E", M_E);
- jsB_propn(J, "LN10", M_LN10);
- jsB_propn(J, "LN2", M_LN2);
- jsB_propn(J, "LOG2E", M_LOG2E);
- jsB_propn(J, "LOG10E", M_LOG10E);
- jsB_propn(J, "PI", M_PI);
- jsB_propn(J, "SQRT1_2", M_SQRT1_2);
- jsB_propn(J, "SQRT2", M_SQRT2);
-
- jsB_propf(J, "abs", Math_abs, 1);
- jsB_propf(J, "acos", Math_acos, 1);
- jsB_propf(J, "asin", Math_asin, 1);
- jsB_propf(J, "atan", Math_atan, 1);
- jsB_propf(J, "atan2", Math_atan2, 2);
- jsB_propf(J, "ceil", Math_ceil, 1);
- jsB_propf(J, "cos", Math_cos, 1);
- jsB_propf(J, "exp", Math_exp, 1);
- jsB_propf(J, "floor", Math_floor, 1);
- jsB_propf(J, "log", Math_log, 1);
- jsB_propf(J, "max", Math_max, 2);
- jsB_propf(J, "min", Math_min, 2);
- jsB_propf(J, "pow", Math_pow, 2);
- jsB_propf(J, "random", Math_random, 0);
- jsB_propf(J, "round", Math_round, 1);
- jsB_propf(J, "sin", Math_sin, 1);
- jsB_propf(J, "sqrt", Math_sqrt, 1);
- jsB_propf(J, "tan", Math_tan, 1);
- }
- js_setglobal(J, "Math");
-}
--- a/jsbnumber.c
+++ /dev/null
@@ -1,88 +1,0 @@
-#include "jsi.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-
-static int jsB_new_Number(js_State *J, int argc)
-{
- js_newnumber(J, argc > 0 ? js_tonumber(J, 1) : 0);
- return 1;
-}
-
-static int jsB_Number(js_State *J, int argc)
-{
- js_pushnumber(J, argc > 0 ? js_tonumber(J, 1) : 0);
- return 1;
-}
-
-static int Np_valueOf(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
- js_pushnumber(J, self->u.number);
- return 1;
-}
-
-static int Np_toString(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
- js_pushliteral(J, jsV_numbertostring(J, self->u.number));
- return 1;
-}
-
-static int Np_toFixed(js_State *J, int argc)
-{
- char buf[40];
- js_Object *self = js_toobject(J, 0);
- int width = js_tonumber(J, 1);
- if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
- sprintf(buf, "%.*f", width, self->u.number);
- js_pushstring(J, buf);
- return 1;
-}
-
-static int Np_toExponential(js_State *J, int argc)
-{
- char buf[40];
- js_Object *self = js_toobject(J, 0);
- int width = js_tonumber(J, 1);
- if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
- sprintf(buf, "%.*e", width, self->u.number);
- js_pushstring(J, buf);
- return 1;
-}
-
-static int Np_toPrecision(js_State *J, int argc)
-{
- char buf[40];
- js_Object *self = js_toobject(J, 0);
- int width = js_tonumber(J, 1);
- if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
- sprintf(buf, "%.*g", width, self->u.number);
- js_pushstring(J, buf);
- return 1;
-}
-
-void jsB_initnumber(js_State *J)
-{
- J->Number_prototype->u.number = 0;
-
- js_pushobject(J, J->Number_prototype);
- {
- 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_newcconstructor(J, jsB_Number, jsB_new_Number);
- {
- 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
+++ /dev/null
@@ -1,98 +1,0 @@
-#include "jsi.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-
-static int jsB_new_Object(js_State *J, int argc)
-{
- if (argc == 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(js_State *J, int argc)
-{
- if (argc == 0 || js_isundefined(J, 1) || js_isnull(J, 1))
- js_newobject(J);
- else
- js_pushobject(J, js_toobject(J, 1));
- return 1;
-}
-
-static int Op_toString(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- switch (self->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 Op_valueOf(js_State *J, int argc)
-{
- /* return the 'this' object */
- return 1;
-}
-
-static int Op_hasOwnProperty(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- const char *name = js_tostring(J, 1);
- js_Property *ref = jsV_getownproperty(J, self, name);
- js_pushboolean(J, ref != NULL);
- return 1;
-}
-
-static int Op_isPrototypeOf(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- if (js_isobject(J, 1)) {
- js_Object *V = js_toobject(J, 1);
- do {
- V = V->prototype;
- if (V == self) {
- js_pushboolean(J, 1);
- return 1;
- }
- } while (V);
- }
- js_pushboolean(J, 0);
- return 1;
-}
-
-static int Op_propertyIsEnumerable(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- const char *name = js_tostring(J, 1);
- js_Property *ref = jsV_getownproperty(J, self, name);
- js_pushboolean(J, ref && !(ref->atts & JS_DONTENUM));
- return 1;
-}
-
-void jsB_initobject(js_State *J)
-{
- js_pushobject(J, J->Object_prototype);
- {
- 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_newcconstructor(J, jsB_Object, jsB_new_Object);
- js_setglobal(J, "Object");
-}
--- /dev/null
+++ b/jsboolean.c
@@ -1,0 +1,44 @@
+#include "jsi.h"
+#include "jsvalue.h"
+#include "jsbuiltin.h"
+
+static int jsB_new_Boolean(js_State *J, int argc)
+{
+ js_newboolean(J, js_toboolean(J, 1));
+ return 1;
+}
+
+static int jsB_Boolean(js_State *J, int argc)
+{
+ js_pushboolean(J, js_toboolean(J, 1));
+ return 1;
+}
+
+static int Bp_toString(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean");
+ js_pushliteral(J, self->u.boolean ? "true" : "false");
+ return 1;
+}
+
+static int Bp_valueOf(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean");
+ js_pushboolean(J, self->u.boolean);
+ return 1;
+}
+
+void jsB_initboolean(js_State *J)
+{
+ J->Boolean_prototype->u.boolean = 0;
+
+ js_pushobject(J, J->Boolean_prototype);
+ {
+ jsB_propf(J, "toString", Bp_toString, 0);
+ jsB_propf(J, "valueOf", Bp_valueOf, 0);
+ }
+ js_newcconstructor(J, jsB_Boolean, jsB_new_Boolean);
+ js_setglobal(J, "Boolean");
+}
--- a/jsbstring.c
+++ /dev/null
@@ -1,120 +1,0 @@
-#include "jsi.h"
-#include "jsvalue.h"
-#include "jsbuiltin.h"
-#include "jsutf.h"
-
-static int jsB_new_String(js_State *J, int argc)
-{
- js_newstring(J, argc > 0 ? js_tostring(J, 1) : "");
- return 1;
-}
-
-static int jsB_String(js_State *J, int argc)
-{
- js_pushliteral(J, argc > 0 ? js_tostring(J, 1) : "");
- return 1;
-}
-
-static int Sp_toString(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
- js_pushliteral(J, self->u.string);
- return 1;
-}
-
-static int Sp_valueOf(js_State *J, int argc)
-{
- js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
- js_pushliteral(J, self->u.string);
- return 1;
-}
-
-static inline Rune runeAt(const char *s, int i)
-{
- Rune rune = 0;
- while (i-- >= 0) {
- rune = *(unsigned char*)s;
- if (rune < Runeself) {
- if (rune == 0)
- return 0;
- ++s;
- } else
- s += chartorune(&rune, s);
- }
- return rune;
-}
-
-static int Sp_charAt(js_State *J, int argc)
-{
- char buf[UTFmax + 1];
- const char *s = js_tostring(J, 0);
- int pos = js_tointeger(J, 1);
- Rune rune = runeAt(s, pos);
- if (rune > 0) {
- buf[runetochar(buf, &rune)] = 0;
- js_pushstring(J, buf);
- } else {
- js_pushliteral(J, "");
- }
- return 1;
-}
-
-static int Sp_charCodeAt(js_State *J, int argc)
-{
- const char *s = js_tostring(J, 0);
- int pos = js_tointeger(J, 1);
- Rune rune = runeAt(s, pos);
- if (rune > 0)
- js_pushnumber(J, rune);
- else
- js_pushnumber(J, NAN);
- return 1;
-}
-
-static int S_fromCharCode(js_State *J, int argc)
-{
- int i;
- Rune c;
- char *s = malloc(argc * UTFmax + 1), *p = s;
- // TODO: guard malloc with try/catch
- for (i = 0; i <= argc; ++i) {
- c = js_tointeger(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->u.string = "";
-
- js_pushobject(J, J->String_prototype);
- {
- jsB_propf(J, "toString", Sp_toString, 0);
- jsB_propf(J, "valueOf", Sp_valueOf, 0);
- jsB_propf(J, "charAt", Sp_charAt, 1);
- jsB_propf(J, "charCodeAt", Sp_charCodeAt, 1);
- //jsB_propf(J, "concat", Sp_concat, 1);
- //jsB_propf(J, "indexOf", Sp_indexOf, 1);
- //jsB_propf(J, "lastIndexOf", Sp_lastIndexOf, 1);
- //jsB_propf(J, "localeCompare", Sp_localeCompare, 1);
- //jsB_propf(J, "slice", Sp_slice, 2);
- // match (uses regexp)
- // replace (uses regexp)
- // search (uses regexp)
- // split (uses regexp)
- //jsB_propf(J, "substring", Sp_substring, 2);
- //jsB_propf(J, "toLowerCase", Sp_toLowerCase, 0);
- //jsB_propf(J, "toUpperCase", Sp_toUpperCase, 0);
- }
- js_newcconstructor(J, jsB_String, jsB_new_String);
- {
- jsB_propf(J, "fromCharCode", S_fromCharCode, 1);
- }
- js_setglobal(J, "String");
-}
--- a/jsbuiltin.c
+++ b/jsbuiltin.c
@@ -1,26 +1,32 @@
#include "jsi.h"
+#include "jscompile.h"
#include "jsvalue.h"
#include "jsbuiltin.h"
-static int jsB_print(js_State *J, int argc)
+static void jsB_globalf(js_State *J, const char *name, js_CFunction cfun, int n)
{
- int i;
- for (i = 1; i <= argc; ++i) {
- const char *s = js_tostring(J, i);
- if (i > 1) putchar(' ');
- fputs(s, stdout);
- }
- putchar('\n');
- return 0;
+ js_newcfunction(J, cfun, n);
+ js_setglobal(J, name);
}
-static int jsB_collectGarbage(js_State *J, int argc)
+void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n)
{
- int report = js_toboolean(J, 1);
- js_gc(J, report);
- return 0;
+ 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_props(js_State *J, const char *name, const char *string)
+{
+ js_pushliteral(J, string);
+ js_setproperty(J, -2, name);
+}
+
static int jsB_eval(js_State *J, int argc)
{
if (!js_isstring(J, -1))
@@ -60,30 +66,25 @@
return 1;
}
-static void jsB_globalf(js_State *J, const char *name, js_CFunction cfun, int n)
+static int jsB_print(js_State *J, int argc)
{
- js_newcfunction(J, cfun, n);
- js_setglobal(J, name);
+ int i;
+ for (i = 1; i <= argc; ++i) {
+ const char *s = js_tostring(J, i);
+ if (i > 1) putchar(' ');
+ fputs(s, stdout);
+ }
+ putchar('\n');
+ return 0;
}
-void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n)
+static int jsB_collectGarbage(js_State *J, int argc)
{
- js_newcfunction(J, cfun, n);
- js_setproperty(J, -2, name);
+ int report = js_toboolean(J, 1);
+ js_gc(J, report);
+ return 0;
}
-void jsB_propn(js_State *J, const char *name, double number)
-{
- js_pushnumber(J, number);
- js_setproperty(J, -2, name);
-}
-
-void jsB_props(js_State *J, const char *name, const char *string)
-{
- js_pushliteral(J, string);
- js_setproperty(J, -2, name);
-}
-
void jsB_init(js_State *J)
{
/* Create the prototype objects here, before the constructors */
@@ -111,7 +112,6 @@
jsB_initnumber(J);
jsB_initstring(J);
jsB_initerror(J);
-
jsB_initmath(J);
/* Initialize the global object */
--- a/jserror.c
+++ b/jserror.c
@@ -1,6 +1,30 @@
#include "jsi.h"
#include "jsvalue.h"
+#include "jsbuiltin.h"
+#define QQ(X) #X
+#define Q(X) QQ(X)
+
+static int Ep_toString(js_State *J, int argc)
+{
+ js_getproperty(J, 0, "name");
+ js_pushliteral(J, ": ");
+ js_concat(J);
+ js_getproperty(J, 0, "message");
+ js_concat(J);
+ return 1;
+}
+
+static int jsB_ErrorX(js_State *J, int argc, js_Object *prototype)
+{
+ js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
+ if (argc > 0) {
+ js_pushstring(J, js_tostring(J, 1));
+ js_setproperty(J, -2, "message");
+ }
+ return 1;
+}
+
static void js_newerrorx(js_State *J, const char *message, js_Object *prototype)
{
js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
@@ -8,27 +32,56 @@
js_setproperty(J, -2, "message");
}
-void js_newerror(js_State *J, const char *s) { js_newerrorx(J, s, J->Error_prototype); }
-void js_newevalerror(js_State *J, const char *s) { js_newerrorx(J, s, J->EvalError_prototype); }
-void js_newrangeerror(js_State *J, const char *s) { js_newerrorx(J, s, J->RangeError_prototype); }
-void js_newreferenceerror(js_State *J, const char *s) { js_newerrorx(J, s, J->ReferenceError_prototype); }
-void js_newsyntaxerror(js_State *J, const char *s) { js_newerrorx(J, s, J->SyntaxError_prototype); }
-void js_newtypeerror(js_State *J, const char *s) { js_newerrorx(J, s, J->TypeError_prototype); }
-void js_newurierror(js_State *J, const char *s) { js_newerrorx(J, s, J->URIError_prototype); }
+#define DERROR(name, Name) \
+ static int jsB_##Name(js_State *J, int n) { \
+ return jsB_ErrorX(J, n, J->Name##_prototype); \
+ } \
+ void js_new##name(js_State *J, const char *s) { \
+ js_newerrorx(J, s, J->Name##_prototype); \
+ } \
+ void js_##name(js_State *J, const char *fmt, ...) { \
+ va_list ap; \
+ char buf[256]; \
+ va_start(ap, fmt); \
+ vsnprintf(buf, sizeof buf, fmt, ap); \
+ va_end(ap); \
+ js_newerrorx(J, buf, J->Name##_prototype); \
+ js_throw(J); \
+ }
-#define ERR(NAME) \
- va_list ap; \
- char buf[256]; \
- va_start(ap, fmt); \
- vsnprintf(buf, sizeof buf, fmt, ap); \
- va_end(ap); \
- js_newerrorx(J, buf, J->NAME##_prototype); \
- js_throw(J)
+DERROR(error, Error)
+DERROR(evalerror, EvalError)
+DERROR(rangeerror, RangeError)
+DERROR(referenceerror, ReferenceError)
+DERROR(syntaxerror, SyntaxError)
+DERROR(typeerror, TypeError)
+DERROR(urierror, URIError)
-void js_error(js_State *J, const char *fmt, ...) { ERR(Error); }
-void js_evalerror(js_State *J, const char *fmt, ...) { ERR(EvalError); }
-void js_rangeerror(js_State *J, const char *fmt, ...) { ERR(RangeError); }
-void js_referenceerror(js_State *J, const char *fmt, ...) { ERR(ReferenceError); }
-void js_syntaxerror(js_State *J, const char *fmt, ...) { ERR(SyntaxError); }
-void js_typeerror(js_State *J, const char *fmt, ...) { ERR(TypeError); }
-void js_urierror(js_State *J, const char *fmt, ...) { ERR(URIError); }
+#undef DERROR
+
+void jsB_initerror(js_State *J)
+{
+ js_pushobject(J, J->Error_prototype);
+ {
+ jsB_props(J, "name", "Error");
+ jsB_props(J, "message", "an error has occurred");
+ jsB_propf(J, "toString", Ep_toString, 0);
+ }
+ js_newcconstructor(J, jsB_Error, jsB_Error);
+ js_setglobal(J, "Error");
+
+ #define IERROR(NAME) \
+ js_pushobject(J, J->NAME##_prototype); \
+ jsB_props(J, "name", Q(NAME)); \
+ js_newcconstructor(J, jsB_##NAME, jsB_##NAME); \
+ js_setglobal(J, Q(NAME));
+
+ IERROR(EvalError);
+ IERROR(RangeError);
+ IERROR(ReferenceError);
+ IERROR(SyntaxError);
+ IERROR(TypeError);
+ IERROR(URIError);
+
+ #undef IERROR
+}
--- /dev/null
+++ b/jsfunction.c
@@ -1,0 +1,103 @@
+#include "jsi.h"
+#include "jscompile.h"
+#include "jsvalue.h"
+#include "jsbuiltin.h"
+
+static int jsB_Function(js_State *J, int argc)
+{
+ return 0;
+}
+
+static int jsB_Function_prototype(js_State *J, int argc)
+{
+ js_pushundefined(J);
+ return 1;
+}
+
+static int Fp_toString(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ char *s;
+ int i, n;
+
+ if (!js_iscallable(J, 0))
+ js_typeerror(J, "not a function");
+
+ if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT) {
+ js_Function *F = self->u.f.function;
+ n = strlen("function () { ... }");
+ n += strlen(F->name);
+ for (i = 0; i < F->numparams; i++)
+ n += strlen(F->params[i]) + 1;
+ s = malloc(n);
+ strcpy(s, "function ");
+ strcat(s, F->name);
+ strcat(s, "(");
+ for (i = 0; i < F->numparams; i++) {
+ if (i > 0) strcat(s, ",");
+ strcat(s, F->params[i]);
+ }
+ strcat(s, ") { ... }");
+ js_pushstring(J, s);
+ free(s);
+ } else {
+ js_pushliteral(J, "function () { ... }");
+ }
+
+ return 1;
+}
+
+static int Fp_apply(js_State *J, int argc)
+{
+ int i, n;
+ char name[20];
+
+ if (!js_iscallable(J, 0))
+ js_typeerror(J, "not a function");
+
+ js_copy(J, 0);
+ js_copy(J, 1);
+
+ js_getproperty(J, 2, "length");
+ n = js_tonumber(J, -1);
+ js_pop(J, 1);
+
+ for (i = 0; i < n; ++i) {
+ sprintf(name, "%d", i);
+ js_getproperty(J, 2, name);
+ }
+
+ js_call(J, n);
+ return 1;
+}
+
+static int Fp_call(js_State *J, int argc)
+{
+ int i;
+
+ if (!js_iscallable(J, 0))
+ js_typeerror(J, "not a function");
+
+ js_copy(J, 0);
+ js_copy(J, 1);
+ for (i = 2; i <= argc; ++i)
+ js_copy(J, i);
+
+ js_call(J, argc - 1);
+ return 1;
+}
+
+void jsB_initfunction(js_State *J)
+{
+ J->Function_prototype->u.c.function = jsB_Function_prototype;
+ J->Function_prototype->u.c.constructor = NULL;
+
+ js_pushobject(J, J->Function_prototype);
+ {
+ jsB_propf(J, "toString", Fp_toString, 2);
+ jsB_propf(J, "apply", Fp_apply, 2);
+ jsB_propf(J, "call", Fp_call, 1);
+ }
+ js_newcconstructor(J, jsB_Function, jsB_Function);
+ js_setglobal(J, "Function");
+}
--- a/jsi.h
+++ b/jsi.h
@@ -12,21 +12,22 @@
#include <math.h>
#include <float.h>
-enum { JS_REGEXP_G = 1, JS_REGEXP_I = 2, JS_REGEXP_M = 4 }; /* RegExp flags */
-
-enum { JS_HNONE, JS_HNUMBER, JS_HSTRING }; /* Hint to ToPrimitive() */
-
typedef struct js_Value js_Value;
typedef struct js_Object js_Object;
-
typedef struct js_Ast js_Ast;
typedef struct js_Function js_Function;
typedef struct js_Environment js_Environment;
-
typedef struct js_StringNode js_StringNode;
+typedef struct js_Jumpbuf js_Jumpbuf;
+
+/* String interning */
+
+const char *js_intern(js_State *J, const char *s);
void jsS_dumpstrings(js_State *J);
void jsS_freestrings(js_State *J);
+/* Private stack functions */
+
void js_newfunction(js_State *J, js_Function *function, js_Environment *scope);
void js_newscript(js_State *J, js_Function *function);
@@ -36,8 +37,6 @@
void js_rot3(js_State *J);
/* Exception handling */
-
-typedef struct js_Jumpbuf js_Jumpbuf;
struct js_Jumpbuf
{
--- /dev/null
+++ b/jsmath.c
@@ -1,0 +1,111 @@
+#include "jsi.h"
+#include "jsvalue.h"
+#include "jsbuiltin.h"
+
+static int Math_abs(js_State *J, int argc) {
+ return js_pushnumber(J, abs(js_tonumber(J, 1))), 1;
+}
+static int Math_acos(js_State *J, int argc) {
+ return js_pushnumber(J, acos(js_tonumber(J, 1))), 1;
+}
+static int Math_asin(js_State *J, int argc) {
+ return js_pushnumber(J, asin(js_tonumber(J, 1))), 1;
+}
+static int Math_atan(js_State *J, int argc) {
+ return js_pushnumber(J, atan(js_tonumber(J, 1))), 1;
+}
+static int Math_atan2(js_State *J, int argc) {
+ return js_pushnumber(J, atan2(js_tonumber(J, 1), js_tonumber(J, 2))), 1;
+}
+static int Math_ceil(js_State *J, int argc) {
+ return js_pushnumber(J, ceil(js_tonumber(J, 1))), 1;
+}
+static int Math_cos(js_State *J, int argc) {
+ return js_pushnumber(J, cos(js_tonumber(J, 1))), 1;
+}
+static int Math_exp(js_State *J, int argc) {
+ return js_pushnumber(J, exp(js_tonumber(J, 1))), 1;
+}
+static int Math_floor(js_State *J, int argc) {
+ return js_pushnumber(J, floor(js_tonumber(J, 1))), 1;
+}
+static int Math_log(js_State *J, int argc) {
+ return js_pushnumber(J, log(js_tonumber(J, 1))), 1;
+}
+static int Math_pow(js_State *J, int argc) {
+ return js_pushnumber(J, pow(js_tonumber(J, 1), js_tonumber(J, 2))), 1;
+}
+static int Math_random(js_State *J, int argc) {
+ return js_pushnumber(J, (double)rand() / (RAND_MAX - 1)), 1;
+}
+static int Math_round(js_State *J, int argc) {
+ return js_pushnumber(J, round(js_tonumber(J, 1))), 1;
+}
+static int Math_sin(js_State *J, int argc) {
+ return js_pushnumber(J, sin(js_tonumber(J, 1))), 1;
+}
+static int Math_sqrt(js_State *J, int argc) {
+ return js_pushnumber(J, sqrt(js_tonumber(J, 1))), 1;
+}
+static int Math_tan(js_State *J, int argc) {
+ return js_pushnumber(J, tan(js_tonumber(J, 1))), 1;
+}
+
+static int Math_max(js_State *J, int argc)
+{
+ double n = js_tonumber(J, 1);
+ int i;
+ for (i = 2; i <= argc; ++i) {
+ double m = js_tonumber(J, i);
+ n = n > m ? n : m;
+ }
+ js_pushnumber(J, n);
+ return 1;
+}
+
+static int Math_min(js_State *J, int argc)
+{
+ double n = js_tonumber(J, 1);
+ int i;
+ for (i = 2; i <= argc; ++i) {
+ double m = js_tonumber(J, i);
+ n = n < m ? n : m;
+ }
+ js_pushnumber(J, n);
+ return 1;
+}
+
+void jsB_initmath(js_State *J)
+{
+ js_pushobject(J, jsV_newobject(J, JS_CMATH, J->Object_prototype));
+ {
+ jsB_propn(J, "E", M_E);
+ jsB_propn(J, "LN10", M_LN10);
+ jsB_propn(J, "LN2", M_LN2);
+ jsB_propn(J, "LOG2E", M_LOG2E);
+ jsB_propn(J, "LOG10E", M_LOG10E);
+ jsB_propn(J, "PI", M_PI);
+ jsB_propn(J, "SQRT1_2", M_SQRT1_2);
+ jsB_propn(J, "SQRT2", M_SQRT2);
+
+ jsB_propf(J, "abs", Math_abs, 1);
+ jsB_propf(J, "acos", Math_acos, 1);
+ jsB_propf(J, "asin", Math_asin, 1);
+ jsB_propf(J, "atan", Math_atan, 1);
+ jsB_propf(J, "atan2", Math_atan2, 2);
+ jsB_propf(J, "ceil", Math_ceil, 1);
+ jsB_propf(J, "cos", Math_cos, 1);
+ jsB_propf(J, "exp", Math_exp, 1);
+ jsB_propf(J, "floor", Math_floor, 1);
+ jsB_propf(J, "log", Math_log, 1);
+ jsB_propf(J, "max", Math_max, 2);
+ jsB_propf(J, "min", Math_min, 2);
+ jsB_propf(J, "pow", Math_pow, 2);
+ jsB_propf(J, "random", Math_random, 0);
+ jsB_propf(J, "round", Math_round, 1);
+ jsB_propf(J, "sin", Math_sin, 1);
+ jsB_propf(J, "sqrt", Math_sqrt, 1);
+ jsB_propf(J, "tan", Math_tan, 1);
+ }
+ js_setglobal(J, "Math");
+}
--- /dev/null
+++ b/jsnumber.c
@@ -1,0 +1,88 @@
+#include "jsi.h"
+#include "jsvalue.h"
+#include "jsbuiltin.h"
+
+static int jsB_new_Number(js_State *J, int argc)
+{
+ js_newnumber(J, argc > 0 ? js_tonumber(J, 1) : 0);
+ return 1;
+}
+
+static int jsB_Number(js_State *J, int argc)
+{
+ js_pushnumber(J, argc > 0 ? js_tonumber(J, 1) : 0);
+ return 1;
+}
+
+static int Np_valueOf(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
+ js_pushnumber(J, self->u.number);
+ return 1;
+}
+
+static int Np_toString(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
+ js_pushliteral(J, jsV_numbertostring(J, self->u.number));
+ return 1;
+}
+
+static int Np_toFixed(js_State *J, int argc)
+{
+ char buf[40];
+ js_Object *self = js_toobject(J, 0);
+ int width = js_tonumber(J, 1);
+ if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
+ sprintf(buf, "%.*f", width, self->u.number);
+ js_pushstring(J, buf);
+ return 1;
+}
+
+static int Np_toExponential(js_State *J, int argc)
+{
+ char buf[40];
+ js_Object *self = js_toobject(J, 0);
+ int width = js_tonumber(J, 1);
+ if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
+ sprintf(buf, "%.*e", width, self->u.number);
+ js_pushstring(J, buf);
+ return 1;
+}
+
+static int Np_toPrecision(js_State *J, int argc)
+{
+ char buf[40];
+ js_Object *self = js_toobject(J, 0);
+ int width = js_tonumber(J, 1);
+ if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
+ sprintf(buf, "%.*g", width, self->u.number);
+ js_pushstring(J, buf);
+ return 1;
+}
+
+void jsB_initnumber(js_State *J)
+{
+ J->Number_prototype->u.number = 0;
+
+ js_pushobject(J, J->Number_prototype);
+ {
+ 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_newcconstructor(J, jsB_Number, jsB_new_Number);
+ {
+ 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");
+}
--- /dev/null
+++ b/jsobject.c
@@ -1,0 +1,98 @@
+#include "jsi.h"
+#include "jsvalue.h"
+#include "jsbuiltin.h"
+
+static int jsB_new_Object(js_State *J, int argc)
+{
+ if (argc == 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(js_State *J, int argc)
+{
+ if (argc == 0 || js_isundefined(J, 1) || js_isnull(J, 1))
+ js_newobject(J);
+ else
+ js_pushobject(J, js_toobject(J, 1));
+ return 1;
+}
+
+static int Op_toString(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ switch (self->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 Op_valueOf(js_State *J, int argc)
+{
+ /* return the 'this' object */
+ return 1;
+}
+
+static int Op_hasOwnProperty(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ const char *name = js_tostring(J, 1);
+ js_Property *ref = jsV_getownproperty(J, self, name);
+ js_pushboolean(J, ref != NULL);
+ return 1;
+}
+
+static int Op_isPrototypeOf(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ if (js_isobject(J, 1)) {
+ js_Object *V = js_toobject(J, 1);
+ do {
+ V = V->prototype;
+ if (V == self) {
+ js_pushboolean(J, 1);
+ return 1;
+ }
+ } while (V);
+ }
+ js_pushboolean(J, 0);
+ return 1;
+}
+
+static int Op_propertyIsEnumerable(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ const char *name = js_tostring(J, 1);
+ js_Property *ref = jsV_getownproperty(J, self, name);
+ js_pushboolean(J, ref && !(ref->atts & JS_DONTENUM));
+ return 1;
+}
+
+void jsB_initobject(js_State *J)
+{
+ js_pushobject(J, J->Object_prototype);
+ {
+ 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_newcconstructor(J, jsB_Object, jsB_new_Object);
+ js_setglobal(J, "Object");
+}
--- a/jsoptim.c
+++ /dev/null
@@ -1,78 +1,0 @@
-#include "jsi.h"
-#include "jsparse.h"
-
-static inline int i32(double d)
-{
- double two32 = 4294967296.0;
- double two31 = 2147483648.0;
-
- if (!isfinite(d) || d == 0)
- return 0;
-
- d = fmod(d, two32);
- d = d >= 0 ? floor(d) : ceil(d) + two32;
- if (d >= two31)
- return d - two32;
- else
- return d;
-}
-
-static inline unsigned int u32(double d)
-{
- return i32(d);
-}
-
-static int N(js_Ast *node, double x)
-{
- node->type = AST_NUMBER;
- node->number = x;
- node->a = node->b = node->c = node->d = NULL;
- return 1;
-}
-
-static int foldnumber(js_Ast *node)
-{
- double x, y;
- int a, b;
-
- if (node->type == AST_NUMBER)
- return 1;
-
- a = node->a ? foldnumber(node->a) : 0;
- b = node->b ? foldnumber(node->b) : 0;
- if (node->c) foldnumber(node->c);
- if (node->d) foldnumber(node->d);
-
- if (a) {
- x = node->a->number;
- switch (node->type) {
- case EXP_NEG: return N(node, -x);
- case EXP_POS: return N(node, x);
- case EXP_BITNOT: return N(node, ~i32(x));
- }
-
- if (b) {
- y = node->b->number;
- switch (node->type) {
- case EXP_MUL: return N(node, x * y);
- case EXP_DIV: return N(node, x / y);
- case EXP_MOD: return N(node, fmod(x, y));
- case EXP_ADD: return N(node, x + y);
- case EXP_SUB: return N(node, x - y);
- case EXP_SHL: return N(node, i32(x) << (u32(y) & 0x1F));
- case EXP_SHR: return N(node, i32(x) >> (u32(y) & 0x1F));
- case EXP_USHR: return N(node, u32(x) >> (u32(y) & 0x1F));
- case EXP_BITAND: return N(node, i32(x) & i32(y));
- case EXP_BITXOR: return N(node, i32(x) ^ i32(y));
- case EXP_BITOR: return N(node, i32(x) | i32(y));
- }
- }
- }
-
- return 0;
-}
-
-void jsP_optimize(js_State *J, js_Ast *prog)
-{
- foldnumber(prog);
-}
--- a/jsparse.c
+++ b/jsparse.c
@@ -54,7 +54,7 @@
fprintf(stderr, "\n");
}
-js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d)
+static js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d)
{
js_Ast *node = malloc(sizeof(js_Ast));
@@ -73,7 +73,7 @@
return node;
}
-js_Ast *jsP_newstrnode(js_State *J, int type, const char *s)
+static js_Ast *jsP_newstrnode(js_State *J, int type, const char *s)
{
js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0);
node->string = s;
@@ -80,7 +80,7 @@
return node;
}
-js_Ast *jsP_newnumnode(js_State *J, int type, double n)
+static js_Ast *jsP_newnumnode(js_State *J, int type, double n)
{
js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0);
node->number = n;
@@ -866,6 +866,81 @@
return a;
}
+/* Constant folding */
+
+static inline int toint32(double d)
+{
+ double two32 = 4294967296.0;
+ double two31 = 2147483648.0;
+
+ if (!isfinite(d) || d == 0)
+ return 0;
+
+ d = fmod(d, two32);
+ d = d >= 0 ? floor(d) : ceil(d) + two32;
+ if (d >= two31)
+ return d - two32;
+ else
+ return d;
+}
+
+static inline unsigned int touint32(double d)
+{
+ return toint32(d);
+}
+
+static int jsP_setnumnode(js_Ast *node, double x)
+{
+ node->type = AST_NUMBER;
+ node->number = x;
+ node->a = node->b = node->c = node->d = NULL;
+ return 1;
+}
+
+static int jsP_foldconst(js_Ast *node)
+{
+ double x, y;
+ int a, b;
+
+ if (node->type == AST_NUMBER)
+ return 1;
+
+ a = node->a ? jsP_foldconst(node->a) : 0;
+ b = node->b ? jsP_foldconst(node->b) : 0;
+ if (node->c) jsP_foldconst(node->c);
+ if (node->d) jsP_foldconst(node->d);
+
+ if (a) {
+ x = node->a->number;
+ switch (node->type) {
+ case EXP_NEG: return jsP_setnumnode(node, -x);
+ case EXP_POS: return jsP_setnumnode(node, x);
+ case EXP_BITNOT: return jsP_setnumnode(node, ~toint32(x));
+ }
+
+ if (b) {
+ y = node->b->number;
+ switch (node->type) {
+ case EXP_MUL: return jsP_setnumnode(node, x * y);
+ case EXP_DIV: return jsP_setnumnode(node, x / y);
+ case EXP_MOD: return jsP_setnumnode(node, fmod(x, y));
+ case EXP_ADD: return jsP_setnumnode(node, x + y);
+ case EXP_SUB: return jsP_setnumnode(node, x - y);
+ case EXP_SHL: return jsP_setnumnode(node, toint32(x) << (touint32(y) & 0x1F));
+ case EXP_SHR: return jsP_setnumnode(node, toint32(x) >> (touint32(y) & 0x1F));
+ case EXP_USHR: return jsP_setnumnode(node, touint32(x) >> (touint32(y) & 0x1F));
+ case EXP_BITAND: return jsP_setnumnode(node, toint32(x) & toint32(y));
+ case EXP_BITXOR: return jsP_setnumnode(node, toint32(x) ^ toint32(y));
+ case EXP_BITOR: return jsP_setnumnode(node, toint32(x) | toint32(y));
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Main entry point */
+
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source)
{
js_Ast *p, *last;
@@ -874,6 +949,8 @@
next(J);
p = script(J);
+
+ jsP_foldconst(p);
/* patch up global and eval code to return value of last expression */
last = p;
--- a/jsparse.h
+++ b/jsparse.h
@@ -125,7 +125,6 @@
};
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source);
-void jsP_optimize(js_State *J, js_Ast *prog);
void jsP_freeparse(js_State *J);
const char *jsP_aststring(js_AstType type);
--- a/jsstate.c
+++ b/jsstate.c
@@ -16,7 +16,6 @@
}
P = jsP_parse(J, filename, source);
- jsP_optimize(J, P);
F = jsC_compile(J, P);
jsP_freeparse(J);
js_newscript(J, F);
--- /dev/null
+++ b/jsstring.c
@@ -1,0 +1,120 @@
+#include "jsi.h"
+#include "jsvalue.h"
+#include "jsbuiltin.h"
+#include "jsutf.h"
+
+static int jsB_new_String(js_State *J, int argc)
+{
+ js_newstring(J, argc > 0 ? js_tostring(J, 1) : "");
+ return 1;
+}
+
+static int jsB_String(js_State *J, int argc)
+{
+ js_pushliteral(J, argc > 0 ? js_tostring(J, 1) : "");
+ return 1;
+}
+
+static int Sp_toString(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
+ js_pushliteral(J, self->u.string);
+ return 1;
+}
+
+static int Sp_valueOf(js_State *J, int argc)
+{
+ js_Object *self = js_toobject(J, 0);
+ if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
+ js_pushliteral(J, self->u.string);
+ return 1;
+}
+
+static inline Rune runeAt(const char *s, int i)
+{
+ Rune rune = 0;
+ while (i-- >= 0) {
+ rune = *(unsigned char*)s;
+ if (rune < Runeself) {
+ if (rune == 0)
+ return 0;
+ ++s;
+ } else
+ s += chartorune(&rune, s);
+ }
+ return rune;
+}
+
+static int Sp_charAt(js_State *J, int argc)
+{
+ char buf[UTFmax + 1];
+ const char *s = js_tostring(J, 0);
+ int pos = js_tointeger(J, 1);
+ Rune rune = runeAt(s, pos);
+ if (rune > 0) {
+ buf[runetochar(buf, &rune)] = 0;
+ js_pushstring(J, buf);
+ } else {
+ js_pushliteral(J, "");
+ }
+ return 1;
+}
+
+static int Sp_charCodeAt(js_State *J, int argc)
+{
+ const char *s = js_tostring(J, 0);
+ int pos = js_tointeger(J, 1);
+ Rune rune = runeAt(s, pos);
+ if (rune > 0)
+ js_pushnumber(J, rune);
+ else
+ js_pushnumber(J, NAN);
+ return 1;
+}
+
+static int S_fromCharCode(js_State *J, int argc)
+{
+ int i;
+ Rune c;
+ char *s = malloc(argc * UTFmax + 1), *p = s;
+ // TODO: guard malloc with try/catch
+ for (i = 0; i <= argc; ++i) {
+ c = js_tointeger(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->u.string = "";
+
+ js_pushobject(J, J->String_prototype);
+ {
+ jsB_propf(J, "toString", Sp_toString, 0);
+ jsB_propf(J, "valueOf", Sp_valueOf, 0);
+ jsB_propf(J, "charAt", Sp_charAt, 1);
+ jsB_propf(J, "charCodeAt", Sp_charCodeAt, 1);
+ //jsB_propf(J, "concat", Sp_concat, 1);
+ //jsB_propf(J, "indexOf", Sp_indexOf, 1);
+ //jsB_propf(J, "lastIndexOf", Sp_lastIndexOf, 1);
+ //jsB_propf(J, "localeCompare", Sp_localeCompare, 1);
+ //jsB_propf(J, "slice", Sp_slice, 2);
+ // match (uses regexp)
+ // replace (uses regexp)
+ // search (uses regexp)
+ // split (uses regexp)
+ //jsB_propf(J, "substring", Sp_substring, 2);
+ //jsB_propf(J, "toLowerCase", Sp_toLowerCase, 0);
+ //jsB_propf(J, "toUpperCase", Sp_toUpperCase, 0);
+ }
+ js_newcconstructor(J, jsB_String, jsB_new_String);
+ {
+ jsB_propf(J, "fromCharCode", S_fromCharCode, 1);
+ }
+ js_setglobal(J, "String");
+}