diff options
| author | 2022-08-08 06:20:24 +0200 | |
|---|---|---|
| committer | 2022-08-08 06:20:24 +0200 | |
| commit | c6ea883724ed389143dbed1806916aa09157b655 (patch) | |
| tree | 313e42900944d8ec5f0c482db4910ab69959c3e0 /bootstrap | |
| parent | 29a059d87af940a232443b59726da900cca83f19 (diff) | |
switch capture by ref
Diffstat (limited to 'bootstrap')
| -rw-r--r-- | bootstrap/all.h | 6 | ||||
| -rw-r--r-- | bootstrap/cgen.c | 39 | ||||
| -rw-r--r-- | bootstrap/parse.c | 21 | ||||
| -rw-r--r-- | bootstrap/test2.cff | 2 |
4 files changed, 54 insertions, 14 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index 6055a07..3145674 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -403,8 +403,9 @@ struct iswitchcase { struct euswitchcase { const char *capt; - int captid; - int vval; + bool captptr; + int captid, vval; + const struct type *captty; struct aggfield *fld; struct blockstmt t; }; @@ -436,6 +437,7 @@ struct stmt { struct expr test; slice_t(struct euswitchcase) cs; struct blockstmt *f; + bool byptr; } euswitch; struct expr *retex; }; diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index 31f2235..8e2fef9 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -368,17 +368,34 @@ genstmt(struct stmt *stmt) { pri("}\n"); break; case Seuswitch: - pri("{ %t __stmp = %e;\n", stmt->euswitch.test.ty, &stmt->euswitch.test); - pri("switch (__stmp.t) {", &stmt->euswitch.test); - for (int i = 0; i < stmt->euswitch.cs.n; ++i) { - struct euswitchcase c = stmt->euswitch.cs.d[i]; - pri("case /* %s */ %d: ", c.fld->name, c.vval); - if (c.capt) - pri("{ %t %s_%d = __stmp.u.%s;\n", c.fld->ty, c.capt, c.captid, c.fld->name); - genblock(c.t); - if (c.capt) - pri("}\n"); - pri("break;\n"); + if (!stmt->euswitch.byptr) { + pri("{ %t __stmp = %e;\n", stmt->euswitch.test.ty, &stmt->euswitch.test); + pri("switch (__stmp.t) {", &stmt->euswitch.test); + for (int i = 0; i < stmt->euswitch.cs.n; ++i) { + struct euswitchcase c = stmt->euswitch.cs.d[i]; + pri("case /* %s */ %d: ", c.fld->name, c.vval); + if (c.capt) + pri("{ %t %s_%d = __stmp.u.%s;\n", c.fld->ty, c.capt, c.captid, c.fld->name); + genblock(c.t); + if (c.capt) + pri("}\n"); + pri("break;\n"); + } + } else { + pri("{ %t *__stmp = &%e;\n", stmt->euswitch.test.ty, &stmt->euswitch.test); + pri("switch (__stmp->t) {", &stmt->euswitch.test); + for (int i = 0; i < stmt->euswitch.cs.n; ++i) { + struct euswitchcase c = stmt->euswitch.cs.d[i]; + pri("case /* %s */ %d: ", c.fld->name, c.vval); + if (c.capt && c.captptr) + pri("{ %t %s_%d = &__stmp->u.%s;\n", c.captty, c.capt, c.captid, c.fld->name); + if (c.capt && !c.captptr) + pri("{ %t %s_%d = __stmp->u.%s;\n", c.captty, c.capt, c.captid, c.fld->name); + genblock(c.t); + if (c.capt) + pri("}\n"); + pri("break;\n"); + } } if (stmt->iswitch.f) { pri("default: "); diff --git a/bootstrap/parse.c b/bootstrap/parse.c index cd41b47..59d3b5f 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -808,6 +808,8 @@ islvalue(const struct expr *ex) { return 1; if (ex->t == Eindex || ex->t == Eget) return 1; + if (ex->t == Eini) + return 1; return 0; } @@ -1970,16 +1972,33 @@ psteuswitch(struct parser *P, const struct expr *test) { c.vval = c.fld - test->ty->agg.flds.d; if (!c.fld) fatal(P, tok.span, "%t has no such variant %T", test->ty, tok); + if (c.fld->ty && lexmatch(P, &tok, '*')) { + if (!islvalue(test)) { + fatal(P, tok.span, "cannot capture by pointer, test expression is not lvalue"); + } + c.captptr = 1; + st.euswitch.byptr = 1; + if (lexpeek(P).t != TKident) + lexexpect(P, TKident); + } if (c.fld->ty && lexmatch(P, &tok, TKident)) { struct env env = {P->curenv}; + const struct type *ty = c.fld->ty; + c.capt = tok.str; + if (c.captptr) { + ty = interntype((struct type) { + TYptr, g_targ.ptrsize, .child = test->ty->konst ? constify(ty) : ty + }); + } pushenv(P, &env); putdecl(P, tok.span, &(struct decl) { Dlet, c.capt, .span = tok.span, .var = { - c.fld->ty, NULL, c.captid = P->varid++, P->curfn->id + c.captty = ty, NULL, c.captid = P->varid++, P->curfn->id } }); } + lexexpect(P, ';'); c.t = parseblock0(P); if (c.capt) popenv(P); diff --git a/bootstrap/test2.cff b/bootstrap/test2.cff index 4690f72..c0fafc5 100644 --- a/bootstrap/test2.cff +++ b/bootstrap/test2.cff @@ -37,6 +37,8 @@ extern fn main() void { case None; case Int i; i; + case Flo *f; + *f += 1.0f; } printf("n %d\n", n.value); |