shithub: mc

Download patch

ref: ebeb642003c6fdbf331968cff9d2e3d769fd6b02
parent: 6a113c23192c0877185aadddbc58b943ed68dd7b
author: S. Gilles <sgilles@umd.edu>
date: Mon Nov 25 11:19:54 EST 2019

Allow specifying padding width from variable

So I can write

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

--- a/lib/std/fmt.myr
+++ b/lib/std/fmt.myr
@@ -283,43 +283,43 @@
 		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 @@
 		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 fltparams = {params
+const fltparams = {ap, params
 	var fp : fltparams
 
 	fp = [
@@ -463,7 +463,12 @@
 	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 @@
 	-> fp
 }
 
-const intparams = {params
+const intparams = {ap, params
 	var ip : intparams
 
 	ip = [
@@ -493,7 +498,12 @@
 		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 @@
 	-> ip
 }
 
-const strfmt = {sb, str, params
+const strfmt = {sb, str, ap, params
 	var w, p, i, raw, esc
 
 	p = ' '
@@ -517,7 +527,12 @@
 
 	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
@@ -575,4 +590,48 @@
 	| `Some w:	-> w;
 	| `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
 }
--- a/lib/std/test/fmt.myr
+++ b/lib/std/test/fmt.myr
@@ -4,8 +4,11 @@
 
 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],
 	][:])
 }
 
@@ -113,6 +116,47 @@
 	check(c, "[]", "{}", v[:0])
 	check(c, "[void]", "{}", v[:1])
 	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