shithub: mc

Download patch

ref: 0b58f43116b059473c24999e488f6471123dcdf8
parent: b319e47808ef74e3ed23a624ac9965551a7f51b5
author: Ori Bernstein <ori@eigenstate.org>
date: Thu Sep 24 05:53:47 EDT 2015

Descend into complex structures to print them.

    There are some really ugly hacks here, but it works.

--- a/lib/std/fmt.myr
+++ b/lib/std/fmt.myr
@@ -143,8 +143,8 @@
 }
 
 const sbfmtv = {sb, fmt, ap -> size
-	var nfmt, nparams, pl, orig
-	var c, params, ty
+	var nfmt, nparams, orig
+	var c, params
 
 	orig = fmt
 	nparams = ap.tc.nelt
@@ -163,15 +163,7 @@
 					die("too few params for fmt\n")
 				;;
 
-				ty = vatype(ap)
-				match htget(fmtmap, ty)
-				| `Some f:
-					pl = parseparams(params, f.optdesc)
-					f.fn(sb, ap, pl)
-					std.slfree(pl)
-				| `None:
-					fallbackfmt(sb, params, ty, ap)
-				;;
+				fmtval(sb, vatype(ap), ap, params)
 			;;
 		| '}':
 			if decode(fmt) == '}'
@@ -189,6 +181,19 @@
 	-> sb.len
 }
 
