summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--6/isel.c2
-rw-r--r--6/simp.c48
-rw-r--r--parse/gram.y3
-rw-r--r--parse/infer.c6
-rw-r--r--parse/ops.def1
-rw-r--r--parse/tok.c1
-rw-r--r--test/idxlen.myr7
-rw-r--r--test/tests1
8 files changed, 58 insertions, 11 deletions
diff --git a/6/isel.c b/6/isel.c
index 9197e1a..18b0e78 100644
--- a/6/isel.c
+++ b/6/isel.c
@@ -885,7 +885,7 @@ Loc *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 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);
diff --git a/6/simp.c b/6/simp.c
index fbdcc61..dd06dff 100644
--- a/6/simp.c
+++ b/6/simp.c
@@ -35,6 +35,10 @@ struct Simp {
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 *idxaddr(Simp *s, Node *seq, Node *idx)
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 *slicebase(Simp *s, Node *n, Node *off)
}
}
+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 @@ static Node *lval(Simp *s, Node *n)
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 @@ static Node *simpcast(Simp *s, Node *val, Type *to)
/* 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,15 +849,18 @@ static Node *simpslice(Simp *s, Node *n, Node *dst)
{
Node *t;
Node *start, *end;
- Node *base, *sz, *len;
+ Node *seq, *base, *sz, *len;
Node *stbase, *stlen;
if (dst)
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 @@ static Node *simpslice(Simp *s, Node *n, Node *dst)
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 @@ static Node *rval(Simp *s, Node *n, Node *dst)
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. */
@@ -1478,6 +1501,11 @@ static Node *rval(Simp *s, Node *n, Node *dst)
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");
break;
diff --git a/parse/gram.y b/parse/gram.y
index 32794ce..f082be1 100644
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -78,6 +78,7 @@ static void setupinit(Node *n);
%token<tok> Tat /* @ */
%token<tok> Ttick /* ` */
%token<tok> Tderef /* # */
+%token<tok> Tidxlen /* $ */
%token<tok> Ttype /* type */
%token<tok> Tfor /* for */
@@ -712,6 +713,8 @@ atomicexpr
{$$ = 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;}
diff --git a/parse/infer.c b/parse/infer.c
index ec21615..11b155a 100644
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1475,6 +1475,12 @@ static void inferexpr(Inferstate *st, Node **np, Type *ret, int *sawret)
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);
diff --git a/parse/ops.def b/parse/ops.def
index dd9447a..2a8f64d 100644
--- a/parse/ops.def
+++ b/parse/ops.def
@@ -55,6 +55,7 @@ O(Oucon, 1, OTmisc, "`")
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 */
diff --git a/parse/tok.c b/parse/tok.c
index a1df12f..9cb6716 100644
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -162,6 +162,7 @@ static void eatspace(void)
static int kwd(char *s)
{
static const struct {char* kw; int tt;} kwmap[] = {
+ {"$", Tidxlen},
{"$noret", Tattr},
{"_", Tgap},
{"break", Tbreak},
diff --git a/test/idxlen.myr b/test/idxlen.myr
new file mode 100644
index 0000000..842a2a2
--- /dev/null
+++ b/test/idxlen.myr
@@ -0,0 +1,7 @@
+use std
+
+const main = {
+ var a = [1,2,3,4]
+ std.put("{} ", a[$-1])
+ std.put("{}\n", a[$-2:])
+}
diff --git a/test/tests b/test/tests
index 9fb9246..819fcb3 100644
--- a/test/tests
+++ b/test/tests
@@ -58,6 +58,7 @@ B voidcall E 12
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