@shd101wyy/yo 0.1.28 → 0.1.29

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 (55) hide show
  1. package/.github/skills/yo-async-effects/SKILL.md +15 -15
  2. package/.github/skills/yo-async-effects/async-effects-recipes.md +110 -121
  3. package/.github/skills/yo-syntax/SKILL.md +2 -2
  4. package/.github/skills/yo-syntax/syntax-cheatsheet.md +49 -75
  5. package/README.md +2 -0
  6. package/out/cjs/index.cjs +622 -611
  7. package/out/cjs/yo-cli.cjs +727 -716
  8. package/out/cjs/yo-lsp.cjs +637 -626
  9. package/out/esm/index.mjs +515 -504
  10. package/out/types/src/codegen/functions/declarations.d.ts +1 -1
  11. package/out/types/src/doc/model.d.ts +0 -1
  12. package/out/types/src/env.d.ts +0 -2
  13. package/out/types/src/evaluator/context.d.ts +1 -1
  14. package/out/types/src/evaluator/exprs/{escape.d.ts → unwind.d.ts} +1 -1
  15. package/out/types/src/evaluator/types/function.d.ts +1 -2
  16. package/out/types/src/evaluator/utils.d.ts +0 -1
  17. package/out/types/src/expr.d.ts +5 -6
  18. package/out/types/src/types/creators.d.ts +4 -6
  19. package/out/types/src/types/definitions.d.ts +7 -16
  20. package/out/types/src/types/guards.d.ts +1 -2
  21. package/out/types/src/types/tags.d.ts +0 -1
  22. package/out/types/src/types/utils.d.ts +1 -0
  23. package/out/types/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +1 -1
  25. package/std/async.yo +1 -1
  26. package/std/crypto/random.yo +6 -6
  27. package/std/encoding/base64.yo +4 -4
  28. package/std/encoding/hex.yo +2 -2
  29. package/std/encoding/json.yo +3 -3
  30. package/std/encoding/utf16.yo +1 -1
  31. package/std/error.yo +14 -2
  32. package/std/fs/dir.yo +56 -62
  33. package/std/fs/file.yo +118 -124
  34. package/std/fs/metadata.yo +11 -17
  35. package/std/fs/temp.yo +21 -27
  36. package/std/fs/walker.yo +10 -16
  37. package/std/http/client.yo +25 -29
  38. package/std/http/index.yo +4 -4
  39. package/std/io/reader.yo +1 -1
  40. package/std/io/writer.yo +2 -2
  41. package/std/net/addr.yo +1 -1
  42. package/std/net/dns.yo +10 -14
  43. package/std/net/errors.yo +1 -1
  44. package/std/net/tcp.yo +67 -71
  45. package/std/net/udp.yo +36 -40
  46. package/std/os/signal.yo +2 -2
  47. package/std/prelude.yo +27 -21
  48. package/std/process/command.yo +32 -38
  49. package/std/regex/parser.yo +10 -10
  50. package/std/sys/bufio/buf_reader.yo +14 -14
  51. package/std/sys/bufio/buf_writer.yo +17 -17
  52. package/std/sys/errors.yo +1 -1
  53. package/std/thread.yo +2 -2
  54. package/std/url/index.yo +2 -2
  55. package/std/worker.yo +2 -2
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shd101wyy/yo",
3
3
  "displayName": "Yo",
4
- "version": "0.1.28",
4
+ "version": "0.1.29",
5
5
  "main": "./out/cjs/index.cjs",
6
6
  "module": "./out/esm/index.mjs",
7
7
  "types": "./out/types/src/index.d.ts",
package/std/async.yo CHANGED
@@ -1,7 +1,7 @@
1
1
  //! Async utilities for cooperative task scheduling.
2
2
  /// Suspend the current async task, allowing other tasks to run on the event loop.
3
3
  /// Implemented as an immediately-completing async block that forces a suspension point.
