Eigenstate: myrddin-dev mailing list

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Support direct tuple access operators "tuple.N"


hey neat, closes https://github.com/oridb/mc/issues/104 :)

On Thu, Jul 12, 2018 at 2:58 AM, Quentin Carbonneaux <quentin@xxxxxx> wrote:

> Hi myrddin-dev,
>
> This patch adds tuple access expressions. If t is a tuple, its
> N-th component can be retrieved with the syntax t.N.  Of course,
> the components are zero indexed.  I believe the code also works
> if 't' is a pointer to a tuple (but I have not checked this).
>
> Feel free to throw the code in a nearby incinerator, it is only
> very mildly tested, and was quite hastily hacked in public
> transportation.
>
> Best,
>
> ---
>  6/isel.c      |  2 +-
>  6/simp.c      |  3 +--
>  6/typeinfo.c  | 35 ++++++++++++++++++++++---------
>  mi/flatten.c  |  3 ++-
>  parse/gram.y  |  2 ++
>  parse/infer.c | 58 +++++++++++++++++++++++++++++++++++----------------
>  parse/ops.def |  1 +
>  7 files changed, 72 insertions(+), 32 deletions(-)
>
> diff --git a/6/isel.c b/6/isel.c
> index 7b30b04c..bb111adc 100644
> --- a/6/isel.c
> +++ b/6/isel.c
> @@ -945,7 +945,7 @@ selexpr(Isel *s, Node *n)
>         case Obandeq: case Obxoreq: case Obsleq: case Obsreq: case Omemb:
>         case Oslbase: case Osllen: case Ocast: case Outag: case Oudata:
>         case Otup: case Oarr: case Ostruct:
> -       case Oslice: case Oidx: case Osize: case Otupget:
> +       case Oslice: case Oidx: case Osize: case Otupget: case Otupmemb:
>         case Obreak: case Ocontinue:
>         case Numops:
>                 dump(n, stdout);
> diff --git a/6/simp.c b/6/simp.c
> index 457227eb..eb866337 100644
> --- a/6/simp.c
> +++ b/6/simp.c
> @@ -1137,8 +1137,7 @@ rval(Simp *s, Node *n, Node *dst)
>                 u = idxaddr(s, t, n->expr.args[1]);
>                 r = load(u);
>                 break;
> -       /* array.len slice.len are magic 'virtual' members.
> -       * they need to be special cased. */
> +       case Otupmemb:
>         case Omemb:
>                 t = membaddr(s, n);
>                 r = load(t);
> diff --git a/6/typeinfo.c b/6/typeinfo.c
> index 312aefb8..0a7045b1 100644
> --- a/6/typeinfo.c
> +++ b/6/typeinfo.c
> @@ -349,7 +349,7 @@ tyalign(Type *ty)
>         return min(align, Ptrsz);
>  }
>
> -/* gets the byte offset of 'memb' within the aggregate type 'aggr' */
> +/* gets the byte offset of 'memb' within the aggregate type 'ty' */
>  ssize_t
>  tyoffset(Type *ty, Node *memb)
>  {
> @@ -360,16 +360,31 @@ tyoffset(Type *ty, Node *memb)
>         if (ty->type == Typtr)
>                 ty = tybase(ty->sub[0]);
>
> -       assert(ty->type == Tystruct);
> -       off = 0;
> -       for (i = 0; i < ty->nmemb; i++) {
> -               off = alignto(off, decltype(ty->sdecls[i]));
> -               if (!strcmp(namestr(memb), declname(ty->sdecls[i])))
> -                       return off;
> -               off += size(ty->sdecls[i]);
> +       switch (memb->type) {
> +       case Nname:
> +               assert(ty->type == Tystruct);
> +               off = 0;
> +               for (i = 0; i < ty->nmemb; i++) {
> +                       off = alignto(off, decltype(ty->sdecls[i]));
> +                       if (!strcmp(namestr(memb),
> declname(ty->sdecls[i])))
> +                               return off;
> +                       off += size(ty->sdecls[i]);
> +               }
> +               die("bad offset");
> +               return 0;
> +       case Nlit:
> +               assert(ty->type == Tytuple);
> +               assert(memb->lit.intval < ty->nsub);
> +               off = 0;
> +               for (i = 0; i < memb->lit.intval; i++) {
> +                       off += tysize(ty->sub[i]);
> +                       off = alignto(off, ty->sub[i+1]);
> +               }
> +               return off;
> +       default:
> +               die("bad offset node type");
> +               return 0;
>         }
> -       die("bad offset");
> -       return 0;
>  }
>
>  size_t
> diff --git a/mi/flatten.c b/mi/flatten.c
> index 5a749962..9d7ab791 100644
> --- a/mi/flatten.c
> +++ b/mi/flatten.c
> @@ -560,8 +560,9 @@ rval(Flattenctx *s, Node *n)
>                 if (ty->type == Tyslice || ty->type == Tyarray) {
>                         r = seqlen(s, args[0], exprtype(n));
>                 } else {
> +       case Otupmemb:
>                         t = rval(s, args[0]);
> -                       r = mkexpr(n->loc, Omemb, t, args[1], NULL);
> +                       r = mkexpr(n->loc, exprop(n), t, args[1], NULL);
>                         r->expr.type = n->expr.type;
>                 }
>                 break;
> diff --git a/parse/gram.y b/parse/gram.y
> index 146c8422..cf058882 100644
> --- a/parse/gram.y
> +++ b/parse/gram.y
> @@ -784,6 +784,8 @@ prefixexpr
>  postfixexpr
>         : postfixexpr Tdot Tident
>         {$$ = mkexpr($1->loc, Omemb, $1, mkname($3->loc, $3->id), NULL);}
> +       | postfixexpr Tdot Tintlit
> +       {$$ = mkexpr($1->loc, Otupmemb, $1, mkint($3->loc, $3->intval),
> NULL);}
>         | postfixexpr Tinc
>         {$$ = mkexpr($1->loc, Opostinc, $1, NULL);}
>         | postfixexpr Tdec
> diff --git a/parse/infer.c b/parse/infer.c
> index c5cad2f1..69e9f9ba 100644
> --- a/parse/infer.c
> +++ b/parse/infer.c
> @@ -228,6 +228,9 @@ ctxstr(Node *n)
>                         case Omemb:
>                                 bprintf(buf, sizeof buf, "<%s>.%s", t1,
> namestr(args[1]));
>                                 break;
> +                       case Otupmemb:
> +                               bprintf(buf, sizeof buf, "<%s>.%llu", t1,
> args[1]->lit.intval);
> +                               break;
>                         default:
>                                 bprintf(buf, sizeof buf, "%s:%s", d, t);
>                                 break;
> @@ -1764,6 +1767,7 @@ inferexpr(Node **np, Type *ret, int *sawret)
>                 break;
>
>                 /* special cases */
> +       case Otupmemb:  /* @a.N -> @b, verify type(@a.N)==@b later */
>         case Omemb:     /* @a.Ident -> @b, verify type(@a.Ident)==@b later
> */
>                 infersub(n, ret, sawret, &isconst);
>                 settype(n, mktyvar(n->loc));
> @@ -2253,27 +2257,22 @@ infercompn(Node *n, Node ***rem, size_t *nrem,
> Stab ***remscope, size_t *nremsco
>         Type *t;
>         size_t i;
>         int found;
> +       int ismemb;
> +       uvlong idx;
>
>         aggr = n->expr.args[0];
>         memb = n->expr.args[1];
> +       ismemb = n->expr.op == Omemb;
>
>         found = 0;
>         t = tybase(tf(type(aggr)));
>         /* all array-like types have a fake "len" member that we emulate */
> -       if (t->type == Tyslice || t->type == Tyarray) {
> +       if (ismemb && (t->type == Tyslice || t->type == Tyarray)) {
>                 if (!strcmp(namestr(memb), "len")) {
>                         constrain(n, type(n), traittab[Tcnum]);
>                         constrain(n, type(n), traittab[Tcint]);
>                         found = 1;
>                 }
> -       /*
> -        * otherwise, we search aggregate types for the member, and unify
> -        * the expression with the member type; ie:
> -        *
> -        *       x: aggrtype    y : memb in aggrtype
> -        *       ---------------------------------------
> -        *                         x.y : membtype
> -        */
>         } else {
>                 if (tybase(t)->type == Typtr)
>                         t = tybase(tf(t->sub[0]));
> @@ -2284,17 +2283,39 @@ infercompn(Node *n, Node ***rem, size_t *nrem,
> Stab ***remscope, size_t *nremsco
>                         lappend(rem, nrem, n);
>                         lappend(remscope, nremscope, curstab());
>                         return;
> -               } else if (tybase(t)->type != Tystruct) {
> -                       fatal(n, "type %s does not support member
> operators near %s",
> -                                       tystr(t), ctxstr(n));
>                 }
> -               nl = t->sdecls;
> -               for (i = 0; i < t->nmemb; i++) {
> -                       if (!strcmp(namestr(memb), declname(nl[i]))) {
> -                               unify(n, type(n), decltype(nl[i]));
> -                               found = 1;
> -                               break;
> +               if (ismemb) {
> +                       /*
> +                        * aggregate types for the member, and unify the
> expression with the
> +                        * member type; ie:
> +                        *
> +                        *       x: aggrtype    y : memb in aggrtype
> +                        *       ---------------------------------------
> +                        *                         x.y : membtype
> +                        */
> +                       if (tybase(t)->type != Tystruct)
> +                               fatal(n, "type %s does not support member
> operators near %s",
> +                                               tystr(t), ctxstr(n));
> +                       nl = t->sdecls;
> +                       for (i = 0; i < t->nmemb; i++) {
> +                               if (!strcmp(namestr(memb),
> declname(nl[i]))) {
> +                                       unify(n, type(n), decltype(nl[i]));
> +                                       found = 1;
> +                                       break;
> +                               }
>                         }
> +               } else {
> +                       /* tuple access; similar to the logic for member
> accesses */
> +                       if (tybase(t)->type != Tytuple)
> +                               fatal(n, "type %s does not support tuple
> access operators near %s",
> +                                               tystr(t), ctxstr(n));
> +                       assert(memb->type == Nlit);
> +                       idx = memb->lit.intval;
> +                       if (idx >= t->nsub)
> +                               fatal(n, "cannot access element %llu of a
> tuple of type %s near %s",
> +                                               idx, tystr(t), ctxstr(n));
> +                       unify(n, type(n), t->sub[idx]);
> +                       found = 1;
>                 }
>         }
>         if (!found)
> @@ -2414,6 +2435,7 @@ postcheckpass(Node ***rem, size_t *nrem, Stab
> ***remscope, size_t *nremscope)
>                 pushstab(postcheckscope[i]);
>                 if (n->type == Nexpr) {
>                         switch (exprop(n)) {
> +                       case Otupmemb:
>                         case Omemb:     infercompn(n, rem, nrem, remscope,
> nremscope);  break;
>                         case Ocast:     checkcast(n, rem, nrem, remscope,
> nremscope);   break;
>                         case Ostruct:   checkstruct(n, rem, nrem,
> remscope, nremscope); break;
> diff --git a/parse/ops.def b/parse/ops.def
> index 909736ec..e2f0b508 100644
> --- a/parse/ops.def
> +++ b/parse/ops.def
> @@ -42,6 +42,7 @@ O(Obsreq,     1,      OTbin,  ">>=")
>  O(Oidx,                1,      OTmisc,  NULL)
>  O(Oslice,      1,      OTmisc,  NULL)
>  O(Omemb,       1,      OTmisc,  NULL)
> +O(Otupmemb,    1,      OTmisc, NULL)
>  O(Osize,       1,      OTmisc,  NULL)
>  O(Ocall,       0,      OTmisc,  NULL)
>  O(Ocast,       1,      OTmisc,  NULL)
> --
> 2.18.0
>
>
>

References:
[PATCH] Support direct tuple access operators "tuple.N"Quentin Carbonneaux <quentin@xxxxxx>