Break and continue to labelled statements.

This commit is contained in:
Tor Andersson
2014-01-22 15:18:02 +01:00
parent 14043f0e11
commit fdd94dc5dd
4 changed files with 105 additions and 19 deletions
+83 -10
View File
@@ -552,7 +552,7 @@ static void cexp(JF, js_Ast *exp)
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 cexp(JF, js_Ast *exp)
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 void labelexit(JF, js_Ast *top, js_Ast *node, js_AstType T, int addr)
}
}
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 @@ static void cstm(JF, js_Ast *stm)
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 @@ static void cstm(JF, js_Ast *stm)
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 @@ static void cstm(JF, js_Ast *stm)
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;
+1
View File
@@ -74,6 +74,7 @@ enum
OP_THROW,
OP_TRY,
OP_ENDTRY,
OP_CATCH,
OP_ENDCATCH,
OP_WITH,
+20 -8
View File
@@ -80,6 +80,18 @@ static js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *
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 @@ static js_Ast *arrayliteral(js_State *J)
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 @@ static js_Ast *objectliteral(js_State *J)
break;
tail = tail->b = LIST(propassign(J));
}
return head;
return jsP_list(head);
}
/* Functions */
@@ -278,7 +290,7 @@ static js_Ast *parameters(js_State *J)
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 @@ static js_Ast *arguments(js_State *J)
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 @@ static js_Ast *vardeclist(js_State *J, int notin)
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 @@ static js_Ast *statementlist(js_State *J)
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 @@ static js_Ast *caselist(js_State *J)
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 @@ static js_Ast *script(js_State *J)
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)
+1 -1
View File
@@ -118,7 +118,7 @@ struct js_Ast
{
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 */