diff options
-rw-r--r-- | 6/isel.c | 2 | ||||
-rw-r--r-- | 6/simp.c | 4 | ||||
-rw-r--r-- | 6/typeinfo.c | 35 | ||||
-rw-r--r-- | mi/flatten.c | 4 | ||||
-rw-r--r-- | parse/gram.y | 2 | ||||
-rw-r--r-- | parse/infer.c | 58 | ||||
-rw-r--r-- | parse/ops.def | 1 | ||||
-rw-r--r-- | parse/tok.c | 8 | ||||
-rw-r--r-- | test/tests | 1 | ||||
-rw-r--r-- | test/tupleaccess.myr | 14 |
10 files changed, 96 insertions, 33 deletions
@@ -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); @@ -540,6 +540,7 @@ lval(Simp *s, Node *n) case Ovar: r = loadvar(s, n, NULL); break; case Oidx: r = loadidx(s, args[0], args[1]); break; case Oderef: r = deref(rval(s, args[0], NULL), NULL); break; + case Otupmemb: r = rval(s, n, NULL); break; case Omemb: r = rval(s, n, NULL); break; case Ostruct: r = rval(s, n, NULL); break; case Oucon: r = rval(s, n, NULL); break; @@ -1137,8 +1138,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 312aefb..0a7045b 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 5a74996..e4817d3 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; @@ -696,6 +697,7 @@ lval(Flattenctx *s, Node *n) case Ovar: r = n; break; case Oidx: r = rval(s, n); break; case Oderef: r = rval(s, n); break; + case Otupmemb: r = rval(s, n); break; case Omemb: r = rval(s, n); break; case Ostruct: r = rval(s, n); break; diff --git a/parse/gram.y b/parse/gram.y index 7d95300..5836b0c 100644 --- a/parse/gram.y +++ b/parse/gram.y @@ -786,6 +786,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 c5cb02e..e32a16c 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; @@ -1769,6 +1772,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)); @@ -2258,27 +2262,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])); @@ -2289,17 +2288,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) @@ -2419,6 +2440,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 909736e..e2f0b50 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) diff --git a/parse/tok.c b/parse/tok.c index 5c55cbc..934f983 100644 --- a/parse/tok.c +++ b/parse/tok.c @@ -657,6 +657,7 @@ number(int base) int start; int c; int isfloat; + int maybefloat; int unsignedval; /* because we allow '_' in numbers, and strtod/stroull don't, we * need a buffer that holds the number without '_'. @@ -669,7 +670,12 @@ number(int base) isfloat = 0; start = fidx; nbuf = 0; - for (c = peek(); isxdigit(c) || c == '.' || c == '_'; c = peek()) { + /* allow floating point literals only if the previous token was + * not a dot; this lets the user write "foo.1.2" to access nested + * tuple fields. + */ + maybefloat = !curtok || (curtok->type != Tdot); + for (c = peek(); isxdigit(c) || (maybefloat && c == '.') || c == '_'; c = peek()) { next(); if (c == '_') continue; @@ -135,6 +135,7 @@ B arraylit E 3 B structlit E 42 B livestructlit E 21 B tuple E 42 +B tupleaccess P 'a: 0, b: 5, c: 2' B slgrow E 42 B tyrec E 42 B infer-named E 99 diff --git a/test/tupleaccess.myr b/test/tupleaccess.myr new file mode 100644 index 0000000..cbd0f05 --- /dev/null +++ b/test/tupleaccess.myr @@ -0,0 +1,14 @@ +use std + +const foo = { + -> (1, 2, (3, 4)) +} + +const main = { + match foo() + | x: + x.0 = 0 + (x.2).1 = 5 + std.put("a: {}, b: {}, c: {}\n", x.0, x.2.1, foo().1) + ;; +} |