shithub: mc

Download patch

ref: c1c1c42c36717dea8dbca9e1bed8d794144ec6f1
parent: eac5baa8515b5e6fe46ecf609d2cac94ffed5dc6
author: Ori Bernstein <[email protected]>
date: Fri Nov 6 18:07:35 EST 2015

Add support for '$' operator.

--- a/6/isel.c
+++ b/6/isel.c
@@ -885,7 +885,7 @@
         case Obandeq: case Obxoreq: case Obsleq: case Obsreq: case Omemb:
         case Oslbase: case Osllen: case Ocast: case Outag: case Oudata: 
         case Oucon: case Otup: case Oarr: case Ostruct:
-        case Oslice: case Oidx: case Osize: case Otupget:
+        case Oslice: case Oidx: case Osize: case Otupget: case Oidxlen:
         case Obreak: case Ocontinue:
         case Numops:
             dump(n, stdout);
--- a/6/simp.c
+++ b/6/simp.c
@@ -35,6 +35,10 @@
     int hasenv;
     int isbigret;
 
+    /* the array we're indexing for context within [] */
+    Node **idxctx;
+    size_t nidxctx;
+
     /* pre/postinc handling */
     Node **incqueue;
     size_t nqueue;
@@ -650,17 +654,16 @@
 
 static Node *slicebase(Simp *s, Node *n, Node *off)
 {
-    Node *t, *u, *v;
+    Node *u, *v;
     Type *ty;
     int sz;
 
-    t = rval(s, n, NULL);
     u = NULL;
     ty = tybase(exprtype(n));
     switch (ty->type) {
-        case Typtr:     u = t; break;
-        case Tyarray:   u = addr(s, t, base(exprtype(n))); break;
-        case Tyslice:   u = load(addr(s, t, mktyptr(n->loc, base(exprtype(n))))); break;
+        case Typtr:     u = n; break;
+        case Tyarray:   u = addr(s, n, base(exprtype(n))); break;
+        case Tyslice:   u = load(addr(s, n, mktyptr(n->loc, base(exprtype(n))))); break;
         default: die("Unslicable type %s", tystr(n->expr.type));
     }
     /* safe: all types we allow here have a sub[0] that we want to grab */
@@ -674,6 +677,17 @@
     }
 }
 
