domain/architecture/system/effs/io.bend
near-v-framework@0.5.0.0 · 135 lines · 0 definitions
1import Base
2
3# V's I/O: running a program with its arguments (the effect below), and reading and writing files with
4# Base's File API.
5
6# ---- running a program ----
7# Temporary: bend-kit-process does this, but no Bend version runs both it (2.0.27 only) and bend-kit-files (2.0.28+).
8def Program.run(cmd: String, args: String) -> IO(Result<&1, &1, U32 & String, String>):
9 import "./program_run.c"
10 import "./program_run.js"
11
12def out_of(r: Result<&1, &1, U32 & String, String>) -> String:
13 match r:
14 case Done{out}:
15 out
16 case Fail{_}:
17 ""
18
19def ok_of(r: Result<&1, &1, U32 & String, String>) -> Bool:
20 match r:
21 case Done{_}:
22 True{}
23 case Fail{_}:
24 False{}
25
26# A program's standard output when it exits 0, else "".
27def run(cmd: String, args: List<&2, String>) -> IO(String):
28 do IO<String>:
29 r : Result<&1, &1, U32 & String, String> <- Program.run(cmd, String.join(args, "\u{1f}"))
30 return out_of(r)
31
32# Whether a program exits 0.
33def succeeds(cmd: String, args: List<&2, String>) -> IO(Bool):
34 do IO<Bool>:
35 r : Result<&1, &1, U32 & String, String> <- Program.run(cmd, String.join(args, "\u{1f}"))
36 return ok_of(r)
37
38def home() -> IO(String):
39 do IO<String>:
40 r : Result<&1, &1, U32 & String, String> <- IO.get_env("HOME")
41 return Result.default(&1, &1, U32 & String, String, r, "")
42
43# ---- reading a file: its text, or "" when it cannot be read ----
44def size_of(r: Result<&1, &1, U32 & String, U32>) -> U32:
45 match r:
46 case Done{n}:
47 n
48 case Fail{_}:
49 0
50
51def text_of(r: Result<&1, &1, U32 & String, String>) -> String:
52 match r:
53 case Done{t}:
54 t
55 case Fail{_}:
56 ""
57
58def read_done(r: File & Result<&1, &1, U32 & String, String>) -> IO(String):
59 match r:
60 case (f, got):
61 do IO<String>:
62 File.close(f)
63 return text_of(got)
64
65def read_sized(r: File & Result<&1, &1, U32 & String, U32>) -> IO(String):
66 match r:
67 case (f, n):
68 do IO<String>:
69 got : File & Result<&1, &1, U32 & String, String> <- File.read(f, size_of(n))
70 read_done(got)
71
72def read_opened(r: Result<&1, &1, U32 & String, File>) -> IO(String):
73 match r:
74 case Done{f}:
75 do IO<String>:
76 n : File & Result<&1, &1, U32 & String, U32> <- File.size(f)
77 read_sized(n)
78 case Fail{_}:
79 IO.pure(String, "")
80
81def read_head_opened(r: Result<&1, &1, U32 & String, File>, max: U32) -> IO(String):
82 match r:
83 case Done{f}:
84 do IO<String>:
85 got : File & Result<&1, &1, U32 & String, String> <- File.read(f, max)
86 read_done(got)
87 case Fail{_}:
88 IO.pure(String, "")
89
90# The first `max` bytes of a file ("" if unreadable): enough for what sits at its top, like imports.
91def read_head(path: String, max: U32) -> IO(String):
92 do IO<String>:
93 r : Result<&1, &1, U32 & String, File> <- File.open(path, "r")
94 read_head_opened(r, max)
95
96def read(path: String) -> IO(String):
97 do IO<String>:
98 r : Result<&1, &1, U32 & String, File> <- File.open(path, "r")
99 read_opened(r)
100
101# ---- writing a file ----
102def after_write(r: File & Result<&1, &1, U32 & String, Unit>) -> IO(Unit):
103 match r:
104 case (f, _):
105 File.close(f)
106
107def write_opened(r: Result<&1, &1, U32 & String, File>, text: String) -> IO(Unit):
108 match r:
109 case Done{f}:
110 do IO<Unit>:
111 w : File & Result<&1, &1, U32 & String, Unit> <- File.write(f, text)
112 after_write(w)
113 case Fail{_}:
114 IO.die(Unit, 1, "cannot write a file")
115
116def write(path: String, text: String) -> IO(Unit):
117 do IO<Unit>:
118 r : Result<&1, &1, U32 & String, File> <- File.open(path, "w")
119 write_opened(r, text)
120
121def keep_filled(c: Bool, x: String, rest: List<&2, String>) -> List<&2, String>:
122 match c:
123 case True{}:
124 x <> rest
125 case False{}:
126 rest
127
128# The trimmed, non-empty strings.
129def nonempty(xs: List<&2, String>) -> List<&2, String>:
130 match xs:
131 case []:
132 []
133 case +x <> rest:
134 keep_filled(Bool.not(String.is_empty(String.trim(x))), String.trim(x), nonempty(rest))
135