@shd101wyy/yo 0.1.28 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/skills/yo-async-effects/SKILL.md +15 -15
- package/.github/skills/yo-async-effects/async-effects-recipes.md +118 -121
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +33 -13
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +1 -1
- package/.github/skills/yo-syntax/SKILL.md +2 -2
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +108 -96
- package/README.md +6 -3
- package/out/cjs/index.cjs +812 -706
- package/out/cjs/yo-cli.cjs +1023 -907
- package/out/cjs/yo-lsp.cjs +836 -730
- package/out/esm/index.mjs +757 -651
- package/out/types/src/codegen/exprs/async.d.ts +2 -0
- package/out/types/src/codegen/exprs/await.d.ts +1 -0
- package/out/types/src/codegen/exprs/closures.d.ts +4 -0
- package/out/types/src/codegen/functions/context.d.ts +6 -0
- package/out/types/src/codegen/functions/declarations.d.ts +1 -1
- package/out/types/src/doc/model.d.ts +0 -1
- package/out/types/src/env.d.ts +2 -2
- package/out/types/src/evaluator/builtins/pragma.d.ts +9 -0
- package/out/types/src/evaluator/builtins/unsafe.d.ts +8 -0
- package/out/types/src/evaluator/context.d.ts +3 -1
- package/out/types/src/evaluator/exprs/{escape.d.ts → unwind.d.ts} +1 -1
- package/out/types/src/evaluator/index.d.ts +1 -1
- package/out/types/src/evaluator/memory-safety.d.ts +14 -0
- package/out/types/src/evaluator/types/flowability.d.ts +6 -0
- package/out/types/src/evaluator/types/function.d.ts +1 -2
- package/out/types/src/evaluator/utils.d.ts +0 -1
- package/out/types/src/expr-traversal.d.ts +1 -0
- package/out/types/src/expr.d.ts +9 -7
- package/out/types/src/public-safe-report.d.ts +19 -0
- package/out/types/src/tests/comptime-ref-gate.test.d.ts +1 -0
- package/out/types/src/tests/pragma-validation.test.d.ts +1 -0
- package/out/types/src/tests/public-safe-report.test.d.ts +1 -0
- package/out/types/src/tests/type-representation-pointer.test.d.ts +1 -0
- package/out/types/src/tests/unsafe-gate.test.d.ts +1 -0
- package/out/types/src/tests/unsafe-report-classify.test.d.ts +1 -0
- package/out/types/src/types/creators.d.ts +4 -6
- package/out/types/src/types/definitions.d.ts +9 -16
- package/out/types/src/types/guards.d.ts +1 -2
- package/out/types/src/types/tags.d.ts +0 -1
- package/out/types/src/types/utils.d.ts +5 -0
- package/out/types/src/unsafe-report.d.ts +29 -0
- package/out/types/src/value.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/scripts/add-pragma-for-pointer-decls.ts +134 -0
- package/scripts/add-pragma.ts +58 -0
- package/scripts/migrate-amp-method-calls.ts +186 -0
- package/scripts/migrate-clone-calls.ts +93 -0
- package/scripts/migrate-get-unwrap.ts +166 -0
- package/scripts/migrate-index-patterns.ts +210 -0
- package/scripts/migrate-index-trait.ts +142 -0
- package/scripts/migrate-iterator.ts +150 -0
- package/scripts/migrate-self-ptr.ts +220 -0
- package/scripts/migrate-skip-pragmas.ts +109 -0
- package/scripts/migrate-tostring.ts +134 -0
- package/scripts/trim-pragma.ts +130 -0
- package/scripts/wrap-extern-calls.ts +161 -0
- package/std/alg/hash.yo +3 -2
- package/std/allocator.yo +6 -5
- package/std/async.yo +2 -2
- package/std/collections/array_list.yo +59 -40
- package/std/collections/btree_map.yo +19 -18
- package/std/collections/deque.yo +9 -8
- package/std/collections/hash_map.yo +101 -13
- package/std/collections/hash_set.yo +5 -4
- package/std/collections/linked_list.yo +39 -4
- package/std/collections/ordered_map.yo +3 -3
- package/std/collections/priority_queue.yo +14 -13
- package/std/crypto/md5.yo +2 -1
- package/std/crypto/random.yo +21 -20
- package/std/crypto/sha256.yo +2 -1
- package/std/encoding/base64.yo +18 -18
- package/std/encoding/hex.yo +5 -5
- package/std/encoding/json.yo +62 -13
- package/std/encoding/punycode.yo +24 -23
- package/std/encoding/toml.yo +4 -3
- package/std/encoding/utf16.yo +3 -3
- package/std/env.yo +43 -28
- package/std/error.yo +15 -3
- package/std/fmt/display.yo +2 -2
- package/std/fmt/index.yo +6 -5
- package/std/fmt/to_string.yo +39 -38
- package/std/fmt/writer.yo +9 -8
- package/std/fs/dir.yo +61 -66
- package/std/fs/file.yo +121 -126
- package/std/fs/metadata.yo +13 -18
- package/std/fs/temp.yo +35 -30
- package/std/fs/walker.yo +14 -19
- package/std/gc.yo +1 -0
- package/std/glob.yo +7 -7
- package/std/http/client.yo +33 -36
- package/std/http/http.yo +6 -6
- package/std/http/index.yo +4 -4
- package/std/imm/list.yo +33 -0
- package/std/imm/map.yo +2 -1
- package/std/imm/set.yo +1 -0
- package/std/imm/sorted_map.yo +1 -0
- package/std/imm/sorted_set.yo +1 -0
- package/std/imm/string.yo +27 -23
- package/std/imm/vec.yo +18 -2
- package/std/io/reader.yo +2 -1
- package/std/io/writer.yo +3 -2
- package/std/libc/assert.yo +1 -0
- package/std/libc/ctype.yo +1 -0
- package/std/libc/dirent.yo +1 -0
- package/std/libc/errno.yo +1 -0
- package/std/libc/fcntl.yo +1 -0
- package/std/libc/float.yo +1 -0
- package/std/libc/limits.yo +1 -0
- package/std/libc/math.yo +1 -0
- package/std/libc/signal.yo +1 -0
- package/std/libc/stdatomic.yo +1 -0
- package/std/libc/stdint.yo +1 -0
- package/std/libc/stdio.yo +1 -0
- package/std/libc/stdlib.yo +1 -0
- package/std/libc/string.yo +1 -0
- package/std/libc/sys/stat.yo +1 -0
- package/std/libc/time.yo +1 -0
- package/std/libc/unistd.yo +1 -0
- package/std/libc/wctype.yo +1 -0
- package/std/libc/windows.yo +2 -0
- package/std/log.yo +7 -6
- package/std/net/addr.yo +6 -5
- package/std/net/dns.yo +13 -16
- package/std/net/errors.yo +9 -9
- package/std/net/tcp.yo +71 -74
- package/std/net/udp.yo +40 -43
- package/std/os/signal.yo +5 -5
- package/std/path.yo +1 -0
- package/std/prelude.yo +377 -200
- package/std/process/command.yo +57 -46
- package/std/process/index.yo +2 -1
- package/std/regex/compiler.yo +10 -9
- package/std/regex/index.yo +41 -41
- package/std/regex/match.yo +2 -2
- package/std/regex/parser.yo +31 -31
- package/std/regex/vm.yo +42 -41
- package/std/string/string.yo +95 -40
- package/std/string/string_builder.yo +9 -9
- package/std/string/unicode.yo +50 -49
- package/std/sync/channel.yo +2 -1
- package/std/sync/cond.yo +5 -4
- package/std/sync/mutex.yo +4 -3
- package/std/sys/advise.yo +1 -0
- package/std/sys/bufio/buf_reader.yo +27 -26
- package/std/sys/bufio/buf_writer.yo +22 -21
- package/std/sys/clock.yo +1 -0
- package/std/sys/copy.yo +1 -0
- package/std/sys/dir.yo +10 -9
- package/std/sys/dns.yo +6 -5
- package/std/sys/errors.yo +12 -12
- package/std/sys/events.yo +1 -0
- package/std/sys/externs.yo +38 -37
- package/std/sys/file.yo +17 -16
- package/std/sys/future.yo +4 -3
- package/std/sys/iov.yo +1 -0
- package/std/sys/mmap.yo +1 -0
- package/std/sys/path.yo +1 -0
- package/std/sys/perm.yo +2 -1
- package/std/sys/pipe.yo +1 -0
- package/std/sys/process.yo +5 -4
- package/std/sys/signal.yo +1 -0
- package/std/sys/socketpair.yo +1 -0
- package/std/sys/sockinfo.yo +1 -0
- package/std/sys/statfs.yo +2 -1
- package/std/sys/statx.yo +1 -0
- package/std/sys/sysinfo.yo +1 -0
- package/std/sys/tcp.yo +15 -14
- package/std/sys/temp.yo +1 -0
- package/std/sys/time.yo +2 -1
- package/std/sys/timer.yo +6 -6
- package/std/sys/tty.yo +2 -1
- package/std/sys/udp.yo +13 -12
- package/std/sys/unix.yo +12 -11
- package/std/testing/bench.yo +4 -3
- package/std/thread.yo +7 -6
- package/std/time/datetime.yo +18 -15
- package/std/time/duration.yo +11 -10
- package/std/time/instant.yo +4 -4
- package/std/time/sleep.yo +1 -0
- package/std/url/index.yo +5 -5
- package/std/worker.yo +4 -3
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plans/EXTERN_UNSAFE_WRAP.md Phase C — apply `unsafe(...)` wraps at
|
|
3
|
+
* every extern "c" call site collected by the evaluator's dump mode.
|
|
4
|
+
*
|
|
5
|
+
* Workflow:
|
|
6
|
+
* 1. YO_EXTERN_WRAP_DUMP_FILE=/tmp/extern_wraps.json ./yo-cli check ./std
|
|
7
|
+
* (the evaluator records each unwrapped call site as JSON)
|
|
8
|
+
* 2. bun run scripts/wrap-extern-calls.ts /tmp/extern_wraps.json --write
|
|
9
|
+
* (this script reads the JSON and applies precise wraps)
|
|
10
|
+
*
|
|
11
|
+
* Dry-run by default. Pass `--write` to apply changes.
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
type Site = {
|
|
17
|
+
modulePath: string;
|
|
18
|
+
characterOffset: number;
|
|
19
|
+
calleeName: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function findMatchingClose(src: string, openIdx: number): number {
|
|
23
|
+
if (src[openIdx] !== "(") {
|
|
24
|
+
throw new Error(`expected '(' at offset ${openIdx}, got '${src[openIdx]}'`);
|
|
25
|
+
}
|
|
26
|
+
let depth = 0;
|
|
27
|
+
for (let i = openIdx; i < src.length; i++) {
|
|
28
|
+
const c = src[i];
|
|
29
|
+
if (c === "(") depth++;
|
|
30
|
+
else if (c === ")") {
|
|
31
|
+
depth--;
|
|
32
|
+
if (depth === 0) return i;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`unmatched '(' at offset ${openIdx}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function alreadyWrapped(src: string, callStart: number): boolean {
|
|
39
|
+
// Look back from callStart past whitespace; check for `unsafe(` immediately
|
|
40
|
+
// before.
|
|
41
|
+
let j = callStart - 1;
|
|
42
|
+
while (j >= 0 && (src[j] === " " || src[j] === "\t" || src[j] === "\n")) {
|
|
43
|
+
j--;
|
|
44
|
+
}
|
|
45
|
+
if (j < 6) return false;
|
|
46
|
+
return src.slice(j - 6, j + 1) === "unsafe(";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function findCallOpenParen(src: string, nameStart: number): number {
|
|
50
|
+
// Scan forward from `nameStart` past the function name to find the `(`.
|
|
51
|
+
// The function name is a sequence of identifier chars; the `(` follows
|
|
52
|
+
// (optionally with whitespace).
|
|
53
|
+
let i = nameStart;
|
|
54
|
+
while (i < src.length && /[A-Za-z0-9_]/.test(src[i]!)) i++;
|
|
55
|
+
while (i < src.length && /\s/.test(src[i]!)) i++;
|
|
56
|
+
if (src[i] !== "(") {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`expected '(' after identifier starting at ${nameStart}, got '${src[i]}' at ${i}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return i;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function main() {
|
|
65
|
+
const args = process.argv.slice(2);
|
|
66
|
+
const jsonPath = args[0];
|
|
67
|
+
const write = args.includes("--write");
|
|
68
|
+
if (!jsonPath) {
|
|
69
|
+
console.error(
|
|
70
|
+
"usage: bun run scripts/wrap-extern-calls.ts <json-path> [--write]"
|
|
71
|
+
);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
const sites: Site[] = JSON.parse(readFileSync(jsonPath, "utf8"));
|
|
75
|
+
|
|
76
|
+
// Dedupe by (modulePath, characterOffset)
|
|
77
|
+
const seen = new Set<string>();
|
|
78
|
+
const unique: Site[] = [];
|
|
79
|
+
for (const s of sites) {
|
|
80
|
+
const k = `${s.modulePath}@${s.characterOffset}`;
|
|
81
|
+
if (seen.has(k)) continue;
|
|
82
|
+
seen.add(k);
|
|
83
|
+
unique.push(s);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Group by file, sort offsets descending so edits don't shift later
|
|
87
|
+
// offsets in the same file.
|
|
88
|
+
const byFile = new Map<string, Site[]>();
|
|
89
|
+
for (const s of unique) {
|
|
90
|
+
const filePath = fileURLToPath(s.modulePath);
|
|
91
|
+
if (!byFile.has(filePath)) byFile.set(filePath, []);
|
|
92
|
+
byFile.get(filePath)!.push(s);
|
|
93
|
+
}
|
|
94
|
+
for (const list of byFile.values()) {
|
|
95
|
+
list.sort((a, b) => b.characterOffset - a.characterOffset);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let totalWraps = 0;
|
|
99
|
+
let totalSkipped = 0;
|
|
100
|
+
const fileStats: { file: string; wraps: number; skipped: number }[] = [];
|
|
101
|
+
for (const [filePath, list] of byFile) {
|
|
102
|
+
let src = readFileSync(filePath, "utf8");
|
|
103
|
+
let wraps = 0;
|
|
104
|
+
let skipped = 0;
|
|
105
|
+
for (const s of list) {
|
|
106
|
+
if (alreadyWrapped(src, s.characterOffset)) {
|
|
107
|
+
skipped++;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
let openParen: number;
|
|
111
|
+
try {
|
|
112
|
+
openParen = findCallOpenParen(src, s.characterOffset);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
console.warn(
|
|
115
|
+
`skip ${filePath}@${s.characterOffset} (${s.calleeName}): ${(e as Error).message}`
|
|
116
|
+
);
|
|
117
|
+
skipped++;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
let close: number;
|
|
121
|
+
try {
|
|
122
|
+
close = findMatchingClose(src, openParen);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
console.warn(
|
|
125
|
+
`skip ${filePath}@${s.characterOffset} (${s.calleeName}): ${(e as Error).message}`
|
|
126
|
+
);
|
|
127
|
+
skipped++;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
src =
|
|
131
|
+
src.slice(0, s.characterOffset) +
|
|
132
|
+
"unsafe(" +
|
|
133
|
+
src.slice(s.characterOffset, close + 1) +
|
|
134
|
+
")" +
|
|
135
|
+
src.slice(close + 1);
|
|
136
|
+
wraps++;
|
|
137
|
+
}
|
|
138
|
+
if (wraps > 0 && write) {
|
|
139
|
+
writeFileSync(filePath, src);
|
|
140
|
+
}
|
|
141
|
+
if (wraps + skipped > 0) {
|
|
142
|
+
fileStats.push({ file: filePath, wraps, skipped });
|
|
143
|
+
totalWraps += wraps;
|
|
144
|
+
totalSkipped += skipped;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
fileStats.sort((a, b) => b.wraps - a.wraps);
|
|
149
|
+
for (const s of fileStats) {
|
|
150
|
+
console.log(
|
|
151
|
+
`${s.file}: ${s.wraps} wrap${s.wraps === 1 ? "" : "s"}` +
|
|
152
|
+
(s.skipped ? `, ${s.skipped} skipped` : "")
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
console.log(
|
|
156
|
+
`\n${write ? "Applied" : "Would apply"} ${totalWraps} wrap(s) across ${fileStats.length} file(s); ${totalSkipped} skipped.`
|
|
157
|
+
);
|
|
158
|
+
if (!write) console.log("Re-run with --write to apply.");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
main();
|
package/std/alg/hash.yo
CHANGED
|
@@ -7,11 +7,12 @@ FNV_OFFSET_BASIS :: u64(14695981039346656037);
|
|
|
7
7
|
/// FNV prime constant (0x100000001b3).
|
|
8
8
|
FNV_PRIME :: u64(1099511628211);
|
|
9
9
|
/// Hash a byte sequence using FNV-1a.
|
|
10
|
-
fnv1a_hash_bytes :: (fn(bytes :
|
|
10
|
+
fnv1a_hash_bytes :: (fn(bytes : Slice(u8)) -> u64)({
|
|
11
11
|
hash := FNV_OFFSET_BASIS;
|
|
12
|
+
length := bytes.len();
|
|
12
13
|
i := usize(0);
|
|
13
14
|
while(i < length, i = (i + usize(1)), {
|
|
14
|
-
byte := (
|
|
15
|
+
byte := bytes(i);
|
|
15
16
|
xor := (hash ^ u64(byte));
|
|
16
17
|
hash = (xor * FNV_PRIME);
|
|
17
18
|
});
|
package/std/allocator.yo
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//! Memory allocation abstractions and global allocator interface.
|
|
2
|
+
pragma(Pragma.AllowUnsafe);
|
|
2
3
|
{ SIZE_MAX } :: import("./libc/stdint.yo");
|
|
3
4
|
/// Memory allocation error variants.
|
|
4
5
|
AllocError :: enum(
|
|
@@ -39,15 +40,15 @@ size_would_overflow ::
|
|
|
39
40
|
/// Implement this trait to provide custom allocation strategies.
|
|
40
41
|
CustomAllocator :: trait(
|
|
41
42
|
/// Allocate memory for `count` items of type T.
|
|
42
|
-
alloc : (fn(self :
|
|
43
|
+
alloc : (fn(ref(self) : Self, comptime(T) : Type, count : usize) -> Result(?*(T), AllocError)),
|
|
43
44
|
/// Allocate zeroed memory for `count` items of type T.
|
|
44
|
-
alloc_zeroed : (fn(self :
|
|
45
|
+
alloc_zeroed : (fn(ref(self) : Self, comptime(T) : Type, count : usize) -> Result(?*(T), AllocError)),
|
|
45
46
|
/// Allocate aligned memory for `count` items of type T with the given alignment.
|
|
46
|
-
alloc_aligned : (fn(self :
|
|
47
|
+
alloc_aligned : (fn(ref(self) : Self, comptime(T) : Type, count : usize, alignment : usize) -> Result(?*(T), AllocError)),
|
|
47
48
|
/// Reallocate memory to `new_count` items, preserving existing data.
|
|
48
|
-
realloc : (fn(forall(T : Type), self :
|
|
49
|
+
realloc : (fn(forall(T : Type), ref(self) : Self, old_ptr : ?*(T), new_count : usize) -> Result(?*(T), AllocError)),
|
|
49
50
|
/// Deallocate memory pointed to by `ptr`.
|
|
50
|
-
dealloc : (fn(forall(T : Type), self :
|
|
51
|
+
dealloc : (fn(forall(T : Type), ref(self) : Self, ptr : *(T)) -> Result(unit, AllocError))
|
|
51
52
|
);
|
|
52
53
|
/// Type-erased dynamic allocator wrapping any `CustomAllocator` implementation.
|
|
53
54
|
Allocator :: Dyn(CustomAllocator);
|
package/std/async.yo
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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(
|
|
5
|
-
io.async(() => {
|
|
4
|
+
yield :: (fn(io : Io) -> Impl(Future(unit)))(
|
|
5
|
+
io.async((io : Io) => {
|
|
6
6
|
return(());
|
|
7
7
|
})
|
|
8
8
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//! Dynamic array (vector) with amortized O(1) push and O(1) indexed access.
|
|
2
|
+
pragma(Pragma.AllowUnsafe);
|
|
2
3
|
{ GlobalAllocator, AllocError } :: import("../allocator.yo");
|
|
3
4
|
{ memmove, memcpy, memset } :: import("../libc/string.yo");
|
|
4
5
|
{ malloc, calloc, realloc, free, aligned_alloc } :: GlobalAllocator;
|
|
@@ -303,7 +304,12 @@ impl(
|
|
|
303
304
|
bytes_to_move := (elements_after * element_size);
|
|
304
305
|
dst_void := *(void)(dst_ptr);
|
|
305
306
|
src_void := *(void)(src_ptr);
|
|
306
|
-
|
|
307
|
+
// SAFETY: dst_ptr and src_ptr both point into self._ptr's
|
|
308
|
+
// contiguous element buffer. `elements_after = self._length - (start + actual_count)`
|
|
309
|
+
// counts elements still in-bounds after the remove range,
|
|
310
|
+
// so `bytes_to_move = elements_after * sizeof(T)` stays within
|
|
311
|
+
// the allocated buffer. memmove handles overlap.
|
|
312
|
+
unsafe(memmove(dst_void, src_void, bytes_to_move));
|
|
307
313
|
}
|
|
308
314
|
);
|
|
309
315
|
},
|
|
@@ -429,7 +435,7 @@ impl(
|
|
|
429
435
|
self._ptr,
|
|
430
436
|
.Some(dst_base) => {
|
|
431
437
|
dst := (*(void))(dst_base &+ self._length);
|
|
432
|
-
_ := memcpy(dst, (*(void))(src), count * sizeof(T));
|
|
438
|
+
_ := unsafe(memcpy(dst, (*(void))(src), count * sizeof(T)));
|
|
433
439
|
self._length = (self._length + count);
|
|
434
440
|
},
|
|
435
441
|
.None => panic("ArrayList.extend_from_ptr: no ptr after ensure_total_capacity")
|
|
@@ -454,7 +460,7 @@ impl(
|
|
|
454
460
|
self._ptr,
|
|
455
461
|
.None => (),
|
|
456
462
|
.Some(_ptr) => {
|
|
457
|
-
_ := memset((*(void))(_ptr), byte_val, self._length * sizeof(T));
|
|
463
|
+
_ := unsafe(memset((*(void))(_ptr), byte_val, self._length * sizeof(T)));
|
|
458
464
|
}
|
|
459
465
|
)
|
|
460
466
|
),
|
|
@@ -475,7 +481,7 @@ impl(
|
|
|
475
481
|
.Some(_ptr) => {
|
|
476
482
|
start := (*(void))(_ptr &+ self._length);
|
|
477
483
|
fill_count := ((new_len - self._length) * sizeof(T));
|
|
478
|
-
_ := memset(start, byte_val, fill_count);
|
|
484
|
+
_ := unsafe(memset(start, byte_val, fill_count));
|
|
479
485
|
self._length = new_len;
|
|
480
486
|
},
|
|
481
487
|
.None => panic("ArrayList.resize_with_byte: no ptr after ensure")
|
|
@@ -491,16 +497,38 @@ impl(
|
|
|
491
497
|
/// The output type is the element type `T`.
|
|
492
498
|
Output : T,
|
|
493
499
|
/// Returns a pointer to the element at the given index. Panics if the index is out of bounds.
|
|
494
|
-
index : (fn(self :
|
|
495
|
-
assert(idx < self
|
|
500
|
+
index : (fn(ref(self) : Self, idx : usize) -> *(Self.Output))({
|
|
501
|
+
assert(idx < self._length, "ArrayList: index out of bounds");
|
|
496
502
|
match(
|
|
497
|
-
self
|
|
503
|
+
self._ptr,
|
|
498
504
|
.Some(_ptr) => (_ptr &+ idx),
|
|
499
505
|
.None => panic("ArrayList: index on empty list")
|
|
500
506
|
)
|
|
501
507
|
})
|
|
502
508
|
)
|
|
503
509
|
);
|
|
510
|
+
/// Indexable impl — projection-style indexing yielding `ref(T)`.
|
|
511
|
+
/// See plans/ITERATOR_REDESIGN.md. Body wraps the pointer arithmetic
|
|
512
|
+
/// in `unsafe(...)` to pass the flowability check.
|
|
513
|
+
impl(
|
|
514
|
+
forall(T : Type),
|
|
515
|
+
ArrayList(T),
|
|
516
|
+
Indexable(usize)(
|
|
517
|
+
Element : T,
|
|
518
|
+
project : (fn(ref(self) : Self, pos : usize) -> ref(T))({
|
|
519
|
+
assert(pos < self._length, "ArrayList: project out of bounds");
|
|
520
|
+
match(
|
|
521
|
+
self._ptr,
|
|
522
|
+
// SAFETY: assert above bounds `pos < self._length` and the
|
|
523
|
+
// length invariant guarantees `pos < self._capacity`, so
|
|
524
|
+
// `_ptr &+ pos` stays inside the Rc-managed heap buffer
|
|
525
|
+
// for the duration of the borrow.
|
|
526
|
+
.Some(_ptr) => unsafe(_ptr &+ pos),
|
|
527
|
+
.None => panic("ArrayList: project on empty list")
|
|
528
|
+
)
|
|
529
|
+
})
|
|
530
|
+
)
|
|
531
|
+
);
|
|
504
532
|
impl(
|
|
505
533
|
forall(T : Type),
|
|
506
534
|
ArrayList(T),
|
|
@@ -539,7 +567,7 @@ impl(
|
|
|
539
567
|
ArrayListIter(T),
|
|
540
568
|
Iterator(
|
|
541
569
|
Item : T,
|
|
542
|
-
next : (fn(self :
|
|
570
|
+
next : (fn(ref(self) : Self) -> Option(T))(
|
|
543
571
|
cond(
|
|
544
572
|
(self._index >= self._list._length) =>.None,
|
|
545
573
|
true => {
|
|
@@ -558,34 +586,26 @@ impl(
|
|
|
558
586
|
ArrayListIter(T)(_list : self, _index : usize(0))
|
|
559
587
|
)
|
|
560
588
|
);
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
_index : usize
|
|
569
|
-
)
|
|
589
|
+
/// Position iterator for ArrayList — yields `usize` indices into the
|
|
590
|
+
/// list. Used by `ArrayList.iter()`; the for-macro pairs each yielded
|
|
591
|
+
/// position with `ArrayList.project(pos)` (Indexable from Phase C) to
|
|
592
|
+
/// bind the body's `ref`-name. See plans/ITERATOR_REDESIGN.md.
|
|
593
|
+
_ArrayListPosIter :: struct(
|
|
594
|
+
_index : usize,
|
|
595
|
+
_len : usize
|
|
570
596
|
);
|
|
571
597
|
impl(
|
|
572
|
-
|
|
573
|
-
ArrayListIterPtr(T),
|
|
598
|
+
_ArrayListPosIter,
|
|
574
599
|
Iterator(
|
|
575
|
-
Item :
|
|
576
|
-
next : (fn(self :
|
|
600
|
+
Item : usize,
|
|
601
|
+
next : (fn(ref(self) : Self) -> Option(usize))(
|
|
577
602
|
cond(
|
|
578
|
-
(self._index >= self.
|
|
579
|
-
true =>
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
self._index = (self._index + usize(1));
|
|
585
|
-
.Some(element_ptr)
|
|
586
|
-
},
|
|
587
|
-
.None =>.None
|
|
588
|
-
)
|
|
603
|
+
(self._index >= self._len) =>.None,
|
|
604
|
+
true => {
|
|
605
|
+
out := self._index;
|
|
606
|
+
self._index = (self._index + usize(1));
|
|
607
|
+
.Some(out)
|
|
608
|
+
}
|
|
589
609
|
)
|
|
590
610
|
)
|
|
591
611
|
)
|
|
@@ -593,8 +613,8 @@ impl(
|
|
|
593
613
|
impl(
|
|
594
614
|
forall(T : Type),
|
|
595
615
|
ArrayList(T),
|
|
596
|
-
iter : (fn(self :
|
|
597
|
-
|
|
616
|
+
iter : (fn(ref(self) : Self) -> _ArrayListPosIter)(
|
|
617
|
+
_ArrayListPosIter(_index : usize(0), _len : self._length)
|
|
598
618
|
)
|
|
599
619
|
);
|
|
600
620
|
impl(
|
|
@@ -760,16 +780,16 @@ impl(
|
|
|
760
780
|
where(T <: Clone),
|
|
761
781
|
ArrayList(T),
|
|
762
782
|
Clone(
|
|
763
|
-
clone : (fn(self :
|
|
764
|
-
n := self
|
|
783
|
+
clone : (fn(ref(self) : Self) -> Self)({
|
|
784
|
+
n := self.len();
|
|
765
785
|
result := Self.with_capacity(n);
|
|
766
786
|
i := usize(0);
|
|
767
787
|
while(i < n, {
|
|
768
|
-
item_opt := self
|
|
788
|
+
item_opt := self.get(i);
|
|
769
789
|
match(
|
|
770
790
|
item_opt,
|
|
771
791
|
.Some(item) => {
|
|
772
|
-
result.push(
|
|
792
|
+
result.push(item.clone());
|
|
773
793
|
},
|
|
774
794
|
.None => ()
|
|
775
795
|
);
|
|
@@ -782,8 +802,7 @@ impl(
|
|
|
782
802
|
export(
|
|
783
803
|
ArrayList,
|
|
784
804
|
ArrayListError,
|
|
785
|
-
ArrayListIter
|
|
786
|
-
ArrayListIterPtr
|
|
805
|
+
ArrayListIter
|
|
787
806
|
);
|
|
788
807
|
// =============================================================================
|
|
789
808
|
// array_list! literal macro
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
//! m.set(String.from("a"), 1);
|
|
11
11
|
//! // Iteration order: a, b
|
|
12
12
|
//! ```
|
|
13
|
+
pragma(Pragma.AllowUnsafe);
|
|
13
14
|
{ ArrayList } :: import("./array_list");
|
|
14
15
|
open(import("../string"));
|
|
15
16
|
/// Key-value pair entry stored in a BTreeMap.
|
|
@@ -48,7 +49,7 @@ impl(
|
|
|
48
49
|
hi := self._entries.len();
|
|
49
50
|
while(lo < hi, {
|
|
50
51
|
mid := (lo + ((hi - lo) / usize(2)));
|
|
51
|
-
entry_key := self._entries
|
|
52
|
+
entry_key := self._entries(mid).key;
|
|
52
53
|
cond(
|
|
53
54
|
(entry_key < k) => {
|
|
54
55
|
lo = (mid + usize(1));
|
|
@@ -67,7 +68,7 @@ impl(
|
|
|
67
68
|
get : (fn(self : Self, k : K, where(K <: Ord(K))) -> ?(V))({
|
|
68
69
|
r := self._find(k);
|
|
69
70
|
cond(
|
|
70
|
-
r.found =>.Some(self._entries
|
|
71
|
+
r.found =>.Some(self._entries(r.idx).value),
|
|
71
72
|
true =>.None
|
|
72
73
|
)
|
|
73
74
|
}),
|
|
@@ -77,7 +78,7 @@ impl(
|
|
|
77
78
|
r := self._find(k);
|
|
78
79
|
cond(
|
|
79
80
|
r.found => {
|
|
80
|
-
entry := self._entries
|
|
81
|
+
entry := self._entries(r.idx);
|
|
81
82
|
&(self._entries(r.idx)).* = BTreeEntry(K, V)(key : entry.key, value : v);
|
|
82
83
|
},
|
|
83
84
|
true => {
|
|
@@ -85,8 +86,8 @@ impl(
|
|
|
85
86
|
self._entries.push(BTreeEntry(K, V)(key : k, value : v));
|
|
86
87
|
pos := (self._entries.len() - usize(1));
|
|
87
88
|
while(pos > r.idx, pos = (pos - usize(1)), {
|
|
88
|
-
curr := self._entries
|
|
89
|
-
prev := self._entries
|
|
89
|
+
curr := self._entries(pos);
|
|
90
|
+
prev := self._entries(pos - usize(1));
|
|
90
91
|
&(self._entries(pos)).* = prev;
|
|
91
92
|
&(self._entries(pos - usize(1))).* = curr;
|
|
92
93
|
});
|
|
@@ -98,7 +99,7 @@ impl(
|
|
|
98
99
|
r := self._find(k);
|
|
99
100
|
cond(
|
|
100
101
|
r.found => {
|
|
101
|
-
v := self._entries
|
|
102
|
+
v := self._entries(r.idx).value;
|
|
102
103
|
self._entries.remove(r.idx);
|
|
103
104
|
.Some(v)
|
|
104
105
|
},
|
|
@@ -109,14 +110,14 @@ impl(
|
|
|
109
110
|
min : (fn(self : Self) -> ?(BTreeEntry(K, V)))(
|
|
110
111
|
cond(
|
|
111
112
|
(self._entries.len() == usize(0)) =>.None,
|
|
112
|
-
true =>.Some(self._entries
|
|
113
|
+
true =>.Some(self._entries(usize(0)))
|
|
113
114
|
)
|
|
114
115
|
),
|
|
115
116
|
// Return the entry with the largest key, or .None.
|
|
116
117
|
max : (fn(self : Self) -> ?(BTreeEntry(K, V)))(
|
|
117
118
|
cond(
|
|
118
119
|
(self._entries.len() == usize(0)) =>.None,
|
|
119
|
-
true =>.Some(self._entries
|
|
120
|
+
true =>.Some(self._entries(self._entries.len() - usize(1)))
|
|
120
121
|
)
|
|
121
122
|
)
|
|
122
123
|
);
|
|
@@ -134,11 +135,11 @@ impl(
|
|
|
134
135
|
BTreeMapIter(K, V),
|
|
135
136
|
Iterator(
|
|
136
137
|
Item : BTreeEntry(K, V),
|
|
137
|
-
next : (fn(self :
|
|
138
|
+
next : (fn(ref(self) : Self) -> Option(BTreeEntry(K, V)))(
|
|
138
139
|
cond(
|
|
139
140
|
(self._index >= self._entries.len()) =>.None,
|
|
140
141
|
true => {
|
|
141
|
-
entry := self._entries
|
|
142
|
+
entry := self._entries(self._index);
|
|
142
143
|
self._index = (self._index + usize(1));
|
|
143
144
|
.Some(entry)
|
|
144
145
|
}
|
|
@@ -167,7 +168,7 @@ impl(
|
|
|
167
168
|
BTreeMapIterPtr(K, V),
|
|
168
169
|
Iterator(
|
|
169
170
|
Item : *(BTreeEntry(K, V)),
|
|
170
|
-
next : (fn(self :
|
|
171
|
+
next : (fn(ref(self) : Self) -> Option(*(BTreeEntry(K, V))))(
|
|
171
172
|
cond(
|
|
172
173
|
(self._index >= self._entries.len()) =>.None,
|
|
173
174
|
true =>
|
|
@@ -187,8 +188,8 @@ impl(
|
|
|
187
188
|
impl(
|
|
188
189
|
forall(K : Type, V : Type),
|
|
189
190
|
BTreeMap(K, V),
|
|
190
|
-
iter : (fn(self :
|
|
191
|
-
BTreeMapIterPtr(K, V)(_entries : self
|
|
191
|
+
iter : (fn(self : Self) -> BTreeMapIterPtr(K, V))(
|
|
192
|
+
BTreeMapIterPtr(K, V)(_entries : self._entries, _index : usize(0))
|
|
192
193
|
)
|
|
193
194
|
);
|
|
194
195
|
/**
|
|
@@ -204,7 +205,7 @@ impl(
|
|
|
204
205
|
BTreeMapKeys(K, V),
|
|
205
206
|
Iterator(
|
|
206
207
|
Item : K,
|
|
207
|
-
next : (fn(self :
|
|
208
|
+
next : (fn(ref(self) : Self) -> Option(K))(
|
|
208
209
|
match(
|
|
209
210
|
self._inner.next(),
|
|
210
211
|
.None =>.None,
|
|
@@ -233,7 +234,7 @@ impl(
|
|
|
233
234
|
BTreeMapValues(K, V),
|
|
234
235
|
Iterator(
|
|
235
236
|
Item : V,
|
|
236
|
-
next : (fn(self :
|
|
237
|
+
next : (fn(ref(self) : Self) -> Option(V))(
|
|
237
238
|
match(
|
|
238
239
|
self._inner.next(),
|
|
239
240
|
.None =>.None,
|
|
@@ -254,10 +255,10 @@ impl(
|
|
|
254
255
|
BTreeMap(K, V),
|
|
255
256
|
Index(K)(
|
|
256
257
|
Output : V,
|
|
257
|
-
index : (fn(self :
|
|
258
|
-
r := self
|
|
258
|
+
index : (fn(ref(self) : Self, idx : K, where(K <: Ord(K))) -> *(Self.Output))({
|
|
259
|
+
r := self._find(idx);
|
|
259
260
|
assert(r.found, "BTreeMap: key not found");
|
|
260
|
-
entry_ptr := &(self
|
|
261
|
+
entry_ptr := &(self._entries(r.idx));
|
|
261
262
|
&(entry_ptr.*.value)
|
|
262
263
|
})
|
|
263
264
|
)
|
package/std/collections/deque.yo
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
//! d.push_front(0);
|
|
11
11
|
//! x := d.pop_front().unwrap(); // 0
|
|
12
12
|
//! ```
|
|
13
|
+
pragma(Pragma.AllowUnsafe);
|
|
13
14
|
{ GlobalAllocator, AllocError } :: import("../allocator");
|
|
14
15
|
{ malloc, realloc, free } :: GlobalAllocator;
|
|
15
16
|
/// Circular buffer supporting efficient push/pop at both front and back.
|
|
@@ -188,7 +189,7 @@ impl(
|
|
|
188
189
|
DequeIter(T),
|
|
189
190
|
Iterator(
|
|
190
191
|
Item : T,
|
|
191
|
-
next : (fn(self :
|
|
192
|
+
next : (fn(ref(self) : Self) -> Option(T))(
|
|
192
193
|
cond(
|
|
193
194
|
(self._remaining == usize(0)) =>.None,
|
|
194
195
|
true => {
|
|
@@ -227,7 +228,7 @@ impl(
|
|
|
227
228
|
DequeIterPtr(T),
|
|
228
229
|
Iterator(
|
|
229
230
|
Item : *(T),
|
|
230
|
-
next : (fn(self :
|
|
231
|
+
next : (fn(ref(self) : Self) -> Option(*(T)))(
|
|
231
232
|
cond(
|
|
232
233
|
(self._remaining == usize(0)) =>.None,
|
|
233
234
|
true => {
|
|
@@ -245,8 +246,8 @@ impl(
|
|
|
245
246
|
impl(
|
|
246
247
|
forall(T : Type),
|
|
247
248
|
Deque(T),
|
|
248
|
-
iter : (fn(self :
|
|
249
|
-
DequeIterPtr(T)(_deque : self
|
|
249
|
+
iter : (fn(self : Self) -> DequeIterPtr(T))(
|
|
250
|
+
DequeIterPtr(T)(_deque : self, _pos : usize(0), _remaining : self._len)
|
|
250
251
|
)
|
|
251
252
|
);
|
|
252
253
|
impl(
|
|
@@ -254,10 +255,10 @@ impl(
|
|
|
254
255
|
Deque(T),
|
|
255
256
|
Index(usize)(
|
|
256
257
|
Output : T,
|
|
257
|
-
index : (fn(self :
|
|
258
|
-
assert(idx < self
|
|
259
|
-
buf := self
|
|
260
|
-
physical_idx := ((self
|
|
258
|
+
index : (fn(ref(self) : Self, idx : usize) -> *(Self.Output))({
|
|
259
|
+
assert(idx < self._len, "Deque: index out of bounds");
|
|
260
|
+
buf := self._buf.unwrap();
|
|
261
|
+
physical_idx := ((self._head + idx) % self._capacity);
|
|
261
262
|
buf &+ physical_idx
|
|
262
263
|
})
|
|
263
264
|
)
|