mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-22 15:13:35 +08:00
Break and continue to labelled statements.
This commit is contained in:
+83
-10
@@ -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;
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ enum
|
||||
|
||||
OP_THROW,
|
||||
OP_TRY,
|
||||
OP_ENDTRY,
|
||||
OP_CATCH,
|
||||
OP_ENDCATCH,
|
||||
OP_WITH,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user