@shd101wyy/yo 0.1.31 → 0.1.33
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/async-effects-recipes.md +2 -2
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +25 -1
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +41 -0
- package/out/cjs/index.cjs +663 -582
- package/out/cjs/yo-cli.cjs +770 -689
- package/out/cjs/yo-lsp.cjs +702 -621
- package/out/esm/index.mjs +577 -496
- package/out/types/src/codegen/functions/context.d.ts +1 -0
- package/out/types/src/evaluator/builtins/contracts.d.ts +35 -0
- package/out/types/src/evaluator/memory-safety.d.ts +1 -1
- package/out/types/src/evaluator/types/flowability.d.ts +1 -0
- package/out/types/src/evaluator/types/function.d.ts +2 -0
- package/out/types/src/expr.d.ts +6 -0
- package/out/types/src/tests/contracts-comptime-violation.test.d.ts +1 -0
- package/out/types/src/tests/contracts-runtime-violation.test.d.ts +1 -0
- package/out/types/src/types/creators.d.ts +3 -1
- package/out/types/src/types/definitions.d.ts +2 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/collections/hash_map.yo +51 -14
- package/std/libc/stdatomic.yo +49 -14
- package/std/prelude.yo +15 -1
- package/std/spec/numeric.yo +30 -0
- package/std/spec/refine.yo +43 -0
|
@@ -160,13 +160,13 @@ process_dir :: (fn(root: Path, ctx : WalkCtx) -> Impl(Future(unit, WalkCtx)))(
|
|
|
160
160
|
stack := ArrayList(Path).new();
|
|
161
161
|
{ stack.push(root); };
|
|
162
162
|
|
|
163
|
-
while(
|
|
163
|
+
while(stack.len() > usize(0), {
|
|
164
164
|
cur := match(stack.pop(), .Some(p) => p, .None => return());
|
|
165
165
|
entries := ctx.io.await(read_dir(cur, ctx.io), ctx.io);
|
|
166
166
|
// process `entries`, push subdirectories to `stack`
|
|
167
167
|
n := entries.len();
|
|
168
168
|
i := usize(0);
|
|
169
|
-
while(
|
|
169
|
+
while(i < n, {
|
|
170
170
|
match(entries.get(i),
|
|
171
171
|
.None => (),
|
|
172
172
|
.Some(e) => {
|
|
@@ -78,6 +78,30 @@ text := match(parsed,
|
|
|
78
78
|
- Prefer combinators for straight-line transforms: `map`, `and_then`, `map_err`, `or_else`
|
|
79
79
|
- Switch to `match(...)` when branches need different logic or side effects
|
|
80
80
|
|
|
81
|
+
### Match destructuring: prefer curly `{field}`, avoid positional `_` padding
|
|
82
|
+
|
|
83
|
+
For a variant with **2+ fields**, destructure by **name** with curly braces —
|
|
84
|
+
name only the fields the arm uses. Do NOT count positions and pad with `_`.
|
|
85
|
+
|
|
86
|
+
```rust
|
|
87
|
+
// ✅ Curly — names only what you need; order-free; partial matches OK.
|
|
88
|
+
// Robust: adding a field to the variant later doesn't shift anything.
|
|
89
|
+
match(v,
|
|
90
|
+
.FuncVal({ func_id }) => use(func_id), // bind field `func_id`
|
|
91
|
+
.Struct({ id, name: n }) => use2(id, n), // rename via `field: alias`
|
|
92
|
+
.EnumT({ id }) => use3(id), // ignore the other 6 fields
|
|
93
|
+
_ => ()
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
// ❌ Avoid — positional with many `_`; brittle and unreadable:
|
|
97
|
+
// .FuncVal(_, _, _, _, _, _, _, _, func_id) => … // count the 8 _'s!
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`{a}` = bind field `a`; `{a: x}` = rename to `x`; `{a: _}` = assert-exists-ignore.
|
|
101
|
+
Empty `{}` and bare `{_}` are rejected. Spec: `tests/match_curly.test.yo`.
|
|
102
|
+
(Full rules: `.github/instructions/yo-syntax.instructions.md` § Match
|
|
103
|
+
destructuring forms.)
|
|
104
|
+
|
|
81
105
|
## Collections
|
|
82
106
|
|
|
83
107
|
```rust
|
|
@@ -303,7 +327,7 @@ node_eq :: (fn(a : Node, b : Node) -> bool)(
|
|
|
303
327
|
true => {
|
|
304
328
|
(i : usize) = usize(0);
|
|
305
329
|
(ok : bool) = true;
|
|
306
|
-
while(
|
|
330
|
+
while(((i < acs.len()) && ok), {
|
|
307
331
|
match(acs.get(i),
|
|
308
332
|
.Some(ac) => match(bcs.get(i),
|
|
309
333
|
.Some(bc) => { ok = recur(ac, bc); },
|
|
@@ -134,6 +134,7 @@ masked := ((A | B) | C);
|
|
|
134
134
|
- **Audit public stdlib safety with `./yo-cli public-safe-report [path]`.** Flags every top-level public `fn(...)` whose params or return type expose `*(T)` outside an `extern(...)` block. Skips FFI-by-construction directories (`libc/`, `linux/`, `darwin/`, `cuda/`, `sys/`, `sync/`) and names that signal raw-pointer use by contract (`*_cstr`, `*_ptr`, `*_raw`, `raw_*`, `from_raw_parts`, `as_ptr`, `argv`, `argc`). Currently reports 0 findings on `./std` and `./yo-self`; keep it that way when adding new APIs.
|
|
135
135
|
- **Extern "c" call sites require `unsafe(...)` even in pragma'd files.** `unsafe(memcpy(dst, src, n))`, `unsafe(strlen(s))`, etc. The pragma authorizes DECLARING the FFI symbol via `extern(...)` / `c_include(...)`; the wrap is the per-call audit marker so `yo unsafe-report` lines up with UB-capable lines. `asm(...)` and `extern(...)` / `c_include(...)` declarations themselves do NOT need a wrap (the keyword / declaration syntax is its own marker). See `plans/EXTERN_UNSAFE_WRAP.md`.
|
|
136
136
|
- **Slice-flowability rule:** a function returning a slice-bearing type (`Slice(T)`, `str`, a struct wrapping a Slice, ...) must root the returned value in caller-owned storage (a `ref`-bound parameter, any non-`ref` parameter, a `comptime`/literal source, or a flowable projection chain). `(fn() -> Option(Slice(i32)))({ arr := ArrayList(i32).new(); arr.as_slice() })` is rejected; `(fn(ref(arr) : ArrayList(i32)) -> Option(Slice(i32)))(arr.as_slice())` is accepted. See `plans/SLICE_FLOWABILITY.md`.
|
|
137
|
+
- **Return-slot modifier placement: on the LABEL, not the type.** In a _labeled_ return slot, a `ref`/`comptime` modifier attaches to the label, mirroring the parameter convention (`ref(name) : T`). Valid: `-> ref(T)` and `-> comptime(T)` (unlabeled — modifier on the sole type), `-> (ref(name) : T)`, `-> (comptime(name) : T)`. **Rejected:** `-> (name : ref(T))`, `-> (name : comptime(T))` (modifier on the type when labeled), and `-> (ref(name) : ref(T))` (double-ref — "pick one"). Enforced at function-type eval in `src/evaluator/types/function.ts` (and the yo-self port).
|
|
137
138
|
- **Signed-integer overflow is defined (wrap-around).** Yo passes `-fwrapv` to clang/gcc/zig by default so `x + i32(1)` on `i32(MAX)` wraps to `i32(MIN)` instead of UB. Opt-out: `--cflags='-fno-wrapv'`.
|
|
138
139
|
- **`// SAFETY:` comment convention.** Every non-obvious `unsafe(...)` site in stdlib should have a `// SAFETY:` comment in the previous ~8 lines explaining the contract. `yo unsafe-report` picks them up and shows them inline under each finding.
|
|
139
140
|
- **User-facing memory-safety guide:** `docs/en-US/MEMORY_SAFETY.md` (English) and `docs/zh-CN/MEMORY_SAFETY.md` (Chinese). Refer users there instead of `plans/MEMORY_SAFETY.md` (which is the design document — not shipped via npm).
|
|
@@ -506,6 +507,46 @@ test("Async test", {
|
|
|
506
507
|
- `comptime_assert(condition)` — compile-time assertion
|
|
507
508
|
- `comptime_expect_error(expr)` — verify code produces a compile error
|
|
508
509
|
|
|
510
|
+
## Design-by-contract clauses
|
|
511
|
+
|
|
512
|
+
`plans/FORMAL_VERIFICATION.md` Phase 0. No SMT verifier yet — these
|
|
513
|
+
lower to runtime `assert(...)` (runtime fns) or `comptime_assert(...)`
|
|
514
|
+
(comptime fns, returning `comptime(T)`).
|
|
515
|
+
|
|
516
|
+
```rust
|
|
517
|
+
// requires/ensures are SIGNATURE clauses, after params and where(...).
|
|
518
|
+
// ENFORCED order: forall, params, where, requires, ensures — a clause
|
|
519
|
+
// out of order is a syntax error ("X appears after Y").
|
|
520
|
+
divide :: (fn(x : i32, y : i32, requires(y != i32(0)), ensures(result == (x / y))) -> i32)(
|
|
521
|
+
x / y
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
// Inside ensures: `result` = return value, old(expr) = entry-time value.
|
|
525
|
+
increment :: (fn(ref(n) : i32, ensures(n == (old(n) + i32(1)))) -> unit)({ n = (n + i32(1)); });
|
|
526
|
+
|
|
527
|
+
// invariant(...) must be the FIRST statement of a while body.
|
|
528
|
+
// NOTE: do NOT wrap the condition in runtime(...) — while conditions are
|
|
529
|
+
// runtime by default, so `while(runtime(i < n), …)` is redundant; use `while(i < n, …)`.
|
|
530
|
+
while(i < n, {
|
|
531
|
+
invariant(i <= n, acc >= i32(0));
|
|
532
|
+
i = (i + i32(1)); acc = (acc + i);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// ghost binding vs ghost function (SEPARATE builtins):
|
|
536
|
+
ghost(snap := (a + b));
|
|
537
|
+
is_pos :: ghost_fn((fn(x : i32) -> bool)(x > i32(0)));
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
- One `requires(...)` and one `ensures(...)` max per signature; put
|
|
541
|
+
multiple predicates inside the single call: `requires(a, b)`. Two
|
|
542
|
+
`requires(...)` clauses, or a zero-arg `requires()`, is a syntax error.
|
|
543
|
+
- `result` is a wrapper-bound local (NOT a reserved word) — it coexists
|
|
544
|
+
with `result` used as an ordinary variable name elsewhere.
|
|
545
|
+
- `pragma(Pragma.NoContracts);` erases contracts; `pragma(Pragma.Verify);`
|
|
546
|
+
parses but warns "verify mode not implemented".
|
|
547
|
+
- `std/spec/` exposes refinement aliases (`NonZero`, `Bounded`,
|
|
548
|
+
`Positive`, …) — Phase 0 they are plain aliases for the base type.
|
|
549
|
+
|
|
509
550
|
## Common pitfalls
|
|
510
551
|
|
|
511
552
|
### `&&` short-circuit with `match`/`cond` on RHS causes C codegen scope bug
|