4
- yield :: (fn(using(io : IO)) -> Impl(Future(unit)))(
4
+ yield :: (fn(io : IO) -> Impl(Future(unit)))(
5
5
  io.async(() => {
6
6
  return(());
7
7
  })
@@ -54,7 +54,7 @@ extern(
54
54
  // ============================================================================
55
55
  // Fill a buffer with cryptographically secure random bytes.
56
56
  // ============================================================================
57
- random_bytes :: (fn(buf : *(u8), size : usize, using(exn : Exception)) -> unit)(
57
+ random_bytes :: (fn(buf : *(u8), size : usize, exn : Exception) -> unit)(
58
58
  cond(
59
59
  (platform == Platform.Macos) => {
60
60
  __yo_arc4random_buf(buf, size);
@@ -104,7 +104,7 @@ export(random_bytes);
104
104
  // ============================================================================
105
105
  // Typed helpers
106
106
  // ============================================================================
107
- random_u32 :: (fn(using(exn : Exception)) -> u32)({
107
+ random_u32 :: (fn(exn : Exception) -> u32)({
108
108
  buf := Array(u8, usize(4)).fill(u8(0));
109
109
  buf_ptr := &(buf(usize(0)));
110
110
  random_bytes(buf_ptr, usize(4));
@@ -113,16 +113,16 @@ random_u32 :: (fn(using(exn : Exception)) -> u32)({
113
113
  (u32(buf(usize(2))) << u32(16)) |
114
114
  (u32(buf(usize(3))) << u32(24))
115
115
  });
116
- random_u64 :: (fn(using(exn : Exception)) -> u64)({
116
+ random_u64 :: (fn(exn : Exception) -> u64)({
117
117
  lo := u64(random_u32());
118
118
  hi := u64(random_u32());
119
119
  lo | (hi << u64(32))
120
120
  });
121
- random_f64 :: (fn(using(exn : Exception)) -> f64)(
121
+ random_f64 :: (fn(exn : Exception) -> f64)(
122
122
  f64(random_u64()) / f64(18446744073709551615.0)
123
123
  );
124
124
  // Return a random integer in the half-open range [min, max).
125
- random_range :: (fn(min : i64, max : i64, using(exn : Exception)) -> i64)({
125
+ random_range :: (fn(min : i64, max : i64, exn : Exception) -> i64)({
126
126
  span := (max - min);
127
127
  cond(
128
128
  (span <= i64(0)) => min,
@@ -137,7 +137,7 @@ export(random_u32, random_u64, random_f64, random_range);
137
137
  // UUID v4
138
138
  // ============================================================================
139
139
  // Generate a random UUID v4 string: "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
140
- uuid_v4 :: (fn(using(exn : Exception)) -> String)({
140
+ uuid_v4 :: (fn(exn : Exception) -> String)({
141
141
  bytes := ArrayList(u8).with_capacity(usize(16));
142
142
  buf := Array(u8, usize(16)).fill(u8(0));
143
143
  buf_ptr := &(buf(usize(0)));
@@ -64,7 +64,7 @@ export(base64_encode, base64_encode_url);
64
64
  // ============================================================================
65
65
  // Decoding
66
66
  // ============================================================================
67
- _decode_char :: (fn(c : u8, alpha : str, using(exn : Exception)) -> u8)({
67
+ _decode_char :: (fn(c : u8, alpha : str, exn : Exception) -> u8)({
68
68
  i := usize(0);
69
69
  while(i < usize(64), i = (i + usize(1)), {
70
70
  cond(
@@ -76,7 +76,7 @@ _decode_char :: (fn(c : u8, alpha : str, using(exn : Exception)) -> u8)({
76
76
  });
77
77
  exn.throw(dyn(EncodingError.InvalidChar(c)))
78
78
  });
79
- _decode_with :: (fn(s : str, alpha : str, using(exn : Exception)) -> ArrayList(u8))({
79
+ _decode_with :: (fn(s : str, alpha : str, exn : Exception) -> ArrayList(u8))({
80
80
  // Strip trailing padding
81
81
  len := s.len();
82
82
  while((len > usize(0)) && (s.bytes(len - usize(1)) == _PAD), len = (len - usize(1)), ());
@@ -107,11 +107,11 @@ _decode_with :: (fn(s : str, alpha : str, using(exn : Exception)) -> ArrayList(u
107
107
  out
108
108
  });
109
109
  /// Decode a standard base64 string to bytes. Throws via `Exception` on invalid input.
110
- base64_decode :: (fn(s : str, using(exn : Exception)) -> ArrayList(u8))(
110
+ base64_decode :: (fn(s : str, exn : Exception) -> ArrayList(u8))(
111
111
  _decode_with(s, _STD_ALPHA)
112
112
  );
113
113
  /// Decode a URL-safe base64 string to bytes. Throws via `Exception` on invalid input.
114
- base64_decode_url :: (fn(s : str, using(exn : Exception)) -> ArrayList(u8))(
114
+ base64_decode_url :: (fn(s : str, exn : Exception) -> ArrayList(u8))(
115
115
  _decode_with(s, _URL_ALPHA)
116
116
  );
117
117
  export(base64_decode, base64_decode_url);
@@ -64,7 +64,7 @@ export(hex_encode);
64
64
  // ============================================================================
65
65
  // Decoding
66
66
  // ============================================================================
67
- _hex_nibble :: (fn(c : u8, using(exn : Exception)) -> u8)(
67
+ _hex_nibble :: (fn(c : u8, exn : Exception) -> u8)(
68
68
  cond(
69
69
  ((c >= u8(48)) && (c <= u8(57))) => (c - u8(48)),
70
70
  // '0'-'9'
@@ -76,7 +76,7 @@ _hex_nibble :: (fn(c : u8, using(exn : Exception)) -> u8)(
76
76
  )
77
77
  );
78
78
  /// Decode a hexadecimal string to bytes. Throws via `Exception` on invalid input.
79
- hex_decode :: (fn(s : str, using(exn : Exception)) -> ArrayList(u8))({
79
+ hex_decode :: (fn(s : str, exn : Exception) -> ArrayList(u8))({
80
80
  cond(
81
81
  ((s.len() % usize(2)) != usize(0)) => {
82
82
  exn.throw(dyn(EncodingError.OddLength));
@@ -8,7 +8,7 @@
8
8
  //! { json_parse, json_stringify, JsonValue } :: import "std/encoding/json";
9
9
  //! { Exception } :: import "std/error";
10
10
  //!
11
- //! given(exn) := Exception(throw : ((err) -> { escape (); }));
11
+ //! exn := Exception(throw : ((err) -> { unwind (); }));
12
12
  //! v := json_parse(`{"x": 1}`);
13
13
  //! println(json_stringify(v));
14
14
  //! ```
@@ -30,7 +30,7 @@ JsonError :: enum(
30
30
  InvalidNumber,
31
31
  /// Invalid escape sequence in a string.
32
32
  InvalidEscape,
33
- /// Invalid Unicode escape in a string.
33
+ /// Invalid Unicode unwind in a string.
34
34
  InvalidUnicode,
35
35
  /// Other error with a descriptive message.
36
36
  Other(msg : String)
@@ -553,7 +553,7 @@ _parse_value :: (fn(p : _Parser) -> Result(JsonValue, JsonError))({
553
553
  // Public API
554
554
  // ============================================================================
555
555
  /// Parse a JSON string into a `JsonValue` tree. Throws via `Exception` on invalid input.
556
- json_parse :: (fn(s : str, using(exn : Exception)) -> JsonValue)({
556
+ json_parse :: (fn(s : str, exn : Exception) -> JsonValue)({
557
557
  p := _Parser.new(s);
558
558
  match(
559
559
  _parse_value(p),
@@ -68,7 +68,7 @@ export(utf8_to_utf16);
68
68
  ///
69
69
  /// Decodes surrogate pairs back into supplementary code points.
70
70
  /// Throws via `Exception` on unpaired surrogates.
71
- utf16_to_utf8 :: (fn(data : ArrayList(u16), using(exn : Exception)) -> String)({
71
+ utf16_to_utf8 :: (fn(data : ArrayList(u16), exn : Exception) -> String)({
72
72
  out := ArrayList(u8).new();
73
73
  i := usize(0);
74
74
  while(i < data.len(), {
package/std/error.yo CHANGED
@@ -15,15 +15,27 @@ export(AnyError);
15
15
  impl(String, Error());
16
16
  /// Non-resumable exception handling effect record.
17
17
  /// Use `throw` to raise an `AnyError` and abort the current computation.
18
+ /// `throw` is `ctl(...)` — handler body may contain `unwind`, and the
19
+ /// handler value is frame-bound (see plans/EXPLICIT_EFFECTS.md §4).
18
20
  Exception :: struct(
19
- throw : (fn(forall(ResumeType : Type), error : AnyError) -> ResumeType)
21
+ throw : (ctl(forall(ResumeType : Type), error : AnyError) -> ResumeType)
20
22
  );
21
23
  export(Exception);
22
24
  /// Creates a resumable exception effect record parameterized by the resume type.
23
25
  /// Unlike `Exception`, the handler can return a value to resume the computation.
26
+ /// `throw` is still `ctl(...)` because the handler MAY choose to unwind;
27
+ /// regular `fn` returns are also valid via subtyping `fn <: ctl`.
24
28
  ResumableException :: (fn(comptime(ResumeType) : Type) -> comptime(Type))(
25
29
  struct(
26
- throw : (fn(error : AnyError) -> ResumeType)
30
+ throw : (ctl(error : AnyError) -> ResumeType)
27
31
  )
28
32
  );
29
33
  export(ResumableException);
34
+ /// Common effect bundle: IO + Exception.
35
+ /// Used as the effect parameter for Futures that perform IO and may throw.
36
+ /// Construct with `{ io, exn }`; project with `e.io` or `e.exn`.
37
+ IOErr :: struct(
38
+ io : IO,
39
+ exn : Exception
40
+ );
41
+ export(IOErr);
package/std/fs/dir.yo CHANGED
@@ -8,16 +8,10 @@
8
8
  //! { create_dir, remove_dir, read_dir } :: import "std/fs/dir";
9
9
  //! { Path } :: import "std/path";
10
10
  //!
11
- //! main :: (fn(using(io : IO)) -> unit)({
12
- //! given(exn) : Exception = {
13
- //! throw : (fn(forall(T : Type), error: AnyError) -> T)(
14
- //! { println(error.to_string()); exit(i32(1)); }
15
- //! )
16
- //! };
17
- //!
18
- //! io.await(create_dir(Path.new(`/tmp/yo_test`)));
19
- //! entries := io.await(read_dir(Path.new(`/tmp/yo_test`)));
20
- //! io.await(remove_dir(Path.new(`/tmp/yo_test`)));
11
+ //! main :: (fn(io : IO, exn : Exception) -> unit)({
12
+ //! io.await(create_dir(Path.new(`/tmp/yo_test`), io), { io, exn });
13
+ //! entries := io.await(read_dir(Path.new(`/tmp/yo_test`), io), { io, exn });
14
+ //! io.await(remove_dir(Path.new(`/tmp/yo_test`), io), { io, exn });
21
15
  //! });
22
16
  //! ```
23
17
  { GlobalAllocator } :: import("../allocator");
@@ -26,7 +20,7 @@
26
20
  open(import("../string"));
27
21
  { Path } :: import("../path");
28
22
  { IOError } :: import("../sys/errors");
29
- { Error, AnyError, Exception } :: import("../error");
23
+ { Error, AnyError, Exception, IOErr } :: import("../error");
30
24
  { EEXIST, ENOENT } :: import("../libc/errno");
31
25
  IO_dir :: import("../sys/dir");
32
26
  IO_file :: import("../sys/file");
@@ -61,30 +55,30 @@ export(DirEntry);
61
55
  // Directory operations
62
56
  // ============================================================================
63
57
  /// Create a directory at the given path.
64
- create_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
65
- io.async((using(io, exn)) => {
58
+ create_dir :: (fn(path : Path, io : IO) -> Impl(Future(unit, IOErr)))(
59
+ io.async((e) => {
66
60
  cstr_bytes := path.to_string().to_cstr();
67
61
  cstr := cstr_bytes.ptr().unwrap();
68
- result := io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)));
62
+ result := e.io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)), e.io);
69
63
  cond(
70
- (result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
64
+ (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
71
65
  true => ()
72
66
  )
73
67
  })
74
68
  );
75
69
  /// Create a directory (`str` path variant).
76
- create_dir_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
77
- create_dir(Path.new(String.from(path)))
70
+ create_dir_str :: (fn(path : str, io : IO) -> Impl(Future(unit, IOErr)))(
71
+ create_dir(Path.new(String.from(path)), io)
78
72
  );
79
73
  /// Create a directory and all missing parent directories.
80
74
  /// Does not error if the directory already exists.
81
- create_dir_all :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
82
- io.async((using(io, exn)) => {
75
+ create_dir_all :: (fn(path : Path, io : IO) -> Impl(Future(unit, IOErr)))(
76
+ io.async((e) => {
83
77
  path_s := path.to_string();
84
78
  cstr_bytes := path_s.to_cstr();
85
79
  cstr := cstr_bytes.ptr().unwrap();
86
80
  // Try creating the directory directly first
87
- result := io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)));
81
+ result := e.io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)), e.io);
88
82
  cond(
89
83
  (result >= i32(0)) => (),
90
84
  true => {
@@ -126,11 +120,11 @@ create_dir_all :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exce
126
120
  prefix := path_s.substring(usize(0), i);
127
121
  prefix_cstr_bytes := prefix.to_cstr();
128
122
  prefix_cstr := prefix_cstr_bytes.ptr().unwrap();
129
- r := io.await(IO_dir.mkdir(AT_FDCWD, prefix_cstr, i32(DEFAULT_DIR_MODE)));
123
+ r := e.io.await(IO_dir.mkdir(AT_FDCWD, prefix_cstr, i32(DEFAULT_DIR_MODE)), e.io);
130
124
  // Ignore EEXIST errors
131
125
  cond(
132
126
  ((r < i32(0)) && ((i32(0) - r) != i32(EEXIST))) => {
133
- exn.throw(dyn(IOError.from_errno(i32(0) - r)));
127
+ e.exn.throw(dyn(IOError.from_errno(i32(0) - r)));
134
128
  },
135
129
  true => ()
136
130
  );
@@ -140,114 +134,114 @@ create_dir_all :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exce
140
134
  i = (i + usize(1));
141
135
  });
142
136
  // Create the final directory
143
- final_result := io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)));
137
+ final_result := e.io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)), e.io);
144
138
  cond(
145
139
  (final_result >= i32(0)) => (),
146
140
  true => {
147
141
  final_errno := (i32(0) - final_result);
148
142
  cond(
149
143
  (final_errno == i32(EEXIST)) => (),
150
- true => exn.throw(dyn(IOError.from_errno(final_errno)))
144
+ true => e.exn.throw(dyn(IOError.from_errno(final_errno)))
151
145
  )
152
146
  }
153
147
  )
154
148
  },
155
- true => exn.throw(dyn(IOError.from_errno(errno)))
149
+ true => e.exn.throw(dyn(IOError.from_errno(errno)))
156
150
  )
157
151
  }
158
152
  )
159
153
  })
160
154
  );
161
155
  /// Create a directory and all missing parents (`str` path variant).
162
- create_dir_all_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
163
- create_dir_all(Path.new(String.from(path)))
156
+ create_dir_all_str :: (fn(path : str, io : IO) -> Impl(Future(unit, IOErr)))(
157
+ create_dir_all(Path.new(String.from(path)), io)
164
158
  );
165
159
  /// Remove an empty directory. Throws if the directory is not empty.
166
- remove_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
167
- io.async((using(io, exn)) => {
160
+ remove_dir :: (fn(path : Path, io : IO) -> Impl(Future(unit, IOErr)))(
161
+ io.async((e) => {
168
162
  cstr_bytes := path.to_string().to_cstr();
169
163
  cstr := cstr_bytes.ptr().unwrap();
170
- result := io.await(IO_dir.unlink(AT_FDCWD, cstr, AT_REMOVEDIR));
164
+ result := e.io.await(IO_dir.unlink(AT_FDCWD, cstr, AT_REMOVEDIR), e.io);
171
165
  cond(
172
- (result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
166
+ (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
173
167
  true => ()
174
168
  )
175
169
  })
176
170
  );
177
- remove_dir_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
178
- remove_dir(Path.new(String.from(path)))
171
+ remove_dir_str :: (fn(path : str, io : IO) -> Impl(Future(unit, IOErr)))(
172
+ remove_dir(Path.new(String.from(path)), io)
179
173
  );
180
174
  /// Remove a file at the given path.
181
- remove_file :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
182
- io.async((using(io, exn)) => {
175
+ remove_file :: (fn(path : Path, io : IO) -> Impl(Future(unit, IOErr)))(
176
+ io.async((e) => {
183
177
  cstr_bytes := path.to_string().to_cstr();
184
178
  cstr := cstr_bytes.ptr().unwrap();
185
- result := io.await(IO_dir.unlink(AT_FDCWD, cstr, i32(0)));
179
+ result := e.io.await(IO_dir.unlink(AT_FDCWD, cstr, i32(0)), e.io);
186
180
  cond(
187
- (result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
181
+ (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
188
182
  true => ()
189
183
  )
190
184
  })
191
185
  );
192
- remove_file_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(remove_file(Path.new(String.from(path))));
186
+ remove_file_str :: (fn(path : str, io : IO) -> Impl(Future(unit, IOErr)))(remove_file(Path.new(String.from(path)), io));
193
187
  /// Rename or move a file or directory from `from` to `to`.
194
- rename :: (fn(from : Path, to : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
195
- io.async((using(io, exn)) => {
188
+ rename :: (fn(from : Path, to : Path, io : IO) -> Impl(Future(unit, IOErr)))(
189
+ io.async((e) => {
196
190
  from_cstr_bytes := from.to_string().to_cstr();
197
191
  from_cstr := from_cstr_bytes.ptr().unwrap();
198
192
  to_cstr_bytes := to.to_string().to_cstr();
199
193
  to_cstr := to_cstr_bytes.ptr().unwrap();
200
- result := io.await(IO_dir.rename(AT_FDCWD, from_cstr, AT_FDCWD, to_cstr));
194
+ result := e.io.await(IO_dir.rename(AT_FDCWD, from_cstr, AT_FDCWD, to_cstr), e.io);
201
195
  cond(
202
- (result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
196
+ (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
203
197
  true => ()
204
198
  )
205
199
  })
206
200
  );
207
- rename_str :: (fn(from : str, to : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(rename(Path.new(String.from(from)), Path.new(String.from(to))));
201
+ rename_str :: (fn(from : str, to : str, io : IO) -> Impl(Future(unit, IOErr)))(rename(Path.new(String.from(from)), Path.new(String.from(to)), io));
208
202
  /// Create a hard link from `src` to `dst`.
209
- hard_link :: (fn(src : Path, dst : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
210
- io.async((using(io, exn)) => {
203
+ hard_link :: (fn(src : Path, dst : Path, io : IO) -> Impl(Future(unit, IOErr)))(
204
+ io.async((e) => {
211
205
  src_cstr_bytes := src.to_string().to_cstr();
212
206
  src_cstr := src_cstr_bytes.ptr().unwrap();
213
207
  dst_cstr_bytes := dst.to_string().to_cstr();
214
208
  dst_cstr := dst_cstr_bytes.ptr().unwrap();
215
- result := io.await(IO_dir.link(AT_FDCWD, src_cstr, AT_FDCWD, dst_cstr, i32(0)));
209
+ result := e.io.await(IO_dir.link(AT_FDCWD, src_cstr, AT_FDCWD, dst_cstr, i32(0)), e.io);
216
210
  cond(
217
- (result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
211
+ (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
218
212
  true => ()
219
213
  )
220
214
  })
221
215
  );
222
- hard_link_str :: (fn(src : str, dst : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(hard_link(Path.new(String.from(src)), Path.new(String.from(dst))));
216
+ hard_link_str :: (fn(src : str, dst : str, io : IO) -> Impl(Future(unit, IOErr)))(hard_link(Path.new(String.from(src)), Path.new(String.from(dst)), io));
223
217
  /// Create a symbolic link at `dst` pointing to `src`.
224
- symlink :: (fn(src : Path, dst : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
225
- io.async((using(io, exn)) => {
218
+ symlink :: (fn(src : Path, dst : Path, io : IO) -> Impl(Future(unit, IOErr)))(
219
+ io.async((e) => {
226
220
  src_cstr_bytes := src.to_string().to_cstr();
227
221
  src_cstr := src_cstr_bytes.ptr().unwrap();
228
222
  dst_cstr_bytes := dst.to_string().to_cstr();
229
223
  dst_cstr := dst_cstr_bytes.ptr().unwrap();
230
- result := io.await(IO_dir.symlink(src_cstr, AT_FDCWD, dst_cstr));
224
+ result := e.io.await(IO_dir.symlink(src_cstr, AT_FDCWD, dst_cstr), e.io);
231
225
  cond(
232
- (result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
226
+ (result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - result))),
233
227
  true => ()
234
228
  )
235
229
  })
236
230
  );
237
- symlink_str :: (fn(src : str, dst : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(symlink(Path.new(String.from(src)), Path.new(String.from(dst))));
231
+ symlink_str :: (fn(src : str, dst : str, io : IO) -> Impl(Future(unit, IOErr)))(symlink(Path.new(String.from(src)), Path.new(String.from(dst)), io));
238
232
  // ============================================================================
239
233
  // Directory listing
240
234
  // ============================================================================
241
235
  /// Read all entries from a directory, returning an `ArrayList(DirEntry)`.
242
236
  /// Skips the `.` and `..` entries.
243
- read_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(ArrayList(DirEntry), IO, Exception)))(
244
- io.async((using(io, exn)) => {
237
+ read_dir :: (fn(path : Path, io : IO) -> Impl(Future(ArrayList(DirEntry), IOErr)))(
238
+ io.async((e) => {
245
239
  cstr_bytes := path.to_string().to_cstr();
246
240
  cstr := cstr_bytes.ptr().unwrap();
247
241
  // Open the directory
248
- fd_result := io.await(IO_file.openat(AT_FDCWD, cstr, O_RDONLY | O_DIRECTORY, i32(0)));
242
+ fd_result := e.io.await(IO_file.openat(AT_FDCWD, cstr, O_RDONLY | O_DIRECTORY, i32(0)), e.io);
249
243
  cond(
250
- (fd_result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - fd_result))),
244
+ (fd_result < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - fd_result))),
251
245
  true => ()
252
246
  );
253
247
  fd := fd_result;
@@ -255,12 +249,12 @@ read_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(ArrayList(DirEntry),
255
249
  buf_size := u32(4096);
256
250
  buf := *(u8)(malloc(usize(buf_size)).unwrap());
257
251
  while(runtime(true), {
258
- n := io.await(IO_dir.getdents(fd, buf, buf_size));
252
+ n := e.io.await(IO_dir.getdents(fd, buf, buf_size), e.io);
259
253
  cond(
260
254
  (n < i32(0)) => {
261
255
  free(.Some(*(void)(buf)));
262
- io.await(IO_file.close(fd));
263
- exn.throw(dyn(IOError.from_errno(i32(0) - n)));
256
+ e.io.await(IO_file.close(fd), e.io);
257
+ e.exn.throw(dyn(IOError.from_errno(i32(0) - n)));
264
258
  },
265
259
  (n == i32(0)) => {
266
260
  break;
@@ -297,11 +291,11 @@ read_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(ArrayList(DirEntry),
297
291
  );
298
292
  });
299
293
  free(.Some(*(void)(buf)));
300
- io.await(IO_file.close(fd));
294
+ e.io.await(IO_file.close(fd), e.io);
301
295
  entries
302
296
  })
303
297
  );
304
- read_dir_str :: (fn(path : str, using(io : IO)) -> Impl(Future(ArrayList(DirEntry), IO, Exception)))(read_dir(Path.new(String.from(path))));
298
+ read_dir_str :: (fn(path : str, io : IO) -> Impl(Future(ArrayList(DirEntry), IOErr)))(read_dir(Path.new(String.from(path)), io));
305
299
  export(
306
300
  create_dir,
307
301
  create_dir_str,