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