Eigenstate: myrddin-dev mailing list

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Support direct tuple access operators "tuple.N"


Hi myrddin-dev,

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).

Feel free to throw the code in a nearby incinerator, it is only
very mildly tested, and was quite hastily hacked in public
transportation.

Best,

---
 6/isel.c      |  2 +-
 6/simp.c      |  3 +--
 6/typeinfo.c  | 35 ++++++++++++++++++++++---------
 mi/flatten.c  |  3 ++-
 parse/gram.y  |  2 ++
 parse/infer.c | 58 +++++++++++++++++++++++++++++++++++----------------
 parse/ops.def |  1 +
 7 files changed, 72 insertions(+), 32 deletions(-)

diff --git a/6/isel.c b/6/isel.c
index 7b30b04c..bb111adc 100644
--- a/6/isel.c
+++ b/6/isel.c
@@ -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);
diff --git a/6/simp.c b/6/simp.c
index 457227eb..eb866337 100644
--- a/6/simp.c
+++ b/6/simp.c
@@ -1137,8 +1137,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 312aefb8..0a7045b1 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 5a749962..9d7ab791 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;
diff --git a/parse/gram.y b/parse/gram.y
index 146c8422..cf058882 100644
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -784,6 +784,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 c5cad2f1..69e9f9ba 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;
@@ -1764,6 +1767,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));
@@ -2253,27 +2257,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]));
@@ -2284,17 +2283,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)
@@ -2414,6 +2435,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 909736ec..e2f0b508 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)
-- 
2.18.0


Follow-Ups:
Re: [PATCH] Support direct tuple access operators "tuple.N"Andrew Chambers <andrewchamberss@xxxxxxxxx>
Re: [PATCH] Support direct tuple access operators "tuple.N"Ori Bernstein <ori@xxxxxxxxxxxxxx>