shithub: libmujs

Download patch

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;