diff options
Diffstat (limited to 'src/nbc/misc.sml')
-rw-r--r-- | src/nbc/misc.sml | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/nbc/misc.sml b/src/nbc/misc.sml new file mode 100644 index 0000000..4790bbc --- /dev/null +++ b/src/nbc/misc.sml @@ -0,0 +1,125 @@ +signature MISC = sig + val inputLine: TextIO.instream -> string option + val sequenceFromRead: (TextIO.instream -> 'a option) -> TextIO.instream -> 'a Sequence.t + val sequenceLines: TextIO.instream -> string Sequence.t + val sortedDirectoryNoPrefix: string -> string list + val sortedDirectory: string -> string list + val substitute: (string * string) list -> string -> string option + val basenameWithoutExtension: string -> string + val split2: string -> (string * string) option + val longestCommonSubstring: string list -> string +end + +structure Misc :> MISC = struct + fun |> (x, f) = f x + infix |> + fun \ f x y = f (x, y) + fun sequenceFromRead f ioc = Sequence.from (fn () => f ioc) + fun inputLine instream = case TextIO.inputLine instream of + NONE => NONE + | SOME x => SOME (String.substring (x, 0, size x - 1)) + val sequenceLines = sequenceFromRead inputLine + fun sortedDirectoryNoPrefix d = + let + val h = OS.FileSys.openDir d + fun loop l = + case OS.FileSys.readDir h of + NONE => ( + OS.FileSys.closeDir h + ; ListMergeSort.sort (op >) l + ) | SOME n => loop ( + if String.sub (n, 0) = #"." then l + else n :: l + ) + in + loop nil + end + fun sortedDirectory d = + map (\OS.Path.concat d) (sortedDirectoryNoPrefix d) + fun assoc list key = + case + List.find (fn (possibility, _) => possibility = key) list + of + NONE => NONE + | SOME (_, answer) => SOME answer + local + exception NotFound + in + fun substitute v s = + Substitution.substitute + (fn s => (case assoc v s of + NONE => raise NotFound + | SOME x => x + )) s + handle NotFound => NONE + end + fun basenameWithoutExtension s = OS.Path.base (OS.Path.file s) + local + fun index f (string, offset) = + let + val last = size string + fun loop i = + if i = last then ~1 + else if f (String.sub (string, i)) then i + else loop (i + 1) + in + loop offset + end + in + val indexWhitespace = index Char.isSpace + val indexNonWhitespace = index (not o Char.isSpace) + end + fun split2 s = + let + val f1b = indexNonWhitespace (s, 0) + in + if f1b = ~1 then NONE + else let + val f1e = indexWhitespace (s, f1b + 1) + in + if f1e = ~1 then NONE + else let + val f2b = indexNonWhitespace (s, f1e + 1) + in + if f2b = ~1 then NONE + else let + val f2e = indexWhitespace (s, f2b + 1) + in + if f2e = ~1 then SOME ( + substring (s, f1b, f1e - f1b) + , substring (s, f2b, size s - f2b) + ) else if indexNonWhitespace (s, f2e + 1) = ~1 then + SOME ( + substring (s, f1b, f1e - f1b) + , substring (s, f2b, f2e - f2b) + ) + else NONE + end + end + end + end + fun longestCommonSubstring strings = + case + foldl (fn (a, b) => (case b of + NONE => SOME a + | SOME b => if size a < size b then SOME a else SOME b + )) NONE strings + of + NONE => "" + | SOME shortest => let + val minimumSize = size shortest + fun loop (size, offset) = + let + fun next () = + if size + offset = minimumSize then + loop (size - 1, 0) + else loop (size, offset + 1) + val sub = substring (shortest, offset, size) + in + if List.all (String.isSubstring sub) strings then sub + else next () + end + in + loop (minimumSize, 0) + end +end |