@shd101wyy/yo 0.1.29 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/.github/skills/yo-async-effects/SKILL.md +3 -3
  2. package/.github/skills/yo-async-effects/async-effects-recipes.md +19 -11
  3. package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +33 -13
  4. package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +1 -1
  5. package/.github/skills/yo-syntax/syntax-cheatsheet.md +59 -21
  6. package/README.md +4 -3
  7. package/out/cjs/index.cjs +771 -676
  8. package/out/cjs/yo-cli.cjs +1003 -898
  9. package/out/cjs/yo-lsp.cjs +834 -739
  10. package/out/esm/index.mjs +716 -621
  11. package/out/types/src/codegen/exprs/async.d.ts +2 -0
  12. package/out/types/src/codegen/exprs/await.d.ts +1 -0
  13. package/out/types/src/codegen/exprs/closures.d.ts +4 -0
  14. package/out/types/src/codegen/functions/context.d.ts +6 -0
  15. package/out/types/src/env.d.ts +2 -0
  16. package/out/types/src/evaluator/builtins/pragma.d.ts +9 -0
  17. package/out/types/src/evaluator/builtins/unsafe.d.ts +8 -0
  18. package/out/types/src/evaluator/context.d.ts +2 -0
  19. package/out/types/src/evaluator/index.d.ts +1 -1
  20. package/out/types/src/evaluator/memory-safety.d.ts +14 -0
  21. package/out/types/src/evaluator/types/flowability.d.ts +6 -0
  22. package/out/types/src/expr-traversal.d.ts +1 -0
  23. package/out/types/src/expr.d.ts +4 -1
  24. package/out/types/src/public-safe-report.d.ts +19 -0
  25. package/out/types/src/tests/comptime-ref-gate.test.d.ts +1 -0
  26. package/out/types/src/tests/pragma-validation.test.d.ts +1 -0
  27. package/out/types/src/tests/public-safe-report.test.d.ts +1 -0
  28. package/out/types/src/tests/type-representation-pointer.test.d.ts +1 -0
  29. package/out/types/src/tests/unsafe-gate.test.d.ts +1 -0
  30. package/out/types/src/tests/unsafe-report-classify.test.d.ts +1 -0
  31. package/out/types/src/types/definitions.d.ts +2 -0
  32. package/out/types/src/types/utils.d.ts +4 -0
  33. package/out/types/src/unsafe-report.d.ts +29 -0
  34. package/out/types/src/value.d.ts +1 -0
  35. package/out/types/tsconfig.tsbuildinfo +1 -1
  36. package/package.json +1 -1
  37. package/scripts/add-pragma-for-pointer-decls.ts +134 -0
  38. package/scripts/add-pragma.ts +58 -0
  39. package/scripts/migrate-amp-method-calls.ts +186 -0
  40. package/scripts/migrate-clone-calls.ts +93 -0
  41. package/scripts/migrate-get-unwrap.ts +166 -0
  42. package/scripts/migrate-index-patterns.ts +210 -0
  43. package/scripts/migrate-index-trait.ts +142 -0
  44. package/scripts/migrate-iterator.ts +150 -0
  45. package/scripts/migrate-self-ptr.ts +220 -0
  46. package/scripts/migrate-skip-pragmas.ts +109 -0
  47. package/scripts/migrate-tostring.ts +134 -0
  48. package/scripts/trim-pragma.ts +130 -0
  49. package/scripts/wrap-extern-calls.ts +161 -0
  50. package/std/alg/hash.yo +3 -2
  51. package/std/allocator.yo +6 -5
  52. package/std/async.yo +2 -2
  53. package/std/collections/array_list.yo +59 -40
  54. package/std/collections/btree_map.yo +19 -18
  55. package/std/collections/deque.yo +9 -8
  56. package/std/collections/hash_map.yo +101 -13
  57. package/std/collections/hash_set.yo +5 -4
  58. package/std/collections/linked_list.yo +39 -4
  59. package/std/collections/ordered_map.yo +3 -3
  60. package/std/collections/priority_queue.yo +14 -13
  61. package/std/crypto/md5.yo +2 -1
  62. package/std/crypto/random.yo +16 -15
  63. package/std/crypto/sha256.yo +2 -1
  64. package/std/encoding/base64.yo +14 -14
  65. package/std/encoding/hex.yo +3 -3
  66. package/std/encoding/json.yo +59 -10
  67. package/std/encoding/punycode.yo +24 -23
  68. package/std/encoding/toml.yo +4 -3
  69. package/std/encoding/utf16.yo +2 -2
  70. package/std/env.yo +43 -28
  71. package/std/error.yo +6 -6
  72. package/std/fmt/display.yo +2 -2
  73. package/std/fmt/index.yo +6 -5
  74. package/std/fmt/to_string.yo +39 -38
  75. package/std/fmt/writer.yo +9 -8
  76. package/std/fs/dir.yo +34 -33
  77. package/std/fs/file.yo +52 -51
  78. package/std/fs/metadata.yo +10 -9
  79. package/std/fs/temp.yo +24 -13
  80. package/std/fs/walker.yo +10 -9
  81. package/std/gc.yo +1 -0
  82. package/std/glob.yo +7 -7
  83. package/std/http/client.yo +15 -14
  84. package/std/http/http.yo +6 -6
  85. package/std/http/index.yo +1 -1
  86. package/std/imm/list.yo +33 -0
  87. package/std/imm/map.yo +2 -1
  88. package/std/imm/set.yo +1 -0
  89. package/std/imm/sorted_map.yo +1 -0
  90. package/std/imm/sorted_set.yo +1 -0
  91. package/std/imm/string.yo +27 -23
  92. package/std/imm/vec.yo +18 -2
  93. package/std/io/reader.yo +2 -1
  94. package/std/io/writer.yo +3 -2
  95. package/std/libc/assert.yo +1 -0
  96. package/std/libc/ctype.yo +1 -0
  97. package/std/libc/dirent.yo +1 -0
  98. package/std/libc/errno.yo +1 -0
  99. package/std/libc/fcntl.yo +1 -0
  100. package/std/libc/float.yo +1 -0
  101. package/std/libc/limits.yo +1 -0
  102. package/std/libc/math.yo +1 -0
  103. package/std/libc/signal.yo +1 -0
  104. package/std/libc/stdatomic.yo +1 -0
  105. package/std/libc/stdint.yo +1 -0
  106. package/std/libc/stdio.yo +1 -0
  107. package/std/libc/stdlib.yo +1 -0
  108. package/std/libc/string.yo +1 -0
  109. package/std/libc/sys/stat.yo +1 -0
  110. package/std/libc/time.yo +1 -0
  111. package/std/libc/unistd.yo +1 -0
  112. package/std/libc/wctype.yo +1 -0
  113. package/std/libc/windows.yo +2 -0
  114. package/std/log.yo +7 -6
  115. package/std/net/addr.yo +5 -4
  116. package/std/net/dns.yo +7 -6
  117. package/std/net/errors.yo +8 -8
  118. package/std/net/tcp.yo +19 -18
  119. package/std/net/udp.yo +13 -12
  120. package/std/os/signal.yo +3 -3
  121. package/std/path.yo +1 -0
  122. package/std/prelude.yo +353 -182
  123. package/std/process/command.yo +40 -23
  124. package/std/process/index.yo +2 -1
  125. package/std/regex/compiler.yo +10 -9
  126. package/std/regex/index.yo +41 -41
  127. package/std/regex/match.yo +2 -2
  128. package/std/regex/parser.yo +21 -21
  129. package/std/regex/vm.yo +42 -41
  130. package/std/string/string.yo +95 -40
  131. package/std/string/string_builder.yo +9 -9
  132. package/std/string/unicode.yo +50 -49
  133. package/std/sync/channel.yo +2 -1
  134. package/std/sync/cond.yo +5 -4
  135. package/std/sync/mutex.yo +4 -3
  136. package/std/sys/advise.yo +1 -0
  137. package/std/sys/bufio/buf_reader.yo +17 -16
  138. package/std/sys/bufio/buf_writer.yo +10 -9
  139. package/std/sys/clock.yo +1 -0
  140. package/std/sys/copy.yo +1 -0
  141. package/std/sys/dir.yo +10 -9
  142. package/std/sys/dns.yo +6 -5
  143. package/std/sys/errors.yo +11 -11
  144. package/std/sys/events.yo +1 -0
  145. package/std/sys/externs.yo +38 -37
  146. package/std/sys/file.yo +17 -16
  147. package/std/sys/future.yo +4 -3
  148. package/std/sys/iov.yo +1 -0
  149. package/std/sys/mmap.yo +1 -0
  150. package/std/sys/path.yo +1 -0
  151. package/std/sys/perm.yo +2 -1
  152. package/std/sys/pipe.yo +1 -0
  153. package/std/sys/process.yo +5 -4
  154. package/std/sys/signal.yo +1 -0
  155. package/std/sys/socketpair.yo +1 -0
  156. package/std/sys/sockinfo.yo +1 -0
  157. package/std/sys/statfs.yo +2 -1
  158. package/std/sys/statx.yo +1 -0
  159. package/std/sys/sysinfo.yo +1 -0
  160. package/std/sys/tcp.yo +15 -14
  161. package/std/sys/temp.yo +1 -0
  162. package/std/sys/time.yo +2 -1
  163. package/std/sys/timer.yo +6 -6
  164. package/std/sys/tty.yo +2 -1
  165. package/std/sys/udp.yo +13 -12
  166. package/std/sys/unix.yo +12 -11
  167. package/std/testing/bench.yo +4 -3
  168. package/std/thread.yo +7 -6
  169. package/std/time/datetime.yo +18 -15
  170. package/std/time/duration.yo +11 -10
  171. package/std/time/instant.yo +4 -4
  172. package/std/time/sleep.yo +1 -0
  173. package/std/url/index.yo +3 -3
  174. package/std/worker.yo +4 -3
