summaryrefslogtreecommitdiff
path: root/parse
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2018-07-17 08:57:58 +0000
committerOri Bernstein <ori@eigenstate.org>2018-07-19 21:29:35 -0700
commitf4a43f90e3ffe1712aec13566e8ac545da4161c4 (patch)
tree57a3edcd99ff2cae6ab74b6435af32d3182174ba /parse
parent8a3e8add6e0180565312d1079395ad39de4d9ce3 (diff)
downloadmc-f4a43f90e3ffe1712aec13566e8ac545da4161c4.tar.gz
Support direct tuple access operators "tuple.N"
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).
Diffstat (limited to 'parse')
-rw-r--r--parse/gram.y2
-rw-r--r--parse/infer.c58
-rw-r--r--parse/ops.def1
-rw-r--r--parse/tok.c8
4 files changed, 50 insertions, 19 deletions
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;