summaryrefslogtreecommitdiff
path: root/common.sml
diff options
context:
space:
mode:
authorVladimir Azarov <avm@intermediate-node.net>2025-05-19 23:43:59 +0200
committerVladimir Azarov <avm@intermediate-node.net>2025-05-19 23:43:59 +0200
commit82701db07a6f9ae3ec79defbcf46e3de9346c766 (patch)
tree9fab427369799e891e8d15bc44810be27ec698c0 /common.sml
parentb2d8dcd8673cfcdbf1e8a02aa19c53e42b8a60b6 (diff)
printf F
Diffstat (limited to 'common.sml')
-rw-r--r--common.sml67
1 files changed, 43 insertions, 24 deletions
diff --git a/common.sml b/common.sml
index f2020e2..5429a5f 100644
--- a/common.sml
+++ b/common.sml
@@ -107,50 +107,69 @@ fun exit code = (
fun output stream s = TextIO.output (stream, s)
-fun fprint stream g = Fold.fold ((false, output stream), fn _ => ()) g
-fun printf g = fprint TextIO.stdOut g
-fun sprintf g =
+fun makePrintfBase output =
let
- val buf = ref []
- fun output s = (buf := s :: (!buf))
- fun finish _ = String.concat (rev (!buf))
+ val firstOnLine = ref true
+ fun endsWithNL "" = raise Unreachable
+ | endsWithNL s = String.sub (s, size s - 1) = #"\n"
+
+ fun output' "" = ()
+ | output' s = (
+ output s;
+ firstOnLine := endsWithNL s
+ )
+ fun mf () =
+ if not $ !firstOnLine then
+ (output "\n"; firstOnLine := true)
+ else
+ ()
in
- Fold.fold ((false, output), finish)
-end g
-fun Printf output g = Fold.fold ((false, output), fn _ => ()) g
+ (output', mf)
+end
+
+local
+ val ctx = ((false, makePrintfBase $ output TextIO.stdOut),
+ fn (_: bool * ((string -> unit) * (unit -> unit))) => ())
+in
+ fun printf g = Fold.fold ctx g
+end
+
+fun Printf out g = Fold.fold ((false, out), fn _ => ()) g
local
fun ifF flag cl = if not flag then cl () else ()
in
- fun ` z = Fold.step1 (fn (s, (ign, output)) =>
- (ifF ign (fn () => output s); (ign, output))) z
-
- fun A0 z = Fold.step1 (fn (f, (ign, output)) =>
- (ifF ign (fn () => f output); (ign, output))) z
- fun A1 z = Fold.step2 (fn (f, v, (ign, output)) =>
- (ifF ign (fn () => f (output, v)); (ign, output))) z
- fun A2 z = Fold.step3 (fn (f, v1, v2, (ign, output)) =>
- (ifF ign (fn () => f (output, v1, v2)); (ign, output))) z
+ fun ` z = Fold.step1 (fn (s, (ign, out as (output, _))) =>
+ (ifF ign (fn () => output s); (ign, out))) z
+
+ fun A0 z = Fold.step1 (fn (f, (ign, out)) =>
+ (ifF ign (fn () => f out); (ign, out))) z
+ fun A1 z = Fold.step2 (fn (f, v, (ign, out)) =>
+ (ifF ign (fn () => f (out, v)); (ign, out))) z
+ fun A2 z = Fold.step3 (fn (f, v1, v2, (ign, out)) =>
+ (ifF ign (fn () => f (out, v1, v2)); (ign, out))) z
end
-fun Ign z = Fold.step0 (fn (_, output) => (true, output)) z
+fun Ign z = Fold.step0 (fn (_, out) => (true, out)) z
fun bind A f = fn z => Fold.fold z A f
-fun bindWith2str to = bind A1 (fn (output, v) => output (to v))
+fun bindWith2str to = bind A1 (fn ((output, _), v) => output $ to v)
+
+fun F z = bind A0 (fn (_, mf) => mf ()) z
val I = fn z => bindWith2str Int.toString z
val C = fn z => bindWith2str str z
val B = fn z => bindWith2str Bool.toString z
-val R = fn z => bind A1 (fn (output, n) => app (fn f => f ())
+val R = fn z => bind A1 (fn ((output, _), n) => app (fn f => f ())
(List.tabulate (n, fn _ => fn () => output "\t"))) z
-type ('t, 'a, 'b) a1printer = (bool * (string -> unit)) * 'a -> 't ->
- ((bool * (string -> unit)) * 'a -> 'b) -> 'b
+type ('t, 'a, 'b, 'c) a1printer = (bool * ((string -> unit) * 'a)) * 'b
+ -> 't -> ((bool * ((string -> unit) * 'a)) * 'b -> 'c) -> 'c
fun die code g =
let
fun finish (true, _) = raise Unreachable
- | finish (false, output) = (
+ | finish (false, (output, _)) = (
output "\n";
exit code
)