shithub: libmujs

Download patch

ref: fdd94dc5ddb48d9998a33e4154fa76a11be3515e
parent: 14043f0e11d6a464df9688a67c239e666b4d84c3
author: Tor Andersson <tor@ccxvii.net>
date: Wed Jan 22 09:23:07 EST 2014

Break and continue to labelled statements.

--- a/jscompile.c
+++ b/jscompile.c
@@ -552,7 +552,7 @@
 		break;
 
 	default:
-		jsC_error(J, exp, "unknown expression");
+		jsC_error(J, exp, "unknown expression: (%s)", jsP_aststring(exp->type));
 	}
 }
 
@@ -560,10 +560,8 @@
 
 static void labelexit(JF, js_Ast *top, js_Ast *node, js_AstType T, int addr)
 {
-	if (node->type == T) {
-		// TODO: check if top is our real target
-		if (F->code[node->inst] == 0)
-			labelto(J, F, node->inst, addr);
+	if (node->type == T && node->target == top) {
+		labelto(J, F, node->inst, addr);
 	} else if (node->type >= STM_BLOCK || node->type == AST_LIST) {
 		if (node->a) labelexit(J, F, top, node->a, T, addr);
 		if (node->b) labelexit(J, F, top, node->b, T, addr);
@@ -572,11 +570,57 @@
 	}
 }
 
+static int isloop(js_AstType T)
+{
+	return T == STM_DO || T == STM_WHILE ||
+		T == STM_FOR || T == STM_FOR_VAR ||
+		T == STM_FOR_IN || T == STM_FOR_IN_VAR;
+}
+
+static int matchlabel(js_Ast *node, const char *label)
+{
+	while (node && node->type == STM_LABEL) {
+		if (!strcmp(node->a->string, label))
+			return 1;
+		node = node->parent;
+	}
+	return 0;
+}
+
+static js_Ast *breaktarget(JF, js_Ast *node, const char *label)
+{
+	while (node) {
+		if (!label) {
+			if (isloop(node->type) || node->type == STM_SWITCH)
+				return node;
+		} else {
+			if (matchlabel(node->parent, label))
+				return node;
+		}
+		node = node->parent;
+	}
+	return NULL;
+}
+
+static js_Ast *continuetarget(JF, js_Ast *node, const char *label)
+{
+	while (node) {
+		if (isloop(node->type)) {
+			if (!label)
+				return node;
+			else if (matchlabel(node->parent, label))
+				return node;
+		}
+		node = node->parent;
+	}
+	return NULL;
+}
+
 /* Statements */
 
 static void cstm(JF, js_Ast *stm)
 {
-	int loop, then, end;
+	int loop, cont, then, end;
 
 	switch (stm->type) {
 	case AST_FUNDEC:
@@ -584,8 +628,6 @@
 
 	case STM_BLOCK:
 		cstmlist(J, F, stm->a);
-		if (stm->parent && stm->parent->type == STM_LABEL)
-			labelexit(J, F, stm, stm->a, STM_BREAK, here(J, F));
 		break;
 
 	case STM_NOP:
@@ -644,11 +686,12 @@
 		cexp(J, F, stm->b);
 		end = jump(J, F, OP_JFALSE);
 		cstm(J, F, stm->d);
+		cont = here(J, F);
 		cexp(J, F, stm->c);
 		emit(J, F, OP_POP);
 		jumpto(J, F, OP_JUMP, loop);
 		label(J, F, end);
-		labelexit(J, F, stm, stm->d, STM_CONTINUE, loop);
+		labelexit(J, F, stm, stm->d, STM_CONTINUE, cont);
 		labelexit(J, F, stm, stm->d, STM_BREAK, here(J, F));
 		break;
 
@@ -673,13 +716,43 @@
 		labelexit(J, F, stm, stm->c, STM_BREAK, here(J, F));
 		break;
 
-	// label
+	case STM_LABEL:
+		cstm(J, F, stm->b);
+		/* skip consecutive labels */
+		while (stm->type == STM_LABEL)
+			stm = stm->b;
+		/* loops and switches have already been labelled */
+		if (!isloop(stm->type) && stm->type != STM_SWITCH) {
+			if (stm->a) labelexit(J, F, stm, stm->a, STM_BREAK, here(J, F));
+			if (stm->b) labelexit(J, F, stm, stm->b, STM_BREAK, here(J, F));
+			if (stm->c) labelexit(J, F, stm, stm->c, STM_BREAK, here(J, F));
+			if (stm->d) labelexit(J, F, stm, stm->d, STM_BREAK, here(J, F));
+		}
+		break;
 
 	case STM_BREAK:
+		if (stm->a) {
+			stm->target = breaktarget(J, F, stm, stm->a->string);
+			if (!stm->target)
+				jsC_error(J, stm, "break label not found: %s", stm->a->string);
+		} else {
+			stm->target = breaktarget(J, F, stm, NULL);
+			if (!stm->target)
+				jsC_error(J, stm, "unlabelled break must be inside loop or switch");
+		}
 		stm->inst = jump(J, F, OP_JUMP);
 		break;
 
 	case STM_CONTINUE:
+		if (stm->a) {
+			stm->target = continuetarget(J, F, stm, stm->a->string);
+			if (!stm->target)
+				jsC_error(J, stm, "continue label not found: %s", stm->a->string);
+		} else {
+			stm->target = continuetarget(J, F, stm, NULL);
+			if (!stm->target)
+				jsC_error(J, stm, "continue must be inside loop");
+		}
 		stm->inst = jump(J, F, OP_JUMP);
 		break;
 
--- a/jscompile.h
+++ b/jscompile.h
@@ -74,6 +74,7 @@
 
 	OP_THROW,
 	OP_TRY,
+	OP_ENDTRY,
 	OP_CATCH,
 	OP_ENDCATCH,
 	OP_WITH,
--- a/jsparse.c
+++ b/jsparse.c
@@ -80,6 +80,18 @@
 	return node;
 }
 
+static js_Ast *jsP_list(js_Ast *head)
+{
+	/* set parent pointers in list nodes */
+	js_Ast *prev = head, *node = head->b;
+	while (node) {
+		node->parent = prev;
+		prev = node;
+		node = node->b;
+	}
+	return head;
+}
+
 static js_Ast *jsP_newstrnode(js_State *J, int type, const char *s)
 {
 	js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0);
@@ -206,7 +218,7 @@
 		if (J->lookahead != ']')
 			tail = tail->b = LIST(arrayelement(J));
 	}
-	return head;
+	return jsP_list(head);
 }
 
 static js_Ast *propname(js_State *J)
