shithub: libmujs

Download patch

ref: 6b1906f3b53c3799dcef6e3e87e05a25ef7479c4
parent: 6d690be9690fc2fb705da5e7c7eb71318b5cc2ce
author: Tor Andersson <tor@ccxvii.net>
date: Tue Jan 14 19:36:22 EST 2014

Add for-in iterator.

--- a/jscompile.c
+++ b/jscompile.c
@@ -174,8 +174,8 @@
 	while (list) {
 		emit(J, F, OP_DUP);
 		emit(J, F, OP_NUMBER_X);
-		cexp(J, F, list->a);
 		emit(J, F, i++);
+		cexp(J, F, list->a);
 		emit(J, F, OP_SETPROP);
 		emit(J, F, OP_POP);
 		list = list->b;
@@ -245,6 +245,35 @@
 	}
 }
 
+static void cassignloop(JF, js_Ast *lhs)
+{
+	switch (lhs->type) {
+	case AST_IDENTIFIER:
+		emitstring(J, F, OP_SETVAR, lhs->string);
+		break;
+	case EXP_INDEX:
+		cexp(J, F, lhs->a);
+		cexp(J, F, lhs->b);
+		emit(J, F, OP_ROT3);
+		emit(J, F, OP_SETPROP);
+		break;
+	case EXP_MEMBER:
+		cexp(J, F, lhs->a);
+		emitstring(J, F, OP_STRING, lhs->b->string);
+		emit(J, F, OP_ROT3);
+		emit(J, F, OP_SETPROP);
+		break;
+	case EXP_CALL: /* host functions may return an assignable l-value */
+		cexp(J, F, lhs);
+		emit(J, F, OP_ROT3);
+		emit(J, F, OP_SETPROP);
+		break;
+	default:
+		jsC_error(J, lhs, "invalid l-value in assignment");
+		break;
+	}
+}
+
 static void cassignop1(JF, js_Ast *lhs, int dup)
 {
 	switch (lhs->type) {
@@ -596,15 +625,13 @@
 		break;
 
 	case STM_FOR:
-		cexp(J, F, stm->a);
-		emit(J, F, OP_POP);
-		goto for_body;
-
 	case STM_FOR_VAR:
-		cvarinit(J, F, stm->a);
-		goto for_body;
-
-	for_body:
+		if (stm->type == STM_FOR_VAR) {
+			cvarinit(J, F, stm->a);
+		} else {
+			cexp(J, F, stm->a);
+			emit(J, F, OP_POP);
+		}
 		loop = here(J, F);
 		cexp(J, F, stm->b);
 		end = jump(J, F, OP_JFALSE);
@@ -614,7 +641,25 @@
 		jumpto(J, F, OP_JUMP, loop);
 		label(J, F, end);
 		break;
-	// for-in
+
+	case STM_FOR_IN:
+	case STM_FOR_IN_VAR:
+		cexp(J, F, stm->b);
+		emit(J, F, OP_UNDEF);
+		loop = here(J, F);
+		emit(J, F, OP_NEXTPROP);
+		end = jump(J, F, OP_JFALSE);
+		if (stm->type == STM_FOR_IN_VAR) {
+			if (stm->a->b)
+				jsC_error(J, stm->a->b, "more than one loop variable in for-in statement");
+			emitstring(J, F, OP_SETVAR, stm->a->a->a->string); /* stm(list(var-init(ident))) */
+		} else {
+			cassignloop(J, F, stm->a);
+		}
+		cstm(J, F, stm->c);
+		jumpto(J, F, OP_JUMP, loop);
+		label(J, F, end);
+		break;
 
 	// break
 	// continue
--- a/jscompile.h
+++ b/jscompile.h
@@ -6,6 +6,7 @@
 	OP_POP,		/* A -- */
 	OP_DUP,		/* A -- A A */
 	OP_DUP2,	/* A B -- A B A B */
+	OP_ROT3,	/* A B C -- C A B */
 	OP_DUP1ROT4,	/* A B C -- C A B C */
 
 	OP_NUMBER_0,	/* -- 0 */
@@ -36,6 +37,7 @@
 	OP_GETPROP,	/* <obj> <name> -- <value> */
 	OP_SETPROP,	/* <obj> <name> <value> -- <value> */
 	OP_DELPROP,	/* <obj> <name> -- <success> */
+	OP_NEXTPROP,	/* <obj> <name> -- <obj> <name+1> true || false */
 
 	OP_CALL,	/* <thisvalue> <closure> <args...> -(numargs)- <returnvalue> */
 	OP_NEW,		/* <closure> <args...> -(numargs)- <returnvalue> */
--- a/jsdump.c
+++ b/jsdump.c
@@ -15,7 +15,7 @@
 	"instanceof", "in", "shl", "shr", "ushr", "add", "sub", "mul", "div",
 	"mod", "cond", "ass", "ass_mul", "ass_div", "ass_mod", "ass_add",
 	"ass_sub", "ass_shl", "ass_shr", "ass_ushr", "ass_bitand",
-	"ass_bitxor", "ass_bitor", "comma", "var_init", "block", "nop", "var",
+	"ass_bitxor", "ass_bitor", "comma", "varexp", "block", "nop", "var",
 	"if", "do_while", "while", "for", "for_var", "for_in", "for_in_var",
 	"continue", "break", "return", "with", "switch", "throw", "try",
 	"debugger", "label", "case", "default",
--- a/jsobject.c
+++ b/jsobject.c
@@ -20,22 +20,20 @@
 
 static js_Property sentinel = { "", &sentinel, &sentinel, 0 };
 
-static js_Property undefined = { "", &sentinel, &sentinel, 0, { {0}, JS_TUNDEFINED } };
-
-static js_Property *newproperty(const char *key)
+static js_Property *newproperty(const char *name)
 {
 	js_Property *node = malloc(sizeof(js_Property));
-	node->key = strdup(key);
+	node->name = strdup(name);
 	node->left = node->right = &sentinel;
 	node->level = 1;
-//	node->value = 0;
+	node->value.type = JS_TUNDEFINED;
 	return node;
 }
 
-static js_Property *lookup(js_Property *node, const char *key)
+static js_Property *lookup(js_Property *node, const char *name)
 {
 	while (node != &sentinel) {
-		int c = strcmp(key, node->key);
+		int c = strcmp(name, node->name);
 		if (c == 0)
 			return node;
 		else if (c < 0)
@@ -73,14 +71,14 @@
 	return node;
 }
 
-static js_Property *insert(js_Property *node, const char *key, js_Property **result)
+static js_Property *insert(js_Property *node, const char *name, js_Property **result)
 {
 	if (node != &sentinel) {
-		int c = strcmp(key, node->key);
+		int c = strcmp(name, node->name);
 		if (c < 0)
-			node->left = insert(node->left, key, result);
+			node->left = insert(node->left, name, result);
 		else if (c > 0)
-			node->right = insert(node->right, key, result);
+			node->right = insert(node->right, name, result);
 		else
 			return *result = node;
 		node = skew(node);
@@ -87,9 +85,48 @@
 		node = split(node);
 		return node;
 	}
-	return *result = newproperty(key);
+	return *result = newproperty(name);
 }
 
+static js_Property *lookupfirst(js_Property *node)
+{
+	while (node != &sentinel) {
+		if (node->left == &sentinel)
+			return node;
+		node = node->left;
+	}
+	return NULL;
+}
+
+static js_Property *lookupnext(js_Property *node, const char *name)
+{
+	js_Property *stack[100], *parent;
+	int top = 0;
+
+	stack[0] = NULL;
+	while (node != &sentinel) {
+		stack[++top] = node;
+		int c = strcmp(name, node->name);
+		if (c == 0)
+			goto found;
+		else if (c < 0)
+			node = node->left;
+		else
+			node = node->right;
+	}
+	return NULL;
+
+found:
+	if (node->right != &sentinel)
+		return lookupfirst(node->right);
+	parent = stack[--top];
+	while (parent && node == parent->right) {
+		node = parent;
+		parent = stack[--top];
+	}
+	return parent;
+}
+
 js_Object *js_newobject(js_State *J)
 {
 	js_Object *obj = malloc(sizeof(js_Object));
@@ -109,6 +146,16 @@
 	return result;
 }
 
+js_Property *js_firstproperty(js_State *J, js_Object *obj)
+{
+	return lookupfirst(obj->properties);
+}
+
+js_Property *js_nextproperty(js_State *J, js_Object *obj, const char *name)
+{
+	return lookupnext(obj->properties, name);
+}
+
 static void js_dumpvalue(js_State *J, js_Value v)
 {
 	switch (v.type) {
@@ -127,7 +174,7 @@
 {
 	if (node->left != &sentinel)
 		js_dumpproperty(J, node->left);
-	printf("\t%s: ", node->key);
+	printf("\t%s: ", node->name);
 	js_dumpvalue(J, node->value);
 	printf(",\n");
 	if (node->right != &sentinel)
--- a/jsobject.h
+++ b/jsobject.h
@@ -27,7 +27,7 @@
 
 struct js_Property
 {
-	char *key;
+	char *name;
 	js_Property *left, *right;
 	int level;
 	js_Value value;
@@ -45,7 +45,9 @@
 js_Property *js_setproperty(js_State *J, js_Object *obj, const char *name);
 void js_deleteproperty(js_State *J, js_Object *obj, const char *name);
 
-void jsC_dumpvalue(js_State *J, js_Value v);
+js_Property *js_firstproperty(js_State *J, js_Object *obj);
+js_Property *js_nextproperty(js_State *J, js_Object *obj, const char *name);
+
 void js_dumpobject(js_State *J, js_Object *obj);
 
 #endif
--- a/jsrun.c
+++ b/jsrun.c
@@ -82,6 +82,18 @@
 	++top;
 }
 
+int js_isundefined(js_State *J, int idx)
+{
+	idx += top;
+	return stack[idx].type == JS_TUNDEFINED;
+}
+
+int js_isstring(js_State *J, int idx)
+{
+	idx += top;
+	return stack[idx].type == JS_TSTRING;
+}
+
 js_Value js_tovalue(js_State *J, int idx)
 {
 	idx += top;
@@ -178,6 +190,15 @@
 	top += 2;
 }
 
+void js_rot3(js_State *J)
+{
+	/* A B C -> C A B */
+	js_Value tmp = stack[top-1];	/* A B C (C) */
+	stack[top-1] = stack[top-2];	/* A B B */
+	stack[top-2] = stack[top-3];	/* A A B */
+	stack[top-3] = tmp;		/* C A B */
+}
+
 void js_rot3pop2(js_State *J)
 {
 	/* A B C -> C */
@@ -192,6 +213,7 @@
 	stack[top-1] = stack[top-2];	/* A B B C */
 	stack[top-2] = stack[top-3];	/* A A B C */
 	stack[top-3] = stack[top];	/* C A B C */
+	++top;
 }
 
 void js_trap(js_State *J)
@@ -219,6 +241,7 @@
 		case OP_POP: js_pop(J, 1); break;
 		case OP_DUP: js_dup(J); break;
 		case OP_DUP2: js_dup2(J); break;
+		case OP_ROT3: js_rot3(J); break;
 		case OP_DUP1ROT4: js_dup1rot4(J); break;
 
 		case OP_NUMBER_0: js_pushnumber(J, 0); break;
@@ -237,8 +260,16 @@
 		case OP_NEWOBJECT: js_pushobject(J, js_newobject(J)); break;
 		case OP_NEWARRAY: js_pushobject(J, js_newobject(J)); break;
 
-		case OP_FUNDEC: js_pop(J, 1); break;
+		case OP_FUNDEC:
+			ref = js_setproperty(J, E, ST[*pc++]);
+//			if (ref)
+//				ref->value = js_toclosure(J, -1);
+			js_pop(J, 1);
+			break;
+
 		case OP_VARDEC: pc++; break;
+			ref = js_setproperty(J, E, ST[*pc++]);
+			break;
 
 		case OP_GETVAR:
 			ref = js_getproperty(J, E, ST[*pc++]);
@@ -285,6 +316,23 @@
 			break;
 
 		// OP_DELPROP
+
+		case OP_NEXTPROP:
+			obj = js_toobject(J, -2);
+			if (js_isundefined(J, -1))
+				ref = js_firstproperty(J, obj);
+			else
+				ref = js_nextproperty(J, obj, js_tostring(J, -1));
+			printf("nextprop -> %s\n", ref ? ref->name : "(end)");
+			if (ref) {
+				js_pop(J, 1);
+				js_pushstring(J, ref->name);
+				js_pushboolean(J, 1);
+			} else {
+				js_pop(J, 2);
+				js_pushboolean(J, 0);
+			}
+			break;
 
 		/* Unary expressions */