@shd101wyy/yo 0.1.26 → 0.1.27
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.
- package/.github/skills/yo-async-effects/SKILL.md +4 -4
- package/.github/skills/yo-async-effects/async-effects-recipes.md +34 -34
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +26 -26
- package/.github/skills/yo-project-workflow/SKILL.md +6 -3
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +34 -11
- package/.github/skills/yo-syntax/SKILL.md +7 -6
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +73 -60
- package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
- package/README.md +10 -8
- package/out/cjs/index.cjs +456 -438
- package/out/cjs/yo-cli.cjs +576 -543
- package/out/cjs/yo-lsp.cjs +559 -532
- package/out/esm/index.mjs +281 -263
- package/out/types/src/formatter.d.ts +11 -0
- package/out/types/src/lsp/formatting.d.ts +2 -0
- package/out/types/src/tests/formatter.test.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/alg/hash.yo +13 -21
- package/std/allocator.yo +25 -40
- package/std/async.yo +3 -7
- package/std/build.yo +105 -151
- package/std/cli/arg_parser.yo +184 -169
- package/std/collections/array_list.yo +350 -314
- package/std/collections/btree_map.yo +142 -131
- package/std/collections/deque.yo +132 -128
- package/std/collections/hash_map.yo +542 -566
- package/std/collections/hash_set.yo +623 -687
- package/std/collections/linked_list.yo +275 -293
- package/std/collections/ordered_map.yo +113 -85
- package/std/collections/priority_queue.yo +73 -73
- package/std/crypto/md5.yo +191 -95
- package/std/crypto/random.yo +56 -64
- package/std/crypto/sha256.yo +151 -107
- package/std/encoding/base64.yo +87 -81
- package/std/encoding/hex.yo +43 -50
- package/std/encoding/html.yo +56 -81
- package/std/encoding/html_char_utils.yo +7 -13
- package/std/encoding/html_entities.yo +2248 -2253
- package/std/encoding/json.yo +316 -224
- package/std/encoding/punycode.yo +86 -116
- package/std/encoding/toml.yo +67 -66
- package/std/encoding/utf16.yo +37 -44
- package/std/env.yo +62 -91
- package/std/error.yo +7 -15
- package/std/fmt/display.yo +5 -9
- package/std/fmt/index.yo +8 -14
- package/std/fmt/to_string.yo +330 -315
- package/std/fmt/writer.yo +58 -87
- package/std/fs/dir.yo +83 -102
- package/std/fs/file.yo +147 -180
- package/std/fs/metadata.yo +45 -78
- package/std/fs/temp.yo +55 -65
- package/std/fs/types.yo +27 -40
- package/std/fs/walker.yo +53 -68
- package/std/gc.yo +5 -8
- package/std/glob.yo +30 -43
- package/std/http/client.yo +107 -120
- package/std/http/http.yo +106 -96
- package/std/http/index.yo +4 -6
- package/std/imm/list.yo +88 -93
- package/std/imm/map.yo +528 -464
- package/std/imm/set.yo +52 -57
- package/std/imm/sorted_map.yo +340 -286
- package/std/imm/sorted_set.yo +57 -63
- package/std/imm/string.yo +404 -345
- package/std/imm/vec.yo +173 -181
- package/std/io/reader.yo +3 -6
- package/std/io/writer.yo +4 -8
- package/std/libc/assert.yo +5 -9
- package/std/libc/ctype.yo +32 -22
- package/std/libc/dirent.yo +26 -25
- package/std/libc/errno.yo +164 -90
- package/std/libc/fcntl.yo +52 -45
- package/std/libc/float.yo +66 -44
- package/std/libc/limits.yo +42 -33
- package/std/libc/math.yo +53 -82
- package/std/libc/signal.yo +72 -47
- package/std/libc/stdatomic.yo +217 -188
- package/std/libc/stdint.yo +5 -29
- package/std/libc/stdio.yo +5 -29
- package/std/libc/stdlib.yo +32 -39
- package/std/libc/string.yo +5 -23
- package/std/libc/sys/stat.yo +58 -56
- package/std/libc/time.yo +5 -19
- package/std/libc/unistd.yo +5 -20
- package/std/libc/wctype.yo +6 -9
- package/std/libc/windows.yo +26 -30
- package/std/log.yo +41 -55
- package/std/net/addr.yo +102 -97
- package/std/net/dns.yo +27 -28
- package/std/net/errors.yo +50 -49
- package/std/net/tcp.yo +113 -124
- package/std/net/udp.yo +55 -66
- package/std/os/env.yo +35 -33
- package/std/os/signal.yo +15 -25
- package/std/path.yo +276 -311
- package/std/prelude.yo +6304 -4315
- package/std/process/command.yo +87 -103
- package/std/process/index.yo +12 -31
- package/std/regex/compiler.yo +196 -95
- package/std/regex/flags.yo +58 -39
- package/std/regex/index.yo +157 -173
- package/std/regex/match.yo +20 -31
- package/std/regex/node.yo +134 -152
- package/std/regex/parser.yo +283 -259
- package/std/regex/unicode.yo +172 -202
- package/std/regex/vm.yo +155 -171
- package/std/string/index.yo +5 -7
- package/std/string/rune.yo +45 -55
- package/std/string/string.yo +937 -964
- package/std/string/string_builder.yo +94 -104
- package/std/string/unicode.yo +46 -64
- package/std/sync/channel.yo +72 -73
- package/std/sync/cond.yo +31 -36
- package/std/sync/mutex.yo +30 -32
- package/std/sync/once.yo +13 -16
- package/std/sync/rwlock.yo +26 -31
- package/std/sync/waitgroup.yo +20 -25
- package/std/sys/advise.yo +16 -24
- package/std/sys/bufio/buf_reader.yo +77 -93
- package/std/sys/bufio/buf_writer.yo +52 -65
- package/std/sys/clock.yo +4 -9
- package/std/sys/constants.yo +77 -61
- package/std/sys/copy.yo +4 -10
- package/std/sys/dir.yo +26 -43
- package/std/sys/dns.yo +41 -61
- package/std/sys/errors.yo +95 -103
- package/std/sys/events.yo +45 -57
- package/std/sys/externs.yo +319 -267
- package/std/sys/fallocate.yo +7 -11
- package/std/sys/fcntl.yo +14 -22
- package/std/sys/file.yo +26 -40
- package/std/sys/future.yo +5 -8
- package/std/sys/iov.yo +12 -25
- package/std/sys/lock.yo +12 -13
- package/std/sys/mmap.yo +38 -43
- package/std/sys/path.yo +3 -8
- package/std/sys/perm.yo +7 -21
- package/std/sys/pipe.yo +5 -12
- package/std/sys/process.yo +23 -29
- package/std/sys/seek.yo +10 -12
- package/std/sys/signal.yo +7 -13
- package/std/sys/signals.yo +52 -35
- package/std/sys/socket.yo +63 -58
- package/std/sys/socketpair.yo +3 -6
- package/std/sys/sockinfo.yo +11 -20
- package/std/sys/statfs.yo +11 -34
- package/std/sys/statx.yo +25 -52
- package/std/sys/sysinfo.yo +15 -20
- package/std/sys/tcp.yo +62 -92
- package/std/sys/temp.yo +5 -9
- package/std/sys/time.yo +5 -15
- package/std/sys/timer.yo +6 -11
- package/std/sys/tty.yo +10 -18
- package/std/sys/udp.yo +22 -39
- package/std/sys/umask.yo +3 -6
- package/std/sys/unix.yo +33 -52
- package/std/testing/bench.yo +49 -52
- package/std/thread.yo +10 -15
- package/std/time/datetime.yo +105 -89
- package/std/time/duration.yo +43 -56
- package/std/time/instant.yo +13 -18
- package/std/time/sleep.yo +5 -9
- package/std/url/index.yo +184 -209
- package/std/worker.yo +6 -10
|
@@ -26,8 +26,8 @@ Use this skill when you need to:
|
|
|
26
26
|
2. Add the necessary `using(...)` parameters to function signatures and call sites.
|
|
27
27
|
3. Use the [async and effects recipes](./async-effects-recipes.md) for working patterns.
|
|
28
28
|
4. Re-check handler semantics before finalizing:
|
|
29
|
-
- `return
|
|
30
|
-
- `escape
|
|
29
|
+
- `return(value)` resumes the continuation
|
|
30
|
+
- `escape(expr)` discards it
|
|
31
31
|
|
|
32
32
|
## High-signal rules
|
|
33
33
|
|
|
@@ -38,8 +38,8 @@ Use this skill when you need to:
|
|
|
38
38
|
- Future types include their effects: `Future(ResultType, IO, Effect...)`.
|
|
39
39
|
- Effects are matched by type, not variable name.
|
|
40
40
|
- `using(name : Type)` declares an implicit effect parameter; `given(name) := Type(...)` installs the handler.
|
|
41
|
-
- `return
|
|
42
|
-
- `Exception` — non-resumable; handler calls `escape` to exit. `ResumableException(T)` — handler calls `return` to resume.
|
|
41
|
+
- `return(value)` inside a handler resumes the continuation; `escape(expr)` discards it.
|
|
42
|
+
- `Exception` — non-resumable; handler calls `escape(...)` to exit. `ResumableException(T)` — handler calls `return(...)` to resume.
|
|
43
43
|
- Effect handlers are standalone, not closures; pass state explicitly.
|
|
44
44
|
- Yo async is single-threaded concurrency, not multithreaded parallelism.
|
|
45
45
|
|
|
@@ -14,7 +14,7 @@ These patterns cover normal Yo async code and algebraic effects.
|
|
|
14
14
|
## Minimal async function
|
|
15
15
|
|
|
16
16
|
```rust
|
|
17
|
-
{ yield } :: import
|
|
17
|
+
{ yield } :: import("std/async");
|
|
18
18
|
|
|
19
19
|
pause_then_answer :: (fn(using(io : IO)) -> Impl(Future(i32, IO)))(
|
|
20
20
|
io.async((using(io : IO)) => {
|
|
@@ -41,7 +41,7 @@ work :: (fn(using(io : IO, raise : Raise)) -> Impl(Future(i32, IO, Raise)))(
|
|
|
41
41
|
## Sequential await
|
|
42
42
|
|
|
43
43
|
```rust
|
|
44
|
-
{ yield } :: import
|
|
44
|
+
{ yield } :: import("std/async");
|
|
45
45
|
|
|
46
46
|
main :: (fn(using(io : IO)) -> unit)({
|
|
47
47
|
task := io.async((using(io : IO)) => {
|
|
@@ -53,13 +53,13 @@ main :: (fn(using(io : IO)) -> unit)({
|
|
|
53
53
|
assert((result == i32(1)), "unexpected result");
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
export
|
|
56
|
+
export(main);
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
## Concurrent tasks on the same thread
|
|
60
60
|
|
|
61
61
|
```rust
|
|
62
|
-
{ yield } :: import
|
|
62
|
+
{ yield } :: import("std/async");
|
|
63
63
|
|
|
64
64
|
main :: (fn(using(io : IO)) -> unit)({
|
|
65
65
|
task1 := io.async((using(io : IO)) => {
|
|
@@ -78,7 +78,7 @@ main :: (fn(using(io : IO)) -> unit)({
|
|
|
78
78
|
result2 := handle2.await(using(io));
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
export
|
|
81
|
+
export(main);
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
- `io.spawn(...)` begins execution without waiting
|
|
@@ -87,8 +87,8 @@ export main;
|
|
|
87
87
|
## Propagating and handling effects
|
|
88
88
|
|
|
89
89
|
```rust
|
|
90
|
-
open
|
|
91
|
-
open
|
|
90
|
+
open(import("std/fmt"));
|
|
91
|
+
open(import("std/string"));
|
|
92
92
|
|
|
93
93
|
Raise :: (fn(msg : String) -> i32);
|
|
94
94
|
|
|
@@ -102,7 +102,7 @@ safe_divide :: (fn(x : i32, y : i32, using(raise : Raise)) -> i32)(
|
|
|
102
102
|
resume_example :: (fn() -> i32)({
|
|
103
103
|
(given(raise) : Raise) = (fn(msg : String) -> i32)({
|
|
104
104
|
println(msg);
|
|
105
|
-
return
|
|
105
|
+
return(i32(0));
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
safe_divide(i32(8), i32(0))
|
|
@@ -111,22 +111,22 @@ resume_example :: (fn() -> i32)({
|
|
|
111
111
|
escape_example :: (fn() -> i32)({
|
|
112
112
|
(given(raise) : Raise) = (fn(msg : String) -> i32)({
|
|
113
113
|
println(msg);
|
|
114
|
-
escape
|
|
114
|
+
escape(i32(-1));
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
safe_divide(i32(8), i32(0))
|
|
118
118
|
});
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
| Handler action
|
|
122
|
-
|
|
|
123
|
-
| `return
|
|
124
|
-
| `escape
|
|
121
|
+
| Handler action | Meaning |
|
|
122
|
+
| --------------- | -------------------------------------------- |
|
|
123
|
+
| `return(value)` | Resume the continuation with `value` |
|
|
124
|
+
| `escape(expr)` | Exit the function that installed the handler |
|
|
125
125
|
|
|
126
126
|
## Futures with multiple effects
|
|
127
127
|
|
|
128
128
|
```rust
|
|
129
|
-
{ yield } :: import
|
|
129
|
+
{ yield } :: import("std/async");
|
|
130
130
|
|
|
131
131
|
work :: (fn(using(io : IO, raise : Raise)) -> Impl(Future(i32, IO, Raise)))(
|
|
132
132
|
io.async((using(io : IO, raise : Raise)) => {
|
|
@@ -146,20 +146,20 @@ work :: (fn(using(io : IO, raise : Raise)) -> Impl(Future(i32, IO, Raise)))(
|
|
|
146
146
|
**Solution**: replace async recursion with an iterative worklist using `ArrayList` as a stack:
|
|
147
147
|
|
|
148
148
|
```rust
|
|
149
|
-
{ read_dir, DirEntry } :: import
|
|
149
|
+
{ read_dir, DirEntry } :: import("std/fs/dir");
|
|
150
150
|
|
|
151
151
|
process_dir :: (fn(root: Path, using(io: IO, exn: Exception)) -> Impl(Future(unit, IO, Exception)))(
|
|
152
152
|
io.async((using(io, exn)) => {
|
|
153
153
|
stack := ArrayList(Path).new();
|
|
154
154
|
{ stack.push(root); };
|
|
155
155
|
|
|
156
|
-
while
|
|
157
|
-
cur := match(stack.pop(), .Some(p) => p, .None => return
|
|
156
|
+
while(runtime((stack.len() > usize(0))), {
|
|
157
|
+
cur := match(stack.pop(), .Some(p) => p, .None => return());
|
|
158
158
|
entries := io.await(read_dir(cur));
|
|
159
159
|
// process `entries`, push subdirectories to `stack`
|
|
160
160
|
n := entries.len();
|
|
161
161
|
i := usize(0);
|
|
162
|
-
while
|
|
162
|
+
while(runtime((i < n)), {
|
|
163
163
|
match(entries.get(i),
|
|
164
164
|
.None => (),
|
|
165
165
|
.Some(e) => {
|
|
@@ -170,8 +170,8 @@ process_dir :: (fn(root: Path, using(io: IO, exn: Exception)) -> Impl(Future(uni
|
|
|
170
170
|
}
|
|
171
171
|
);
|
|
172
172
|
i = (i + usize(1));
|
|
173
|
-
};
|
|
174
|
-
};
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
175
|
})
|
|
176
176
|
);
|
|
177
177
|
```
|
|
@@ -189,8 +189,8 @@ process_dir :: (fn(root: Path, using(io: IO, exn: Exception)) -> Impl(Future(uni
|
|
|
189
189
|
`Exception` is a built-in struct-record effect for non-resumable error handling. When the handler calls `escape`, the continuation is discarded:
|
|
190
190
|
|
|
191
191
|
```rust
|
|
192
|
-
open
|
|
193
|
-
open
|
|
192
|
+
open(import("std/error"));
|
|
193
|
+
open(import("std/fmt"));
|
|
194
194
|
|
|
195
195
|
DivError :: enum(DivByZero);
|
|
196
196
|
impl(DivError, ToString(to_string : ((self) -> `division by zero`)));
|
|
@@ -207,7 +207,7 @@ main :: (fn() -> unit)({
|
|
|
207
207
|
given(exn) := Exception(
|
|
208
208
|
throw : ((err) -> {
|
|
209
209
|
println(`Error: ${err}`);
|
|
210
|
-
escape
|
|
210
|
+
escape();
|
|
211
211
|
})
|
|
212
212
|
);
|
|
213
213
|
|
|
@@ -217,7 +217,7 @@ main :: (fn() -> unit)({
|
|
|
217
217
|
safe_divide(i32(10), i32(0));
|
|
218
218
|
});
|
|
219
219
|
|
|
220
|
-
export
|
|
220
|
+
export(main);
|
|
221
221
|
```
|
|
222
222
|
|
|
223
223
|
- `Exception` has a single field `throw : (fn(error : AnyError) -> T)`
|
|
@@ -230,32 +230,32 @@ export main;
|
|
|
230
230
|
When an exception is thrown inside an async operation (e.g., `cmd.status()` or `cmd.output()`), you can **swallow the error and resume with a fallback value** by using `return` in the handler (not `escape`). The `ResumeType` is the return type of the operation that would have thrown.
|
|
231
231
|
|
|
232
232
|
```rust
|
|
233
|
-
{ Command, ExitStatus, Output } :: import
|
|
233
|
+
{ Command, ExitStatus, Output } :: import("std/process/command");
|
|
234
234
|
|
|
235
235
|
// Check if a tool is available — returns false if it throws (e.g., not found)
|
|
236
236
|
given(try_exn) := Exception(throw: ((err) -> {
|
|
237
|
-
return
|
|
237
|
+
return(ExitStatus(raw: i32(1))); // resume with "failed" exit status
|
|
238
238
|
}));
|
|
239
239
|
status := io.await(cmd.status(using(io, try_exn)));
|
|
240
240
|
available := status.success(); // false if exception was swallowed
|
|
241
241
|
|
|
242
242
|
// For cmd.output(), resume with a failed Output:
|
|
243
243
|
given(out_exn) := Exception(throw: ((err) -> {
|
|
244
|
-
return
|
|
244
|
+
return(Output(status: ExitStatus(raw: i32(1)), stdout: ArrayList(u8).new(), stderr: ArrayList(u8).new()));
|
|
245
245
|
}));
|
|
246
246
|
out := io.await(cmd.output(using(io, out_exn)));
|
|
247
|
-
if((!(out.status.success())), { return
|
|
247
|
+
if((!(out.status.success())), { return(); }); // handle failure
|
|
248
248
|
```
|
|
249
249
|
|
|
250
250
|
Key: the `return` inside the handler resumes the _effect invocation site_ with the provided value. The calling code then sees the fallback as if the operation returned normally. Use `escape` only when the enclosing function returns `unit` (e.g., test bodies).
|
|
251
251
|
|
|
252
|
-
**`escape
|
|
252
|
+
**`escape(T_value)` constraint**: `escape(T_value)` inside an `Exception` handler requires that the enclosing `io.async` closure's return type matches `T_value`. Due to forward type inference, the evaluator may not know the closure's return type at the point where `given` is declared. This causes a "Expected: unit" error when `escape(non_unit)` is used in a handler declared before the final return expression. Prefer `return(fallback_value)` (resume) when possible.
|
|
253
253
|
|
|
254
254
|
`ResumableException(ResumeType)` is a struct-record effect for resumable error handling. The handler uses `return` to resume with a recovery value:
|
|
255
255
|
|
|
256
256
|
```rust
|
|
257
|
-
open
|
|
258
|
-
open
|
|
257
|
+
open(import("std/error"));
|
|
258
|
+
open(import("std/fmt"));
|
|
259
259
|
|
|
260
260
|
safe_divide :: (fn(x : i32, y : i32, using(exn : ResumableException(i32))) -> i32)(
|
|
261
261
|
cond(
|
|
@@ -268,7 +268,7 @@ main :: (fn() -> unit)({
|
|
|
268
268
|
given(exn) := ResumableException(i32)(
|
|
269
269
|
throw : ((err) -> {
|
|
270
270
|
println(`Recovering from: ${err}`);
|
|
271
|
-
return
|
|
271
|
+
return(i32(0));
|
|
272
272
|
})
|
|
273
273
|
);
|
|
274
274
|
|
|
@@ -276,10 +276,10 @@ main :: (fn() -> unit)({
|
|
|
276
276
|
assert((result == i32(0)), "recovered with 0");
|
|
277
277
|
});
|
|
278
278
|
|
|
279
|
-
export
|
|
279
|
+
export(main);
|
|
280
280
|
```
|
|
281
281
|
|
|
282
|
-
- Handler uses `return
|
|
282
|
+
- Handler uses `return(value)` to resume the continuation with the recovery value
|
|
283
283
|
- The call site receives the returned value and continues normally
|
|
284
284
|
|
|
285
285
|
## Struct-record effects vs function-type effects
|
|
@@ -40,7 +40,7 @@ Use this skill when you need to:
|
|
|
40
40
|
- Use `derive(Type, Eq, Hash, Clone, Ord, ToString)` to auto-generate common trait impls.
|
|
41
41
|
- Custom error types implement `ToString` + `Error`; wrap with `dyn(...)` into `AnyError`.
|
|
42
42
|
- Use `(params) => expr` for closures; `Impl(Fn(...) -> T)` for the closure type.
|
|
43
|
-
- Use `for
|
|
43
|
+
- Use `for(collection.iter(), (item) => { ... })` for iteration.
|
|
44
44
|
- Indexed modules import cleanly as `std/url`, `std/regex`, `std/http`, `std/log`, and `std/glob`; multi-module families use explicit submodules.
|
|
45
45
|
|
|
46
46
|
## Resource
|
|
@@ -5,8 +5,8 @@ These patterns are aimed at everyday Yo application and library code.
|
|
|
5
5
|
## Strings and output
|
|
6
6
|
|
|
7
7
|
```rust
|
|
8
|
-
open
|
|
9
|
-
open
|
|
8
|
+
open(import("std/fmt"));
|
|
9
|
+
open(import("std/string"));
|
|
10
10
|
|
|
11
11
|
(name : str) = "yo";
|
|
12
12
|
greeting := `Hello ${name}`;
|
|
@@ -38,13 +38,13 @@ Key rules:
|
|
|
38
38
|
## Import patterns
|
|
39
39
|
|
|
40
40
|
```rust
|
|
41
|
-
{ LocalType } :: import
|
|
42
|
-
open
|
|
43
|
-
{ ArrayList } :: import
|
|
44
|
-
{ HashMap } :: import
|
|
45
|
-
{ Url } :: import
|
|
46
|
-
{ Regex } :: import
|
|
47
|
-
{ fetch, HttpRequest } :: import
|
|
41
|
+
{ LocalType } :: import("./local_type.yo");
|
|
42
|
+
open(import("std/string"));
|
|
43
|
+
{ ArrayList } :: import("std/collections/array_list");
|
|
44
|
+
{ HashMap } :: import("std/collections/hash_map");
|
|
45
|
+
{ Url } :: import("std/url");
|
|
46
|
+
{ Regex } :: import("std/regex");
|
|
47
|
+
{ fetch, HttpRequest } :: import("std/http");
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
| Need | Import pattern |
|
|
@@ -60,7 +60,7 @@ Do not import `std/prelude`; it is already available.
|
|
|
60
60
|
## Option and Result
|
|
61
61
|
|
|
62
62
|
```rust
|
|
63
|
-
open
|
|
63
|
+
open(import("std/string"));
|
|
64
64
|
|
|
65
65
|
(value : Option(i32)) = .Some(i32(21));
|
|
66
66
|
doubled := value.map((x) => (x * i32(2)));
|
|
@@ -81,9 +81,9 @@ text := match(parsed,
|
|
|
81
81
|
## Collections
|
|
82
82
|
|
|
83
83
|
```rust
|
|
84
|
-
{ ArrayList } :: import
|
|
85
|
-
{ HashMap } :: import
|
|
86
|
-
open
|
|
84
|
+
{ ArrayList } :: import("std/collections/array_list");
|
|
85
|
+
{ HashMap } :: import("std/collections/hash_map");
|
|
86
|
+
open(import("std/string"));
|
|
87
87
|
|
|
88
88
|
numbers := ArrayList(i32).new();
|
|
89
89
|
numbers.push(i32(1));
|
|
@@ -161,7 +161,7 @@ parent := Node(value: i32(1), next: Option(Box(Node)).Some(child));
|
|
|
161
161
|
## Unicode and platform checks
|
|
162
162
|
|
|
163
163
|
```rust
|
|
164
|
-
{ Platform, platform } :: import
|
|
164
|
+
{ Platform, platform } :: import("std/process");
|
|
165
165
|
|
|
166
166
|
separator := cond(
|
|
167
167
|
(platform == Platform.Windows) => `\\`,
|
|
@@ -285,7 +285,7 @@ node_eq :: (fn(a : Node, b : Node) -> bool)(
|
|
|
285
285
|
true => {
|
|
286
286
|
(i : usize) = usize(0);
|
|
287
287
|
(ok : bool) = true;
|
|
288
|
-
while
|
|
288
|
+
while(runtime(((i < acs.len()) && ok)), {
|
|
289
289
|
match(acs.get(i),
|
|
290
290
|
.Some(ac) => match(bcs.get(i),
|
|
291
291
|
.Some(bc) => { ok = recur(ac, bc); },
|
|
@@ -294,7 +294,7 @@ node_eq :: (fn(a : Node, b : Node) -> bool)(
|
|
|
294
294
|
.None => { ok = false; }
|
|
295
295
|
);
|
|
296
296
|
i = (i + usize(1));
|
|
297
|
-
};
|
|
297
|
+
});
|
|
298
298
|
ok
|
|
299
299
|
}
|
|
300
300
|
)
|
|
@@ -324,15 +324,15 @@ derived or implemented. For **tag-only equality** (checking which variant), use
|
|
|
324
324
|
if(my_type != t_unit(), { ... });
|
|
325
325
|
|
|
326
326
|
// CORRECT — compare tags instead
|
|
327
|
-
{ type_value_tag } :: import
|
|
328
|
-
{ TypeTag } :: import
|
|
327
|
+
{ type_value_tag } :: import("../../types/type.yo");
|
|
328
|
+
{ TypeTag } :: import("../../types/tags.yo");
|
|
329
329
|
if((type_value_tag(my_type) != TypeTag.TUnit), { ... });
|
|
330
330
|
```
|
|
331
331
|
|
|
332
332
|
## Error handling
|
|
333
333
|
|
|
334
334
|
```rust
|
|
335
|
-
open
|
|
335
|
+
open(import("std/error"));
|
|
336
336
|
|
|
337
337
|
DivError :: enum(DivByZero);
|
|
338
338
|
impl(DivError, ToString(to_string : ((self) -> `division by zero`)));
|
|
@@ -358,9 +358,9 @@ safe_div :: (fn(a : i32, b : i32) -> Result(i32, DivError))(
|
|
|
358
358
|
result := inc(i32(5));
|
|
359
359
|
|
|
360
360
|
transform :: (fn(values : ArrayList(i32), f : Impl(Fn(x : i32) -> i32)) -> unit)({
|
|
361
|
-
for
|
|
361
|
+
for(values.iter(), (ptr) => {
|
|
362
362
|
ptr.* = f(ptr.*);
|
|
363
|
-
};
|
|
363
|
+
});
|
|
364
364
|
});
|
|
365
365
|
```
|
|
366
366
|
|
|
@@ -372,19 +372,19 @@ transform :: (fn(values : ArrayList(i32), f : Impl(Fn(x : i32) -> i32)) -> unit)
|
|
|
372
372
|
## Iterator and for loop
|
|
373
373
|
|
|
374
374
|
```rust
|
|
375
|
-
{ ArrayList } :: import
|
|
375
|
+
{ ArrayList } :: import("std/collections/array_list");
|
|
376
376
|
|
|
377
377
|
list := ArrayList(i32).new();
|
|
378
378
|
list.push(i32(1));
|
|
379
379
|
list.push(i32(2));
|
|
380
380
|
|
|
381
|
-
for
|
|
381
|
+
for(list.iter(), (ptr) => {
|
|
382
382
|
println(ptr.*);
|
|
383
|
-
};
|
|
383
|
+
});
|
|
384
384
|
|
|
385
|
-
for
|
|
385
|
+
for(list.into_iter(), (value) => {
|
|
386
386
|
println(value);
|
|
387
|
-
};
|
|
387
|
+
});
|
|
388
388
|
```
|
|
389
389
|
|
|
390
390
|
| Method | Yields | Semantics |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yo-project-workflow
|
|
3
|
-
description: Build, test, scaffold, and manage Yo projects. Use this when working with yo init, build.yo, yo build, yo compile, yo test, yo install, yo fetch, yo version, or cross-platform Yo project setup.
|
|
3
|
+
description: Build, test, scaffold, format, and manage Yo projects. Use this when working with yo init, build.yo, yo build, yo compile, yo test, yo fmt, yo install, yo fetch, yo version, or cross-platform Yo project setup.
|
|
4
4
|
argument-hint: "[project task or command]"
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -17,6 +17,7 @@ Use this skill when you need to:
|
|
|
17
17
|
- scaffold a new Yo project
|
|
18
18
|
- understand or edit `build.yo`
|
|
19
19
|
- choose between `yo build`, `yo compile`, and `yo test`
|
|
20
|
+
- format source with `yo fmt`
|
|
20
21
|
- manage dependencies with `yo install` or `yo fetch`
|
|
21
22
|
- pin or manage Yo versions with `yo version`
|
|
22
23
|
- install AI agent skill files with `yo skills install`
|
|
@@ -28,8 +29,9 @@ Use this skill when you need to:
|
|
|
28
29
|
1. If the repository has `build.yo`, prefer `yo build` and named steps for whole-project work.
|
|
29
30
|
2. For single-file experiments or reproductions, use `yo compile`.
|
|
30
31
|
3. For tests, use `yo test [path]` and narrow to a file or pattern before broad runs.
|
|
31
|
-
4.
|
|
32
|
-
5.
|
|
32
|
+
4. For source formatting, use `yo fmt`; use `yo fmt --check` in CI-style verification.
|
|
33
|
+
5. To pin the project to a specific Yo version, use `yo version pin`.
|
|
34
|
+
6. Consult the [workflow cheatsheet](./workflow-cheatsheet.md) for command shapes, project layout, and a minimal `build.yo`.
|
|
33
35
|
|
|
34
36
|
## High-signal rules
|
|
35
37
|
|
|
@@ -37,6 +39,7 @@ Use this skill when you need to:
|
|
|
37
39
|
- `build.yo` is Yo code that imports `std/build`; build functions register compile-time steps.
|
|
38
40
|
- `yo build run` and `yo build test` are the standard project entry points.
|
|
39
41
|
- `yo test ./tests/some.test.yo --parallel 1` is the focused single-file test pattern.
|
|
42
|
+
- `yo fmt` applies the fixed Yo style with 2-space indentation; there are no formatter options.
|
|
40
43
|
- Use `yo install` and `yo fetch` for git or path dependencies.
|
|
41
44
|
- Use `yo version pin` to create a `.yo-version` file for reproducible builds.
|
|
42
45
|
- Use `yo skills install` to copy Yo skill files into all agent config directories in the project.
|
|
@@ -18,6 +18,8 @@ These commands and patterns are aimed at normal Yo projects that use the public
|
|
|
18
18
|
| Inspect generated C | `yo compile main.yo --emit-c --skip-c-compiler` |
|
|
19
19
|
| Run tests in one file | `yo test ./tests/main.test.yo --parallel 1` |
|
|
20
20
|
| Filter tests by name | `yo test ./tests/main.test.yo --test-name-pattern "Name"` |
|
|
21
|
+
| Format Yo source | `yo fmt ./src ./tests` |
|
|
22
|
+
| Check Yo formatting | `yo fmt --check` |
|
|
21
23
|
| Generate docs for project | `yo doc ./src` |
|
|
22
24
|
| Generate docs (custom) | `yo doc ./src -o docs --title "My Project"` |
|
|
23
25
|
| Install AI agent skills | `yo skills install` |
|
|
@@ -48,7 +50,7 @@ my-project/
|
|
|
48
50
|
## Minimal `build.yo`
|
|
49
51
|
|
|
50
52
|
```rust
|
|
51
|
-
build :: import
|
|
53
|
+
build :: import("std/build");
|
|
52
54
|
|
|
53
55
|
mod :: build.module({ name: "my-project", root: "./src/lib.yo" });
|
|
54
56
|
|
|
@@ -89,6 +91,7 @@ doc_step.depend_on(docs);
|
|
|
89
91
|
| Whole project with `build.yo` | `yo build ...` |
|
|
90
92
|
| One standalone file | `yo compile ...` |
|
|
91
93
|
| One test file or test directory | `yo test ...` |
|
|
94
|
+
| Formatting Yo source | `yo fmt ...` |
|
|
92
95
|
| Dependency changes | `yo install ...` then `yo fetch` if needed |
|
|
93
96
|
|
|
94
97
|
## Testing patterns
|
|
@@ -103,25 +106,45 @@ yo test ./tests/main.test.yo --bail --verbose --parallel 1
|
|
|
103
106
|
- Use `--test-name-pattern` when a file contains many tests
|
|
104
107
|
- Use `yo build test` when the repository's main test workflow is defined in `build.yo`
|
|
105
108
|
|
|
109
|
+
## Formatting
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
yo fmt
|
|
113
|
+
yo fmt ./src ./tests
|
|
114
|
+
yo fmt --check
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- `yo fmt` recursively formats `.yo` files under the current directory by default
|
|
118
|
+
- Pass files or directories to limit the scope
|
|
119
|
+
- `yo fmt --check` reports files that need formatting without writing changes
|
|
120
|
+
- Formatting is intentionally fixed: 2-space indentation and no configuration
|
|
121
|
+
- Formatting must be idempotent: a second `yo fmt` run on the same files should report no changes and must not produce parser errors
|
|
122
|
+
- The formatter removes redundant grouping parentheses, e.g. `return((1 + 2))` → `return(1 + 2)`
|
|
123
|
+
- Infix-like separators keep spaces on both sides, including `{ x : value }` fields and `[T ; N]` array type sugar
|
|
124
|
+
- It preserves delimiter syntax whose meaning is not just grouping: tuples, `{...}` struct/begin forms, `[T ; N]` arrays, `[T]` slices, call parentheses, function body calls, and prefix-operator operands
|
|
125
|
+
- It preserves grouping or operator line breaks where removing them would expose ambiguous infix syntax, e.g. `{ x : (1 + 2), y : 3 }`, `true => (x / y)`, `(ptr &+ 1).*`, and line-leading `|` chains
|
|
126
|
+
- When an operator ends a line, `yo fmt` indents the RHS one extra level as a continuation
|
|
127
|
+
- `yo fmt` canonicalizes legacy deref spelling `ptr.(*)` to `ptr.*` and keeps single-line array/tuple literals compact
|
|
128
|
+
|
|
106
129
|
### Writing tests in Yo
|
|
107
130
|
|
|
108
131
|
```rust
|
|
109
|
-
test
|
|
132
|
+
test("Basic assertion", {
|
|
110
133
|
assert(((i32(1) + i32(1)) == i32(2)), "1+1 should be 2");
|
|
111
|
-
};
|
|
134
|
+
});
|
|
112
135
|
|
|
113
|
-
test
|
|
136
|
+
test("Compile-time check", {
|
|
114
137
|
comptime_assert((2 + 2) == 4);
|
|
115
138
|
comptime_expect_error({ x :: (1 / 0); });
|
|
116
|
-
};
|
|
139
|
+
});
|
|
117
140
|
|
|
118
|
-
test
|
|
119
|
-
{ yield } :: import
|
|
141
|
+
test("Async test", {
|
|
142
|
+
{ yield } :: import("std/async");
|
|
120
143
|
io.await(yield());
|
|
121
|
-
};
|
|
144
|
+
});
|
|
122
145
|
```
|
|
123
146
|
|
|
124
|
-
- `test
|
|
147
|
+
- `test("name", { body })` defines a test — `io : IO` is automatically available
|
|
125
148
|
- All tests can use `io.async(...)`, `io.await(...)`, etc. without a `using` clause
|
|
126
149
|
- `assert(condition, "message")` — always include a message string
|
|
127
150
|
- `comptime_assert(expr)` — verified at compile time
|
|
@@ -147,7 +170,7 @@ yo test ./tests/main.test.yo --target wasm-wasi
|
|
|
147
170
|
For projects that compile to WASM npm packages, use `target: build.CompilationTarget.Wasm32_Emscripten` and `add_c_flags(...)` for Emscripten settings:
|
|
148
171
|
|
|
149
172
|
```rust
|
|
150
|
-
build :: import
|
|
173
|
+
build :: import("std/build");
|
|
151
174
|
|
|
152
175
|
wasm_api :: build.executable({
|
|
153
176
|
name: "my_lib_wasm_api",
|
|
@@ -191,7 +214,7 @@ yo doc --document-private # Include non-exported items
|
|
|
191
214
|
In `build.yo`:
|
|
192
215
|
|
|
193
216
|
```rust
|
|
194
|
-
build :: import
|
|
217
|
+
build :: import("std/build");
|
|
195
218
|
|
|
196
219
|
docs :: build.doc({ name: "docs", root: "./src" });
|
|
197
220
|
doc_step :: build.step("doc", "Generate documentation");
|
|
@@ -31,26 +31,27 @@ Use this skill when you need to:
|
|
|
31
31
|
- `cond(...)` and `match(...)` always require parentheses.
|
|
32
32
|
- `{ expr }` is a struct literal; `{ expr; }` is a begin block.
|
|
33
33
|
- Yo has no operator precedence. Parenthesize every binary operation.
|
|
34
|
-
- Use `func(arg)` with no space before `(` for
|
|
34
|
+
- Use `func(arg)` with no space before `(` for every call; `func arg` and `func (arg)` are invalid.
|
|
35
|
+
- Use `return(value)` / `return()` and `escape(value)` / `escape()`; bare control-flow arguments are invalid.
|
|
35
36
|
- Use `recur(...)` for self-recursion instead of the function name.
|
|
36
37
|
- Use `forall(T : Type)` for generic type parameters, `comptime(x) : T` for compile-time parameters.
|
|
37
38
|
- Use `where(T <: Trait)` to constrain type parameters.
|
|
38
39
|
- Use `using(name : Type)` for implicit/effect parameters and `given(name) := Type(...)` to install handlers.
|
|
39
40
|
- Use `(params) => expr` for closures; `Impl(Fn(...) -> T)` for the closure type.
|
|
40
|
-
- Every executable needs `export
|
|
41
|
+
- Every executable needs `export(main);`.
|
|
41
42
|
- Import sibling modules with relative paths like `./file.yo`.
|
|
42
43
|
- Do not import `std/prelude`; it is loaded automatically.
|
|
43
44
|
- Use `snake_case` for names, `PascalCase` for types/traits, 2-space indentation.
|
|
44
45
|
|
|
45
46
|
## Common traps
|
|
46
47
|
|
|
47
|
-
- `return
|
|
48
|
+
- `return expr` is invalid; use `return(expr)` or `return()` for unit.
|
|
48
49
|
- Nested patterns like `.Ok(.Some(x))` are not supported; match in stages.
|
|
49
|
-
- Unary operators need parenthesized operands: `!(ready)`.
|
|
50
|
-
- `while
|
|
50
|
+
- Unary operators need parenthesized operands: `!(ready)`, `&(value)`.
|
|
51
|
+
- Use `while(true, { ... })` for infinite runtime loops; use `while(comptime(cond), { ... })` only for compile-time unrolling.
|
|
51
52
|
- A single-expression lambda body should not be wrapped in `{ ... }` unless semicolons make it a begin block.
|
|
52
53
|
- `"hello"` is `comptime_string` inside `comptime` functions, not `str`. In runtime code, `"hello"` is always `str`.
|
|
53
|
-
-
|
|
54
|
+
- Calls in match/cond branches must use immediate `(...)`; this avoids trailing-comma ambiguity.
|
|
54
55
|
|
|
55
56
|
## Resource
|
|
56
57
|
|