Eigenstate: myrddin-dev mailing list

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

[PATCH 2/2] Allow formatting arguments from variables


So I can write

    std.put("{w=?}{w=?}\n", max_width, field_a, max_width, field_b)
---
 lib/std/fmt.myr      | 32 +++++++++++++++++++++++++++-----
 lib/std/test/fmt.myr | 36 ++++++++++++++++++++++++++++++++++--
 2 files changed, 61 insertions(+), 7 deletions(-)

diff --git a/lib/std/fmt.myr b/lib/std/fmt.myr
index c4c3797e..8f0a632a 100644
--- a/lib/std/fmt.myr
+++ b/lib/std/fmt.myr
@@ -163,10 +163,11 @@ const sbfmt = {sb, fmt, args
 }
 
 const sbfmtv = {sb, fmt, ap -> size
-	var buf : byte[256], param : (byte[:], byte[:])[8]
+	var buf : byte[256], param : (byte[:], byte[:])[8], arg
 	var state, startp, endp, starta, nbuf
-	var nfmt, nvarargs, nparam
+	var nfmt, npulled, nvarargs, nparam
 	var b, i
+	var temps : byte[:][:] = [][:]
 
 	nvarargs = ap.tc.nelt
 	nfmt = 0
@@ -174,6 +175,7 @@ const sbfmtv = {sb, fmt, ap -> size
 	starta = 0
 	nparam = 0
 	nbuf = 0
+	npulled = 0
 	endp = 0
 	state = `Copy
 	i = 0
@@ -229,13 +231,15 @@ const sbfmtv = {sb, fmt, ap -> size
 		/* {param=arg} */
 		| (`ParamArg, ','):
 			state = `ParamOpt
-			param[nparam++] = (buf[startp:endp], buf[starta:nbuf])
+			arg = maybepullarg(buf[starta:nbuf], &temps, &npulled, ap)
+			param[nparam++] = (buf[startp:endp], arg)
 			startp = nbuf
 			endp = nbuf
 		| (`ParamArg, '}'):
 			state = `Copy
 			if startp != nbuf
-				param[nparam++] = (buf[startp:endp], buf[starta:nbuf])
+				arg = maybepullarg(buf[starta:nbuf], &temps, &npulled, ap)
+				param[nparam++] = (buf[startp:endp], arg)
 			;;
 			fmtval(sb, vatype(ap), ap, param[:nparam])
 			nfmt++
@@ -245,12 +249,30 @@ const sbfmtv = {sb, fmt, ap -> size
 			buf[nbuf++] = b
 		;;
 	;;
-	if nfmt != nvarargs
+	if nfmt + npulled != nvarargs
 		die("too many values for fmt\n")
 	;;
+	for t : temps
+		slfree(t)
+	;;
+	slfree(temps)
 	-> sb.len
 }
 
+/* Distinguish between things like {w=5} and {w=?} */
+const maybepullarg = {default : byte[:], storage : byte[:][:]#, npulled : size#, ap
+	if !std.eq(default, "?")
+		-> default
+	;;
+
+	var pulled_arg : strbuf# = mksb()
+	fallbackfmt(pulled_arg, [][:], vatype(ap), ap)
+	var arg = sbfin(pulled_arg)
+	slpush(storage, arg)
+	npulled#++
+	-> arg
+}
+
 const fmtval = {sb, ty, ap, params
 	match htget(fmtmap, ty)
 	| `Some f:
diff --git a/lib/std/test/fmt.myr b/lib/std/test/fmt.myr
index b80bafc6..e19a5543 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="question-marks", .fn=questionmarks],
+
+		/* This one has to go at the end, since it clobbers default formatters */
+		[.name="installed",      .fn=installed],
 	][:])
 }
 
@@ -151,7 +154,36 @@ const installed = {c
 	/* in aggregates */
 	check(c, "[formatted a pair: [-10, -10]]", "{}", [p])
 	check(c, "[formatted a pair: [-10, -10]]", "{}", [p][:])
+}
+
+const questionmarks = {c
+	check(c, "x", "{w=1,p=x}", "")
+	check(c, "x", "{w=?,p=x}", 1, "")
+	check(c, "x", "{w=?,p=?}", 1, "x", "")
+	check(c, "x", "{w=1,p=?}", "x", "")
+
+	check(c, "  8", "{w=3,p= }", 8)
+	check(c, "  8", "{w=3,p= }", "8")
+	check(c, "  8", "{w=?,p= }", 3, 8)
+	check(c, "  8", "{w=?,p= }", 3, "8")
+	check(c, "  8", "{w=?,p= }", "3", 8)
+	check(c, "  8", "{w=?,p= }", "3", "8")
+
+	check(c, "8.00", "{s=3}", 8.0)
+	check(c, "8.00", "{s=?}", 3, 8.0)
+
+	check(c, "x", "{w=?}", 0, "x")
+	check(c, "x", "{w=?}", -20, "x")
+	check(c, "                           x", "{w=?}", 28, "x")
+	check(c, "???????????????????????????x", "{w=?,p=?}", 28, "?", "x")
+	check(c, "???????????????????????????x", "{w=?,p=?}", 28, "?anddiscardtherest", "x")
+
+	check(c, "yyyyyyyyyyfoo..bar..xxxxxxxxxxxxxxxxbaz", "{w=?,p=?,p=?}..{w=3,p=?,p=x}..{w=?,p=x}", "13", "x", "y", "foo", 10, "bar", "19", "baz")
+
+	check(c, "a1xy2xy3xy4b", "a{j=?}b", "xy", [ 1, 2, 3, 4 ][:])
 
+	check(c, "1.111", "{s=?}", 4, 1.11111111)
+	check(c, "1.111", "{s=?}", "4", 1.11111111)
 }
 
 const intfmt = {sb, ap, opts
-- 
2.24.0


References:
[PATCH 0/2] Use ? in format specifiers"S. Gilles" <sgilles@xxxxxxx>