@shd101wyy/yo 0.1.25 → 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 +40 -40
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +30 -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 +78 -60
- package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
- package/README.md +10 -8
- package/out/cjs/index.cjs +583 -567
- package/out/cjs/yo-cli.cjs +664 -632
- package/out/cjs/yo-lsp.cjs +510 -485
- package/out/esm/index.mjs +538 -522
- package/out/types/src/codegen/codegen-c.d.ts +2 -2
- package/out/types/src/codegen/functions/collection.d.ts +2 -2
- package/out/types/src/codegen/functions/context.d.ts +3 -2
- package/out/types/src/codegen/types/collection.d.ts +2 -2
- package/out/types/src/codegen/utils/index.d.ts +3 -1
- package/out/types/src/doc/builder.d.ts +2 -2
- package/out/types/src/evaluator/calls/closure-type.d.ts +2 -2
- package/out/types/src/evaluator/calls/record-type.d.ts +11 -0
- package/out/types/src/evaluator/context.d.ts +8 -9
- package/out/types/src/evaluator/index.d.ts +3 -3
- package/out/types/src/evaluator/types/record.d.ts +14 -0
- package/out/types/src/evaluator/types/validation.d.ts +2 -2
- package/out/types/src/evaluator/values/anonymous-module.d.ts +5 -5
- package/out/types/src/evaluator/values/impl.d.ts +1 -1
- package/out/types/src/expr.d.ts +1 -4
- package/out/types/src/formatter.d.ts +11 -0
- package/out/types/src/function-value.d.ts +1 -1
- package/out/types/src/lsp/document-manager.d.ts +1 -1
- package/out/types/src/lsp/formatting.d.ts +2 -0
- package/out/types/src/module-manager.d.ts +3 -3
- package/out/types/src/tests/formatter.test.d.ts +1 -0
- package/out/types/src/types/creators.d.ts +3 -4
- package/out/types/src/types/definitions.d.ts +8 -19
- package/out/types/src/types/guards.d.ts +3 -3
- package/out/types/src/types/tags.d.ts +0 -1
- package/out/types/src/types/utils.d.ts +1 -1
- package/out/types/src/value-tag.d.ts +0 -1
- package/out/types/src/value.d.ts +6 -13
- 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 +12 -20
- 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 +6316 -4333
- 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
- package/out/types/src/evaluator/calls/module-type.d.ts +0 -11
- package/out/types/src/evaluator/types/module.d.ts +0 -19
|
@@ -13,7 +13,7 @@ These are baseline syntax rules for portable Yo code.
|
|
|
13
13
|
## Common declaration forms
|
|
14
14
|
|
|
15
15
|
```rust
|
|
16
|
-
{ println } :: import
|
|
16
|
+
{ println } :: import("std/fmt");
|
|
17
17
|
|
|
18
18
|
app_name :: "yo-demo";
|
|
19
19
|
|
|
@@ -23,21 +23,22 @@ main :: (fn() -> unit)({
|
|
|
23
23
|
println(message);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
export
|
|
26
|
+
export(main);
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
- Top-level binding: `name :: expr;`
|
|
30
30
|
- Local binding: `name := expr;`
|
|
31
31
|
- Typed binding: `(name : Type) = expr;`
|
|
32
32
|
- Function definition: `name :: (fn(args...) -> ReturnType)(body);`
|
|
33
|
+
- Export: `export(name);`
|
|
33
34
|
|
|
34
35
|
## Blocks and expressions
|
|
35
36
|
|
|
36
|
-
| Goal | Write
|
|
37
|
-
| ----------------- |
|
|
38
|
-
| Single expression | `cond(...)`
|
|
39
|
-
| Begin block | `{ x := i32(1); x }`
|
|
40
|
-
| Struct literal | `{ name: "yo", ok: true }` | `{ name: "yo"; ok: true }` |
|
|
37
|
+
| Goal | Write | Avoid |
|
|
38
|
+
| ----------------- | ---------------------------- | ---------------------------- |
|
|
39
|
+
| Single expression | `cond(...)` | `{ cond(...) }` |
|
|
40
|
+
| Begin block | `{ x := i32(1); x }` | `{ x := i32(1), x }` |
|
|
41
|
+
| Struct literal | `{ name : "yo", ok : true }` | `{ name : "yo"; ok : true }` |
|
|
41
42
|
|
|
42
43
|
```rust
|
|
43
44
|
result := cond(
|
|
@@ -53,6 +54,8 @@ total := {
|
|
|
53
54
|
|
|
54
55
|
Remember: `{ expr }` without semicolons is a struct literal, not a block. The parser now detects this mistake and emits a clear error if the single expression is not a valid struct field.
|
|
55
56
|
|
|
57
|
+
In struct literals, keep spaces around `:` and parenthesize infix field values: `{ x : (1 + 2), y : 3 }`, not `{ x: 1 + 2, y: 3 }`.
|
|
58
|
+
|
|
56
59
|
## Control flow
|
|
57
60
|
|
|
58
61
|
```rust
|
|
@@ -74,6 +77,8 @@ if(done, println("done"), println("pending"));
|
|
|
74
77
|
- Always write `cond(...)`, never bare `cond ...`
|
|
75
78
|
- Always write `match(...)`, never bare `match ...`
|
|
76
79
|
- `if(a, b)` and `if(a, b, c)` are macro forms over `cond`
|
|
80
|
+
- Write `return(value)` or `return()`; `return value` is invalid.
|
|
81
|
+
- Write `escape(value)` or `escape()`; `escape value` is invalid.
|
|
77
82
|
|
|
78
83
|
## String types
|
|
79
84
|
|
|
@@ -101,10 +106,18 @@ flag := ((a > b) && (b > c));
|
|
|
101
106
|
masked := ((A | B) | C);
|
|
102
107
|
```
|
|
103
108
|
|
|
104
|
-
-
|
|
105
|
-
- `func
|
|
109
|
+
- Calls require immediate parentheses: `func(arg1, arg2)`
|
|
110
|
+
- `func arg1, arg2` and `func (arg1, arg2)` are invalid
|
|
106
111
|
- Yo has no operator precedence; fully parenthesize binary expressions
|
|
107
|
-
-
|
|
112
|
+
- Preserve grouping around infix expressions on operator RHS positions: `true => (x / y)`, `value := (x + y)`, `(ptr &+ 1).*`
|
|
113
|
+
- Line breaks can disambiguate operator chains; keep line-leading operators like `(4\n| 5\n| 6)` and newlines after `:` before a lambda unless you add equivalent grouping
|
|
114
|
+
- When an operator ends a line, indent its RHS one level as a continuation: `(given(x) : T) =\n (v) -> { ... }`
|
|
115
|
+
- Prefix operators (`!`, `&`, `-`, `~`) require parenthesized operands: `func(&(s), a, b)`, `!(ready)`, `-(value)`.
|
|
116
|
+
- Tight special forms also require immediate parentheses: `#(expr)`, `?*(u8)`, `T <: !(Runtime)`
|
|
117
|
+
- Dynamic field access with unquote must keep grouping after the dot: `value.(#(field_expr))`, not `value.#(field_expr)`.
|
|
118
|
+
- Unquote splicing is the tight operator `...#(exprs)`; do not insert a space between `...` and `#`.
|
|
119
|
+
- Canonical pointer dereference is `ptr.*`; formatter should canonicalize legacy `ptr.(*)` to `ptr.*`.
|
|
120
|
+
- Keep single-line array and tuple literals compact during formatting: `[1, 2, 3]`, `(1, 2, 3)`.
|
|
108
121
|
- Parenthesize other unary operands too: `!(ready)`, `-(value)`
|
|
109
122
|
- **`!x && y` is parsed as `!(x && y)`**, not `(!x) && y`. Prefix `!` greedily consumes the full right-hand expression. To get `(!x) && y`, write `((!x) && y)` with explicit inner parens.
|
|
110
123
|
- **Nested `&&` / `||` in a single compound condition causes "Ambiguous operator precedence"** even with explicit parentheses: `((A && B) && (C && D))` on one line triggers the error. Fix: extract sub-conditions into named booleans first: `_c1 := (A && B); _c2 := (C && D); if((_c1 && _c2), ...)`.
|
|
@@ -129,6 +142,11 @@ impl(Counter,
|
|
|
129
142
|
- No space between a function type and its body: `(fn(...) -> T)(...)`
|
|
130
143
|
- Use `Self` in method signatures and in type definitions for recursive references (the type name is not available during its own definition)
|
|
131
144
|
- `Self` also works inside generic type constructors — it refers to the current instantiation (e.g., `Tree(T)` inside `Tree`). Use `recur(args)` only when type arguments differ from the current instantiation.
|
|
145
|
+
- Use `struct(...)` for record and effect-record types. The legacy `module(...)`,
|
|
146
|
+
`Module`, and `SelfModule` syntax has been removed; imported files are
|
|
147
|
+
represented as namespace structs, and recursive references use normal `Self`.
|
|
148
|
+
- Bare `Module` is not a type alias. Use `Type` for comptime type values; type
|
|
149
|
+
reflection reports source-module namespaces as `TypeInfo.Struct(...)`.
|
|
132
150
|
- Wrap `fn` types in parentheses when they appear after `:`
|
|
133
151
|
- **Forward references between methods in the same `impl` block are supported.** A method defined later in the block can be called by a method defined earlier. Both `self.method()` and `Self.method(...)` dispatch work. Only the canonical `name : (fn(...) -> R)(body)` method shape participates; bare lambdas do not get forward-ref shells.
|
|
134
152
|
- **Module-level `::` function definitions are processed in order.** A function body that calls another function declared later in the same file will fail with "Variable not found". Always define leaf helpers first (bottom-up order): `eval_identifier` → `eval_atom` → `evaluate`.
|
|
@@ -164,7 +182,7 @@ safe_divide :: (fn(x : i32, y : i32, using(raise : Raise)) -> i32)(
|
|
|
164
182
|
|
|
165
183
|
caller :: (fn() -> i32)({
|
|
166
184
|
(given(raise) : Raise) = (fn(msg : String) -> i32)({
|
|
167
|
-
return
|
|
185
|
+
return(i32(0));
|
|
168
186
|
});
|
|
169
187
|
|
|
170
188
|
safe_divide(i32(10), i32(0))
|
|
@@ -184,9 +202,9 @@ caller :: (fn() -> i32)({
|
|
|
184
202
|
result := closure(i32(5));
|
|
185
203
|
|
|
186
204
|
transform :: (fn(list : ArrayList(i32), f : Impl(Fn(x : i32) -> i32)) -> unit)({
|
|
187
|
-
for
|
|
205
|
+
for(list.iter(), (ptr) => {
|
|
188
206
|
ptr.* = f(ptr.*);
|
|
189
|
-
};
|
|
207
|
+
});
|
|
190
208
|
});
|
|
191
209
|
```
|
|
192
210
|
|
|
@@ -198,15 +216,15 @@ transform :: (fn(list : ArrayList(i32), f : Impl(Fn(x : i32) -> i32)) -> unit)({
|
|
|
198
216
|
## Imports and modules
|
|
199
217
|
|
|
200
218
|
```rust
|
|
201
|
-
{ Parser } :: import
|
|
202
|
-
parser_module :: import
|
|
219
|
+
{ Parser } :: import("./parser.yo");
|
|
220
|
+
parser_module :: import("./parser.yo");
|
|
203
221
|
|
|
204
|
-
open
|
|
205
|
-
{ ArrayList } :: import
|
|
222
|
+
open(import("std/string"));
|
|
223
|
+
{ ArrayList } :: import("std/collections/array_list");
|
|
206
224
|
```
|
|
207
225
|
|
|
208
226
|
- Use relative imports for nearby `.yo` files
|
|
209
|
-
- Use `open
|
|
227
|
+
- Use `open(import("std/module"))` for standard-library modules you want fully in scope
|
|
210
228
|
- Do not write `import "./file.yo" as name`
|
|
211
229
|
- Do not import `std/prelude`
|
|
212
230
|
|
|
@@ -268,17 +286,17 @@ show :: (fn(forall(T : Type), value : T, where(T <: ToString)) -> unit)(
|
|
|
268
286
|
|
|
269
287
|
```rust
|
|
270
288
|
main :: (fn() -> unit)(());
|
|
271
|
-
export
|
|
289
|
+
export(main);
|
|
272
290
|
|
|
273
|
-
export
|
|
291
|
+
export(
|
|
274
292
|
helper,
|
|
275
293
|
Config
|
|
276
|
-
;
|
|
294
|
+
);
|
|
277
295
|
```
|
|
278
296
|
|
|
279
|
-
- `export
|
|
297
|
+
- `export(name);` exports a single binding
|
|
280
298
|
- Block form exports multiple bindings separated by commas
|
|
281
|
-
- Every executable needs `export
|
|
299
|
+
- Every executable needs `export(main);`
|
|
282
300
|
|
|
283
301
|
## Static and dynamic dispatch types
|
|
284
302
|
|
|
@@ -316,15 +334,15 @@ factorial :: (fn(n : i32) -> i32)(
|
|
|
316
334
|
)
|
|
317
335
|
);
|
|
318
336
|
|
|
319
|
-
// Runtime infinite loop — `while
|
|
320
|
-
while
|
|
337
|
+
// Runtime infinite loop — `while(cond, body)` is ALWAYS runtime
|
|
338
|
+
while(true, {
|
|
321
339
|
work();
|
|
322
|
-
};
|
|
340
|
+
});
|
|
323
341
|
|
|
324
342
|
// Compile-time loop unrolling — requires comptime() modifier
|
|
325
|
-
while
|
|
343
|
+
while(comptime((i < 10)), {
|
|
326
344
|
// body evaluated/unrolled at compile time
|
|
327
|
-
};
|
|
345
|
+
});
|
|
328
346
|
|
|
329
347
|
// for loop — 2-arg prelude macro; first arg MUST be an iterator (has .next()):
|
|
330
348
|
for(list.iter(), x => { // ArrayList, array → call .iter() first
|
|
@@ -341,8 +359,8 @@ for(list.iter(), (ptr) => { // ptr is a mutable reference to each element
|
|
|
341
359
|
```
|
|
342
360
|
|
|
343
361
|
- Use `recur(...)` for self-recursion
|
|
344
|
-
- `while
|
|
345
|
-
- `while
|
|
362
|
+
- `while(cond, body)` is **always a runtime loop** — use this for open-ended loops (e.g., server accept loops, event loops)
|
|
363
|
+
- `while(comptime(cond), body)` explicitly unrolls at compile time — `cond` must be a compile-time-known value
|
|
346
364
|
- Using a comptime-only (`::`) variable in a bare `while` condition without `comptime()` is a **compile error** (would be an infinite loop at runtime)
|
|
347
365
|
- **`for(arr, item => { body })`** — correct 2-arg prelude macro form. The `item => { body }` is an anonymous closure.
|
|
348
366
|
- **Do NOT use `for(x, arr, { body })`** — this older 3-arg form is an evaluator-internal representation, not valid top-level Yo syntax. (The self-hosted evaluator currently only understands the 3-arg form in its internal for-loop handler; track issue: `issues/eval-for-loop-3arg-vs-2arg.md`)
|
|
@@ -350,19 +368,19 @@ for(list.iter(), (ptr) => { // ptr is a mutable reference to each element
|
|
|
350
368
|
## Return and branch safety
|
|
351
369
|
|
|
352
370
|
```rust
|
|
353
|
-
// WRONG — return
|
|
371
|
+
// WRONG — paren-less return is invalid:
|
|
354
372
|
match(opt,
|
|
355
|
-
.Some(v) => return v,
|
|
373
|
+
.Some(v) => return v,
|
|
356
374
|
.None => default_value()
|
|
357
375
|
);
|
|
358
376
|
|
|
359
|
-
// CORRECT —
|
|
377
|
+
// CORRECT — explicit return calls in begin blocks:
|
|
360
378
|
match(opt,
|
|
361
379
|
.Some(v) => {
|
|
362
|
-
return
|
|
380
|
+
return(v);
|
|
363
381
|
},
|
|
364
382
|
.None => {
|
|
365
|
-
return
|
|
383
|
+
return(default_value());
|
|
366
384
|
}
|
|
367
385
|
);
|
|
368
386
|
|
|
@@ -375,11 +393,11 @@ get_value :: (fn(opt : Option(i32)) -> i32)(
|
|
|
375
393
|
);
|
|
376
394
|
```
|
|
377
395
|
|
|
378
|
-
- `return
|
|
396
|
+
- `return expr` is invalid; write `return(expr)` or `return()` for unit
|
|
379
397
|
- In `cond` or `match` branches, **always use begin blocks** when you need `return`
|
|
380
|
-
- `return` must be the **last expression** in a begin block — dead code after `return` is rejected. Do NOT write `{ return
|
|
398
|
+
- `return(...)` must be the **last expression** in a begin block — dead code after `return(...)` is rejected. Do NOT write `{ return(x); fallback_val }`. Write `{ return(x); }` only.
|
|
381
399
|
- If the whole function is one expression, prefer expression-bodied style and skip `return` entirely
|
|
382
|
-
- The same
|
|
400
|
+
- The same rule applies to all calls in match branches: use immediate `(...)`
|
|
383
401
|
|
|
384
402
|
## String concatenation pitfall
|
|
385
403
|
|
|
@@ -401,43 +419,43 @@ content := String.from("line1\nline2\n");
|
|
|
401
419
|
## Iterator and for loop
|
|
402
420
|
|
|
403
421
|
```rust
|
|
404
|
-
{ ArrayList } :: import
|
|
422
|
+
{ ArrayList } :: import("std/collections/array_list");
|
|
405
423
|
|
|
406
424
|
list := ArrayList(i32).new();
|
|
407
425
|
list.push(i32(10));
|
|
408
426
|
list.push(i32(20));
|
|
409
427
|
|
|
410
|
-
for
|
|
428
|
+
for(list.iter(), (ptr) => {
|
|
411
429
|
println(ptr.*);
|
|
412
|
-
};
|
|
430
|
+
});
|
|
413
431
|
|
|
414
|
-
for
|
|
432
|
+
for(list.into_iter(), (value) => {
|
|
415
433
|
println(value);
|
|
416
|
-
};
|
|
434
|
+
});
|
|
417
435
|
```
|
|
418
436
|
|
|
419
|
-
- `for
|
|
437
|
+
- `for(collection, (variable) => { body })` iterates via the `Iterator` trait
|
|
420
438
|
- `.iter()` borrows the collection and yields pointers
|
|
421
439
|
- `.into_iter()` takes ownership and yields values
|
|
422
440
|
|
|
423
441
|
## Testing
|
|
424
442
|
|
|
425
443
|
```rust
|
|
426
|
-
test
|
|
444
|
+
test("Addition works", {
|
|
427
445
|
assert(((i32(1) + i32(1)) == i32(2)), "1+1 should be 2");
|
|
428
|
-
};
|
|
446
|
+
});
|
|
429
447
|
|
|
430
|
-
test
|
|
448
|
+
test("Compile-time check", {
|
|
431
449
|
comptime_assert((2 + 2) == 4);
|
|
432
450
|
comptime_expect_error({ x :: (1 / 0); });
|
|
433
|
-
};
|
|
451
|
+
});
|
|
434
452
|
|
|
435
|
-
test
|
|
453
|
+
test("Async test", {
|
|
436
454
|
io.await(yield());
|
|
437
|
-
};
|
|
455
|
+
});
|
|
438
456
|
```
|
|
439
457
|
|
|
440
|
-
- `test
|
|
458
|
+
- `test("description", { body })` defines a test — `io : IO` is automatically available
|
|
441
459
|
- All tests can use `io.async(...)`, `io.await(...)`, etc. without a `using` clause
|
|
442
460
|
- `assert(condition, "message")` — runtime assertion (always include a message)
|
|
443
461
|
- `comptime_assert(condition)` — compile-time assertion
|
|
@@ -666,7 +684,7 @@ if((!cond), { do_thing(); });
|
|
|
666
684
|
|
|
667
685
|
### `escape` requires a nested-function context
|
|
668
686
|
|
|
669
|
-
`escape
|
|
687
|
+
`escape(value)` exits the **enclosing function** — the nearest `fn(...)` that
|
|
670
688
|
wraps the current code. It requires that the code is inside a nested function
|
|
671
689
|
(e.g., a closure or `given` handler lambda), NOT at the top level of a
|
|
672
690
|
standalone function definition.
|
|
@@ -674,20 +692,20 @@ standalone function definition.
|
|
|
674
692
|
```rust
|
|
675
693
|
// CORRECT — escape inside a given handler lambda (lambda has enclosing fn):
|
|
676
694
|
given(exn) := Exception(throw: ((err) -> {
|
|
677
|
-
escape
|
|
695
|
+
escape(result); // exits the outer function that contains this given()
|
|
678
696
|
}));
|
|
679
697
|
do_something(using(exn));
|
|
680
698
|
|
|
681
699
|
// CORRECT — escape inside a closure passed as argument:
|
|
682
700
|
result := match(opt, .Some(x) => x, .None => {
|
|
683
701
|
// This is NOT a nested function — use return:
|
|
684
|
-
// WRONG: escape
|
|
685
|
-
return
|
|
702
|
+
// WRONG: escape(default_val) // ERROR: no enclosing fn
|
|
703
|
+
return(default_val); // CORRECT: return exits the enclosing fn directly
|
|
686
704
|
});
|
|
687
705
|
|
|
688
706
|
// WRONG — escape inside a match arm (not a nested fn):
|
|
689
707
|
match(opt,
|
|
690
|
-
.Some(x) => { escape
|
|
708
|
+
.Some(x) => { escape(x); } // ERROR: "can only be used inside a function that has an enclosing function"
|
|
691
709
|
);
|
|
692
710
|
```
|
|
693
711
|
|
|
@@ -918,16 +936,16 @@ if (((is_tuple_type(ty) || is_struct_type(ty)) || is_union_type(ty)), ...)
|
|
|
918
936
|
|
|
919
937
|
### Duplicate imports from the same path must be merged
|
|
920
938
|
|
|
921
|
-
Having two `:: import
|
|
939
|
+
Having two `:: import("path")` lines importing from the same file causes a compile error.
|
|
922
940
|
Always merge them into a single destructuring import:
|
|
923
941
|
|
|
924
942
|
```rust
|
|
925
943
|
// ❌ Two imports from the same path
|
|
926
|
-
{ Foo } :: import
|
|
927
|
-
{ Bar } :: import
|
|
944
|
+
{ Foo } :: import("../../mod.yo");
|
|
945
|
+
{ Bar } :: import("../../mod.yo");
|
|
928
946
|
|
|
929
947
|
// ✅ Merged
|
|
930
|
-
{ Foo, Bar } :: import
|
|
948
|
+
{ Foo, Bar } :: import("../../mod.yo");
|
|
931
949
|
```
|
|
932
950
|
|
|
933
951
|
### Implicit (`using`) parameters cannot be used with `:=` assignment
|
|
@@ -16,7 +16,7 @@ Export C-compatible functions that operate on linear memory:
|
|
|
16
16
|
|
|
17
17
|
```rust
|
|
18
18
|
// src/wasm_api.yo
|
|
19
|
-
open
|
|
19
|
+
open(import("std/string"));
|
|
20
20
|
|
|
21
21
|
// Allocate WASM memory for the caller
|
|
22
22
|
wasm_alloc :: (fn(size : usize) -> *(u8))(
|
|
@@ -89,7 +89,7 @@ The `Executable` struct accepts: `name`, `root`, `target`, `optimize`, `allocato
|
|
|
89
89
|
Emscripten-specific flags go in `add_c_flags(...)` after creating the step.
|
|
90
90
|
|
|
91
91
|
```rust
|
|
92
|
-
build :: import
|
|
92
|
+
build :: import("std/build");
|
|
93
93
|
|
|
94
94
|
wasm_api :: build.executable({
|
|
95
95
|
name: "my_lib_wasm_api",
|
|
@@ -242,7 +242,7 @@ cd npm && node -e "const m = require('.'); m.createRenderer().render('hello').th
|
|
|
242
242
|
- **Memory leaks**: Always `_wasm_free` every `_wasm_alloc` on the JavaScript side.
|
|
243
243
|
- **String encoding**: WASM only sees bytes — use `TextEncoder`/`TextDecoder` for UTF-8.
|
|
244
244
|
- **Errno differences**: WASI errno values differ from POSIX. Use `std/libc/errno` constants.
|
|
245
|
-
- **No `main` needed**: Library WASM modules don't need `main` or `export
|
|
245
|
+
- **No `main` needed**: Library WASM modules don't need `main` or `export(main);` — just export the API functions.
|
|
246
246
|
- **Emscripten environment**: Set `-sENVIRONMENT='web,node'` to support both contexts, or `'node'` for Node.js only.
|
|
247
247
|
- **Module initialization is async**: Emscripten's `createModule()` returns a Promise. Initialize once and reuse.
|
|
248
248
|
- **WASM memory growth**: Always use `-sALLOW_MEMORY_GROWTH=1` for dynamic allocations.
|
package/README.md
CHANGED
|
@@ -202,14 +202,14 @@ my-project/
|
|
|
202
202
|
|
|
203
203
|
`src/main.yo`:
|
|
204
204
|
|
|
205
|
-
```
|
|
206
|
-
{ println } :: import
|
|
205
|
+
```rust
|
|
206
|
+
{ println } :: import("std/fmt");
|
|
207
207
|
|
|
208
208
|
main :: (fn() -> unit)({
|
|
209
209
|
println("Hello, world!");
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
-
export
|
|
212
|
+
export(main);
|
|
213
213
|
```
|
|
214
214
|
|
|
215
215
|
Common build commands:
|
|
@@ -220,6 +220,8 @@ $ yo build run # Build and run the executable
|
|
|
220
220
|
$ yo build test # Run tests
|
|
221
221
|
$ yo build --list-steps # List available build steps
|
|
222
222
|
$ yo build doc # Generate HTML documentation
|
|
223
|
+
$ yo fmt # Format Yo source files
|
|
224
|
+
$ yo fmt --check # Check formatting without writing changes
|
|
223
225
|
```
|
|
224
226
|
|
|
225
227
|
## Prelude
|
|
@@ -254,15 +256,15 @@ Check the [./tests](./tests/) and [./std](./std/) folders for more code examples
|
|
|
254
256
|
|
|
255
257
|
### Hello World
|
|
256
258
|
|
|
257
|
-
```
|
|
259
|
+
```rust
|
|
258
260
|
// main.yo
|
|
259
|
-
{ println } :: import
|
|
261
|
+
{ println } :: import("std/fmt");
|
|
260
262
|
|
|
261
|
-
main :: (fn() -> unit)
|
|
263
|
+
main :: (fn() -> unit)({
|
|
262
264
|
println("Hello, world!");
|
|
263
|
-
};
|
|
265
|
+
});
|
|
264
266
|
|
|
265
|
-
export
|
|
267
|
+
export(main);
|
|
266
268
|
|
|
267
269
|
// $ yo compile main.yo --release -o main
|
|
268
270
|
// $ ./main
|