[PATCH] New auto operator.
[Thread Prev] | [Thread Next]
- Subject: [PATCH] New auto operator.
- From: Quentin Carbonneaux <quentin@xxxxxx>
- Reply-to: myrddin-dev@xxxxxxxxxxxxxx
- Date: Thu, 18 Jan 2018 11:46:13 +0000
- To: myrddin-dev@xxxxxxxxxxxxxx
Summary: -------- During the Myrcon in September Ori suggested an 'auto' operator that would evaluate what it applies to, store the result in a temporary t, and call __dispose__(t) when the current block exits. This patch implements this idea under the form of a unary operator. This, for instance, allows to have: impl disposable regex# = __dispose__ = {r; regex.free(r)} ;; regex.exec(auto std.try(regex.compile("f..bar")), "foobar") Like before, it is guaranteed that __dispose__ is called in reverse order of auto appearance. Backward compatibility: ----------------------- Nope. Auto variables are now gone. This should not be a problem, simply rewrite: var auto x = foo() into: var x = auto foo() Implementation: --------------- It largely reuses the code I had written for 'auto' variables but needs a little finer grain tracking because we don't always want to call __dispose__ for *all* auto expression results when leaving a block (some might not be evaluated yet). For example: auto 1 if b -> void ;; auto 2 Only __dispose__(1) must be called when '-> void' is executed. If the block falls through, __dispose__(2) and __dispose__(1) will be called in sequence. TODO: ----- - Err when goto jumps in/out of a block that has auto expressions. - Support auto in patterns. match ... | `std.Some (auto x): ... is essentially rewritten to: match ... | `std.Some (auto x): auto x ... - Test edge cases (e.g., auto in loop condition) Actually, test. Cheers, --- 6/isel.c | 2 +- mi/flatten.c | 49 ++++++++++++++++++++++++++++++------------------- parse/dump.c | 1 - parse/gram.y | 15 ++++++--------- parse/infer.c | 35 ++++++++++++++++++++--------------- parse/ops.def | 2 +- parse/parse.h | 7 ++++--- parse/stab.c | 4 ---- test/pkgtrait.myr | 3 +-- 9 files changed, 63 insertions(+), 55 deletions(-) diff --git a/6/isel.c b/6/isel.c index d7ec0c03..ff8a6825 100644 --- a/6/isel.c +++ b/6/isel.c @@ -931,7 +931,7 @@ selexpr(Isel *s, Node *n) /* These operators should never show up in the reduced trees, * since they should have been replaced with more primitive * expressions by now */ - case Obad: case Opreinc: case Opostinc: case Opredec: + case Obad: case Oauto: case Opreinc: case Opostinc: case Opredec: case Opostdec: case Olor: case Oland: case Oaddeq: case Osubeq: case Omuleq: case Odiveq: case Omodeq: case Oboreq: case Obandeq: case Obxoreq: case Obsleq: case Obsreq: case Omemb: diff --git a/mi/flatten.c b/mi/flatten.c index 1b95d0f9..467c8285 100644 --- a/mi/flatten.c +++ b/mi/flatten.c @@ -114,10 +114,10 @@ islbl(Node *n) static Node * temp(Flattenctx *flatten, Node *e) { - Node *t, *dcl; + Node *t; assert(e->type == Nexpr); - t = gentemp(e->loc, e->expr.type, &dcl); + t = gentemp(e->loc, e->expr.type, NULL); return t; } @@ -225,23 +225,20 @@ traitfn(Srcloc loc, Trait *tr, char *fn, Type *ty) } static void -dispose(Flattenctx *s, Stab *st) +dispose(Flattenctx *s, Stab *st, size_t n) { - Node *d, *call, *func, *val; + Node *e, *call, *func; Trait *tr; Type *ty; size_t i; tr = traittab[Tcdisp]; - /* dispose in reverse order of declaration */ - for (i = st->nautodcl; i-- > 0;) { - d = st->autodcl[i]; - ty = decltype(d); - val = mkexpr(Zloc, Ovar, d->decl.name, NULL); - val->expr.type = ty; - val->expr.did = d->decl.did; + /* dispose in reverse order of appearance */ + for (i = st->nautotmp; i-- > n;) { + e = st->autotmp[i]; + ty = exprtype(e); func = traitfn(Zloc, tr, "__dispose__", ty); - call = mkexpr(Zloc, Ocall, func, val, NULL); + call = mkexpr(Zloc, Ocall, func, e, NULL); call->expr.type = mktype(Zloc, Tyvoid); flatten(s, call); } @@ -418,18 +415,23 @@ assign(Flattenctx *s, Node *lhs, Node *rhs) /* returns 1 when the exit jump needs to be emitted */ static int -exitscope(Flattenctx *s, Stab *stop, Srcloc loc, int x) +exitscope(Flattenctx *s, Stab *stop, Srcloc loc, Exit x) { + Node *exit; Stab *st; for (st = s->curst;; st = st->super) { - if (st->exit[x]) { - jmp(s, st->exit[x]); + exit = st->exit[x]; + if (st->ndisposed[x] < st->nautotmp) { + st->exit[x] = genlbl(loc); + flatten(s, st->exit[x]); + dispose(s, st, st->ndisposed[x]); + st->ndisposed[x] = st->nautotmp; + } + if (exit) { + jmp(s, exit); return 0; } - st->exit[x] = genlbl(loc); - flatten(s, st->exit[x]); - dispose(s, st); if ((!stop && st->isfunc) || st == stop) { return 1; } @@ -461,6 +463,12 @@ rval(Flattenctx *s, Node *n) r = NULL; args = n->expr.args; switch (exprop(n)) { + case Oauto: + r = rval(s, n->expr.args[0]); + t = temp(s, r); + r = asn(t, r); + lappend(&s->curst->autotmp, &s->curst->nautotmp, t); + break; case Osize: r = n; /* don't touch subexprs; they're a pseudo decl */ break; @@ -655,7 +663,10 @@ flattenblk(Flattenctx *s, Node *n) flatten(s, n->block.stmts[i]); } assert(s->curst == n->block.scope); - dispose(s, s->curst); + if (st->isfunc) + exitscope(s, NULL, Zloc, Xret); + else + dispose(s, s->curst, 0); s->curst = st; } diff --git a/parse/dump.c b/parse/dump.c index 847c0edc..94379846 100644 --- a/parse/dump.c +++ b/parse/dump.c @@ -186,7 +186,6 @@ outnode(Node *n, FILE *fd, int depth) findentf(fd, depth + 1, "isimport=%d\n", n->decl.isimport); findentf(fd, depth + 1, "isnoret=%d\n", n->decl.isnoret); findentf(fd, depth + 1, "isexportinit=%d\n", n->decl.isexportinit); - findentf(fd, depth + 1, "isauto=%d\n", n->decl.isauto); findentf(fd, depth, ")\n"); outsym(n, fd, depth + 1); outnode(n->decl.init, fd, depth + 1); diff --git a/parse/gram.y b/parse/gram.y index 5c73295c..adc63c4d 100644 --- a/parse/gram.y +++ b/parse/gram.y @@ -147,7 +147,7 @@ static void setupinit(Node *n); %type<node> littok literal lorexpr landexpr borexpr strlit bandexpr %type<node> cmpexpr addexpr mulexpr shiftexpr prefixexpr %type<node> postfixexpr funclit seqlit tuplit name block stmt label -%type<node> use fnparam declbody declcore typedeclcore autodecl structent +%type<node> use fnparam declbody declcore typedeclcore structent %type<node> arrayelt structelt tuphead ifstmt forstmt whilestmt %type<node> matchstmt elifs optexprln loopcond optexpr match @@ -419,8 +419,8 @@ pkgtydef: attrs tydef { } ; -declbody: autodecl Tasn expr {$$ = $1; $1->decl.init = $3;} - | autodecl +declbody: declcore Tasn expr {$$ = $1; $1->decl.init = $3;} + | declcore ; declcore: name {$$ = mkdecl($1->loc, $1, mktyvar($1->loc));} @@ -431,10 +431,6 @@ typedeclcore : name Tcolon type {$$ = mkdecl($1->loc, $1, $3);} ; -autodecl: Tauto declcore {$$ = $2; $$->decl.isauto = 1;} - | declcore - ; - name : Tident {$$ = mkname($1->loc, $1->id);} | Tident Tdot Tident { $$ = mknsname($3->loc, $1->id, $3->id); @@ -764,7 +760,8 @@ shiftexpr shiftop : Tbsl | Tbsr; prefixexpr - : Tinc prefixexpr {$$ = mkexpr($1->loc, Opreinc, $2, NULL);} + : Tauto prefixexpr {$$ = mkexpr($1->loc, Oauto, $2, NULL);} + | Tinc prefixexpr {$$ = mkexpr($1->loc, Opreinc, $2, NULL);} | Tdec prefixexpr {$$ = mkexpr($1->loc, Opredec, $2, NULL);} | Tband prefixexpr {$$ = mkexpr($1->loc, Oaddr, $2, NULL);} | Tlnot prefixexpr {$$ = mkexpr($1->loc, Olnot, $2, NULL);} @@ -923,7 +920,7 @@ params : fnparam { | /* empty */ {$$.nl = NULL; $$.nn = 0;} ; -fnparam : autodecl {$$ = $1;} +fnparam : declcore {$$ = $1;} | Tgap { $$ = mkpseudodecl($1->loc, mktyvar($1->loc)); } | Tgap Tcolon type { $$ = mkpseudodecl($1->loc, $3); } ; diff --git a/parse/infer.c b/parse/infer.c index 548c1f2e..a627c007 100644 --- a/parse/infer.c +++ b/parse/infer.c @@ -261,7 +261,7 @@ adddispspecialization(Node *n, Stab *stab) Type *ty; tr = traittab[Tcdisp]; - ty = decltype(n); + ty = exprtype(n); assert(tr->nproto == 1); if (hthas(tr->proto[0]->decl.impls, ty)) return; @@ -880,7 +880,7 @@ tryconstrain(Type *base, Trait *tr, int update) if (update) bsput(ty->trneed, tr->uid); return 1; - } + } if (bshas(tm->traits, tr->uid)) return 1; if (tm->name && ty->type == Tyname) { @@ -1635,6 +1635,13 @@ inferexpr(Node **np, Type *ret, int *sawret) infernode(&n->expr.idx, NULL, NULL); n = checkns(n, np); switch (exprop(n)) { + case Oauto: /* @a -> @a */ + infersub(n, ret, sawret, &isconst); + t = type(args[0]); + constrain(n, t, traittab[Tcdisp]); + n->expr.isconst = isconst; + settype(n, t); + break; /* all operands are same type */ case Oadd: /* @a + @a -> @a */ case Osub: /* @a - @a -> @a */ @@ -2076,8 +2083,6 @@ infernode(Node **np, Type *ret, int *sawret) inferdecl(n); if (hasparams(type(n)) && !ingeneric) fatal(n, "generic type in non-generic near %s", ctxstr(n)); - if (n->decl.isauto) - constrain(n, type(n), traittab[Tcdisp]); popenv(n->decl.env); indentdepth--; if (n->decl.isgeneric) @@ -2608,8 +2613,6 @@ typesub(Node *n, int noerr) if (streq(declname(n), "__init__")) if (!initcompatible(tybase(decltype(n)))) fatal(n, "__init__ must be (->void), got %s", tystr(decltype(n))); - if (n->decl.isauto) - adddispspecialization(n, curstab()); popenv(n->decl.env); break; case Nblock: @@ -2656,6 +2659,8 @@ typesub(Node *n, int noerr) settype(n->expr.args[0], exprtype(n)); settype(n->expr.args[0]->expr.args[0], exprtype(n)); } + if (exprop(n) == Oauto) + adddispspecialization(n, curstab()); for (i = 0; i < n->expr.nargs; i++) typesub(n->expr.args[i], noerr); if (!noerr) @@ -2721,7 +2726,15 @@ specialize(void) for (i = 0; i < nspecializations; i++) { pushstab(specializationscope[i]); n = specializations[i]; - if (n->type == Nexpr) { + if (n->type == Nexpr && exprop(n) == Oauto) { + tr = traittab[Tcdisp]; + assert(tr->nproto == 1); + ty = exprtype(n); + dt = mktyfunc(n->loc, NULL, 0, mktype(n->loc, Tyvoid)); + lappend(&dt->sub, &dt->nsub, ty); + d = specializedcl(tr->proto[0], ty, dt, &name); + htput(tr->proto[0]->decl.impls, ty, d); + } else if (n->type == Nexpr && exprop(n) == Ovar) { d = specializedcl(genericdecls[i], n->expr.param, n->expr.type, &name); n->expr.args[0] = name; n->expr.did = d->decl.did; @@ -2743,14 +2756,6 @@ specialize(void) it = itertype(n->iterstmt.seq, mktype(n->loc, Tyvoid)); d = specializedcl(tr->proto[1], ty, it, &name); htput(tr->proto[1]->decl.impls, ty, d); - } else if (n->type == Ndecl && n->decl.isauto) { - tr = traittab[Tcdisp]; - assert(tr->nproto == 1); - ty = decltype(n); - dt = mktyfunc(n->loc, NULL, 0, mktype(n->loc, Tyvoid)); - lappend(&dt->sub, &dt->nsub, ty); - d = specializedcl(tr->proto[0], ty, dt, &name); - htput(tr->proto[0]->decl.impls, ty, d); } else { die("unknown node for specialization\n"); } diff --git a/parse/ops.def b/parse/ops.def index dd9447ab..d81ace54 100644 --- a/parse/ops.def +++ b/parse/ops.def @@ -1,5 +1,6 @@ /* operator name, is it pure, pretty name */ O(Obad, 1, OTmisc, "BAD") +O(Oauto, 1, OTpre, "auto") O(Oadd, 1, OTbin, "+") O(Osub, 1, OTbin, "-") O(Omul, 1, OTbin, "*") @@ -104,4 +105,3 @@ O(Ougt, 1, OTmisc, NULL) O(Ouge, 1, OTmisc, NULL) O(Oult, 1, OTmisc, NULL) O(Oule, 1, OTmisc, NULL) - diff --git a/parse/parse.h b/parse/parse.h index 06b0b119..070434dc 100644 --- a/parse/parse.h +++ b/parse/parse.h @@ -108,10 +108,12 @@ struct Stab { Htab *lbl; /* labels */ Htab *impl; /* trait implementations: really a set of implemented traits. */ - Node **autodcl; /* declarations in dcl marked 'auto' */ - size_t nautodcl; + /* See mi/flatten.c for the following. */ + Node **autotmp; /* temporaries for 'auto' expressions */ + size_t nautotmp; Node *exit[Nexits]; + size_t ndisposed[Nexits]; }; struct Tyenv { @@ -331,7 +333,6 @@ struct Node { char isnoret; char isexportinit; char isinit; - char isauto; } decl; struct { diff --git a/parse/stab.c b/parse/stab.c index 2d190d90..7e1b8c01 100644 --- a/parse/stab.c +++ b/parse/stab.c @@ -417,10 +417,6 @@ putdcl(Stab *st, Node *s) st = findstab(st, s->decl.name); old = htget(st->dcl, s->decl.name); - if (s->decl.isauto) { - assert(!old); - lappend(&st->autodcl, &st->nautodcl, s); - } if (!old) forcedcl(st, s); else if (!mergedecl(old, s)) diff --git a/test/pkgtrait.myr b/test/pkgtrait.myr index 40eb5944..38826342 100644 --- a/test/pkgtrait.myr +++ b/test/pkgtrait.myr @@ -8,7 +8,6 @@ impl disposable regex.regex# = ;; const main = { - var auto r : regex.regex# - r = std.try(regex.compile(".*")) + auto std.try(regex.compile(".*")) std.exit(42) } -- 2.15.1
Re: [PATCH] New auto operator. | "S. Gilles" <sgilles@xxxxxxxxxxxx> |
Re: [PATCH] New auto operator. | Ori Bernstein <ori@xxxxxxxxxxxxxx> |
Re: [PATCH] New auto operator. | Ori Bernstein <ori@xxxxxxxxxxxxxx> |
- Prev by Date: Re: [PATCH] Fix iter.byperm when there are duplicates.
- Next by Date: Re: [PATCH] New auto operator.
- Previous by thread: Re: [PATCH] Fix iter.byperm when there are duplicates.
- Next by thread: Re: [PATCH] New auto operator.
- Index(es):