aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-05 17:36:51 +0200
committerlemon <lsof@mailbox.org>2022-08-05 17:36:51 +0200
commitc2a13e05596c724fbdbc3e8ff1266c099b675e56 (patch)
tree3be2194055a624d718c94c528651d487b2571273 /bootstrap
parentd95555f87eced5fcb3458d76c765afe2de89bdcb (diff)
modify let and static decls to allow multiple vars
this involved transforming statement and declaration parsing code to use a CPS-like style to yield many decls within one lexical decl
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/all.h2
-rw-r--r--bootstrap/cgen.c11
-rw-r--r--bootstrap/dump.c2
-rw-r--r--bootstrap/parse.c227
-rw-r--r--bootstrap/test.cff7
5 files changed, 159 insertions, 90 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h
index 3048d99..33ac7e7 100644
--- a/bootstrap/all.h
+++ b/bootstrap/all.h
@@ -355,7 +355,7 @@ struct stmt {
struct stmt *f;
} ifelse;
struct {
- struct stmt *ini;
+ slice_t(struct stmt) ini;
struct expr test;
struct expr *next;
struct blockstmt body;
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c
index b4cea42..9e13e12 100644
--- a/bootstrap/cgen.c
+++ b/bootstrap/cgen.c
@@ -295,14 +295,16 @@ genstmt(struct stmt *stmt) {
genblock(stmt->loop.body);
break;
case Sfor:
- pri("for (\n");
- if (stmt->loop.ini)
- genstmt(stmt->loop.ini);
+ pri("{\n");
+ for (int i = 0; i < stmt->loop.ini.n; ++i)
+ genstmt(&stmt->loop.ini.d[i]);
+ pri("for (; ");
pri("%e;", &stmt->loop.test);
if (stmt->loop.next)
pri(" %e", stmt->loop.next);
pri(")");
genblock(stmt->loop.body);
+ pri("}\n");
break;
case Siswitch:
pri("switch (%e) {", &stmt->iswitch.test);
@@ -434,7 +436,8 @@ liftnested(struct stmt *stmt) {
liftnested(blocktostmt(stmt->loop.body));
break;
case Sfor:
- liftnested(stmt->loop.ini);
+ for (int i = 0; i < stmt->loop.ini.n; ++i)
+ liftnested(&stmt->loop.ini.d[i]);
liftnestedex(&stmt->loop.test);
liftnestedex(stmt->loop.next);
liftnested(blocktostmt(stmt->loop.body));
diff --git a/bootstrap/dump.c b/bootstrap/dump.c
index 5d83503..12a5a2a 100644
--- a/bootstrap/dump.c
+++ b/bootstrap/dump.c
@@ -323,6 +323,7 @@ dumpstmt(const struct stmt *stmt, int ws) {
break;
case Sfor:
epri("%wfor \n", ws);
+ /*
if (stmt->loop.ini)
dumpstmt(stmt->loop.ini, ws + 1);
epri("%w; %e; ", ws + 1, &stmt->loop.test);
@@ -330,6 +331,7 @@ dumpstmt(const struct stmt *stmt, int ws) {
epri("%e", stmt->loop.next);
epri("\n");
dumpblock(&stmt->loop.body, ws + 1);
+ */
break;
case Siswitch:
epri("%wswitch %e {\n", ws, &stmt->iswitch.test);
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index 3f854d7..32cd202 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -1366,64 +1366,93 @@ stmtdup(struct stmt st) {
return memcpy(xmalloc(sizeof st), &st, sizeof st);
}
+typedef void (*decl_yielder_t)(struct decl *, void *);
+static void parsedecl(decl_yielder_t, void *, struct parser *, bool toplevel);
+
static void
-parsevardecl(struct parser *P, struct decl *decl) {
+parsevardecl(decl_yielder_t yield, void *yarg, struct parser *P) {
struct tok tok;
- const char *name;
- const struct type *ty = NULL;
- struct expr *ini = NULL;
- bool konst = 0;
- static int id;
+
+ do {
+ struct decl decl = {0};
+ const char *name;
+ const struct type *ty = NULL;
+ struct expr *ini = NULL;
+ bool konst = 0;
+ static int id;
- if (lexmatch(P, NULL, TKkw_const))
- konst = 1;
+ if (lexmatch(P, NULL, TKkw_const))
+ konst = 1;
- tok = lexexpect(P, TKident);
- name = tok.str;
+ tok = lexexpect(P, TKident);
+ name = tok.str;
- if (lexmatch(P, NULL, '=')) {
- ini = exprdup(parseexpr(P));
- ty = ini->ty;
- } else {
- ty = parsetype(P);
if (lexmatch(P, NULL, '=')) {
- P->targty = ty;
ini = exprdup(parseexpr(P));
- } else if (decl->t == Dlet) {
- fatal(P, tok.span, "variable %T must be initialized", tok);
+ ty = ini->ty;
+ } else {
+ ty = parsetype(P);
+ if (lexmatch(P, NULL, '=')) {
+ P->targty = ty;
+ ini = exprdup(parseexpr(P));
+ } else if (decl.t == Dlet) {
+ fatal(P, tok.span, "variable %T must be initialized", tok);
+ }
}
- }
- // TODO static initialzier constants are a superset of folded constants
- // if (ini && decl->t == Dstatic && !fold(ini))
- // fatal(P, ini->span, "static initializer isn't constant");
+ // TODO static initialzier constants are a superset of folded constants
+ // if (ini && decl.t == Dstatic && !fold(ini))
+ // fatal(P, ini->span, "static initializer isn't constant");
+
+ if (ini && !typeof2(ty, ini->ty))
+ fatal(P, tok.span, "incompatible initializer type (%t, expected %t)",
+ ini->ty, ty);
- if (ini && !typeof2(ty, ini->ty))
- fatal(P, tok.span, "incompatible initializer type (%t, expected %t)",
- ini->ty, ty);
+ if (!completetype(ty))
+ fatal(P, tok.span, "let `%s': variable type %t is incomplete",
+ name, ty);
+
+ if (konst)
+ ty = constify(ty);
+
+ assert(ty);
+ decl.name = name;
+ decl.var.ty = ty;
+ decl.var.ini = ini;
+ decl.var.id = id++;
+ decl.var.fnid = P->curfn ? P->curfn->id : -1;
+ yield(&decl, yarg);
+ if (!lexmatch(P, &tok, ',')) {
+ lexexpect(P, ';');
+ break;
+ }
+ } while (!lexmatch(P, &tok, ';'));
+}
- if (!completetype(ty))
- fatal(P, tok.span, "let `%s': variable type %t is incomplete",
- name, ty);
+typedef void (*stmt_yielder_t)(struct stmt *, void *);
- if (konst)
- ty = constify(ty);
+struct letstmtyarg {
+ struct parser *P;
+ void *stmt_yarg;
+ stmt_yielder_t yield;
+};
- assert(ty);
- decl->name = name;
- decl->var.ty = ty;
- decl->var.ini = ini;
- decl->var.id = id++;
- decl->var.fnid = P->curfn ? P->curfn->id : -1;
+static void
+letstmtyield(struct decl *decl, void *arg) {
+ struct letstmtyarg *a = arg;
+ struct stmt st = { Sdecl };
+ decl->t = Dlet;
+ putdecl(a->P, decl->span, decl);
+ st.decl = *decl;
+ a->yield(&st, a->stmt_yarg);
}
-static struct stmt
-pstlet(struct parser *P) {
- struct stmt st = {Sdecl};
- st.decl.t = Dlet;
- parsevardecl(P, &st.decl);
- putdecl(P, st.decl.span, &st.decl);
- return st;
+static void
+pstlet(stmt_yielder_t yield, void *yarg, struct parser *P) {
+ struct letstmtyarg arg = {
+ P, yarg, yield
+ };
+ parsevardecl(letstmtyield, &arg, P);
}
static struct stmt
@@ -1449,20 +1478,28 @@ pstifelse(struct parser *P) {
return st;
}
+static void
+pstforletyield(struct stmt *st, void *arg) {
+ vec_t(struct stmt) *sts = arg;
+ vec_push(sts, *st);
+}
+
static struct stmt
pstfor(struct parser *P) {
struct stmt st = {Sfor};
struct tok tok;
if (lexmatch(P, NULL, TKkw_let)) {
- st.loop.ini = stmtdup(pstlet(P));
- lexexpect(P, ';');
+ vec_t(struct stmt) sts = {0};
+ pstlet(pstforletyield, &sts, P);
+ vec_slice_cpy(&st.loop.ini, &sts);
} else if (lexmatch(P, NULL, ';')) {
// pass
} else {
- st.loop.ini = stmtdup((struct stmt) {
+ st.loop.ini.d = stmtdup((struct stmt) {
Sexpr, .expr = parseexpr(P)
});
+ st.loop.ini.n = 1;
lexexpect(P, ';');
}
@@ -1487,7 +1524,7 @@ pstfor(struct parser *P) {
return st;
}
-static struct stmt parsestmt(struct parser *P);
+static void parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P);
static struct stmt
pstiswitch(struct parser *P, const struct expr *test) {
@@ -1552,9 +1589,6 @@ pstswitch(struct parser *P) {
}
}
-typedef void (*decl_yielder_t)(const struct decl *, void *);
-static void parsedecl(decl_yielder_t, void *, struct parser *, bool toplevel);
-
static bool
isdecltokt(int tokt) {
switch (tokt)
@@ -1664,13 +1698,25 @@ ok:
}
static void
-yieldstdecl(const struct decl *d0, void *arg) {
+yieldstdecl(struct decl *d0, void *arg) {
struct decl *decl = arg;
*decl = *d0;
}
-static struct stmt
-parsestmt(struct parser *P) {
+struct stmtletyarg {
+ stmt_yielder_t yield;
+ void *yarg;
+};
+
+static void
+stmtletyield(struct stmt *stmt, void *arg) {
+ struct stmtletyarg *a = arg;
+ stmt->t = Sdecl;
+ a->yield(stmt, a->yarg);
+}
+
+static void
+parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) {
struct stmt st = {0};
struct tok tok;
@@ -1678,9 +1724,8 @@ parsestmt(struct parser *P) {
st.span = tok.span;
st = parseblock(P);
} else if (lexmatch(P, &tok, TKkw_let)) {
- st = pstlet(P);
- st.span = tok.span;
- lexexpect(P, ';');
+ pstlet(stmtletyield, &(struct stmtletyarg) { yield, yarg }, P);
+ return;
} else if (lexmatch(P, &tok, TKkw_if)) {
st.span = tok.span;
st = pstifelse(P);
@@ -1737,7 +1782,7 @@ parsestmt(struct parser *P) {
if ((decl = finddecl(P, tok.str)) && decl->t == Dmacro) {
lex(P);
parseexpandmacro(P, &decl->macro);
- return parsestmt(P);
+ return parsestmt(yield, yarg, P);
}
}
@@ -1747,7 +1792,13 @@ parsestmt(struct parser *P) {
st.t = Sexpr;
st.expr = ex;
}
- return st;
+ yield(&st, yarg);
+}
+
+static void
+parseblockstyield(struct stmt *st, void *arg) {
+ vec_t(struct stmt) *stmts = arg;
+ vec_push(stmts, *st);
}
static struct blockstmt
@@ -1761,7 +1812,7 @@ parseblock0(struct parser *P) {
while ((tokt = lexpeek(P).t) != '}' && tokt != TKkw_case && tokt != ')') {
if (lexmatch(P, NULL, ';'))
continue;
- vec_push(&stmts, parsestmt(P));
+ parsestmt(parseblockstyield, &stmts, P);
}
vec_slice_cpy(&block.stmts, &stmts);
@@ -2083,13 +2134,40 @@ doimport(struct parser *P, const char *path) {
rpath = xstrdup(rpath);
vec_push(&seen, rpath);
- P2.primenv = P->primenv;
+ // P2.primenv = P->primenv;
initparser(&P2, path);
P2.is_header = 1;
parse(&cf, &P2);
return cf;
}
+struct staticvaryarg {
+ struct parser *P;
+ bool externp, toplevel;
+ struct span espan;
+ decl_yielder_t yield;
+ void *yarg;
+};
+
+static void
+staticvaryield(struct decl *decl, void *arg) {
+ struct staticvaryarg *a = arg;
+ decl->t = Dstatic;
+ decl->externp = a->externp;
+ decl->_cname = xcalloc(1, sizeof (char *));
+ decl->span = a->espan;
+ if (!a->toplevel && !a->externp && !decl->var.ini)
+ fatal(a->P, decl->span,
+ "static variable inside function cannot be forward-declared");
+ if (!a->toplevel && a->externp && decl->var.ini)
+ fatal(a->P, decl->span,
+ "extern static variable inside function cannot be initialized");
+ if (a->P->is_header && a->externp && decl->var.ini)
+ fatal(a->P, decl->span,
+ "cannot define extern variable in header");
+ a->yield(decl, a->yarg);
+}
+
static void
parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) {
struct tok tok = { .span = P->tokspan };
@@ -2114,21 +2192,10 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) {
fatal(P, decl.span,
"cannot define extern function in header");
} else if (lexmatch(P, &tok, TKkw_static)) {
- decl.t = Dstatic;
- decl.externp = externp;
- decl._cname = xcalloc(1, sizeof (char *));
- decl.span = tok.span;
- parsevardecl(P, &decl);
- if (!toplevel && !externp && !decl.var.ini)
- fatal(P, decl.span,
- "static variable inside function cannot be forward-declared");
- if (!toplevel && externp && decl.var.ini)
- fatal(P, decl.span,
- "extern static variable inside function cannot be initialized");
- if (P->is_header && externp && decl.var.ini)
- fatal(P, decl.span,
- "cannot define extern variable in header");
- lexexpect(P, ';');
+ parsevardecl(staticvaryield, &(struct staticvaryarg) {
+ P, externp, toplevel, tok.span, yield, yarg
+ }, P);
+ return;
} else if (lexmatch(P, &tok, TKkw_typedef)) {
if (externp) fatal(P, tok.span, "typedef cannot be `extern'");
decl.t = Dtype;
@@ -2195,7 +2262,7 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) {
}
static void
-yieldexdecl(const struct decl *decl, void *arg) {
+yieldexdecl(struct decl *decl, void *arg) {
vec_t(struct decl) *decls = arg;
vec_push(decls, *decl);
}
@@ -2210,18 +2277,14 @@ parse(struct comfile *cf, struct parser *P) {
void
initparser(struct parser *P, const char *fname) {
- struct env *primenv = P->primenv;
assert(NUM_KEYWORDS - 1 < '!');
memset(P, 0, sizeof *P);
- P->primenv = primenv;
P->curfile = fname;
if (!(P->fp = fopen(fname, "r")))
perror(fname), exit(1);
P->tokspan = P->curspan = (struct span) { addfilepath(fname), 0, 1, 1 };
P->peekchr = -1;
P->curenv = P->tlenv = xcalloc(1, sizeof *P->tlenv);
- if (!P->primenv) {
- P->primenv = xcalloc(1, sizeof *P->primenv);
- putprimtypes(P->primenv);
- }
+ P->primenv = xcalloc(1, sizeof *P->primenv);
+ putprimtypes(P->primenv);
}
diff --git a/bootstrap/test.cff b/bootstrap/test.cff
index 5e74cf1..46e3b8c 100644
--- a/bootstrap/test.cff
+++ b/bootstrap/test.cff
@@ -17,12 +17,13 @@ enum Color {
Red, Green, Blue
}
-static xs *void = {};
+static xs *void = {},
+ ok = 6;
fn isort(xs *int, n usize) void {
fn icmp(lhs *const void, rhs *const void, _ *void) int {
- let lhs = *as(*int)lhs;
- let rhs = *as(*int)rhs;
+ let lhs = *as(*int)lhs,
+ rhs = *as(*int)rhs;
return lhs - rhs;
}
qsort(xs, n, 4, &icmp);