shithub: libmujs

Download patch

ref: b595422da9eb0260f2457cbf30e3a5f69de76029
parent: 56042de82bbb4f4cee4fbb1e352a45d3acf134b2
author: Tor Andersson <[email protected]>
date: Thu Jan 16 22:03:10 EST 2014

Add object property accessor functions to public API.

--- a/jsobject.h
+++ b/jsobject.h
@@ -79,6 +79,7 @@
 
 /* jsproperty.c */
 js_Object *jsR_newobject(js_State *J, js_Class type);
+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);
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -142,9 +142,20 @@
 	return obj;
 }
 
-js_Property *jsR_getproperty(js_State *J, js_Object *obj, const char *name)
+js_Property *jsR_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)
+{
+	do {
+		js_Property *ref = lookup(obj->properties, name);
+		if (ref)
+			return ref;
+		obj = obj->prototype;
+	} while (obj);
+	return NULL;
 }
 
 js_Property *jsR_setproperty(js_State *J, js_Object *obj, const char *name)
--- a/jsrun.c
+++ b/jsrun.c
@@ -5,22 +5,12 @@
 #include "jsrun.h"
 #include "jsstate.h"
 
+static void jsR_run(js_State *J, js_Function *F, js_Environment *E);
+
 static js_Value stack[256];
 static int top = 0;
 static int bot = 0;
 
-static void jsR_run(js_State *J, js_Function *F, js_Environment *E);
-
-static void js_dumpstack(js_State *J)
-{
-	int i;
-	for (i = 0; i < top; ++i) {
-		printf("stack %d: ", i);
-		js_dumpvalue(J, stack[i]);
-		putchar('\n');
-	}
-}
-
 static inline double tointeger(double n)
 {
 	double sign = n < 0 ? -1 : 1;
@@ -50,6 +40,15 @@
 	return toint32(n);
 }
 
+/* Push and read stack values stack */
+
+static int stackidx(js_State *J, int idx)
+{
+	if (idx < 0)
+		return top + idx;
+	return bot + idx;
+}
+
 static void js_pushvalue(js_State *J, js_Value v)
 {
 	stack[top] = v;
@@ -123,13 +122,6 @@
 	js_pushobject(J, jsR_newcfunction(J, v));
 }
 
-static int stackidx(js_State *J, int idx)
-{
-	if (idx < 0)
-		return top + idx;
-	return bot + idx;
-}
-
 int js_isundefined(js_State *J, int idx)
 {
 	idx = stackidx(J, idx);
@@ -172,14 +164,17 @@
 	return jsR_toobject(J, &stack[idx]);
 }
 
+/* Stack manipulation */
+
 void js_pop(js_State *J, int n)
 {
 	top -= n;
 }
 
-void js_dup(js_State *J)
+void js_dup(js_State *J, int idx)
 {
-	stack[top] = stack[top-1];
+	idx = stackidx(J, idx);
+	stack[top] = stack[idx];
 	++top;
 }
 
@@ -224,12 +219,106 @@
 	++top;
 }
 
-void js_trap(js_State *J)
+/* Global and object property accessors */
+
+void js_getglobal(js_State *J, const char *name)
 {
-	fprintf(stderr, "trap!\n");
-	js_dumpstack(J);
+	js_Property *ref = jsR_getproperty(J, J->G, name);
+	if (ref)
+		js_pushvalue(J, ref->value);
+	else
+		js_pushundefined(J);
 }
 
+void js_setglobal(js_State *J, const char *name)
+{
+	js_Property *ref = jsR_setproperty(J, J->G, name);
+	if (ref)
+		ref->value = js_tovalue(J, -1);
+	js_pop(J, 1);
+}
+
+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);
+	if (ref)
+		js_pushvalue(J, ref->value);
+	else
+		js_pushundefined(J);
+}
+
+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);
+	if (ref)
+		js_pushvalue(J, ref->value);
+	else
+		js_pushundefined(J);
+}
+
+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);
+	if (ref)
+		ref->value = js_tovalue(J, -1);
+	js_pop(J, 1);
+}
+
+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_pop(J, 1);
+	if (ref) {
+		js_pushliteral(J, ref->name);
+		js_pushvalue(J, ref->value);
+		return 1;
+	}
+	return 0;
+}
+
+/* Environment records */
+
+js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
+{
+	js_Environment *E = malloc(sizeof *E);
+	E->outer = outer;
+	E->variables = vars;
+	return E;
+}
+
+static js_Property *js_decvar(js_State *J, js_Environment *E, const char *name)
+{
+	return jsR_setproperty(J, E->variables, name);
+}
+
+static js_Property *js_getvar(js_State *J, js_Environment *E, const char *name)
+{
+	do {
+		js_Property *ref = jsR_getproperty(J, E->variables, name);
+		if (ref)
+			return ref;
+		E = E->outer;
+	} while (E);
+	return NULL;
+}
+
+static js_Property *js_setvar(js_State *J, js_Environment *E, const char *name)
+{
+	do {
+		js_Property *ref = jsR_getproperty(J, E->variables, name);
+		if (ref)
+			return ref;
+		E = E->outer;
+	} while (E);
+	return jsR_setproperty(J, J->G, name);
+}
+
+/* Function calls */
+
 static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment *scope)
 {
 	js_Environment *E;
@@ -275,6 +364,23 @@
 	bot = savebot;
 }
 