+static Node *loadidx(Simp *s, Node *arr, Node *idx)
+{
+    Node *v, *a;
+
+    a = rval(s, arr, NULL);
+    lappend(&s->idxctx, &s->nidxctx, a);
+    v = deref(idxaddr(s, a, idx), NULL);
+    lpop(&s->idxctx, &s->nidxctx);
+    return v;
+}
+
 static Node *lval(Simp *s, Node *n)
 {
     Node *r;
@@ -682,7 +696,7 @@
     args = n->expr.args;
     switch (exprop(n)) {
         case Ovar:      r = loadvar(s, n, NULL);  break;
-        case Oidx:      r = deref(idxaddr(s, args[0], args[1]), NULL); break;
+        case Oidx:      r = loadidx(s, args[0], args[1]); break;
         case Oderef:    r = deref(rval(s, args[0], NULL), NULL); break;
         case Omemb:     r = rval(s, n, NULL); break;
         case Ostruct:   r = rval(s, n, NULL); break;
@@ -770,6 +784,7 @@
                     /* FIXME: we should only allow casting to pointers. */
                     if (tysize(to) != Ptrsz)
                         fatal(val, "bad cast from %s to %s", tystr(exprtype(val)), tystr(to));
+                    val = rval(s, val, NULL);
                     r = slicebase(s, val, NULL);
                     break;
                 case Tyfunc:
@@ -834,7 +849,7 @@
 {
     Node *t;
     Node *start, *end;
-    Node *base, *sz, *len;
+    Node *seq, *base, *sz, *len;
     Node *stbase, *stlen;
 
     if (dst)
@@ -841,8 +856,11 @@
         t = dst;
     else
         t = temp(s, n);
+    seq = rval(s, n->expr.args[0], NULL);
+    if (tybase(exprtype(seq))->type != Typtr)
+        lappend(&s->idxctx, &s->nidxctx, seq);
     /* *(&slice) = (void*)base + off*sz */
-    base = slicebase(s, n->expr.args[0], n->expr.args[1]);
+    base = slicebase(s, seq, n->expr.args[1]);
     start = ptrsized(s, rval(s, n->expr.args[1], NULL));
     end = ptrsized(s, rval(s, n->expr.args[2], NULL));
     len = sub(end, start);
@@ -855,6 +873,8 @@
         stbase = set(deref(addr(s, t, tyintptr), NULL), base);
         sz = addk(addr(s, t, tyintptr), Ptrsz);
     }
+    if (tybase(exprtype(seq))->type != Typtr)
+        lpop(&s->idxctx, &s->nidxctx);
     /* *(&slice + ptrsz) = len */
     stlen = set(deref(sz, NULL), len);
     append(s, stbase);
@@ -1360,8 +1380,11 @@
             r = simpslice(s, n, dst);
             break;
         case Oidx:
-            t = idxaddr(s, n->expr.args[0], n->expr.args[1]);
-            r = load(t);
+            t = rval(s, n->expr.args[0], NULL);
+            lappend(&s->idxctx, &s->nidxctx, t);
+            u = idxaddr(s, t, n->expr.args[1]);
+            lpop(&s->idxctx, &s->nidxctx);
+            r = load(u);
             break;
         /* array.len slice.len are magic 'virtual' members.
          * they need to be special cased. */
@@ -1477,6 +1500,11 @@
             break;
         case Ovar:
             r = loadvar(s, n, dst);
+            break;
+        case Oidxlen:
+            if (s->nidxctx == 0)
+                fatal(n, "'$' undefined outside of index or slice expression");
+            return seqlen(s, s->idxctx[s->nidxctx - 1], exprtype(n));
             break;
         case Ogap:
             fatal(n, "'_' may not be an rvalue");
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -78,6 +78,7 @@
 %token<tok> Tat      /* @ */
 %token<tok> Ttick    /* ` */
 %token<tok> Tderef   /* # */
+%token<tok> Tidxlen  /* $ */
 
 %token<tok> Ttype    /* type */
 %token<tok> Tfor     /* for */
@@ -712,6 +713,8 @@
             {$$ = mkexpr($1->loc, Ovar, mkname($1->loc, $1->id), NULL);}
         | Tgap
             {$$ = mkexpr($1->loc, Ogap, NULL);}
+        | Tidxlen
+            {$$ = mkexpr($1->loc, Oidxlen, NULL);}
         | literal
         | Toparen expr Tcparen
             {$$ = $2;}
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1475,6 +1475,12 @@
             infersub(st, n, ret, sawret, &isconst);
             settype(st, n, mktype(n->loc, Tyvoid));
             break;
+        case Oidxlen:
+            t = mktyvar(n->loc);
+            constrain(st, n, t, traittab[Tcnum]);
+            constrain(st, n, t, traittab[Tcint]);
+            settype(st, n, t);
+            break;
         case Odef:
         case Odead:
             n->expr.type = mktype(n->loc, Tyvoid);
--- a/parse/ops.def
+++ b/parse/ops.def
@@ -55,6 +55,7 @@
 O(Otup,	        1,	OTmisc, NULL)
 O(Ostruct,	1,	OTmisc, NULL)
 O(Oarr,	        1,	OTmisc, NULL)
+O(Oidxlen,	1,	OTmisc, "$")
 
 /* all below this point are backend-only */
 O(Odead,        0,      OTmisc, "DEAD")         /* dead code */
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -162,6 +162,7 @@
 static int kwd(char *s)
 {
     static const struct {char* kw; int tt;} kwmap[] = {
+        {"$",           Tidxlen},
         {"$noret",      Tattr},
         {"_",           Tgap},
         {"break",       Tbreak},
--- /dev/null
+++ b/test/idxlen.myr
@@ -1,0 +1,7 @@
+use std
+
+const main = {
+	var a = [1,2,3,4]
+	std.put("{} ", a[$-1])
+	std.put("{}\n", a[$-2:])
+}
--- a/test/tests
+++ b/test/tests
@@ -58,6 +58,7 @@
 B callbig	E	42
 B nestfn	E	42
 B foldidx	P	123,456
+B idxlen	P	"4 [3, 4]"
 B closure	P	111555333666
 B fncast	P	ok
 B loop		P	0123401236789