ref: f487a7db10164e68f2f7d02d2bdc1f0b1aa2e8ef
parent: 5ce44f9d4a73250fefc15a6102e60773f7b3b8db
author: Tor Andersson <tor@ccxvii.net>
date: Fri Jan 17 14:41:41 EST 2014
Set prototype internal property when creating objects.
--- /dev/null
+++ b/jsbuiltin.c
@@ -1,0 +1,114 @@
+#include "js.h"
+#include "jsobject.h"
+#include "jsrun.h"
+#include "jsstate.h"
+
+static int jsB_print(js_State *J, int argc)
+{
+ 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;
+}
+
+static int jsB_eval(js_State *J, int argc)
+{
+ const char *s;
+
+ if (!js_isstring(J, -1))
+ return 1;
+
+ // FIXME: return value if eval string is an expression
+
+ s = js_tostring(J, -1);
+ if (jsR_loadscript(J, "(eval)", s))
+ jsR_error(J, "SyntaxError (eval)");
+
+ js_dup(J, 0); /* copy this */
+ js_call(J, 0);
+ return 1;
+}
+
+static int jsB_Object(js_State *J, int n) { return 0; }
+static int jsB_Array(js_State *J, int n) { return 0; }
+static int jsB_Function(js_State *J, int n) { return 0; }
+static int jsB_Boolean(js_State *J, int n) { return 0; }
+static int jsB_Number(js_State *J, int n) { return 0; }
+static int jsB_String(js_State *J, int n) { return 0; }
+
+static void jsB_initobject(js_State *J)
+{
+ J->Object_prototype = jsR_newobject(J, JS_COBJECT, NULL);
+ js_pushcfunction(J, jsB_Object);
+ js_pushobject(J, J->Object_prototype);
+ js_setproperty(J, -2, "prototype");
+ js_setglobal(J, "Object");
+}
+
+static void jsB_initarray(js_State *J)
+{
+ J->Array_prototype = jsR_newobject(J, JS_COBJECT, NULL);
+ js_pushcfunction(J, jsB_Array);
+ js_pushobject(J, J->Array_prototype);
+ js_setproperty(J, -2, "prototype");
+ js_setglobal(J, "Array");
+}
+
+static void jsB_initfunction(js_State *J)
+{
+ J->Function_prototype = jsR_newobject(J, JS_COBJECT, NULL);
+ js_pushcfunction(J, jsB_Function);
+ js_pushobject(J, J->Function_prototype);
+ js_setproperty(J, -2, "prototype");
+ js_setglobal(J, "Function");
+}
+
+static void jsB_initboolean(js_State *J)
+{
+ J->Boolean_prototype = jsR_newobject(J, JS_COBJECT, NULL);
+ js_pushcfunction(J, jsB_Boolean);
+ js_pushobject(J, J->Boolean_prototype);
+ js_setproperty(J, -2, "prototype");
+ js_setglobal(J, "Boolean");
+}
+
+static void jsB_initnumber(js_State *J)
+{
+ J->Number_prototype = jsR_newobject(J, JS_COBJECT, NULL);
+ js_pushcfunction(J, jsB_Number);
+ js_pushobject(J, J->Number_prototype);
+ js_setproperty(J, -2, "prototype");
+ js_setglobal(J, "Number");
+}
+
+static void jsB_initstring(js_State *J)
+{
+ J->String_prototype = jsR_newobject(J, JS_COBJECT, NULL);
+ js_pushcfunction(J, jsB_String);
+ js_pushobject(J, J->String_prototype);
+ js_setproperty(J, -2, "prototype");
+ js_setglobal(J, "String");
+}
+
+static void jsB_register(js_State *J, const char *name, js_CFunction cfun)
+{
+ js_pushcfunction(J, cfun);
+ js_setglobal(J, name);
+}
+
+void jsB_init(js_State *J)
+{
+ jsB_initobject(J);
+ jsB_initarray(J);
+ jsB_initfunction(J);
+ jsB_initboolean(J);
+ jsB_initnumber(J);
+ jsB_initstring(J);
+
+ jsB_register(J, "eval", jsB_eval);
+ jsB_register(J, "print", jsB_print);
+}
--- a/jsobject.c
+++ b/jsobject.c
@@ -1,9 +1,10 @@
#include "js.h"
#include "jsobject.h"
+#include "jsstate.h"
js_Object *jsR_newfunction(js_State *J, js_Function *function, js_Environment *scope)
{
- js_Object *obj = jsR_newobject(J, JS_CFUNCTION);
+ js_Object *obj = jsR_newobject(J, JS_CFUNCTION, J->Function_prototype);
obj->function = function;
obj->scope = scope;
return obj;
@@ -11,7 +12,7 @@
js_Object *jsR_newscript(js_State *J, js_Function *function)
{
- js_Object *obj = jsR_newobject(J, JS_CSCRIPT);
+ js_Object *obj = jsR_newobject(J, JS_CSCRIPT, NULL);
obj->function = function;
return obj;
}
@@ -18,7 +19,7 @@
js_Object *jsR_newcfunction(js_State *J, js_CFunction cfunction)
{
- js_Object *obj = jsR_newobject(J, JS_CCFUNCTION);
+ js_Object *obj = jsR_newobject(J, JS_CCFUNCTION, NULL);
obj->cfunction = cfunction;
return obj;
}
@@ -25,7 +26,7 @@
js_Object *jsR_newboolean(js_State *J, int v)
{
- js_Object *obj = jsR_newobject(J, JS_CBOOLEAN);
+ js_Object *obj = jsR_newobject(J, JS_CBOOLEAN, J->Boolean_prototype);
obj->primitive.boolean = v;
return obj;
}
@@ -32,7 +33,7 @@
js_Object *jsR_newnumber(js_State *J, double v)
{
- js_Object *obj = jsR_newobject(J, JS_CNUMBER);
+ js_Object *obj = jsR_newobject(J, JS_CNUMBER, J->Number_prototype);
obj->primitive.number = v;
return obj;
}
@@ -39,7 +40,7 @@
js_Object *jsR_newstring(js_State *J, const char *v)
{
- js_Object *obj = jsR_newobject(J, JS_CSTRING);
+ js_Object *obj = jsR_newobject(J, JS_CSTRING, J->String_prototype);
obj->primitive.string = v;
return obj;
}
--- a/jsobject.h
+++ b/jsobject.h
@@ -86,7 +86,7 @@
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 *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);
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -129,12 +129,12 @@
return parent;
}
-js_Object *jsR_newobject(js_State *J, js_Class type)
+js_Object *jsR_newobject(js_State *J, js_Class type, js_Object *prototype)
{
js_Object *obj = malloc(sizeof(js_Object));
obj->type = type;
obj->properties = &sentinel;
- obj->prototype = NULL;
+ obj->prototype = prototype;
obj->primitive.number = 0;
obj->scope = NULL;
obj->function = NULL;
--- a/jsrun.c
+++ b/jsrun.c
@@ -109,12 +109,12 @@
void js_newobject(js_State *J)
{
- js_pushobject(J, jsR_newobject(J, JS_COBJECT));
+ 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));
+ js_pushobject(J, jsR_newobject(J, JS_CARRAY, J->Array_prototype));
}
void js_pushcfunction(js_State *J, js_CFunction v)
@@ -334,7 +334,7 @@
saveE = J->E;
- J->E = jsR_newenvironment(J, jsR_newobject(J, JS_COBJECT), scope);
+ J->E = jsR_newenvironment(J, jsR_newobject(J, JS_COBJECT, NULL), scope);
for (i = 0; i < n; i++) {
js_Property *ref = js_decvar(J, F->params[i]);
if (i < n)
@@ -392,7 +392,7 @@
printf("stack {\n");
for (i = 0; i < top; ++i) {
putchar(i == bot ? '>' : ' ');
- printf("% 3d: ", i);
+ printf("% 4d: ", i);
js_dumpvalue(J, stack[i]);
putchar('\n');
}
@@ -523,15 +523,22 @@
case OP_NEXTPROP:
obj = js_toobject(J, -2);
if (js_isundefined(J, -1))
- ref = jsR_nextproperty(J, obj, NULL);
+ str = NULL;
else
- ref = jsR_nextproperty(J, obj, js_tostring(J, -1));
+ str = js_tostring(J, -1);
+
+ ref = jsR_nextproperty(J, obj, str);
+ if (!ref && obj->prototype) {
+ obj = obj->prototype;
+ ref = jsR_nextproperty(J, obj, NULL);
+ }
+
+ js_pop(J, 2);
if (ref) {
- js_pop(J, 1);
+ js_pushobject(J, obj);
js_pushliteral(J, ref->name);
js_pushboolean(J, 1);
} else {
- js_pop(J, 2);
js_pushboolean(J, 0);
}
break;
--- a/jsrun.h
+++ b/jsrun.h
@@ -7,9 +7,10 @@
js_Object *variables;
};
+void jsB_init(js_State *J);
js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer);
-
int jsR_loadscript(js_State *J, const char *filename, const char *source);
+void jsR_error(js_State *J, const char *fmt, ...);
void js_call(js_State *J, int n);
--- a/jsstate.c
+++ b/jsstate.c
@@ -74,49 +74,15 @@
return rv;
}
-static int jsB_print(js_State *J, int argc)
-{
- 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;
-}
-
-static int jsB_eval(js_State *J, int argc)
-{
- const char *s;
-
- if (!js_isstring(J, -1))
- return 1;
-
- // FIXME: return value if eval string is an expression
-
- s = js_tostring(J, -1);
- if (jsR_loadscript(J, "(eval)", s))
- jsR_error(J, "SyntaxError (eval)");
-
- js_dup(J, 0); /* copy this */
- js_call(J, 0);
- return 1;
-}
-
js_State *js_newstate(void)
{
js_State *J = malloc(sizeof *J);
memset(J, 0, sizeof(*J));
- J->G = jsR_newobject(J, JS_COBJECT);
+ J->G = jsR_newobject(J, JS_COBJECT, NULL);
J->E = jsR_newenvironment(J, J->G, NULL);
- js_pushcfunction(J, jsB_eval);
- js_setglobal(J, "eval");
-
- js_pushcfunction(J, jsB_print);
- js_setglobal(J, "print");
+ jsB_init(J);
return J;
}
--- a/jsstate.h
+++ b/jsstate.h
@@ -29,6 +29,13 @@
int strict;
/* runtime */
+ js_Object *Object_prototype;
+ js_Object *Array_prototype;
+ js_Object *Function_prototype;
+ js_Object *Boolean_prototype;
+ js_Object *Number_prototype;
+ js_Object *String_prototype;
+
js_Object *G;
js_Environment *E;