+/* Main interpreter loop */
+
+void js_dumpstack(js_State *J)
+{
+	int i;
+	for (i = 0; i < top; ++i) {
+		printf("stack %d: ", i);
+		js_dumpvalue(J, stack[i]);
+		putchar('\n');
+	}
+}
+
+void js_trap(js_State *J)
+{
+	fprintf(stderr, "trap!\n");
+}
+
 static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
 {
 	js_Function **FT = F->funtab;
@@ -294,7 +400,7 @@
 		opcode = *pc++;
 		switch (opcode) {
 		case OP_POP: js_pop(J, 1); break;
-		case OP_DUP: js_dup(J); break;
+		case OP_DUP: js_dup(J, -1); break;
 		case OP_DUP2: js_dup2(J); break;
 		case OP_ROT2: js_rot2(J); break;
 		case OP_ROT3: js_rot3(J); break;
@@ -315,7 +421,7 @@
 		case OP_TRUE: js_pushboolean(J, 1); break;
 		case OP_FALSE: js_pushboolean(J, 0); break;
 
-		case OP_THIS: js_pushobject(J, js_toobject(J, 0)); break;
+		case OP_THIS: js_dup(J, 0); break;
 		case OP_GLOBAL: js_pushobject(J, J->G); break;
 
 		case OP_FUNDEC:
@@ -355,8 +461,11 @@
 			break;
 
 		case OP_GETPROP:
-			obj = js_toobject(J, -2);
 			str = js_tostring(J, -1);
+			js_pop(J, 1);
+			js_getproperty(J, -1, str);
+
+			obj = js_toobject(J, -2);
 			ref = jsR_getproperty(J, obj, str);
 			js_pop(J, 2);
 			if (ref)
@@ -581,14 +690,6 @@
 	}
 }
 
-js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
-{
-	js_Environment *E = malloc(sizeof *E);
-	E->outer = outer;
-	E->variables = vars;
-	return E;
-}
-
 int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Environment *E)
 {
 	js_Ast *P;
@@ -605,42 +706,6 @@
 
 	js_pushobject(J, jsR_newfunction(J, F, E));
 	return 0;
-}
-
-void js_setglobal(js_State *J, const char *name)
-{
-	js_Property *ref = jsR_setproperty(J, J->G, name);
-	ref->value = js_tovalue(J, -1);
-	js_pop(J, 1);
-}
-
-js_Property *js_decvar(js_State *J, js_Environment *E, const char *name)
-{
-	return jsR_setproperty(J, E->variables, name);
-}
-
-js_Property *js_getvar(js_State *J, js_Environment *E, const char *name)
-{
-	while (E) {
-		js_Property *ref = jsR_getproperty(J, E->variables, name);
-		if (ref)
-			return ref;
-		E = E->outer;
-	}
-	return NULL;
-}
-
-js_Property *js_setvar(js_State *J, js_Environment *E, const char *name)
-{
-	while (1) {
-		js_Property *ref = jsR_getproperty(J, E->variables, name);
-		if (ref)
-			return ref;
-		if (!E->outer)
-			break;
-		E = E->outer;
-	}
-	return jsR_setproperty(J, E->variables, name);
 }
 
 void jsR_error(js_State *J, const char *fmt, ...)
--- a/jsrun.h
+++ b/jsrun.h
@@ -7,19 +7,19 @@
 	js_Object *variables;
 };
 
-void js_setglobal(js_State *J, const char *name);
-
 js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer);
-js_Property *js_decvar(js_State *J, js_Environment *E, const char *name);
-js_Property *js_getvar(js_State *J, js_Environment *E, const char *name);
-js_Property *js_setvar(js_State *J, js_Environment *E, const char *name);
 
 int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Environment *E);
 
-void jsR_runfunction(js_State *J, js_Function *F);
-
 void js_call(js_State *J, int n);
 
+void js_getglobal(js_State *J, const char *name);
+void js_setglobal(js_State *J, const char *name);
+void js_getownproperty(js_State *J, int idx, const char *name);
+void js_getproperty(js_State *J, int idx, const char *name);
+void js_setproperty(js_State *J, int idx, const char *name);
+int js_nextproperty(js_State *J, int idx);
+
 void js_pushglobal(js_State *J);
 void js_pushundefined(js_State *J);
 void js_pushnull(js_State *J);
@@ -29,13 +29,16 @@
 void js_newobject(js_State *J);
 void js_newarray(js_State *J);
 void js_pushcfunction(js_State *J, js_CFunction v);
+
 int js_isundefined(js_State *J, int idx);
 int js_isstring(js_State *J, int idx);
+
 int js_toboolean(js_State *J, int idx);
 double js_tonumber(js_State *J, int idx);
 double js_tointeger(js_State *J, int idx);
 const char *js_tostring(js_State *J, int idx);
+
 void js_pop(js_State *J, int n);
-void js_dup(js_State *J);
+void js_dup(js_State *J, int idx);
 
 #endif
--- a/jsstate.c
+++ b/jsstate.c
@@ -89,10 +89,13 @@
 static int jsB_eval(js_State *J, int argc)
 {
 	const char *s;
+
 	if (!js_isstring(J, -1))
 		return 1;
 
-	// FIXME: need the real environment!
+	// FIXME: use the real environment
+	// FIXME: return value if eval string is an expression
+
 	s = js_tostring(J, -1);
 	if (jsR_loadstring(J, "(eval)", s, J->GE))
 		jsR_error(J, "SyntaxError (eval)");
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -85,7 +85,7 @@
 			return jsR_tostring(J, &vv);
 		}
 	}
-	return NULL;
+	return "undefined";
 }
 
 js_Object *jsR_toobject(js_State *J, const js_Value *v)
@@ -98,5 +98,5 @@
 	case JS_TSTRING: return jsR_newstring(J, v->u.string);
 	case JS_TOBJECT: return v->u.object;
 	}
-	return NULL;
+	jsR_error(J, "TypeError (ToObject)");
 }