ref: 2a76c9fc491ab08492491ddce7fb26d953879791
parent: 16bbf82067cacf44828b5f5023bdd6ec3b80b570
author: Ori Bernstein <ori@eigenstate.org>
date: Thu Feb 25 10:28:14 EST 2016
Fix forward labels in nested blocks. Fixes #91
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -19,6 +19,8 @@
Stab *curscope;
+static Node **lbls;
+static size_t nlbls;
void yyerror(const char *s);
int yylex(void);
@@ -783,10 +785,30 @@
}
;
-funclit : Tobrace params Tendln blkbody Tcbrace
- {$$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);}
- | Tobrace params Tret type Tendln blkbody Tcbrace
- {$$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);}
+funclit : Tobrace params Tendln blkbody Tcbrace {
+ size_t i;
+ Node *fn, *lit;
+
+ $$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);
+ fn = $$->lit.fnval;
+ for (i = 0; i < nlbls; i++) {
+ lit = lbls[i]->expr.args[0];
+ putlbl(fn->func.scope, lit->lit.lblname, lbls[i]);
+ }
+ lfree(&lbls, &nlbls);
+ }
+ | Tobrace params Tret type Tendln blkbody Tcbrace {
+ size_t i;
+ Node *fn, *lit;
+
+ $$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);
+ fn = $$->lit.fnval;
+ for (i = 0; i < nlbls; i++) {
+ lit = lbls[i]->expr.args[0];
+ putlbl(fn->func.scope, lbls[i]->lit.lblname, lbls[i]);
+ }
+ lfree(&lbls, &nlbls);
+ }
;
params : fnparam {
@@ -981,6 +1003,7 @@
genlblstr(buf, sizeof buf, $2->id);
$$ = mklbl($2->loc, buf);
$$->expr.args[0]->lit.lblname = strdup($2->id);
+ lappend(&lbls, &nlbls, $$);
}
;
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1795,20 +1795,6 @@
free(k);
}
-static void addlbl(Inferstate *st, Node *n)
-{
- Node *lit;
-
- if (n->type != Nexpr)
- return;
- if (exprop(n) != Olit)
- return;
- lit = n->expr.args[0];
- if (lit->lit.littype != Llbl)
- return;
- putlbl(curstab(), lit->lit.lblname, n);
-}
-
static void infernode(Inferstate *st, Node **np, Type *ret, int *sawret)
{
size_t i, nbound;
@@ -1844,8 +1830,6 @@
setsuper(n->block.scope, curstab());
pushstab(n->block.scope);
inferstab(st, n->block.scope);
- for (i = 0; i < n->block.nstmts; i++)
- addlbl(st, n->block.stmts[i]);
for (i = 0; i < n->block.nstmts; i++)
infernode(st, &n->block.stmts[i], ret, sawret);
popstab();
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -184,10 +184,7 @@
void putlbl(Stab *st, char *name, Node *lbl)
{
- while (st && !st->isfunc)
- st = st->super;
- if (!st)
- fatal(lbl, "label %s defined outside function\n", name);
+ assert(st && st->isfunc);
if (hthas(st->lbl, name))
fatal(lbl, "duplicate label %s, first defined on line %d\n", name, lbl->loc.line);
htput(st->lbl, name, lbl);