aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-08 06:20:24 +0200
committerlemon <lsof@mailbox.org>2022-08-08 06:20:24 +0200
commitc6ea883724ed389143dbed1806916aa09157b655 (patch)
tree313e42900944d8ec5f0c482db4910ab69959c3e0 /bootstrap
parent29a059d87af940a232443b59726da900cca83f19 (diff)
switch capture by ref
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/all.h6
-rw-r--r--bootstrap/cgen.c39
-rw-r--r--bootstrap/parse.c21
-rw-r--r--bootstrap/test2.cff2
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);