aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/all.h13
-rw-r--r--bootstrap/cgen.c40
-rw-r--r--bootstrap/dump.c4
-rw-r--r--bootstrap/parse.c33
4 files changed, 69 insertions, 21 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h
index 1bfe919..64ab9b1 100644
--- a/bootstrap/all.h
+++ b/bootstrap/all.h
@@ -38,6 +38,7 @@ struct span {
_(const) \
_(continue) \
_(def) \
+ _(defer) \
_(defmacro) \
_(do) \
_(else) \
@@ -125,6 +126,7 @@ struct parser {
struct env *primenv;
struct env *tlenv;
struct env *curenv;
+ struct blockstmt *curblock;
struct fn *curfn;
struct expan {
struct expan *prev;
@@ -343,6 +345,7 @@ enum exprtype {
struct blockstmt {
struct env env;
slice_t(struct stmt) stmts;
+ struct defer *defers;
};
struct expr {
@@ -475,7 +478,10 @@ struct stmt {
struct blockstmt *f;
bool byptr;
} euswitch;
- struct expr *retex;
+ struct {
+ struct expr *ex;
+ int deferage;
+ } ret;
struct {
int id;
} brkcon;
@@ -488,6 +494,11 @@ struct stmt {
} cswitch;
};
};
+struct defer {
+ struct defer *next;
+ int age;
+ struct expr ex;
+} ;
struct comfile {
slice_t(struct decl *) decls;
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c
index e047f08..94ae420 100644
--- a/bootstrap/cgen.c
+++ b/bootstrap/cgen.c
@@ -318,7 +318,7 @@ static void genfn(bool externp, const char *cname, struct fn *fn);
static void genstatic(bool externp, const char *cname, struct var *var);
static void
-genstmt(struct stmt *stmt) {
+genstmt(struct blockstmt *block, struct stmt *stmt) {
const char *p = fileid2path(stmt->span.fileid);
if (stmt->t != Sblock)
pri("#line %d %S\n", stmt->span.line, p, (u64)strlen(p));
@@ -367,7 +367,7 @@ genstmt(struct stmt *stmt) {
genblock(stmt->ifelse.t);
if (stmt->ifelse.f) {
pri("else\n");
- genstmt(stmt->ifelse.f);
+ genstmt(block, stmt->ifelse.f);
}
break;
case Swhile:
@@ -384,7 +384,7 @@ genstmt(struct stmt *stmt) {
case Sfor:
pri("{\n");
for (int i = 0; i < stmt->loop.ini.n; ++i)
- genstmt(&stmt->loop.ini.d[i]);
+ genstmt(block, &stmt->loop.ini.d[i]);
pri("for (; ");
pri("%e;", &stmt->loop.test);
if (stmt->loop.next)
@@ -446,10 +446,22 @@ genstmt(struct stmt *stmt) {
pri("}\n"); pri("}\n");
break;
case Sreturn:
- pri("return");
- if (stmt->retex)
- pri(" %e", stmt->retex);
- pri(";\n");
+ pri("do { ");
+ if (stmt->ret.ex) {
+ if (stmt->ret.ex->ty->t != TYvoid)
+ pri("__auto_type __ret = ");
+ pri("%e;", stmt->ret.ex);
+ }
+ for (struct defer* defer = block->defers; defer; defer = defer->next) {
+ if (defer->age < stmt->ret.deferage) {
+ const char *p = fileid2path(defer->ex.span.fileid);
+ pri("\n#line %d %S\n", defer->ex.span.line, p, (u64)strlen(p));
+ genexpr(&defer->ex);
+ pri(";\n");
+ }
+ }
+ pri("return%s;", (stmt->ret.ex && stmt->ret.ex->ty->t != TYvoid) ? " __ret" : "");
+ pri("} while (0);\n");
break;
case Sbreak:
pri("goto _brk%d;\n", stmt->brkcon.id);
@@ -475,7 +487,7 @@ static void
genblock(struct blockstmt block) {
pri("{\n");
for (int i = 0; i < block.stmts.n; ++i)
- genstmt(&block.stmts.d[i]);
+ genstmt(&block, &block.stmts.d[i]);
pri("}\n");
}
@@ -644,8 +656,8 @@ liftnested(struct stmt *stmt) {
liftnested(blocktostmt(*stmt->iswitch.f));
break;
case Sreturn:
- if (stmt->retex)
- liftnestedex(stmt->retex);
+ if (stmt->ret.ex)
+ liftnestedex(stmt->ret.ex);
break;
case Seuswitch:
liftnestedex(&stmt->euswitch.test);
@@ -687,7 +699,15 @@ genfn(bool externp, const char *cname, struct fn *fn) {
if (!fn->body) {
pri(";\n");
} else {
+ pri("{");
genblock(fn->body->block);
+ for (struct defer* defer = fn->body->block.defers; defer; defer = defer->next) {
+ const char *p = fileid2path(defer->ex.span.fileid);
+ pri("\n#line %d %S\n", defer->ex.span.line, p, (u64)strlen(p));
+ genexpr(&defer->ex);
+ pri(";\n");
+ }
+ pri("}");
}
}
diff --git a/bootstrap/dump.c b/bootstrap/dump.c
index 0cf5670..c6b20ff 100644
--- a/bootstrap/dump.c
+++ b/bootstrap/dump.c
@@ -386,8 +386,8 @@ dumpstmt(const struct stmt *stmt, int ws) {
epri("%w}\n", ws);
break;
case Sreturn:
- if (stmt->retex)
- epri("%wreturn %e;\n", ws, stmt->retex);
+ if (stmt->ret.ex)
+ epri("%wreturn %e;\n", ws, stmt->ret.ex);
else
epri("%wreturn;\n", ws);
break;
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index 31469df..4b56c2b 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -2443,6 +2443,7 @@ parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) {
struct stmt st = {0};
struct tok tok;
const char *label = NULL;
+ static int deferage;
if (lexmatch(P, &tok, '{')) {
st.span = tok.span;
@@ -2520,15 +2521,16 @@ parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) {
if (!P->curfn)
fatal(P, tok.span, "return disallowed here");
st.t = Sreturn;
+ st.ret.deferage = deferage;
st.span = tok.span;
if (!lexmatch(P, &tok, ';')) {
P->targty = P->curfn->retty;
- st.retex = exprdup(parseexpr(P));
+ st.ret.ex = exprdup(parseexpr(P));
lexexpect(P, ';');
- if (!typematchestarg(P->curfn->retty, st.retex->ty))
- fatal(P, st.retex->span,
+ if (!typematchestarg(P->curfn->retty, st.ret.ex->ty))
+ fatal(P, st.ret.ex->span,
"incompatible type in return statement (%t, expected %t)",
- st.retex->ty, P->curfn->retty);
+ st.ret.ex->ty, P->curfn->retty);
} else if (P->curfn->retty != ty_void) {
fatal(P, tok.span,
"return statement in non-void function must return a value");
@@ -2559,6 +2561,18 @@ parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) {
st.brkcon.id = decl->loopid;
}
lexexpect(P, ';');
+ } else if (lexmatch(P, &tok, TKkw_defer)) {
+ struct expr ex = parseexpr(P);
+ struct blockstmt *block = P->curblock;
+ struct defer *defer = malloc(sizeof *defer);
+ lexexpect(P, ';');
+ assert(block != NULL && "defer outside block");
+ defer->age = deferage++;
+ defer->ex = ex;
+ defer->next = block->defers;
+ block->defers = defer;
+ st.t = Sblock;
+ st.block = (struct blockstmt){0};
} else if (isdecltokt((tok = lexpeek(P)).t)) {
st.t = Sdecl;
st.span = tok.span;
@@ -2606,10 +2620,13 @@ parseblock0(struct parser *P) {
block.env.parent = P->curenv;
pushenv(P, &block.env);
- while ((tokt = lexpeek(P).t) != '}' && tokt != TKkw_case && tokt != ')') {
- if (lexmatch(P, NULL, ';'))
- continue;
- parsestmt(parseblockstyield, &stmts, P);
+ block.defers = P->curblock ? P->curblock->defers : NULL;
+ WITH_TMPCHANGE(struct blockstmt *, P->curblock, &block) {
+ while ((tokt = lexpeek(P).t) != '}' && tokt != TKkw_case && tokt != ')') {
+ if (lexmatch(P, NULL, ';'))
+ continue;
+ parsestmt(parseblockstyield, &stmts, P);
+ }
}
vec_slice_cpy(&block.stmts, &stmts);