+const fmtval = {sb, ty, ap, params
+	var pl
+
+	match htget(fmtmap, ty)
+	| `Some f:
+		pl = parseparams(params, f.optdesc)
+		f.fn(sb, ap, pl)
+		std.slfree(pl)
+	| `None:
+		fallbackfmt(sb, params, ty, ap)
+	;;
+}
+
 const parseparams = {paramstr, optdesc
 	var params, opts
 	var o, a, ha : bool, gotarg : bool
@@ -246,6 +251,7 @@
 	var i : int, i64 : int64
 	var ui8 : int8, ui16: int16, ui32 : int32
 	var ui : int, ui64 : int64
+	var subap, subenc, subname
 
 	match typedesc(tyenc)
 	| `Tynone:	/* nothing */
@@ -317,7 +323,16 @@
 			s_val = vanext(ap)
 			strfmt(sb, s_val, params)
 		| _:
-			sbputs(sb, "slice[:]")
+			subap = vaenter(ap)
+			sbputs(sb, "[")
+			while subap.tc.nelt != 0
+				fmtval(sb, vatype(&subap), &subap, "")
+				if subap.tc.nelt > 0
+					sbfmt(sb, ", ")
+				;;
+			;;
+			sbputs(sb, "]")
+			vabytes(ap)
 		;;
 	| `Tyfunc tc:
 		p_val = vanext(ap)
@@ -326,20 +341,61 @@
 			[.base=16, .padto=2*sizeof(void#), .padfill='0'], \
 			false, p_val castto(intptr))
 		sbputs(sb, "}")
-	| `Tyarray (sz, data):
-		sbputs(sb, "array")
+		vabytes(ap)
+	| `Tyarray (sz, desc):
+		subap = vaenter(ap)
+		sbputs(sb, "[")
+		while subap.tc.nelt != 0
+			fmtval(sb, vatype(&subap), &subap, "")
+			if subap.tc.nelt > 0
+				sbfmt(sb, ", ")
+			;;
+		;;
+		sbputs(sb, "]")
+		vabytes(ap)
 	/* aggregate types */
-	| `Tytuple typecursor:
+	| `Tytuple tc:
+		subap = vaenter(ap)
+		sbfmt(sb, "(")
+		for var i = 0; i < subap.tc.nelt; i++
+			fmtval(sb, vatype(&subap), &subap, "")
+			if subap.tc.nelt == 1
+				sbfmt(sb, ",")
+			elif i != subap.tc.nelt -1 
+				sbfmt(sb, ", ")
+			;;
+		;;
+		sbfmt(sb, ")")
 		vabytes(ap)
-		sbputs(sb, "tuple")
-	| `Tystruct namecursor:
+	| `Tystruct nc:
+		subap = vaenter(ap)
+		sbfmt(sb, "[")
+		for var i = 0; i < subap.tc.nelt; i++
+			(subname, subenc) = ncpeek(&subap.tc)
+			sbfmt(sb, ".{}=", subname)
+			fmtval(sb, vatype(&subap), &subap, "")
+			if subap.tc.nelt == 1
+				sbfmt(sb, ",")
+			elif i != subap.tc.nelt -1 
+				sbfmt(sb, ", ")
+			;;
+		;;
+		sbfmt(sb, "]")
 		vabytes(ap)
-		sbputs(sb, "struct")
-	| `Tyunion namecursor:
+	| `Tyunion nc:
+		subap = vaenter(ap)
+		i_val = (ap.args castto(int32#))#
+		for var i = 0; i < i_val; i++
+			ncnext(&nc)
+		;;
+		(subname, subenc) = ncnext(&nc)
+		sbfmt(sb, "`{} ", subname)
+		fmtval(sb, subenc, &subap, "")
 		vabytes(ap)
-		sbputs(sb, "union")
 	| `Tyname (name, desc):
-		fallbackfmt(sb, params, desc, ap)
+		subap = vaenter(ap)
+		fallbackfmt(sb, params, desc, &subap)
+		vabytes(ap)
 	;;
 }
 
--- a/lib/std/introspect.myr
+++ b/lib/std/introspect.myr
@@ -34,8 +34,8 @@
 
 		/* aggregate types */
 		`Tytuple	typecursor
-		`Tystruct	namecursor
-		`Tyunion	namecursor
+		`Tystruct	typecursor
+		`Tyunion	typecursor
 		/* name info */
 		`Tyname (byte[:], byte[:])
 	;;
@@ -43,13 +43,10 @@
 	type typecursor = struct
 		nelt	: size
 		rem	: byte[:]
+		isnamed	: bool
+		isiter	: bool
 	;;
 
-	type namecursor = struct
-		nelt	: size
-		rem	: byte[:]
-	;;
-
 	type typeinfo = struct
 		size	: size
 		align	: size
@@ -57,13 +54,14 @@
 
 	generic typeof	: (v : @a -> byte[:])
 	const typeenc	: (p : ...# -> typecursor)
-	const typedecode	: (e : byte[:] -> typedesc)
+	const typeenccursor	: (e : byte[:] -> typecursor)
 	const typedesc	: (e : byte[:] -> typedesc)
 	const typeinfo	: (e : byte[:] -> typeinfo)
 
 	const tcnext	: (t : typecursor# -> byte[:])
 	const tcpeek	: (t : typecursor# -> byte[:])
-	const ncnext	: (t : namecursor# -> (byte[:], byte[:]))
+	const ncpeek	: (t : typecursor# -> (byte[:], byte[:]))
+	const ncnext	: (t : typecursor# -> (byte[:], byte[:]))
 ;;
 
 extern const put	: (fmt : byte[:], args : ... -> size)
@@ -116,6 +114,10 @@
 	e = skiptypeinfo(e[1:])
 	-> lentypecursor(e)
 }
+
+const typeenccursor = {e
+	-> [.nelt=1, .rem=e, .isiter=false]
+}
 	
 const typesof : (a : ... -> typecursor) = {a : ...
 	-> typeenc(&a)
@@ -122,43 +124,71 @@
 }
 
 const tcnext = {tc
-	var n, sz, cur
+	var enc
 
-	if tc.rem.len == 0
-		-> ""
-	;;
-	(n, sz) = getipacked(tc.rem)
-	cur = tc.rem[sz:sz+n]
-	tc.rem = tc.rem[sz+n:]
-	-> cur
+	(_, enc) = ncnext(tc)
+	-> enc
 }
 
 const tcpeek = {tc
+	var enc
+
+	(_, enc) = ncpeek(tc)
+	-> enc
+}
+
+const ncpeek = {tc
+	var name, enc, rem
 	var n, sz
 
-	if tc.rem.len == 0
-		-> ""
+	if tc.rem.len == 0 || tc.nelt == 0
+		-> ("", "")
+	elif !tc.isiter
+		-> ("", tc.rem)
 	;;
-	(n, sz) = getipacked(tc.rem)
-	-> tc.rem[sz:sz+n]
+
+	n = 0
+	sz = 0
+	name = ""
+	rem = tc.rem
+	if tc.isnamed
+		/* get the name */
+		(n, sz) = getipacked(tc.rem)
+		name = rem[sz:sz+n]
+		rem = rem[sz+n:]
+	;;
+
+	/* and the type */
+	(n, sz) = getipacked(rem)
+	enc = rem[sz:sz+n]
+	-> (name, enc)
 }
 
-const ncnext = {nc
+const ncnext = {tc
 	var n, sz, name, enc
 
-	if nc.rem.len == 0
+	if tc.rem.len == 0 || tc.nelt == 0
 		-> ("", "")
+	elif !tc.isiter
+		/* a bit of a trick, if we want to fake arrays */
+		tc.nelt--
+		-> ("", tc.rem)
 	;;
 
-	/* get the name */
-	(n, sz) = getipacked(nc.rem)
-	name = nc.rem[sz:sz+n]
-	nc.rem = nc.rem[sz+n:]
+	n = 0
+	sz = 0
+	name = ""
+	if tc.isnamed
+		/* get the name */
+		(n, sz) = getipacked(tc.rem)
+		name = tc.rem[sz:sz+n]
+		tc.rem = tc.rem[sz+n:]
+	;;
 
 	/* and the type */
-	(n, sz) = getipacked(nc.rem)
-	enc = nc.rem[sz:sz+n]
-	nc.rem = nc.rem[sz+n:]
+	(n, sz) = getipacked(tc.rem)
+	enc = tc.rem[sz:sz+n]
+	tc.rem = tc.rem[sz+n:]
 	-> (name, enc)
 }
 
@@ -320,7 +350,7 @@
 	var n, sz
 
 	(n, sz) = getipacked(e)
-	-> [.nelt=n, .rem=e[sz:]]
+	-> [.nelt=n, .rem=e[sz:], .isnamed=false, .isiter=true]
 }
 
 const lennamecursor = {e 
@@ -327,7 +357,7 @@
 	var n, sz
 
 	(n, sz) = getipacked(e)
-	-> [.nelt=n, .rem=e[sz:]]
+	-> [.nelt=n, .rem=e[sz:], .isnamed=true, .isiter=true]
 }
 
 const getsub = {e
--- a/lib/std/test/fmt.myr
+++ b/lib/std/test/fmt.myr
@@ -1,7 +1,20 @@
 use std
 
 pkg =
-	type pair
+	type blah
+	type blah = struct
+		a : byte[:]
+		b : int
+	;;
+	type u = union
+		`First
+		`Second int
+		`Third byte[:]
+	;;
+	type pair = struct
+		x : int16
+		y : int32
+	;;
 ;;
 
 const check = {expected, fmt, args : ...
@@ -15,6 +28,7 @@
 	;;
 }
 
+
 const main = {
 	builtins()
 	installed()
@@ -21,6 +35,10 @@
 }
 
 const builtins = {
+	var s : blah
+	var m : u
+
+	/* basic types */
 	check("      abcd", "{w=10}", "abcd")
 	check("00000bdcae", "{p=0,w=10}", "bdcae")
 	check("abcdefghijkl", "{p=0,w=10}", "abcdefghijkl")
@@ -43,6 +61,26 @@
 	check("666.91972", "{}", 666.91972)
 	check("1.0001", "{}", 1.0001)
 	check("0.000101323461002", "{}", 0.000101323461002)
+
+	/* 
+	compound types, followed by single value to make
+	sure we consume the right byte count.
+	*/
+	check("(1, 2) true", "{} {}", (1, 2), true)
+	check("(1,) true", "{} {}", (1,), true)
+
+	s = [.a="foo true", .b=123]
+	/*check("[.a=foo, .b=123] true", "{} {}", s, true) BUSTED */
+
+	m = `First
+	check("`First  true", "{} {}", m, true)
+	m = `Second 123
+	check("`Second 123 true", "{} {}", m, true)
+	m = `Third "foo"
+	check("`Third foo true", "{} {}", m, true)
+
+	check("[1, 2, 3] true", "{} {}", [1,2,3], true)
+	check("[1, 2, 3] true", "{} {}", [1,2,3][:], true)
 }
 
 const installed = {
@@ -72,6 +110,7 @@
 	check("formatted a pair: [-10, -10] x=foo", "{x=foo}", p)
 	check("formatted a pair: [-10, -10] y present", "{y}", p)
 	check("formatted a pair: [-10, -10] x=bar y present", "{x=bar,y}", p)
+	check("formatted a pair: [-10, -10] x=bar y present", "{x=bar,y}", p)
 
 	/* multiple values */
 	check("formatted a pair: [-10, -10], formatted a pair: [-10, -10]", "{}, {}", p, p)
@@ -78,12 +117,11 @@
 	/* multiple values of different types */
 	check("11, formatted a pair: [-10, -10], formatted an int: 111", "{}, {}, {}", 11 castto(byte), p, 111)
 
-}
+	/* in aggregates */
+	check("[formatted a pair: [-10, -10]]", "{}", [p])
+	check("[formatted a pair: [-10, -10]]", "{}", [p][:])
 
-type pair = struct
-	x : int16
-	y : int32
-;;
+}
 
 const intfmt = {sb, ap, opts
 	var x : int
--- a/lib/std/varargs.myr
+++ b/lib/std/varargs.myr
@@ -9,6 +9,7 @@
 	const vastart	: (args : ...# -> valist)
 	const vatype	: (ap : valist# -> byte[:])
 	const vabytes	: (ap : valist# -> byte[:])
+	const vaenter	: (ap : valist# -> valist)
 	generic vanext	: (ap : valist# -> @a)
 ;;
 
@@ -51,6 +52,18 @@
 	-> [.args = a, .tc = tc]
 }
 
+const vaenter = {ap
+	match typedesc(vatype(ap))
+	| `Tyslice enc:	-> [.args=sliceptr(ap.args), .tc=[.nelt=slicelen(ap.args), .rem=enc, .isiter=false]]
+	| `Tytuple tc:	-> [.args=ap.args, .tc=tc]
+	| `Tystruct tc:	-> [.args=ap.args, .tc=tc]
+	| `Tyunion tc:	-> [.args=addp(ap.args, 4), .tc=tc]
+	| `Tyarray (sz, enc):	-> [.args=ap.args, .tc=[.nelt=sz, .rem=enc, .isiter=false]]
+	| `Tyname (name, enc):	-> [.args=ap.args, .tc=typeenccursor(enc)]
+	| _:	std.die("unable to enter type")
+	;;
+}
+
 const vatype = {ap
 	-> tcpeek(&ap.tc)
 }
@@ -94,4 +107,17 @@
 	/* only move on after we read through the value */
 	ap.args = ((p castto(intptr)) + sizeof(@a)) castto(byte#)
 	-> (p castto(@a#))#
+}
+
+const addp = {p, k
+	-> (p castto(intptr)) + k castto(byte#)
+}
+
+const sliceptr = {p
+	-> (p castto(byte##))#
+}
+
+const slicelen = {p
+	p = addp(p, sizeof(intptr))
+	-> (p castto(size#))#
 }
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -90,7 +90,10 @@
         sep = ", ";
         free(t);
     }
-    t = tystr(tyfix(st, NULL, exprtype(args[0])->sub[0], 1));
+    if (exprtype(args[0])->nsub)
+        t = tystr(tyfix(st, NULL, exprtype(args[0])->sub[0], 1));
+    else
+        t = strdup("unknown");
     p += bprintf(p, end - p, "): %s", t);
     free(t);
 }