~james/remy

4
14346e112835db44d5eba27da0ca97089f621a91
main
remy/cli/driver.ML -rw-r--r--3.7 KiB ViewLogBlameView rawPermalink 14346e1128 feat(cli): accept source input from standard input 19 days ago
1val root = valOf (OS.Process.getEnv "REMY_ROOT");
2val _ = use (root ^ "/.build/Remy.Export/code/remy.ML");
3
4fun chars s = map (Remy.ascii o IntInf.fromInt o Char.ord) (String.explode s);
5fun text cs = String.implode (map (Char.chr o IntInf.toInt o Remy.ordinal) cs);
6
7fun read path =
8 let
9 val stream = if path = "-" then TextIO.stdIn else TextIO.openIn path
10 fun close () = if path = "-" then () else TextIO.closeIn stream
11 val input = TextIO.inputN (stream, 65537)
12 handle exn => (close (); raise exn)
13 val _ = close ()
14 in
15 if size input > 65536 then raise Fail "source exceeds 64 KiB" else chars input
16 end;
17
18fun write path data =
19 let
20 val bytes = Byte.stringToBytes (text data)
21 val pid = SysWord.toString (Posix.Process.pidToWord (Posix.ProcEnv.getpid ()))
22 val prefix = OS.Path.concat (OS.Path.dir path, "." ^ OS.Path.file path ^ "." ^ pid ^ ".")
23 val defaultMode = Posix.FileSys.S.flags [Posix.FileSys.S.irusr, Posix.FileSys.S.iwusr,
24 Posix.FileSys.S.irgrp, Posix.FileSys.S.iwgrp, Posix.FileSys.S.iroth, Posix.FileSys.S.iwoth]
25 val mode = Posix.FileSys.S.intersect [Posix.FileSys.ST.mode (Posix.FileSys.stat path),
26 Posix.FileSys.S.flags [Posix.FileSys.S.irwxu, Posix.FileSys.S.irwxg, Posix.FileSys.S.irwxo]]
27 handle exn as OS.SysErr (_, SOME error) =>
28 if error = Posix.Error.noent then defaultMode else raise exn
29 fun reserve n =
30 if n = 128 then raise Fail "cannot reserve output file"
31 else
32 let
33 val temporary = prefix ^ Int.toString n
34 in
35 (temporary, Posix.FileSys.createf
36 (temporary, Posix.FileSys.O_WRONLY, Posix.FileSys.O.excl, mode))
37 end handle exn as OS.SysErr (_, SOME error) =>
38 if error = Posix.Error.exist then reserve (n + 1) else raise exn
39 val (temporary, fd) = reserve 0
40 val closed = ref false
41 fun close () = (Posix.IO.close fd; closed := true)
42 fun discard () =
43 ((if !closed then () else close ()) handle _ => ();
44 OS.FileSys.remove temporary handle _ => ())
45 fun loop offset =
46 if offset = Word8Vector.length bytes then ()
47 else
48 let
49 val count = Posix.IO.writeVec (fd, Word8VectorSlice.slice (bytes, offset, NONE))
50 in
51 if count = 0 then raise Fail "output write made no progress" else loop (offset + count)
52 end
53 in
54 (loop 0; close (); OS.FileSys.rename {old = temporary, new = path})
55 handle exn => (discard (); raise exn)
56 end;
57
58fun output (ok, message) =
59 (TextIO.output (if ok then TextIO.stdOut else TextIO.stdErr, text message);
60 if ok then () else OS.Process.exit OS.Process.failure);
61
62fun emit destination ((ok, bytes), report) =
63 if ok then (write destination bytes; output (true,report)) else output (false,report);
64
65fun main () =
66 (case CommandLine.arguments () of
67 ["vectors", source, destination] =>
68 (case Remy.vectors (read source) of (true, bytes) => write destination bytes | result => output result)
69 | ["eval", source, x, y, t] => output (Remy.reference (read source) (chars x) (chars y) (chars t))
70 | ["limits", depth, nodes, stack, source, destination] =>
71 emit destination (Remy.configured (chars depth) (chars nodes) (chars stack) (read source))
72 | ["check", binary] => output (Remy.validate (read binary))
73 | ["disassemble", binary] => output (Remy.disassemble (read binary))
74 | [source, destination] => emit destination (Remy.artifact (read source))
75 | _ => raise Fail "usage: remy check binary | remy disassemble binary | remy limits depth nodes stack source binary | remy source binary | remy vectors source data | remy eval source x y t (source - reads standard input)")
76 handle exn =>
77 (TextIO.output (TextIO.stdErr, "remy: " ^ General.exnMessage exn ^ "\n");
78 OS.Process.exit OS.Process.failure);