package/std/fs/file.yo CHANGED
@@ -8,7 +8,7 @@
8
8
  //! ```rust
9
9
  //! { File, read_string, write_file, OpenMode } :: import "std/fs/file";
10
10
  //!
11
- //! main :: (fn(io : IO, exn : Exception) -> unit)({
11
+ //! main :: (fn(io : Io, exn : Exception) -> unit)({
12
12
  //! // Write a file
13
13
  //! io.await(write_file(Path.new(`test.txt`), `hello world`, io), { io, exn });
14
14
  //!
@@ -20,14 +20,15 @@
20
20
  //! f := io.await(File.open(Path.new(`test.txt`), .Read, io), { io, exn });
21
21
  //! });
22
22
  //! ```
23
+ pragma(Pragma.AllowUnsafe);
23
24
  { GlobalAllocator } :: import("../allocator");
24
25
  { malloc, free } :: GlobalAllocator;
25
26
  { ArrayList } :: import("../collections/array_list");
26
27
  open(import("../string"));
27
28
  open(import("../fmt"));
28
29
  { Path } :: import("../path");
29
- { IOError } :: import("../sys/errors");
30
- { Error, AnyError, Exception, IOErr } :: import("../error");
30
+ { IoError } :: import("../sys/errors");
31
+ { Error, AnyError, Exception, IoExn } :: import("../error");
31
32
  { Metadata } :: import("./metadata");
32
33
  _metadata_mod :: import("./metadata");
33
34
  { Statx } :: import("../sys/statx");
