ref: b262cc3673965e53ed73606668dedd3acb045881
parent: 759acbd4ddaa706d2f457616d4e5ea32ea4127f6
author: Tor Andersson <[email protected]>
date: Mon Jan 20 12:44:56 EST 2014
Rename many jsR functions to jsV. Danger! jsV work on values internally without the stack. Also rearrange how C-constructors are created.
--- a/js.h
+++ b/js.h
@@ -56,7 +56,12 @@
void js_newobject(js_State *J);
void js_newarray(js_State *J);
+void js_newboolean(js_State *J, int v);
+void js_newnumber(js_State *J, double v);
+void js_newstring(js_State *J, const char *v);
+void js_newerror(js_State *J, const char *message);
void js_newcfunction(js_State *J, js_CFunction fun, int length);
+void js_newcconstructor(js_State *J, js_CFunction fun, js_CFunction con);
int js_isundefined(js_State *J, int idx);
int js_isnull(js_State *J, int idx);
--- a/jsbarray.c
+++ b/jsbarray.c
@@ -1,5 +1,5 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int jsB_Array(js_State *J, int n) { return 0; }
@@ -13,23 +13,14 @@
return 1;
}
js_pushboolean(J, 0);
- return 0;
+ return 1;
}
void jsB_initarray(js_State *J)
{
- js_pushobject(J, jsR_newcconstructor(J, jsB_Array, jsB_new_Array));
+ js_pushobject(J, J->Array_prototype);
+ js_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);
}
--- a/jsbboolean.c
+++ b/jsbboolean.c
@@ -1,10 +1,10 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int jsB_new_Boolean(js_State *J, int n)
{
- js_pushobject(J, jsR_newboolean(J, js_toboolean(J, 0)));
+ js_newboolean(J, js_toboolean(J, 0));
return 1;
}
@@ -34,17 +34,11 @@
{
J->Boolean_prototype->u.boolean = 0;
- js_pushobject(J, jsR_newcconstructor(J, jsB_Boolean, jsB_new_Boolean));
+ js_pushobject(J, J->Boolean_prototype);
{
- 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");
+ 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
+++ b/jsberror.c
@@ -1,5 +1,5 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int Ep_toString(js_State *J, int n)
@@ -17,7 +17,7 @@
#define DECL(NAME) \
static int jsB_new_##NAME(js_State *J, int n) { \
- js_pushobject(J, jsR_newobject(J, JS_CERROR, J->NAME##_prototype)); \
+ js_pushobject(J, jsV_newobject(J, JS_CERROR, J->NAME##_prototype)); \
if (n > 0) { \
js_pushstring(J, js_tostring(J, 0)); \
js_setproperty(J, -2, "message"); \
@@ -25,7 +25,7 @@
return 1; \
} \
static int jsB_##NAME(js_State *J, int n) { \
- js_pushobject(J, jsR_newobject(J, JS_CERROR, J->NAME##_prototype)); \
+ js_pushobject(J, jsV_newobject(J, JS_CERROR, J->NAME##_prototype)); \
if (n > 1) { \
js_pushstring(J, js_tostring(J, 1)); \
js_setproperty(J, -2, "message"); \
@@ -33,23 +33,17 @@
return 1; \
} \
static void jsB_init##NAME(js_State *J) { \
- js_pushobject(J, jsR_newcconstructor(J, jsB_##NAME, jsB_new_##NAME)); \
+ js_pushobject(J, J->NAME##_prototype); \
{ \
- jsB_propn(J, "length", 1); \
- js_pushobject(J, J->NAME##_prototype); \
- { \
- js_copy(J, -2); \
- js_setproperty(J, -2, "constructor"); \
- jsB_props(J, "name", STR(NAME)); \
- jsB_props(J, "message", "an error has occurred"); \
- jsB_propf(J, "toString", Ep_toString, 0); \
- } \
- js_setproperty(J, -2, "prototype"); \
+ jsB_props(J, "name", STR(NAME)); \
+ jsB_props(J, "message", "an error has occurred"); \
+ jsB_propf(J, "toString", Ep_toString, 0); \
} \
+ js_newcconstructor(J, jsB_##NAME, jsB_new_##NAME); \
js_setglobal(J, STR(NAME)); \
} \
void jsR_throw##NAME(js_State *J, const char *message) { \
- js_pushobject(J, jsR_newobject(J, JS_CERROR, J->NAME##_prototype)); \
+ js_pushobject(J, jsV_newobject(J, JS_CERROR, J->NAME##_prototype)); \
js_pushstring(J, message); \
js_setproperty(J, -2, "message"); \
js_throw(J); \
--- a/jsbfunction.c
+++ b/jsbfunction.c
@@ -1,6 +1,6 @@
#include "jsi.h"
#include "jscompile.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int jsB_new_Function(js_State *J, int n) { return 0; }
@@ -91,19 +91,12 @@
J->Function_prototype->u.c.function = jsB_Function_prototype;
J->Function_prototype->u.c.constructor = NULL;
- js_pushobject(J, jsR_newcconstructor(J, jsB_Function, jsB_new_Function));
+ js_pushobject(J, J->Function_prototype);
{
- 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");
+ 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
+++ b/jsbmath.c
@@ -1,5 +1,5 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int Math_abs(js_State *J, int nargs) {
@@ -77,7 +77,7 @@
void jsB_initmath(js_State *J)
{
- js_pushobject(J, jsR_newobject(J, JS_CMATH, J->Object_prototype));
+ js_pushobject(J, jsV_newobject(J, JS_CMATH, J->Object_prototype));
{
jsB_propn(J, "E", M_E);
jsB_propn(J, "LN10", M_LN10);
--- a/jsbnumber.c
+++ b/jsbnumber.c
@@ -1,10 +1,10 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int jsB_new_Number(js_State *J, int n)
{
- js_pushobject(J, jsR_newnumber(J, n > 0 ? js_tonumber(J, 0) : 0));
+ js_newnumber(J, n > 0 ? js_tonumber(J, 0) : 0);
return 1;
}
@@ -26,7 +26,7 @@
{
js_Object *self = js_toobject(J, 0);
if (self->type != JS_CNUMBER) jsR_throwTypeError(J, "not a number");
- js_pushliteral(J, jsR_stringfromnumber(J, self->u.number));
+ js_pushliteral(J, jsV_numbertostring(J, self->u.number));
return 1;
}
@@ -67,23 +67,17 @@
{
J->Number_prototype->u.number = 0;
- js_pushobject(J, jsR_newcconstructor(J, jsB_Number, jsB_new_Number));
+ js_pushobject(J, J->Number_prototype);
{
- jsB_propn(J, "length", 1);
-
- js_pushobject(J, J->Number_prototype);
- {
- js_copy(J, -2);
- js_setproperty(J, -2, "constructor");
- 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");
-
+ 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);
--- a/jsbobject.c
+++ b/jsbobject.c
@@ -1,5 +1,5 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int jsB_new_Object(js_State *J, int n)
@@ -51,7 +51,7 @@
{
js_Object *self = js_toobject(J, 0);
const char *name = js_tostring(J, 1);
- js_Property *ref = jsR_getownproperty(J, self, name);
+ js_Property *ref = jsV_getownproperty(J, self, name);
js_pushboolean(J, ref != NULL);
return 1;
}
@@ -77,28 +77,22 @@
{
js_Object *self = js_toobject(J, 0);
const char *name = js_tostring(J, 1);
- js_Property *ref = jsR_getownproperty(J, self, name);
- js_pushboolean(J, ref && !ref->dontenum);
+ 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, jsR_newcconstructor(J, jsB_Object, jsB_new_Object));
+ js_pushobject(J, J->Object_prototype);
{
- jsB_propn(J, "length", 1);
- js_pushobject(J, J->Object_prototype);
- {
- js_copy(J, -2);
- js_setproperty(J, -2, "constructor");
- 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");
+ 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/jsbstring.c
+++ b/jsbstring.c
@@ -1,11 +1,11 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
#include "jsutf.h"
static int jsB_new_String(js_State *J, int n)
{
- js_pushobject(J, jsR_newstring(J, n > 0 ? js_tostring(J, 0) : ""));
+ js_newstring(J, n > 0 ? js_tostring(J, 0) : "");
return 1;
}
@@ -93,21 +93,15 @@
{
J->String_prototype->u.string = "";
- js_pushobject(J, jsR_newcconstructor(J, jsB_String, jsB_new_String));
+ js_pushobject(J, J->String_prototype);
{
- 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);
- jsB_propf(J, "charAt", Sp_charAt, 1);
- jsB_propf(J, "charCodeAt", Sp_charCodeAt, 1);
- }
- js_setproperty(J, -2, "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);
+ }
+ 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,5 +1,5 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsbuiltin.h"
static int jsB_print(js_State *J, int argc)
@@ -42,7 +42,7 @@
static int jsB_parseFloat(js_State *J, int argc)
{
const char *s = js_tostring(J, 1);
- js_pushnumber(J, jsR_numberfromstring(J, s));
+ js_pushnumber(J, strtod(s, NULL));
return 1;
}
@@ -87,21 +87,21 @@
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);
+ J->Object_prototype = jsV_newobject(J, JS_COBJECT, NULL);
+ J->Array_prototype = jsV_newobject(J, JS_CARRAY, J->Object_prototype);
+ J->Function_prototype = jsV_newobject(J, JS_CCFUNCTION, J->Object_prototype);
+ J->Boolean_prototype = jsV_newobject(J, JS_CBOOLEAN, J->Object_prototype);
+ J->Number_prototype = jsV_newobject(J, JS_CNUMBER, J->Object_prototype);
+ J->String_prototype = jsV_newobject(J, JS_CSTRING, J->Object_prototype);
/* All the native error types */
- J->Error_prototype = jsR_newobject(J, JS_CERROR, J->Object_prototype);
- J->EvalError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
- J->RangeError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
- J->ReferenceError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
- J->SyntaxError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
- J->TypeError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
- J->URIError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
+ J->Error_prototype = jsV_newobject(J, JS_CERROR, J->Object_prototype);
+ J->EvalError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
+ J->RangeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
+ J->ReferenceError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
+ J->SyntaxError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
+ J->TypeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
+ J->URIError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
/* Create the constructors and fill out the prototype objects */
jsB_initobject(J);
--- a/jsdump.c
+++ b/jsdump.c
@@ -1,7 +1,7 @@
#include "jsi.h"
#include "jsparse.h"
#include "jscompile.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include <assert.h>
@@ -29,16 +29,16 @@
const char *jsP_aststring(js_AstType type)
{
- if (type < 0 || type > nelem(astname))
+ if (type > nelem(astname))
return "<unknown>";
return astname[type];
}
-const char *jsC_opcodestring(int type)
+const char *jsC_opcodestring(int opcode)
{
- if (type < 0 || type > nelem(opname))
+ if (opcode < 0 || opcode > nelem(opname))
return "<unknown>";
- return opname[type];
+ return opname[opcode];
}
static inline void pc(int c)
--- a/jsgc.c
+++ b/jsgc.c
@@ -1,6 +1,6 @@
#include "jsi.h"
#include "jscompile.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsrun.h"
static void jsG_markobject(js_State *J, int mark, js_Object *obj);
@@ -98,9 +98,25 @@
mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
+ jsG_markobject(J, mark, J->Object_prototype);
+ jsG_markobject(J, mark, J->Array_prototype);
+ jsG_markobject(J, mark, J->Function_prototype);
+ jsG_markobject(J, mark, J->Boolean_prototype);
+ jsG_markobject(J, mark, J->Number_prototype);
+ jsG_markobject(J, mark, J->String_prototype);
+
+ jsG_markobject(J, mark, J->Error_prototype);
+ jsG_markobject(J, mark, J->EvalError_prototype);
+ jsG_markobject(J, mark, J->RangeError_prototype);
+ jsG_markobject(J, mark, J->ReferenceError_prototype);
+ jsG_markobject(J, mark, J->SyntaxError_prototype);
+ jsG_markobject(J, mark, J->TypeError_prototype);
+ jsG_markobject(J, mark, J->URIError_prototype);
+
+ jsG_markobject(J, mark, J->G);
+
jsG_markstack(J, mark);
- if (J->E)
- jsG_markenvironment(J, mark, J->E);
+ jsG_markenvironment(J, mark, J->E);
prevnextenv = &J->gcenv;
for (env = J->gcenv; env; env = nextenv) {
--- a/jsi.h
+++ b/jsi.h
@@ -35,13 +35,9 @@
JS_NORETURN void jsR_throwTypeError(js_State *J, const char *message);
JS_NORETURN void jsR_throwURIError(js_State *J, const char *message);
-js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor);
-
-const char *jsR_stringfromnumber(js_State *J, double number);
-double jsR_numberfromstring(js_State *J, const char *string);
-
void js_newfunction(js_State *J, js_Function *function, js_Environment *scope);
void js_newscript(js_State *J, js_Function *function);
+
void js_dup(js_State *J);
void js_rot(js_State *J, int n);
void js_rot2(js_State *J);
--- a/jsobject.c
+++ /dev/null
@@ -1,112 +1,0 @@
-#include "jsi.h"
-#include "jscompile.h"
-#include "jsobject.h"
-#include "jsrun.h"
-#include "jsutf.h"
-
-static js_Object *jsR_newfunction(js_State *J, js_Function *function, js_Environment *scope)
-{
- js_Object *obj = jsR_newobject(J, JS_CFUNCTION, J->Function_prototype);
- obj->u.f.function = function;
- obj->u.f.scope = scope;
- return obj;
-}
-
-static js_Object *jsR_newscript(js_State *J, js_Function *function)
-{
- js_Object *obj = jsR_newobject(J, JS_CSCRIPT, NULL);
- obj->u.f.function = function;
- obj->u.f.scope = NULL;
- return obj;
-}
-
-static js_Object *jsR_newcfunction(js_State *J, js_CFunction cfunction)
-{
- js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, J->Function_prototype);
- obj->u.c.function = cfunction;
- obj->u.c.constructor = NULL;
- return obj;
-}
-
-js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor)
-{
- js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, J->Function_prototype);
- obj->u.c.function = cfunction;
- obj->u.c.constructor = cconstructor;
- return obj;
-}
-
-js_Object *jsR_newboolean(js_State *J, int v)
-{
- js_Object *obj = jsR_newobject(J, JS_CBOOLEAN, J->Boolean_prototype);
- obj->u.boolean = v;
- return obj;
-}
-
-js_Object *jsR_newnumber(js_State *J, double v)
-{
- js_Object *obj = jsR_newobject(J, JS_CNUMBER, J->Number_prototype);
- obj->u.number = v;
- return obj;
-}
-
-js_Object *jsR_newstring(js_State *J, const char *v)
-{
- js_Object *obj = jsR_newobject(J, JS_CSTRING, J->String_prototype);
- obj->u.string = v;
- {
- js_Property *ref;
- ref = jsR_setproperty(J, obj, "length");
- ref->value.type = JS_TNUMBER;
- ref->value.u.number = utflen(v);
- ref->readonly = 1;
- ref->dontenum = 1;
- ref->dontconf = 1;
- }
- return obj;
-}
-
-void js_newobject(js_State *J)
-{
- js_pushobject(J, jsR_newobject(J, JS_COBJECT, J->Object_prototype));
-}
-
-void js_newarray(js_State *J)
-{
- js_pushobject(J, jsR_newobject(J, JS_CARRAY, J->Array_prototype));
-}
-
-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");
- }
-}
-
-void js_newscript(js_State *J, js_Function *F)
-{
- js_pushobject(J, jsR_newscript(J, F));
-}
-
-void js_newcfunction(js_State *J, js_CFunction fun, int length)
-{
- js_pushobject(J, jsR_newcfunction(J, fun));
- {
- 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");
- }
-}
--- a/jsobject.h
+++ /dev/null
@@ -1,108 +1,0 @@
-#ifndef js_object_h
-#define js_object_h
-
-typedef enum js_Type js_Type;
-typedef enum js_Class js_Class;
-
-typedef struct js_Property js_Property;
-
-enum js_Type {
- JS_TUNDEFINED,
- JS_TNULL,
- JS_TBOOLEAN,
- JS_TNUMBER,
- JS_TSTRING,
- JS_TOBJECT,
-};
-
-enum js_Class {
- JS_COBJECT,
- JS_CARRAY,
- JS_CFUNCTION,
- JS_CSCRIPT, /* function created from global/eval code */
- JS_CCFUNCTION, /* built-in function */
- JS_CERROR,
- JS_CBOOLEAN,
- JS_CNUMBER,
- JS_CSTRING,
- JS_CREGEXP,
- JS_CDATE,
- JS_CMATH,
-};
-
-struct js_Value
-{
- js_Type type;
- union {
- int boolean;
- double number;
- const char *string;
- js_Object *object;
- } u;
-};
-
-struct js_Object
-{
- js_Class type;
- js_Property *properties;
- js_Object *prototype;
- union {
- int boolean;
- double number;
- const char *string;
- struct {
- js_Function *function;
- js_Environment *scope;
- } f;
- struct {
- js_CFunction function;
- js_CFunction constructor;
- } c;
- } u;
- js_Object *gcnext;
- int gcmark;
-};
-
-struct js_Property
-{
- const char *name;
- js_Property *left, *right;
- int level;
- unsigned short readonly, dontenum, dontconf;
- js_Value value;
-};
-
-js_Value js_tovalue(js_State *J, int idx);
-js_Value js_toprimitive(js_State *J, int idx, int hint);
-js_Object *js_toobject(js_State *J, int idx);
-
-void js_pushvalue(js_State *J, js_Value v);
-void js_pushobject(js_State *J, js_Object *v);
-
-/* jsvalue.c */
-int jsR_toboolean(js_State *J, const js_Value *v);
-double jsR_tonumber(js_State *J, const js_Value *v);
-const char *jsR_tostring(js_State *J, const js_Value *v);
-js_Object *jsR_toobject(js_State *J, const js_Value *v);
-js_Value jsR_toprimitive(js_State *J, const js_Value *v, int preferred);
-
-/* jsproperty.c */
-js_Object *jsR_newobject(js_State *J, js_Class type, js_Object *prototype);
-js_Property *jsR_getownproperty(js_State *J, js_Object *obj, const char *name);
-js_Property *jsR_getproperty(js_State *J, js_Object *obj, const char *name);
-js_Property *jsR_setproperty(js_State *J, js_Object *obj, const char *name);
-js_Property *jsR_nextproperty(js_State *J, js_Object *obj, const char *name);
-
-/* jsobject.c */
-js_Object *jsR_newboolean(js_State *J, int v);
-js_Object *jsR_newnumber(js_State *J, double v);
-js_Object *jsR_newstring(js_State *J, const char *v);
-
-/* jsrun.c */
-void jsR_pushobject(js_State *J, js_Object *v);
-js_Object *js_toobject(js_State *J, int idx);
-
-void js_dumpobject(js_State *J, js_Object *obj);
-void js_dumpvalue(js_State *J, js_Value v);
-
-#endif
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -1,5 +1,5 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jsvalue.h"
/*
Use an AA-tree to quickly look up properties in objects:
@@ -26,9 +26,7 @@
node->name = js_intern(J, name);
node->left = node->right = &sentinel;
node->level = 1;
- node->readonly = 0;
- node->dontenum = 0;
- node->dontconf = 0;
+ node->atts = 0;
node->value.type = JS_TUNDEFINED;
node->value.u.number = 0;
return node;
@@ -131,7 +129,7 @@
return parent;
}
-js_Object *jsR_newobject(js_State *J, js_Class type, js_Object *prototype)
+js_Object *jsV_newobject(js_State *J, js_Class type, js_Object *prototype)
{
js_Object *obj = calloc(sizeof(js_Object), 1);
obj->gcmark = 0;
@@ -145,12 +143,12 @@
return obj;
}
-js_Property *jsR_getownproperty(js_State *J, js_Object *obj, const char *name)
+js_Property *jsV_getownproperty(js_State *J, js_Object *obj, const char *name)
{
return lookup(obj->properties, name);
}
-js_Property *jsR_getproperty(js_State *J, js_Object *obj, const char *name)
+js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name)
{
do {
js_Property *ref = lookup(obj->properties, name);
@@ -161,7 +159,7 @@
return NULL;
}
-js_Property *jsR_setproperty(js_State *J, js_Object *obj, const char *name)
+js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name)
{
js_Property *result;
obj->properties = insert(J, obj->properties, name, &result);
@@ -168,7 +166,7 @@
return result;
}
-js_Property *jsR_nextproperty(js_State *J, js_Object *obj, const char *name)
+js_Property *jsV_nextproperty(js_State *J, js_Object *obj, const char *name)
{
if (!name)
return lookupfirst(obj->properties);
--- a/jsrun.c
+++ b/jsrun.c
@@ -1,6 +1,6 @@
#include "jsi.h"
#include "jscompile.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsrun.h"
static void jsR_run(js_State *J, js_Function *F);
@@ -145,42 +145,42 @@
int js_toboolean(js_State *J, int idx)
{
- return jsR_toboolean(J, stackidx(J, idx));
+ return jsV_toboolean(J, stackidx(J, idx));
}
double js_tonumber(js_State *J, int idx)
{
- return jsR_tonumber(J, stackidx(J, idx));
+ return jsV_tonumber(J, stackidx(J, idx));
}
double js_tointeger(js_State *J, int idx)
{
- return tointeger(jsR_tonumber(J, stackidx(J, idx)));
+ return tointeger(jsV_tonumber(J, stackidx(J, idx)));
}
int js_toint32(js_State *J, int idx)
{
- return toint32(jsR_tonumber(J, stackidx(J, idx)));
+ return toint32(jsV_tonumber(J, stackidx(J, idx)));
}
unsigned int js_touint32(js_State *J, int idx)
{
- return touint32(jsR_tonumber(J, stackidx(J, idx)));
+ return touint32(jsV_tonumber(J, stackidx(J, idx)));
}
const char *js_tostring(js_State *J, int idx)
{
- return jsR_tostring(J, stackidx(J, idx));
+ return jsV_tostring(J, stackidx(J, idx));
}
js_Object *js_toobject(js_State *J, int idx)
{
- return jsR_toobject(J, stackidx(J, idx));
+ return jsV_toobject(J, stackidx(J, idx));
}
js_Value js_toprimitive(js_State *J, int idx, int hint)
{
- return jsR_toprimitive(J, stackidx(J, idx), hint);
+ return jsV_toprimitive(J, stackidx(J, idx), hint);
}
/* Stack manipulation */
@@ -256,7 +256,7 @@
void js_getglobal(js_State *J, const char *name)
{
- js_Property *ref = jsR_getproperty(J, J->G, name);
+ js_Property *ref = jsV_getproperty(J, J->G, name);
if (ref)
js_pushvalue(J, ref->value);
else
@@ -265,7 +265,7 @@
void js_setglobal(js_State *J, const char *name)
{
- js_Property *ref = jsR_setproperty(J, J->G, name);
+ js_Property *ref = jsV_setproperty(J, J->G, name);
if (ref)
ref->value = js_tovalue(J, -1);
js_pop(J, 1);
@@ -274,7 +274,7 @@
void js_getownproperty(js_State *J, int idx, const char *name)
{
js_Object *obj = js_toobject(J, idx);
- js_Property *ref = jsR_getownproperty(J, obj, name);
+ js_Property *ref = jsV_getownproperty(J, obj, name);
if (ref)
js_pushvalue(J, ref->value);
else
@@ -284,7 +284,7 @@
void js_getproperty(js_State *J, int idx, const char *name)
{
js_Object *obj = js_toobject(J, idx);
- js_Property *ref = jsR_getproperty(J, obj, name);
+ js_Property *ref = jsV_getproperty(J, obj, name);
if (ref)
js_pushvalue(J, ref->value);
else
@@ -294,7 +294,7 @@
void js_setproperty(js_State *J, int idx, const char *name)
{
js_Object *obj = js_toobject(J, idx);
- js_Property *ref = jsR_setproperty(J, obj, name);
+ js_Property *ref = jsV_setproperty(J, obj, name);
if (ref)
ref->value = js_tovalue(J, -1);
js_pop(J, 1);
@@ -303,7 +303,7 @@
int js_nextproperty(js_State *J, int idx)
{
js_Object *obj = js_toobject(J, idx);
- js_Property *ref = jsR_nextproperty(J, obj, js_tostring(J, -1));
+ js_Property *ref = jsV_nextproperty(J, obj, js_tostring(J, -1));
js_pop(J, 1);
if (ref) {
js_pushliteral(J, ref->name);
@@ -330,7 +330,7 @@
static js_Property *js_decvar(js_State *J, const char *name)
{
- return jsR_setproperty(J, J->E->variables, name);
+ return jsV_setproperty(J, J->E->variables, name);
}
static js_Property *js_getvar(js_State *J, const char *name)
@@ -337,7 +337,7 @@
{
js_Environment *E = J->E;
do {
- js_Property *ref = jsR_getproperty(J, E->variables, name);
+ js_Property *ref = jsV_getproperty(J, E->variables, name);
if (ref)
return ref;
E = E->outer;
@@ -349,12 +349,12 @@
{
js_Environment *E = J->E;
do {
- js_Property *ref = jsR_getproperty(J, E->variables, name);
+ js_Property *ref = jsV_getproperty(J, E->variables, name);
if (ref)
return ref;
E = E->outer;
} while (E);
- return jsR_setproperty(J, J->G, name);
+ return jsV_setproperty(J, J->G, name);
}
/* Function calls */
@@ -366,7 +366,7 @@
saveE = J->E;
- J->E = jsR_newenvironment(J, jsR_newobject(J, JS_COBJECT, NULL), scope);
+ J->E = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
for (i = 0; i < n; i++) {
js_Property *ref = js_decvar(J, F->params[i]);
if (i < n)
@@ -439,7 +439,7 @@
js_pop(J, 1);
/* create a new object with above prototype, and shift it into the 'this' slot */
- js_pushobject(J, jsR_newobject(J, JS_COBJECT, prototype));
+ js_pushobject(J, jsV_newobject(J, JS_COBJECT, prototype));
if (n > 0)
js_rot(J, n + 1);
@@ -585,7 +585,7 @@
case OP_IN:
str = js_tostring(J, -2);
obj = js_toobject(J, -1);
- ref = jsR_getproperty(J, obj, str);
+ ref = jsV_getproperty(J, obj, str);
js_pop(J, 2);
js_pushboolean(J, ref != NULL);
break;
@@ -596,7 +596,7 @@
js_getproperty(J, -1, str);
obj = js_toobject(J, -2);
- ref = jsR_getproperty(J, obj, str);
+ ref = jsV_getproperty(J, obj, str);
js_pop(J, 2);
if (ref)
js_pushvalue(J, ref->value);
@@ -607,7 +607,7 @@
case OP_SETPROP:
obj = js_toobject(J, -3);
str = js_tostring(J, -2);
- ref = jsR_setproperty(J, obj, str);
+ ref = jsV_setproperty(J, obj, str);
if (ref)
ref->value = js_tovalue(J, -1);
js_rot3pop2(J);
@@ -622,10 +622,10 @@
else
str = js_tostring(J, -1);
- ref = jsR_nextproperty(J, obj, str);
+ ref = jsV_nextproperty(J, obj, str);
if (!ref && obj->prototype) {
obj = obj->prototype;
- ref = jsR_nextproperty(J, obj, NULL);
+ ref = jsV_nextproperty(J, obj, NULL);
}
js_pop(J, 2);
--- a/jsstate.c
+++ b/jsstate.c
@@ -1,7 +1,7 @@
#include "jsi.h"
#include "jsparse.h"
#include "jscompile.h"
-#include "jsobject.h"
+#include "jsvalue.h"
#include "jsrun.h"
#include "jsbuiltin.h"
@@ -107,7 +107,7 @@
J->gcmark = 1;
- J->G = jsR_newobject(J, JS_COBJECT, NULL);
+ J->G = jsV_newobject(J, JS_COBJECT, NULL);
J->E = jsR_newenvironment(J, J->G, NULL);
jsB_init(J);
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -1,24 +1,11 @@
#include "jsi.h"
-#include "jsobject.h"
+#include "jscompile.h"
+#include "jsvalue.h"
+#include "jsutf.h"
-const char *jsR_stringfromnumber(js_State *J, double n)
+/* obj.toString() */
+static int jsV_toString(js_State *J, js_Object *obj)
{
- char buf[32];
- if (isnan(n)) return "NaN";
- if (isinf(n)) return n < 0 ? "-Infinity" : "Infinity";
- if (n == 0) return "0";
- sprintf(buf, "%.17g", n); /* DBL_DECIMAL_DIG == 17 */
- return js_intern(J, buf);
-}
-
-double jsR_numberfromstring(js_State *J, const char *s)
-{
- /* TODO: use lexer to parse string grammar */
- return strtod(s, NULL);
-}
-
-static int jsR_toString(js_State *J, js_Object *obj)
-{
js_pushobject(J, obj);
js_getproperty(J, -1, "toString");
if (js_iscallable(J, -1)) {
@@ -33,7 +20,8 @@
return 0;
}
-static int jsR_valueOf(js_State *J, js_Object *obj)
+/* obj.valueOf() */
+static int jsV_valueOf(js_State *J, js_Object *obj)
{
js_pushobject(J, obj);
js_getproperty(J, -1, "valueOf");
@@ -49,7 +37,8 @@
return 0;
}
-js_Value jsR_toprimitive(js_State *J, const js_Value *v, int preferred)
+/* ToPrimitive() on a value */
+js_Value jsV_toprimitive(js_State *J, const js_Value *v, int preferred)
{
js_Value vv;
js_Object *obj;
@@ -63,13 +52,13 @@
preferred = obj->type == JS_CDATE ? JS_HSTRING : JS_HNUMBER;
if (preferred == JS_HSTRING) {
- if (jsR_toString(J, obj) || jsR_valueOf(J, obj)) {
+ if (jsV_toString(J, obj) || jsV_valueOf(J, obj)) {
vv = js_tovalue(J, -1);
js_pop(J, 1);
return vv;
}
} else {
- if (jsR_valueOf(J, obj) || jsR_toString(J, obj)) {
+ if (jsV_valueOf(J, obj) || jsV_toString(J, obj)) {
vv = js_tovalue(J, -1);
js_pop(J, 1);
return vv;
@@ -78,7 +67,8 @@
jsR_throwTypeError(J, "cannot convert object to primitive");
}
-int jsR_toboolean(js_State *J, const js_Value *v)
+/* ToBoolean() on a value */
+int jsV_toboolean(js_State *J, const js_Value *v)
{
switch (v->type) {
case JS_TUNDEFINED: return 0;
@@ -91,60 +81,199 @@
return 0;
}
-double jsR_tonumber(js_State *J, const js_Value *v)
+/* ToNumber() on a string */
+double jsV_stringtonumber(js_State *J, const char *s)
{
+ /* TODO: use lexer to parse string grammar */
+ return strtod(s, NULL);
+}
+
+/* ToNumber() on a value */
+double jsV_tonumber(js_State *J, const js_Value *v)
+{
switch (v->type) {
case JS_TUNDEFINED: return NAN;
case JS_TNULL: return 0;
case JS_TBOOLEAN: return v->u.boolean;
case JS_TNUMBER: return v->u.number;
- case JS_TSTRING: return jsR_numberfromstring(J, v->u.string);
+ case JS_TSTRING: return jsV_stringtonumber(J, v->u.string);
case JS_TOBJECT:
{
- js_Value vv = jsR_toprimitive(J, v, JS_HNUMBER);
- return jsR_tonumber(J, &vv);
+ js_Value vv = jsV_toprimitive(J, v, JS_HNUMBER);
+ return jsV_tonumber(J, &vv);
}
}
return 0;
}
-const char *jsR_tostring(js_State *J, const js_Value *v)
+/* ToString() on a number */
+const char *jsV_numbertostring(js_State *J, double n)
{
+ char buf[32];
+ if (isnan(n)) return "NaN";
+ if (isinf(n)) return n < 0 ? "-Infinity" : "Infinity";
+ if (n == 0) return "0";
+ sprintf(buf, "%.17g", n); /* DBL_DECIMAL_DIG == 17 */
+ return js_intern(J, buf);
+}
+
+/* ToString() on a value */
+const char *jsV_tostring(js_State *J, const js_Value *v)
+{
switch (v->type) {
case JS_TUNDEFINED: return "undefined";
case JS_TNULL: return "null";
case JS_TBOOLEAN: return v->u.boolean ? "true" : "false";
- case JS_TNUMBER: return jsR_stringfromnumber(J, v->u.number);
+ case JS_TNUMBER: return jsV_numbertostring(J, v->u.number);
case JS_TSTRING: return v->u.string;
case JS_TOBJECT:
{
- js_Value vv = jsR_toprimitive(J, v, JS_HSTRING);
- return jsR_tostring(J, &vv);
+ js_Value vv = jsV_toprimitive(J, v, JS_HSTRING);
+ return jsV_tostring(J, &vv);
}
}
return "undefined";
}
-js_Object *jsR_toobject(js_State *J, const js_Value *v)
+/* Objects */
+
+static js_Object *jsV_newboolean(js_State *J, int v)
{
+ js_Object *obj = jsV_newobject(J, JS_CBOOLEAN, J->Boolean_prototype);
+ obj->u.boolean = v;
+ return obj;
+}
+
+static js_Object *jsV_newnumber(js_State *J, double v)
+{
+ js_Object *obj = jsV_newobject(J, JS_CNUMBER, J->Number_prototype);
+ obj->u.number = v;
+ return obj;
+}
+
+static js_Object *jsV_newstring(js_State *J, const char *v)
+{
+ js_Object *obj = jsV_newobject(J, JS_CSTRING, J->String_prototype);
+ obj->u.string = v;
+ {
+ js_Property *ref;
+ ref = jsV_setproperty(J, obj, "length");
+ ref->value.type = JS_TNUMBER;
+ ref->value.u.number = utflen(v);
+ ref->atts = JS_READONLY | JS_DONTENUM | JS_DONTDELETE;
+ }
+ return obj;
+}
+
+/* ToObject() on a value */
+js_Object *jsV_toobject(js_State *J, const js_Value *v)
+{
switch (v->type) {
case JS_TUNDEFINED: jsR_throwTypeError(J, "cannot convert undefined to object");
case JS_TNULL: jsR_throwTypeError(J, "cannot convert null to object");
- case JS_TBOOLEAN: return jsR_newboolean(J, v->u.boolean);
- case JS_TNUMBER: return jsR_newnumber(J, v->u.number);
- case JS_TSTRING: return jsR_newstring(J, v->u.string);
+ case JS_TBOOLEAN: return jsV_newboolean(J, v->u.boolean);
+ case JS_TNUMBER: return jsV_newnumber(J, v->u.number);
+ case JS_TSTRING: return jsV_newstring(J, v->u.string);
case JS_TOBJECT: return v->u.object;
}
jsR_throwTypeError(J, "cannot convert value to object");
}
+void js_newobject(js_State *J)
+{
+ js_pushobject(J, jsV_newobject(J, JS_COBJECT, J->Object_prototype));
+}
+
+void js_newarray(js_State *J)
+{
+ js_pushobject(J, jsV_newobject(J, JS_CARRAY, J->Array_prototype));
+}
+
+void js_newboolean(js_State *J, int v)
+{
+ js_pushobject(J, jsV_newboolean(J, v));
+}
+
+void js_newnumber(js_State *J, double v)
+{
+ js_pushobject(J, jsV_newnumber(J, v));
+}
+
+void js_newstring(js_State *J, const char *v)
+{
+ js_pushobject(J, jsV_newstring(J, v));
+}
+
+void js_newfunction(js_State *J, js_Function *fun, js_Environment *scope)
+{
+ js_Object *obj = jsV_newobject(J, JS_CFUNCTION, J->Function_prototype);
+ obj->u.f.function = fun;
+ obj->u.f.scope = scope;
+ js_pushobject(J, obj);
+ {
+ js_pushnumber(J, fun->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 *fun)
+{
+ js_Object *obj = jsV_newobject(J, JS_CSCRIPT, NULL);
+ obj->u.f.function = fun;
+ obj->u.f.scope = NULL;
+ js_pushobject(J, obj);
+}
+
+void js_newcfunction(js_State *J, js_CFunction cfun, int length)
+{
+ js_Object *obj = jsV_newobject(J, JS_CCFUNCTION, J->Function_prototype);
+ obj->u.c.function = cfun;
+ obj->u.c.constructor = NULL;
+ js_pushobject(J, obj);
+ {
+ 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");
+ }
+}
+
+/* prototype -- constructor */
+void js_newcconstructor(js_State *J, js_CFunction cfun, js_CFunction ccon)
+{
+ js_Object *obj = jsV_newobject(J, JS_CCFUNCTION, J->Function_prototype);
+ obj->u.c.function = cfun;
+ obj->u.c.constructor = ccon;
+ js_pushobject(J, obj); /* proto obj */
+ {
+ js_pushnumber(J, 1);
+ js_setproperty(J, -2, "length");
+ js_rot2(J); /* obj proto */
+ js_copy(J, -2); /* obj proto obj */
+ js_setproperty(J, -2, "constructor");
+ js_setproperty(J, -2, "prototype");
+ }
+}
+
+/* Non-trivial operations on values. These are implemented using the stack. */
+
void js_concat(js_State *J)
{
js_Value va = js_toprimitive(J, -2, JS_HNONE);
js_Value vb = js_toprimitive(J, -1, JS_HNONE);
if (va.type == JS_TSTRING || vb.type == JS_TSTRING) {
- const char *sa = jsR_tostring(J, &va);
- const char *sb = jsR_tostring(J, &vb);
+ const char *sa = jsV_tostring(J, &va);
+ const char *sb = jsV_tostring(J, &vb);
char *sab = malloc(strlen(sa) + strlen(sb) + 1);
strcpy(sab, sa);
strcat(sab, sb);
@@ -152,8 +281,8 @@
js_pushstring(J, sab);
free(sab);
} else {
- double x = jsR_tonumber(J, &va);
- double y = jsR_tonumber(J, &vb);
+ double x = jsV_tonumber(J, &va);
+ double y = jsV_tonumber(J, &vb);
js_pop(J, 2);
js_pushnumber(J, x + y);
}
@@ -167,8 +296,8 @@
if (va.type == JS_TSTRING && vb.type == JS_TSTRING) {
return strcmp(va.u.string, va.u.string);
} else {
- double x = jsR_tonumber(J, &va);
- double y = jsR_tonumber(J, &vb);
+ double x = jsV_tonumber(J, &va);
+ double y = jsV_tonumber(J, &vb);
return x < y ? -1 : x > y ? 1 : 0;
}
}
@@ -194,16 +323,16 @@
if (va.type == JS_TUNDEFINED && vb.type == JS_TNULL) return 1;
if (va.type == JS_TNUMBER && (vb.type == JS_TSTRING || vb.type == JS_TBOOLEAN))
- return va.u.number == jsR_tonumber(J, &vb);
+ return va.u.number == jsV_tonumber(J, &vb);
if ((va.type == JS_TSTRING || va.type == JS_TBOOLEAN) && vb.type == JS_TNUMBER)
- return jsR_tonumber(J, &va) == vb.u.number;
+ return jsV_tonumber(J, &va) == vb.u.number;
if ((va.type == JS_TSTRING || va.type == JS_TNUMBER) && vb.type == JS_TOBJECT) {
- vb = jsR_toprimitive(J, &vb, JS_HNONE);
+ vb = jsV_toprimitive(J, &vb, JS_HNONE);
goto retry;
}
if (va.type == JS_TOBJECT && (vb.type == JS_TSTRING || vb.type == JS_TNUMBER)) {
- va = jsR_toprimitive(J, &va, JS_HNONE);
+ va = jsV_toprimitive(J, &va, JS_HNONE);
goto retry;
}
--- /dev/null
+++ b/jsvalue.h
@@ -1,0 +1,103 @@
+#ifndef js_object_h
+#define js_object_h
+
+typedef enum js_Type js_Type;
+typedef enum js_Class js_Class;
+
+typedef struct js_Property js_Property;
+
+enum js_Type {
+ JS_TUNDEFINED,
+ JS_TNULL,
+ JS_TBOOLEAN,
+ JS_TNUMBER,
+ JS_TSTRING,
+ JS_TOBJECT,
+};
+
+enum js_Class {
+ JS_COBJECT,
+ JS_CARRAY,
+ JS_CFUNCTION,
+ JS_CSCRIPT, /* function created from global/eval code */
+ JS_CCFUNCTION, /* built-in function */
+ JS_CERROR,
+ JS_CBOOLEAN,
+ JS_CNUMBER,
+ JS_CSTRING,
+ JS_CREGEXP,
+ JS_CDATE,
+ JS_CMATH,
+};
+
+struct js_Value
+{
+ js_Type type;
+ union {
+ int boolean;
+ double number;
+ const char *string;
+ js_Object *object;
+ } u;
+};
+
+struct js_Object
+{
+ js_Class type;
+ js_Property *properties;
+ js_Object *prototype;
+ union {
+ int boolean;
+ double number;
+ const char *string;
+ struct {
+ js_Function *function;
+ js_Environment *scope;
+ } f;
+ struct {
+ js_CFunction function;
+ js_CFunction constructor;
+ } c;
+ } u;
+ js_Object *gcnext;
+ int gcmark;
+};
+
+struct js_Property
+{
+ const char *name;
+ js_Property *left, *right;
+ int level;
+ int atts;
+ js_Value value;
+};
+
+/* jsrun.c */
+js_Value js_tovalue(js_State *J, int idx);
+js_Value js_toprimitive(js_State *J, int idx, int hint);
+js_Object *js_toobject(js_State *J, int idx);
+void js_pushvalue(js_State *J, js_Value v);
+void js_pushobject(js_State *J, js_Object *v);
+
+/* jsvalue.c */
+int jsV_toboolean(js_State *J, const js_Value *v);
+double jsV_tonumber(js_State *J, const js_Value *v);
+const char *jsV_tostring(js_State *J, const js_Value *v);
+js_Object *jsV_toobject(js_State *J, const js_Value *v);
+js_Value jsV_toprimitive(js_State *J, const js_Value *v, int preferred);
+
+const char *jsV_numbertostring(js_State *J, double number);
+double jsV_stringtonumber(js_State *J, const char *string);
+
+/* jsproperty.c */
+js_Object *jsV_newobject(js_State *J, js_Class type, js_Object *prototype);
+js_Property *jsV_getownproperty(js_State *J, js_Object *obj, const char *name);
+js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name);
+js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name);
+js_Property *jsV_nextproperty(js_State *J, js_Object *obj, const char *name);
+
+/* jsdump.c */
+void js_dumpobject(js_State *J, js_Object *obj);
+void js_dumpvalue(js_State *J, js_Value v);
+
+#endif