@@ -264,7 +276,7 @@
 			break;
 		tail = tail->b = LIST(propassign(J));
 	}
-	return head;
+	return jsP_list(head);
 }
 
 /* Functions */
@@ -278,7 +290,7 @@
 	while (accept(J, ',')) {
 		tail = tail->b = LIST(identifier(J));
 	}
-	return head;
+	return jsP_list(head);
 }
 
 static js_Ast *fundec(js_State *J)
@@ -364,7 +376,7 @@
 	while (accept(J, ',')) {
 		tail = tail->b = LIST(assignment(J, 0));
 	}
-	return head;
+	return jsP_list(head);
 }
 
 static js_Ast *newexp(js_State *J)
@@ -576,7 +588,7 @@
 	head = tail = LIST(vardec(J, notin));
 	while (accept(J, ','))
 		tail = tail->b = LIST(vardec(J, notin));
-	return head;
+	return jsP_list(head);
 }
 
 static js_Ast *statementlist(js_State *J)
@@ -587,7 +599,7 @@
 	head = tail = LIST(statement(J));
 	while (J->lookahead != '}' && J->lookahead != TK_CASE && J->lookahead != TK_DEFAULT)
 		tail = tail->b = LIST(statement(J));
-	return head;
+	return jsP_list(head);
 }
 
 static js_Ast *caseclause(js_State *J)
@@ -619,7 +631,7 @@
 	head = tail = LIST(caseclause(J));
 	while (J->lookahead != '}')
 		tail = tail->b = LIST(caseclause(J));
-	return head;
+	return jsP_list(head);
 }
 
 static js_Ast *block(js_State *J)
@@ -844,7 +856,7 @@
 	head = tail = LIST(scriptelement(J));
 	while (J->lookahead != '}' && J->lookahead != 0)
 		tail = tail->b = LIST(scriptelement(J));
-	return head;
+	return jsP_list(head);
 }
 
 static js_Ast *funbody(js_State *J)
--- a/jsparse.h
+++ b/jsparse.h
@@ -118,7 +118,7 @@
 {
 	int type;
 	int line;
-	js_Ast *parent, *a, *b, *c, *d;
+	js_Ast *parent, *target, *a, *b, *c, *d;
 	double number;
 	const char *string;
 	int inst; /* for patching jumps */