@@ -51,7 +52,7 @@ File :: object(
51
52
  impl(
52
53
  File,
53
54
  /// Open a file at `path` with the given mode and custom permissions.
54
- open_with : (fn(path : Path, mode : OpenMode, perm : FilePermission, io : IO) -> Impl(Future(File, IOErr)))({
55
+ open_with : (fn(path : Path, mode : OpenMode, perm : FilePermission, io : Io) -> Impl(Future(File, IoExn)))({
55
56
  flags := _open_mode_to_flags(mode);
56
57
  file_mode := cond(
57
58
  _open_mode_needs_perm(mode) => i32(perm.mode),
@@ -62,7 +63,7 @@ impl(
62
63
  cstr_bytes := path_str.to_cstr();
63
64
  cstr := cstr_bytes.ptr().unwrap();
64
65
  result := e.io.await(IO_file.openat(AT_FDCWD, cstr, flags, file_mode), e.io);
65
- fd := IOError.check(result, e.exn);
66
+ fd := IoError.check(result, e.exn);
66
67
  File(
67
68
  _fd : fd,
68
69
  _path : path,
@@ -71,37 +72,37 @@ impl(
71
72
  })
72
73
  }),
73
74
  /// Open a file from a `str` path with the given mode and custom permissions.
74
- open_with_str : (fn(path : str, mode : OpenMode, perm : FilePermission, io : IO) -> Impl(Future(File, IOErr)))(
75
+ open_with_str : (fn(path : str, mode : OpenMode, perm : FilePermission, io : Io) -> Impl(Future(File, IoExn)))(
75
76
  File.open_with(Path.new(String.from(path)), mode, perm, io)
76
77
  ),
77
78
  /// Open a file from a C string path with the given mode and custom permissions.
78
- open_with_cstr : (fn(path : *(u8), mode : OpenMode, perm : FilePermission, io : IO) -> Impl(Future(File, IOErr)))(
79
+ open_with_cstr : (fn(path : *(u8), mode : OpenMode, perm : FilePermission, io : Io) -> Impl(Future(File, IoExn)))(
79
80
  File.open_with(Path.from_cstr(path), mode, perm, io)
80
81
  ),
81
82
  /// Open a file at `path` with the given mode and default permissions (0o644).
82
- open : (fn(path : Path, mode : OpenMode, io : IO) -> Impl(Future(File, IOErr)))(
83
+ open : (fn(path : Path, mode : OpenMode, io : Io) -> Impl(Future(File, IoExn)))(
83
84
  File.open_with(path, mode, FilePermission.default(), io)
84
85
  ),
85
86
  /// Open a file from a `str` path with the given mode and default permissions.
86
- open_str : (fn(path : str, mode : OpenMode, io : IO) -> Impl(Future(File, IOErr)))(
87
+ open_str : (fn(path : str, mode : OpenMode, io : Io) -> Impl(Future(File, IoExn)))(
87
88
  File.open(Path.new(String.from(path)), mode, io)
88
89
  ),
89
90
  /// Open a file from a C string path with the given mode and default permissions.
90
- open_cstr : (fn(path : *(u8), mode : OpenMode, io : IO) -> Impl(Future(File, IOErr)))(
91
+ open_cstr : (fn(path : *(u8), mode : OpenMode, io : Io) -> Impl(Future(File, IoExn)))(
91
92
  File.open(Path.from_cstr(path), mode, io)
92
93
  ),
93
94
  /// Read up to `size` bytes into the buffer `buf`.
94
95
  /// Returns the number of bytes actually read.
95
- read : (fn(self : Self, buf : *(u8), size : u32, io : IO) -> Impl(Future(i32, IOErr)))({
96
+ read : (fn(self : Self, buf : *(u8), size : u32, io : Io) -> Impl(Future(i32, IoExn)))({
96
97
  fd := self._fd;
97
98
  io.async((e) => {
98
99
  result := e.io.await(IO_file.read(fd, buf, size, u64(0)), e.io);
99
- IOError.check(result, e.exn)
100
+ IoError.check(result, e.exn)
100
101
  })
101
102
  }),
102
103
  /// Write a `String` to the file.
103
104
  /// Returns the number of bytes written.
104
- write_string : (fn(self : Self, data : String, io : IO) -> Impl(Future(i32, IOErr)))({
105
+ write_string : (fn(self : Self, data : String, io : Io) -> Impl(Future(i32, IoExn)))({
105
106
  fd := self._fd;
106
107
  io.async((e) => {
107
108
  data_bytes := data.as_bytes();
@@ -109,14 +110,14 @@ impl(
109
110
  (data_bytes.len() == usize(0)) => i32(0),
110
111
  true => {
111
112
  result := e.io.await(IO_file.write(fd, data_bytes.ptr().unwrap(), u32(data_bytes.len()), u64(0)), e.io);
112
- IOError.check(result, e.exn)
113
+ IoError.check(result, e.exn)
113
114
  }
114
115
  )
115
116
  })
116
117
  }),
117
118
  /// Write bytes from an `ArrayList(u8)` to the file.
118
119
  /// Returns the number of bytes written.
119
- write_bytes : (fn(self : Self, data : ArrayList(u8), io : IO) -> Impl(Future(i32, IOErr)))({
120
+ write_bytes : (fn(self : Self, data : ArrayList(u8), io : Io) -> Impl(Future(i32, IoExn)))({
120
121
  fd := self._fd;
121
122
  io.async(
122
123
  (e) =>
@@ -124,13 +125,13 @@ impl(
124
125
  (data.len() == usize(0)) => i32(0),
125
126
  true => {
126
127
  result := e.io.await(IO_file.write(fd, data.ptr().unwrap(), u32(data.len()), u64(0)), e.io);
127
- IOError.check(result, e.exn)
128
+ IoError.check(result, e.exn)
128
129
  }
129
130
  )
130
131
  )
131
132
  }),
132
133
  /// Read the entire file contents into an `ArrayList(u8)`.
133
- read_bytes : (fn(self : Self, io : IO) -> Impl(Future(ArrayList(u8), IOErr)))({
134
+ read_bytes : (fn(self : Self, io : Io) -> Impl(Future(ArrayList(u8), IoExn)))({
134
135
  fd := self._fd;
135
136
  io.async((e) => {
136
137
  buf_size := usize(4096);
@@ -142,7 +143,7 @@ impl(
142
143
  cond(
143
144
  (n < i32(0)) => {
144
145
  free(.Some(*(void)(buf)));
145
- e.exn.throw(dyn(IOError.from_errno(i32(0) - n)));
146
+ e.exn.throw(dyn(IoError.from_errno(i32(0) - n)));
146
147
  },
147
148
  (n == i32(0)) => break,
148
149
  true => {
@@ -160,19 +161,19 @@ impl(
160
161
  })
161
162
  }),
162
163
  /// Read the entire file contents into a `String`.
163
- read_string : (fn(self : Self, io : IO) -> Impl(Future(String, IOErr)))(
164
+ read_string : (fn(self : Self, io : Io) -> Impl(Future(String, IoExn)))(
164
165
  io.async((e) => {
165
166
  bytes := e.io.await(self.read_bytes(io), e);
166
167
  String.from_bytes(bytes)
167
168
  })
168
169
  ),
169
170
  /// Flush (fsync) file data to disk.
170
- flush : (fn(self : Self, io : IO) -> Impl(Future(unit, IOErr)))({
171
+ flush : (fn(self : Self, io : Io) -> Impl(Future(unit, IoExn)))({
171
172
  fd := self._fd;
172
173
  io.async((e) => {
173
174
  result := e.io.await(IO_file.fsync(fd), e.io);
174
175
  cond(
175
- (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
176
+ (result < i32(0)) => e.exn.throw(dyn(IoError.from_errno(i32(0) - result))),
176
177
  true => ()
177
178
  )
178
179
  })
@@ -181,7 +182,7 @@ impl(
181
182
  seek : (fn(self : Self, offset : i64, from : SeekFrom, exn : Exception) -> i64)({
182
183
  result := IO_seek.lseek(self._fd, offset, _seek_from_to_whence(from));
183
184
  cond(
184
- (result < i64(0)) => exn.throw(dyn(IOError.from_errno(i32(i64(0) - result)))),
185
+ (result < i64(0)) => exn.throw(dyn(IoError.from_errno(i32(i64(0) - result)))),
185
186
  true => result
186
187
  )
187
188
  }),
@@ -194,7 +195,7 @@ impl(
194
195
  IO_file.file_size(self._fd)
195
196
  ),
196
197
  /// Close the file descriptor. Safe to call multiple times.
197
- close : (fn(self : Self, io : IO) -> Impl(Future(unit, IOErr)))({
198
+ close : (fn(self : Self, io : Io) -> Impl(Future(unit, IoExn)))({
198
199
  fd := self._fd;
199
200
  io.async(
200
201
  (e) =>
@@ -204,7 +205,7 @@ impl(
204
205
  result := e.io.await(IO_file.close(fd), e.io);
205
206
  self._is_closed = true;
206
207
  cond(
207
- (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
208
+ (result < i32(0)) => e.exn.throw(dyn(IoError.from_errno(i32(0) - result))),
208
209
  true => ()
209
210
  )
210
211
  }
@@ -220,7 +221,7 @@ impl(
220
221
  self._path
221
222
  ),
222
223
  /// Get file metadata (size, permissions, timestamps).
223
- metadata : (fn(self : Self, io : IO) -> Impl(Future(Metadata, IOErr)))(
224
+ metadata : (fn(self : Self, io : Io) -> Impl(Future(Metadata, IoExn)))(
224
225
  _metadata_mod.metadata(self._path, io)
225
226
  )
226
227
  );
@@ -243,7 +244,7 @@ export(File, OpenMode, FilePermission, SeekFrom);
243
244
  // Convenience functions
244
245
  // ============================================================================
245
246
  /// Read an entire file into a `String`.
246
- read_string :: (fn(path : Path, io : IO) -> Impl(Future(String, IOErr)))(
247
+ read_string :: (fn(path : Path, io : Io) -> Impl(Future(String, IoExn)))(
247
248
  io.async((e) => {
248
249
  file := e.io.await(File.open(path,.Read, io), e);
249
250
  content := e.io.await(file.read_string(io), e);
@@ -252,15 +253,15 @@ read_string :: (fn(path : Path, io : IO) -> Impl(Future(String, IOErr)))(
252
253
  })
253
254
  );
254
255
  /// Read an entire file into a `String` (`str` path variant).
255
- read_string_str :: (fn(path : str, io : IO) -> Impl(Future(String, IOErr)))(
256
+ read_string_str :: (fn(path : str, io : Io) -> Impl(Future(String, IoExn)))(
256
257
  read_string(Path.new(String.from(path)), io)
257
258
  );
258
259
  /// Read an entire file into a `String` (C string path variant).
259
- read_string_cstr :: (fn(path : *(u8), io : IO) -> Impl(Future(String, IOErr)))(
260
+ read_string_cstr :: (fn(path : *(u8), io : Io) -> Impl(Future(String, IoExn)))(
260
261
  read_string(Path.from_cstr(path), io)
261
262
  );
262
263
  /// Read an entire file into a byte list (`ArrayList(u8)`).
263
- read_file :: (fn(path : Path, io : IO) -> Impl(Future(ArrayList(u8), IOErr)))(
264
+ read_file :: (fn(path : Path, io : Io) -> Impl(Future(ArrayList(u8), IoExn)))(
264
265
  io.async((e) => {
265
266
  file := e.io.await(File.open(path,.Read, io), e);
266
267
  content := e.io.await(file.read_bytes(io), e);
@@ -269,15 +270,15 @@ read_file :: (fn(path : Path, io : IO) -> Impl(Future(ArrayList(u8), IOErr)))(
269
270
  })
270
271
  );
271
272
  /// Read an entire file into bytes (`str` path variant).
272
- read_file_str :: (fn(path : str, io : IO) -> Impl(Future(ArrayList(u8), IOErr)))(
273
+ read_file_str :: (fn(path : str, io : Io) -> Impl(Future(ArrayList(u8), IoExn)))(
273
274
  read_file(Path.new(String.from(path)), io)
274
275
  );
275
276
  /// Read an entire file into bytes (C string path variant).
276
- read_file_cstr :: (fn(path : *(u8), io : IO) -> Impl(Future(ArrayList(u8), IOErr)))(
277
+ read_file_cstr :: (fn(path : *(u8), io : Io) -> Impl(Future(ArrayList(u8), IoExn)))(
277
278
  read_file(Path.from_cstr(path), io)
278
279
  );
279
280
  /// Write a `String` to a file, creating or truncating it.
280
- write_file :: (fn(path : Path, data : String, io : IO) -> Impl(Future(unit, IOErr)))(
281
+ write_file :: (fn(path : Path, data : String, io : Io) -> Impl(Future(unit, IoExn)))(
281
282
  io.async((e) => {
282
283
  file := e.io.await(File.open(path,.Write, io), e);
283
284
  e.io.await(file.write_string(data, io), e);
@@ -285,15 +286,15 @@ write_file :: (fn(path : Path, data : String, io : IO) -> Impl(Future(unit, IOEr
285
286
  })
286
287
  );
287
288
  /// Write a `str` to a file, creating or truncating it (`str` path variant).
288
- write_file_str :: (fn(path : str, data : str, io : IO) -> Impl(Future(unit, IOErr)))(
289
+ write_file_str :: (fn(path : str, data : str, io : Io) -> Impl(Future(unit, IoExn)))(
289
290
  write_file(Path.new(String.from(path)), String.from(data), io)
290
291
  );
291
292
  /// Write a `str` to a file, creating or truncating it (C string path variant).
292
- write_file_cstr :: (fn(path : *(u8), data : str, io : IO) -> Impl(Future(unit, IOErr)))(
293
+ write_file_cstr :: (fn(path : *(u8), data : str, io : Io) -> Impl(Future(unit, IoExn)))(
293
294
  write_file(Path.from_cstr(path), String.from(data), io)
294
295
  );
295
296
  /// Write bytes to a file, creating or truncating it.
296
- write_bytes :: (fn(path : Path, data : ArrayList(u8), io : IO) -> Impl(Future(unit, IOErr)))(
297
+ write_bytes :: (fn(path : Path, data : ArrayList(u8), io : Io) -> Impl(Future(unit, IoExn)))(
297
298
  io.async((e) => {
298
299
  file := e.io.await(File.open(path,.Write, io), e);
299
300
  e.io.await(file.write_bytes(data, io), e);
@@ -301,7 +302,7 @@ write_bytes :: (fn(path : Path, data : ArrayList(u8), io : IO) -> Impl(Future(un
301
302
  })
302
303
  );
303
304
  /// Append a `String` to a file, creating it if it does not exist.
304
- append_file :: (fn(path : Path, data : String, io : IO) -> Impl(Future(unit, IOErr)))(
305
+ append_file :: (fn(path : Path, data : String, io : Io) -> Impl(Future(unit, IoExn)))(
305
306
  io.async((e) => {
306
307
  file := e.io.await(File.open(path,.Append, io), e);
307
308
  e.io.await(file.write_string(data, io), e);
@@ -309,7 +310,7 @@ append_file :: (fn(path : Path, data : String, io : IO) -> Impl(Future(unit, IOE
309
310
  })
310
311
  );
311
312
  /// Append a `str` to a file (`str` path variant).
312
- append_file_str :: (fn(path : str, data : str, io : IO) -> Impl(Future(unit, IOErr)))(
313
+ append_file_str :: (fn(path : str, data : str, io : Io) -> Impl(Future(unit, IoExn)))(
313
314
  append_file(Path.new(String.from(path)), String.from(data), io)
314
315
  );
315
316
  extern(
@@ -318,7 +319,7 @@ extern(
318
319
  );
319
320
  /// Check if a path exists. Returns `false` for any error including file not found.
320
321
  /// Does not use the `Exception` effect.
321
- exists :: (fn(path : Path, io : IO) -> Impl(Future(bool, IO)))(
322
+ exists :: (fn(path : Path, io : Io) -> Impl(Future(bool, Io)))(
322
323
  io.async((io) => {
323
324
  cstr_bytes := path.to_string().to_cstr();
324
325
  cstr := cstr_bytes.ptr().unwrap();
@@ -330,15 +331,15 @@ exists :: (fn(path : Path, io : IO) -> Impl(Future(bool, IO)))(
330
331
  })
331
332
  );
332
333
  /// Check if a path exists (`str` path variant).
333
- exists_str :: (fn(path : str, io : IO) -> Impl(Future(bool, IO)))(
334
+ exists_str :: (fn(path : str, io : Io) -> Impl(Future(bool, Io)))(
334
335
  exists(Path.new(String.from(path)), io)
335
336
  );
336
337
  /// Check if a path exists (C string path variant).
337
- exists_cstr :: (fn(path : *(u8), io : IO) -> Impl(Future(bool, IO)))(
338
+ exists_cstr :: (fn(path : *(u8), io : Io) -> Impl(Future(bool, Io)))(
338
339
  exists(Path.from_cstr(path), io)
339
340
  );
340
341
  /// Check if a path is a regular file. Returns `false` for any error.
341
- is_file :: (fn(path : Path, io : IO) -> Impl(Future(bool, IO)))(
342
+ is_file :: (fn(path : Path, io : Io) -> Impl(Future(bool, Io)))(
342
343
  io.async((io) => {
343
344
  path_str := path.to_string();
344
345
  cstr_bytes := path_str.to_cstr();
@@ -358,15 +359,15 @@ is_file :: (fn(path : Path, io : IO) -> Impl(Future(bool, IO)))(
358
359
  })
359
360
  );
360
361
  /// Check if a path is a regular file (`str` path variant).
361
- is_file_str :: (fn(path : str, io : IO) -> Impl(Future(bool, IO)))(
362
+ is_file_str :: (fn(path : str, io : Io) -> Impl(Future(bool, Io)))(
362
363
  is_file(Path.new(String.from(path)), io)
363
364
  );
364
365
  /// Check if a path is a regular file (C string path variant).
365
- is_file_cstr :: (fn(path : *(u8), io : IO) -> Impl(Future(bool, IO)))(
366
+ is_file_cstr :: (fn(path : *(u8), io : Io) -> Impl(Future(bool, Io)))(
366
367
  is_file(Path.from_cstr(path), io)
367
368
  );
368
369
  /// Check if a path is a directory. Returns `false` for any error.
369
- is_dir :: (fn(path : Path, io : IO) -> Impl(Future(bool, IO)))(
370
+ is_dir :: (fn(path : Path, io : Io) -> Impl(Future(bool, Io)))(
370
371
  io.async((io) => {
371
372
  path_str := path.to_string();
372
373
  cstr_bytes := path_str.to_cstr();
@@ -386,16 +387,16 @@ is_dir :: (fn(path : Path, io : IO) -> Impl(Future(bool, IO)))(
386
387
  })
387
388
  );
388
389
  /// Check if a path is a directory (`str` path variant).
389
- is_dir_str :: (fn(path : str, io : IO) -> Impl(Future(bool, IO)))(
390
+ is_dir_str :: (fn(path : str, io : Io) -> Impl(Future(bool, Io)))(
390
391
  is_dir(Path.new(String.from(path)), io)
391
392
  );
392
393
  /// Check if a path is a directory (C string path variant).
393
- is_dir_cstr :: (fn(path : *(u8), io : IO) -> Impl(Future(bool, IO)))(
394
+ is_dir_cstr :: (fn(path : *(u8), io : Io) -> Impl(Future(bool, Io)))(
394
395
  is_dir(Path.from_cstr(path), io)
395
396
  );
396
397
  /// Resolve a path to its canonical absolute form (resolves symlinks, `.` and `..`).
397
398
  /// Throws if the path does not exist.
398
- canonical :: (fn(path : Path, io : IO) -> Impl(Future(Path, IOErr)))(
399
+ canonical :: (fn(path : Path, io : Io) -> Impl(Future(Path, IoExn)))(
399
400
  io.async((e) => {
400
401
  path_str := path.to_string();
401
402
  cstr_bytes := path_str.to_cstr();
@@ -405,14 +406,14 @@ canonical :: (fn(path : Path, io : IO) -> Impl(Future(Path, IOErr)))(
405
406
  stat_buf := *(u8)(malloc(buf_size).unwrap());
406
407
  stat_result := e.io.await(IO_file.statx(AT_FDCWD, cstr, AT_STATX_SYNC_AS_STAT, STATX_BASIC_STATS, stat_buf), e.io);
407
408
  free(.Some(*(void)(stat_buf)));
408
- IOError.check(stat_result, e.exn);
409
+ IoError.check(stat_result, e.exn);
409
410
  // Resolve the canonical path
410
411
  resolved_buf := *(u8)(malloc(usize(4096)).unwrap());
411
412
  rp_result := IO_path.realpath(cstr, resolved_buf);
412
413
  cond(
413
414
  (rp_result < i32(0)) => {
414
415
  free(.Some(*(void)(resolved_buf)));
415
- IOError.check(rp_result, e.exn);
416
+ IoError.check(rp_result, e.exn);
416
417
  },
417
418
  true => ()
418
419
  );
@@ -422,11 +423,11 @@ canonical :: (fn(path : Path, io : IO) -> Impl(Future(Path, IOErr)))(
422
423
  })
423
424
  );
424
425
  /// Resolve a path to its canonical absolute form (`str` path variant).
425
- canonical_str :: (fn(path : str, io : IO) -> Impl(Future(Path, IOErr)))(
426
+ canonical_str :: (fn(path : str, io : Io) -> Impl(Future(Path, IoExn)))(
426
427
  canonical(Path.new(String.from(path)), io)
427
428
  );
428
429
  /// Resolve a path to its canonical absolute form (C string path variant).
429
- canonical_cstr :: (fn(path : *(u8), io : IO) -> Impl(Future(Path, IOErr)))(
430
+ canonical_cstr :: (fn(path : *(u8), io : Io) -> Impl(Future(Path, IoExn)))(
430
431
  canonical(Path.from_cstr(path), io)
431
432
  );
432
433
  export(
@@ -6,18 +6,19 @@
6
6
  //! ```rust
7
7
  //! { metadata } :: import "std/fs/metadata";
8
8
  //!
9
- //! main :: (fn(io : IO, exn : Exception) -> unit)({
9
+ //! main :: (fn(io : Io, exn : Exception) -> unit)({
10
10
  //! m := io.await(metadata(Path.new(`/tmp/test.txt`), io), { io, exn });
11
11
  //! printf("size: %lld\n", m.size());
12
12
  //! printf("is file: %d\n", i32(m.is_file()));
13
13
  //! });
14
14
  //! ```
15
+ pragma(Pragma.AllowUnsafe);
15
16
  { GlobalAllocator } :: import("../allocator");
16
17
  { malloc, free } :: GlobalAllocator;
17
18
  open(import("../string"));
18
19
  { Path } :: import("../path");
19
- { IOError } :: import("../sys/errors");
20
- { Error, AnyError, Exception, IOErr } :: import("../error");
20
+ { IoError } :: import("../sys/errors");
21
+ { Error, AnyError, Exception, IoExn } :: import("../error");
21
22
  { Statx } :: import("../sys/statx");
22
23
  IO_file :: import("../sys/file");
23
24
  { AT_FDCWD, AT_SYMLINK_NOFOLLOW, AT_STATX_SYNC_AS_STAT, STATX_BASIC_STATS, S_IFMT, S_IFREG, S_IFDIR, S_IFLNK, S_IWUSR, S_IWGRP, S_IWOTH } :: import("../sys/constants");
@@ -101,7 +102,7 @@ extern(
101
102
  // ============================================================================
102
103
  // Internal helper to stat a path
103
104
  // ============================================================================
104
- _stat_path :: (fn(path : Path, flags : i32, io : IO) -> Impl(Future(Metadata, IOErr)))(
105
+ _stat_path :: (fn(path : Path, flags : i32, io : Io) -> Impl(Future(Metadata, IoExn)))(
105
106
  io.async((e) => {
106
107
  cstr_bytes := path.to_string().to_cstr();
107
108
  cstr := cstr_bytes.ptr().unwrap();
@@ -111,7 +112,7 @@ _stat_path :: (fn(path : Path, flags : i32, io : IO) -> Impl(Future(Metadata, IO
111
112
  cond(
112
113
  (result < i32(0)) => {
113
114
  free(.Some(*(void)(buf)));
114
- e.exn.throw(dyn(IOError.from_errno(i32(0) - result)))
115
+ e.exn.throw(dyn(IoError.from_errno(i32(0) - result)))
115
116
  },
116
117
  true => {
117
118
  sx := Statx(_buf_ptr : buf, _buf_size : buf_size);
@@ -121,11 +122,11 @@ _stat_path :: (fn(path : Path, flags : i32, io : IO) -> Impl(Future(Metadata, IO
121
122
  })
122
123
  );
123
124
  /// Get metadata for a path (follows symlinks).
124
- metadata :: (fn(path : Path, io : IO) -> Impl(Future(Metadata, IOErr)))(_stat_path(path, AT_STATX_SYNC_AS_STAT, io));
125
+ metadata :: (fn(path : Path, io : Io) -> Impl(Future(Metadata, IoExn)))(_stat_path(path, AT_STATX_SYNC_AS_STAT, io));
125
126
  /// Get metadata for a path given as a raw string (follows symlinks).
126
- metadata_str :: (fn(path : str, io : IO) -> Impl(Future(Metadata, IOErr)))(metadata(Path.new(String.from(path)), io));
127
+ metadata_str :: (fn(path : str, io : Io) -> Impl(Future(Metadata, IoExn)))(metadata(Path.new(String.from(path)), io));
127
128
  /// Get metadata for a path (does NOT follow symlinks).
128
- symlink_metadata :: (fn(path : Path, io : IO) -> Impl(Future(Metadata, IOErr)))(_stat_path(path, AT_SYMLINK_NOFOLLOW | AT_STATX_SYNC_AS_STAT, io));
129
+ symlink_metadata :: (fn(path : Path, io : Io) -> Impl(Future(Metadata, IoExn)))(_stat_path(path, AT_SYMLINK_NOFOLLOW | AT_STATX_SYNC_AS_STAT, io));
129
130
  /// Get metadata for a path given as a raw string (does NOT follow symlinks).
130
- symlink_metadata_str :: (fn(path : str, io : IO) -> Impl(Future(Metadata, IOErr)))(symlink_metadata(Path.new(String.from(path)), io));
131
+ symlink_metadata_str :: (fn(path : str, io : Io) -> Impl(Future(Metadata, IoExn)))(symlink_metadata(Path.new(String.from(path)), io));
131
132
  export(metadata, metadata_str, symlink_metadata, symlink_metadata_str);
package/std/fs/temp.yo CHANGED
@@ -5,19 +5,20 @@
5
5
  //! ```rust
6
6
  //! { TempDir } :: import "std/fs/temp";
7
7
  //!
8
- //! main :: (fn(io : IO, exn : Exception) -> unit)({
8
+ //! main :: (fn(io : Io, exn : Exception) -> unit)({
9
9
  //! dir := io.await(TempDir.new(io), { io, exn });
10
10
  //! println(dir.path());
11
11
  //! io.await(dir.remove(io), { io, exn });
12
12
  //! });
13
13
  //! ```
14
+ pragma(Pragma.AllowUnsafe);
14
15
  { GlobalAllocator } :: import("../allocator");
15
16
  { malloc, free } :: GlobalAllocator;
16
17
  open(import("../string"));
17
18
  open(import("../fmt"));
18
19
  { Path } :: import("../path");
19
- { IOError } :: import("../sys/errors");
20
- { Error, AnyError, Exception, IOErr } :: import("../error");
20
+ { IoError } :: import("../sys/errors");
21
+ { Error, AnyError, Exception, IoExn } :: import("../error");
21
22
  _file_mod :: import("./file");
22
23
  _dir_mod :: import("./dir");
23
24
  IO_temp :: import("../sys/temp");
@@ -53,7 +54,7 @@ TempDir :: object(
53
54
  impl(
54
55
  TempDir,
55
56
  // Create a temporary directory in the given parent directory.
56
- new_in : (fn(parent : Path, io : IO) -> Impl(Future(TempDir, IOErr)))(
57
+ new_in : (fn(parent : Path, io : Io) -> Impl(Future(TempDir, IoExn)))(
57
58
  io.async((e) => {
58
59
  // Build template: parent/yo_tmp_XXXXXX
59
60
  template_path := parent.join(Path.new(`yo_tmp_XXXXXX`));
@@ -62,13 +63,19 @@ impl(
62
63
  template_bytes := template_str.as_bytes();
63
64
  buf_len := (template_bytes.len() + usize(1));
64
65
  buf := *(u8)(malloc(buf_len).unwrap());
65
- memcpy(*(void)(buf), *(void)(template_bytes.ptr().unwrap()), template_bytes.len());
66
+ // SAFETY: `buf` is a fresh malloc'd `buf_len = template_bytes.len() + 1`
67
+ // byte buffer; we copy exactly `template_bytes.len()` bytes from
68
+ // `template_bytes`'s underlying storage (alive for the duration of this
69
+ // statement — it's the bytes of `template_str` which we own) and write
70
+ // the trailing NUL at `buf[template_bytes.len()]`. `buf` is freed in
71
+ // both the error branch and after `IO_temp.mkdtemp` returns.
72
+ unsafe(memcpy(*(void)(buf), *(void)(template_bytes.ptr().unwrap()), template_bytes.len()));
66
73
  (buf &+ template_bytes.len()).* = u8(0);
67
74
  result := IO_temp.mkdtemp(buf);
68
75
  cond(
69
76
  (result < i32(0)) => {
70
77
  free(.Some(*(void)(buf)));
71
- e.exn.throw(dyn(IOError.from_errno(i32(0) - result)));
78
+ e.exn.throw(dyn(IoError.from_errno(i32(0) - result)));
72
79
  },
73
80
  true => ()
74
81
  );
@@ -78,7 +85,7 @@ impl(
78
85
  })
79
86
  ),
80
87
  // Create a temporary directory in the system temp dir.
81
- new : (fn(io : IO) -> Impl(Future(TempDir, IOErr)))(
88
+ new : (fn(io : Io) -> Impl(Future(TempDir, IoExn)))(
82
89
  TempDir.new_in(Path.new(_default_tmp_dir()), io)
83
90
  ),
84
91
  // Get the path of the temporary directory.
@@ -86,7 +93,7 @@ impl(
86
93
  self._path
87
94
  ),
88
95
  // Remove the temporary directory.
89
- remove : (fn(self : Self, io : IO) -> Impl(Future(unit, IOErr)))({
96
+ remove : (fn(self : Self, io : Io) -> Impl(Future(unit, IoExn)))({
90
97
  self_path := self._path;
91
98
  io.async(
92
99
  (e) =>
@@ -110,7 +117,7 @@ TempFile :: object(
110
117
  impl(
111
118
  TempFile,
112
119
  // Create a temporary file in the given parent directory.
113
- new_in : (fn(parent : Path, io : IO) -> Impl(Future(TempFile, IOErr)))(
120
+ new_in : (fn(parent : Path, io : Io) -> Impl(Future(TempFile, IoExn)))(
114
121
  io.async((e) => {
115
122
  // Build template: parent/yo_tmp_XXXXXX
116
123
  template_path := parent.join(Path.new(`yo_tmp_XXXXXX`));
@@ -118,13 +125,17 @@ impl(
118
125
  template_bytes := template_str.as_bytes();
119
126
  buf_len := (template_bytes.len() + usize(1));
120
127
  buf := *(u8)(malloc(buf_len).unwrap());
121
- memcpy(*(void)(buf), *(void)(template_bytes.ptr().unwrap()), template_bytes.len());
128
+ // SAFETY: as in `TempDir.new_in` above — `buf` is a fresh malloc'd
129
+ // `template_bytes.len() + 1` byte buffer, we copy exactly the template
130
+ // bytes plus a trailing NUL. `buf` is freed in the error branch and
131
+ // released to mkstemp's owned-fd lifecycle on success.
132
+ unsafe(memcpy(*(void)(buf), *(void)(template_bytes.ptr().unwrap()), template_bytes.len()));
122
133
  (buf &+ template_bytes.len()).* = u8(0);
123
134
  fd := IO_temp.mkstemp(buf);
124
135
  cond(
125
136
  (fd < i32(0)) => {
126
137
  free(.Some(*(void)(buf)));
127
- e.exn.throw(dyn(IOError.from_errno(i32(0) - fd)));
138
+ e.exn.throw(dyn(IoError.from_errno(i32(0) - fd)));
128
139
  },
129
140
  true => ()
130
141
  );
@@ -136,7 +147,7 @@ impl(
136
147
  })
137
148
  ),
138
149
  // Create a temporary file in the system temp dir.
139
- new : (fn(io : IO) -> Impl(Future(TempFile, IOErr)))(
150
+ new : (fn(io : Io) -> Impl(Future(TempFile, IoExn)))(
140
151
  TempFile.new_in(Path.new(_default_tmp_dir()), io)
141
152
  ),
142
153
  // Get the underlying File object.
@@ -148,7 +159,7 @@ impl(
148
159
  self._path
149
160
  ),
150
161
  // Remove the temporary file.
151
- remove : (fn(self : Self, io : IO) -> Impl(Future(unit, IOErr)))({
162
+ remove : (fn(self : Self, io : Io) -> Impl(Future(unit, IoExn)))({
152
163
  self_file := self._file;
153
164
  self_path := self._path;
154
165
  io.async(
package/std/fs/walker.yo CHANGED
@@ -5,21 +5,22 @@
5
5
  //! ```rust
6
6
  //! { walk, WalkEntry } :: import "std/fs/walker";
7
7
  //!
8
- //! main :: (fn(io : IO, exn : Exception) -> unit)({
8
+ //! main :: (fn(io : Io, exn : Exception) -> unit)({
9
9
  //! entries := io.await(walk(Path.new(`/tmp`), io), { io, exn });
10
10
  //! i := usize(0);
11
11
  //! while runtime((i < entries.len())), {
12
- //! e := entries.get(i).unwrap();
12
+ //! e := entries(i);
13
13
  //! println(e.path);
14
14
  //! i = (i + usize(1));
15
15
  //! };
16
16
  //! });
17
17
  //! ```
18
+ pragma(Pragma.AllowUnsafe);
18
19
  { ArrayList } :: import("../collections/array_list");
19
20
  open(import("../string"));
20
21
  { Path } :: import("../path");
21
- { IOError } :: import("../sys/errors");
22
- { Error, AnyError, Exception, IOErr } :: import("../error");
22
+ { IoError } :: import("../sys/errors");
23
+ { Error, AnyError, Exception, IoExn } :: import("../error");
23
24
  { FileType } :: import("./dir");
24
25
  { DirEntry } :: import("./dir");
25
26
  _dir :: import("./dir");
@@ -61,7 +62,7 @@ _join_path :: (fn(base : String, name : String) -> String)(
61
62
  // Walk functions
62
63
  // ============================================================================
63
64
  // Walk a directory tree with custom options.
64
- walk_with :: (fn(root : Path, options : WalkOptions, io : IO) -> Impl(Future(ArrayList(WalkEntry), IOErr)))({
65
+ walk_with :: (fn(root : Path, options : WalkOptions, io : Io) -> Impl(Future(ArrayList(WalkEntry), IoExn)))({
65
66
  root_s := root.to_string();
66
67
  io.async((e) => {
67
68
  results := ArrayList(WalkEntry).new();
@@ -83,7 +84,7 @@ walk_with :: (fn(root : Path, options : WalkOptions, io : IO) -> Impl(Future(Arr
83
84
  entries := e.io.await(_dir.read_dir(Path.new(cur_path), e.io), e);
84
85
  i := usize(0);
85
86
  while(runtime(i < entries.len()), {
86
- entry := entries.get(i).unwrap();
87
+ entry := entries(i);
87
88
  entry_path := _join_path(cur_path, entry.name);
88
89
  match(
89
90
  entry.file_type,
@@ -124,10 +125,10 @@ walk_with :: (fn(root : Path, options : WalkOptions, io : IO) -> Impl(Future(Arr
124
125
  results
125
126
  })
126
127
  });
127
- walk_with_cstr :: (fn(root : *(u8), options : WalkOptions, io : IO) -> Impl(Future(ArrayList(WalkEntry), IOErr)))(
128
+ walk_with_cstr :: (fn(root : *(u8), options : WalkOptions, io : Io) -> Impl(Future(ArrayList(WalkEntry), IoExn)))(
128
129
  walk_with(Path.from_cstr(root), options, io)
129
130
  );
130
131
  /// Walk a directory tree with default options.
131
- walk :: (fn(root : Path, io : IO) -> Impl(Future(ArrayList(WalkEntry), IOErr)))(walk_with(root, WalkOptions.defaults(), io));
132
- walk_cstr :: (fn(root : *(u8), io : IO) -> Impl(Future(ArrayList(WalkEntry), IOErr)))(walk(Path.from_cstr(root), io));
132
+ walk :: (fn(root : Path, io : Io) -> Impl(Future(ArrayList(WalkEntry), IoExn)))(walk_with(root, WalkOptions.defaults(), io));
133
+ walk_cstr :: (fn(root : *(u8), io : Io) -> Impl(Future(ArrayList(WalkEntry), IoExn)))(walk(Path.from_cstr(root), io));
133
134
  export(walk, walk_cstr, walk_with, walk_with_cstr);
package/std/gc.yo CHANGED
@@ -1,4 +1,5 @@
1
1
  //! Garbage collection interface for cycle collection.
2
+ pragma(Pragma.AllowUnsafe);
2
3
  extern(
3
4
  "Yo",
4
5
  __yo_gc_collect : (fn() -> unit),