Eigenstate: myrddin-dev mailing list

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

[PATCH v2 3/3] Allow specifying padding width from variable


So I can write

    std.put("{w=?}{w=?}\n", field_a, max_width, field_b, max_width)
---

My apologies -- this one didn't seem to go through the first time I sent
it. I'm not sure why the others did.

 lib/std/fmt.myr      | 99 +++++++++++++++++++++++++++++++++++---------
 lib/std/test/fmt.myr | 48 ++++++++++++++++++++-
 2 files changed, 125 insertions(+), 22 deletions(-)

diff --git a/lib/std/fmt.myr b/lib/std/fmt.myr
index b7155f68..41785244 100644
--- a/lib/std/fmt.myr
+++ b/lib/std/fmt.myr
@@ -283,43 +283,43 @@ const fallbackfmt = {sb, params, tyenc, ap : valist# -> void
 		sbputc(sb, val)
 	| `Tyint8:
 		var val : int8 = vanext(ap)
-		intfmt(sb, intparams(params), true, (val : uint64), 8)
+		intfmt(sb, intparams(ap, params), true, (val : uint64), 8)
 	| `Tyint16:
 		var val : int16 = vanext(ap)
-		intfmt(sb, intparams(params), true, (val : uint64), 16)
+		intfmt(sb, intparams(ap, params), true, (val : uint64), 16)
 	| `Tyint:
 		var val : int = vanext(ap)
-		intfmt(sb, intparams(params), true, (val : uint64), 32)
+		intfmt(sb, intparams(ap, params), true, (val : uint64), 32)
 	| `Tyint32:
 		var val : int32 = vanext(ap)
-		intfmt(sb, intparams(params), true, (val : uint64), 32)
+		intfmt(sb, intparams(ap, params), true, (val : uint64), 32)
 	| `Tyint64:
 		var val : int64 = vanext(ap)
-		intfmt(sb, intparams(params), true, (val : uint64), 64)
+		intfmt(sb, intparams(ap, params), true, (val : uint64), 64)
 	| `Tybyte:
 		var val : byte = vanext(ap)
-		intfmt(sb, intparams(params), false, (val : uint64), 8)
+		intfmt(sb, intparams(ap, params), false, (val : uint64), 8)
 	| `Tyuint8:
 		var val : uint8 = vanext(ap)
-		intfmt(sb, intparams(params), false, (val : uint64), 8)
+		intfmt(sb, intparams(ap, params), false, (val : uint64), 8)
 	| `Tyuint16:
 		var val : uint16 = vanext(ap)
-		intfmt(sb, intparams(params), false, (val : uint64), 16)
+		intfmt(sb, intparams(ap, params), false, (val : uint64), 16)
 	| `Tyuint:
 		var val : uint = vanext(ap)
-		intfmt(sb, intparams(params), false, (val : uint64), 32)
+		intfmt(sb, intparams(ap, params), false, (val : uint64), 32)
 	| `Tyuint32:
 		var val : uint32 = vanext(ap)
-		intfmt(sb, intparams(params), false, (val : uint64), 32)
+		intfmt(sb, intparams(ap, params), false, (val : uint64), 32)
 	| `Tyuint64:
 		var val : uint64 = vanext(ap)
-		intfmt(sb, intparams(params), false, (val : uint64), 64)
+		intfmt(sb, intparams(ap, params), false, (val : uint64), 64)
 	| `Tyflt32:
 		var val : flt32 = vanext(ap)
-		flt32bfmt(sb, fltparams(params), val)
+		flt32bfmt(sb, fltparams(ap, params), val)
 	| `Tyflt64:
 		var val : flt64 = vanext(ap)
-		flt64bfmt(sb, fltparams(params), val)
+		flt64bfmt(sb, fltparams(ap, params), val)
 	| `Tyvalist:
 		sbputs(sb, "...")
 
@@ -334,7 +334,7 @@ const fallbackfmt = {sb, params, tyenc, ap : valist# -> void
 		match typedesc(desc)
 		| `Tybyte:
 			var val : byte[:] = vanext(ap)
-			strfmt(sb, val, params)
+			strfmt(sb, val, ap, params)
 		| _:
 			subap = vaenter(ap)
 			fmtslice(sb, subap, params)
@@ -449,7 +449,7 @@ const fmtslice = {sb, subap, params
 	;;
 }
 
-const fltparams = {params
+const fltparams = {ap, params
 	var fp : fltparams
 
 	fp = [
@@ -463,7 +463,12 @@ const fltparams = {params
 	for p : params
 		match p
 		| ("e", ""):	fp.scientific = true
-		| ("w", wid):	fp.padto = getint(wid, "fmt: width must be integer")
+		| ("w", wid):
+			if eq(wid, "?")
+				fp.padto = pullint(ap, "fmt: width = ? must be integer")
+			else
+				fp.padto = getint(wid, "fmt: width must be integer")
+			;;
 		| ("p", pad):	fp.padfill = decode(pad)
 		| ("s", sig):
 			fp.mode = MRelative
@@ -480,7 +485,7 @@ const fltparams = {params
 	-> fp
 }
 
-const intparams = {params
+const intparams = {ap, params
 	var ip : intparams
 
 	ip = [
@@ -493,7 +498,12 @@ const intparams = {params
 		match p
 		| ("b", bas):	ip.base = getint(bas, "fmt: base must be integer")
 		| ("x", ""):	ip.base = 16
-		| ("w", wid):	ip.padto = getint(wid, "fmt: width must be integer")
+		| ("w", wid):
+			if eq(wid, "?")
+				ip.padto = pullint(ap, "fmt: width = ? must be integer")
+			else
+				ip.padto = getint(wid, "fmt: width must be integer")
+			;;
 		| ("p", pad):	ip.padfill = decode(pad)
 		| (opt, arg):
 			std.write(2, "fmt: ")
@@ -507,7 +517,7 @@ const intparams = {params
 	-> ip
 }
 
-const strfmt = {sb, str, params
+const strfmt = {sb, str, ap, params
 	var w, p, i, raw, esc
 
 	p = ' '
@@ -517,7 +527,12 @@ const strfmt = {sb, str, params
 
 	for pp : params
 		match pp
-		| ("w", wid):	w = getint(wid, "fmt: width must be integer")
+		| ("w", wid):
+			if eq(wid, "?")
+				w = pullint(ap, "fmt: width = ? must be integer")
+			else
+				w = getint(wid, "fmt: width must be integer")
+			;;
 		| ("p", pad):	p = decode(pad)
 		| ("r", ""):	raw = true
 		| ("e", ""):	esc = true
@@ -576,3 +591,47 @@ const getint = {s, msg
 	| `None:	die(msg)
 	;;
 }
+
+const pullint = {ap, msg
+	match typedesc(vatype(ap))
+	| `Tyint8:
+		var val : int8 = vanext(ap)
+		-> val < 0 ? 0 : (val : size)
+	| `Tyint16:
+		var val : int16 = vanext(ap)
+		-> val < 0 ? 0 : (val : size)
+	| `Tyint:
+		var val : int = vanext(ap)
+		-> val < 0 ? 0 : (val : size)
+	| `Tyint32:
+		var val : int32 = vanext(ap)
+		-> val < 0 ? 0 : (val : size)
+	| `Tyint64:
+		var val : int64 = vanext(ap)
+		-> val < 0 ? 0 : (val : size)
+	| `Tyuint8:
+		var val : uint8 = vanext(ap)
+		-> (val : size)
+	| `Tyuint16:
+		var val : uint16 = vanext(ap)
+		-> (val : size)
+	| `Tyuint:
+		var val : uint = vanext(ap)
+		-> (val : size)
+	| `Tyuint32:
+		var val : uint32 = vanext(ap)
+		-> (val : size)
+	| `Tyuint64:
+		var val : uint64 = vanext(ap)
+		-> (val : size)
+	| `Tyname (_, desc):
+		/* This is primarily for handling std.size */
+		var subap = vaenter(ap)
+		var ret = pullint(&subap, msg)
+		vabytes(ap) /* Pull one element out to keep ap synchronized with subap */
+		-> ret
+	| _: die(msg)
+	;;
+
+	-> 0
+}
diff --git a/lib/std/test/fmt.myr b/lib/std/test/fmt.myr
index b80bafc6..0d0385d2 100644
--- a/lib/std/test/fmt.myr
+++ b/lib/std/test/fmt.myr
@@ -4,8 +4,11 @@ use testr
 
 const main = {
 	testr.run([
-		[.name="builtins",  .fn=builtins ],
-		[.name="installed", .fn=installed],
+		[.name="builtins",       .fn=builtins ],
+		[.name="variable-width", .fn=variablewidth ],
+
+		/* Must come last -- clobbers builtins */
+		[.name="installed",      .fn=installed],
 	][:])
 }
 
@@ -115,6 +118,47 @@ const builtins = {c
 	check(c, "[void, void]", "{}", v[:2])
 }
 
+const variablewidth = {c
+	check(c, "....xyz", "{p=.,w=7}", "xyz")
+	check(c, "....xyz", "{w=7,p=.}", "xyz")
+	check(c, "....xyz", "{p=.,w=?}", "xyz", 7)
+	check(c, "....xyz", "{w=?,p=.}", "xyz", 7)
+	check(c, "=====xyz", "{p==,w=?}", "xyz", 8)
+	check(c, "=====xyz", "{w=?,p==}", "xyz", 8)
+	check(c, "=====xyz", "{p==,w=?}", "xyz", (8 : uint8))
+	check(c, "=====xyz", "{w=?,p==}", "xyz", (8 : uint8))
+	check(c, "=====xyz", "{p==,w=?}", "xyz", (8 : std.size))
+	check(c, "=====xyz", "{w=?,p==}", "xyz", (8 : std.size))
+	check(c, "=====xyz", "{p==,w=?}", "xyz", (8 : uint64))
+	check(c, "=====xyz", "{w=?,p==}", "xyz", (8 : uint64))
+	check(c, "=====xyz", "{p==,w=?}", "xyz", (8 : int16))
+	check(c, "=====xyz", "{w=?,p==}", "xyz", (8 : int16))
+	check(c, "xyz", "{w=?,p==}", "xyz", (-34 : int16))
+
+	check(c, "     1", "{w=?}", 1, 6)
+	check(c, "77", "{w=?}", 77, (-1 : int8))
+	check(c, "77", "{w=?}", 77, (-1 : int16))
+	check(c, "77", "{w=?}", 77, (-1 : int32))
+	check(c, "77", "{w=?}", 77, (-4294967294 : int32))
+	check(c, "77", "{w=?}", 77, (-1 : int64))
+	check(c, "77", "{w=?}", 77, (-18446744073709551614 : int64))
+	check(c, "77", "{w=?}", 77, (0 : int8))
+	check(c, "77", "{w=?}", 77, (0 : int16))
+	check(c, "77", "{w=?}", 77, (0 : int32))
+	check(c, "77", "{w=?}", 77, (0 : int64))
+	check(c, "______________________________77", "{p=_,w=?}", 77, (32 : int8))
+
+	check(c, "1.0", "{w=?,p=X}", 1.0, (0 : int16))
+	check(c, "1.0", "{w=?,p=X}", 1.0, (1 : int16))
+	check(c, "1.0", "{w=?,p=X}", 1.0, (2 : int16))
+	check(c, "1.0", "{w=?,p=X}", 1.0, (3 : int16))
+	check(c, "X1.0", "{w=?,p=X}", 1.0, (4 : int16))
+	check(c, "XXXXX1.0", "{w=?,p=X}", (1.0 : flt32), (8 : int16))
+	check(c, "XXXXX1.0", "{w=?,p=X}", (1.0 : flt64), (8 : int16))
+
+	check(c, "XXab cd YYde ZZZZ1.0", "{w=4,p=X} {w=?,p=0} {p=Y,w=?} {w=?,p=Z}", "ab", "cd", (-99 : std.size), "de", (4 : uint64), (1.0 : flt32), (7 : std.size))
+}
+
 const installed = {c
 	var x : int
 	var p : pair
-- 
2.24.0


References:
[PATCH v2 0/3] Use ? for width specifiers"S. Gilles" <sgilles@xxxxxxx>