@shd101wyy/yo 0.1.29 → 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.
Files changed (174) hide show
  1. package/.github/skills/yo-async-effects/SKILL.md +3 -3
  2. package/.github/skills/yo-async-effects/async-effects-recipes.md +19 -11
  3. package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +33 -13
  4. package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +1 -1
  5. package/.github/skills/yo-syntax/syntax-cheatsheet.md +59 -21
  6. package/README.md +4 -3
  7. package/out/cjs/index.cjs +771 -676
  8. package/out/cjs/yo-cli.cjs +1003 -898
  9. package/out/cjs/yo-lsp.cjs +834 -739
  10. package/out/esm/index.mjs +716 -621
  11. package/out/types/src/codegen/exprs/async.d.ts +2 -0
  12. package/out/types/src/codegen/exprs/await.d.ts +1 -0
  13. package/out/types/src/codegen/exprs/closures.d.ts +4 -0
  14. package/out/types/src/codegen/functions/context.d.ts +6 -0
  15. package/out/types/src/env.d.ts +2 -0
  16. package/out/types/src/evaluator/builtins/pragma.d.ts +9 -0
  17. package/out/types/src/evaluator/builtins/unsafe.d.ts +8 -0
  18. package/out/types/src/evaluator/context.d.ts +2 -0
  19. package/out/types/src/evaluator/index.d.ts +1 -1
  20. package/out/types/src/evaluator/memory-safety.d.ts +14 -0
  21. package/out/types/src/evaluator/types/flowability.d.ts +6 -0
  22. package/out/types/src/expr-traversal.d.ts +1 -0
  23. package/out/types/src/expr.d.ts +4 -1
  24. package/out/types/src/public-safe-report.d.ts +19 -0
  25. package/out/types/src/tests/comptime-ref-gate.test.d.ts +1 -0
  26. package/out/types/src/tests/pragma-validation.test.d.ts +1 -0
  27. package/out/types/src/tests/public-safe-report.test.d.ts +1 -0
  28. package/out/types/src/tests/type-representation-pointer.test.d.ts +1 -0
  29. package/out/types/src/tests/unsafe-gate.test.d.ts +1 -0
  30. package/out/types/src/tests/unsafe-report-classify.test.d.ts +1 -0
  31. package/out/types/src/types/definitions.d.ts +2 -0
  32. package/out/types/src/types/utils.d.ts +4 -0
  33. package/out/types/src/unsafe-report.d.ts +29 -0
  34. package/out/types/src/value.d.ts +1 -0
  35. package/out/types/tsconfig.tsbuildinfo +1 -1
  36. package/package.json +1 -1
  37. package/scripts/add-pragma-for-pointer-decls.ts +134 -0
  38. package/scripts/add-pragma.ts +58 -0
  39. package/scripts/migrate-amp-method-calls.ts +186 -0
  40. package/scripts/migrate-clone-calls.ts +93 -0
  41. package/scripts/migrate-get-unwrap.ts +166 -0
  42. package/scripts/migrate-index-patterns.ts +210 -0
  43. package/scripts/migrate-index-trait.ts +142 -0
  44. package/scripts/migrate-iterator.ts +150 -0
  45. package/scripts/migrate-self-ptr.ts +220 -0
  46. package/scripts/migrate-skip-pragmas.ts +109 -0
  47. package/scripts/migrate-tostring.ts +134 -0
  48. package/scripts/trim-pragma.ts +130 -0
  49. package/scripts/wrap-extern-calls.ts +161 -0
  50. package/std/alg/hash.yo +3 -2
  51. package/std/allocator.yo +6 -5
  52. package/std/async.yo +2 -2
  53. package/std/collections/array_list.yo +59 -40
  54. package/std/collections/btree_map.yo +19 -18
  55. package/std/collections/deque.yo +9 -8
  56. package/std/collections/hash_map.yo +101 -13
  57. package/std/collections/hash_set.yo +5 -4
  58. package/std/collections/linked_list.yo +39 -4
  59. package/std/collections/ordered_map.yo +3 -3
  60. package/std/collections/priority_queue.yo +14 -13
  61. package/std/crypto/md5.yo +2 -1
  62. package/std/crypto/random.yo +16 -15
  63. package/std/crypto/sha256.yo +2 -1
  64. package/std/encoding/base64.yo +14 -14
  65. package/std/encoding/hex.yo +3 -3
  66. package/std/encoding/json.yo +59 -10
  67. package/std/encoding/punycode.yo +24 -23
  68. package/std/encoding/toml.yo +4 -3
  69. package/std/encoding/utf16.yo +2 -2
  70. package/std/env.yo +43 -28
  71. package/std/error.yo +6 -6
  72. package/std/fmt/display.yo +2 -2
  73. package/std/fmt/index.yo +6 -5
  74. package/std/fmt/to_string.yo +39 -38
  75. package/std/fmt/writer.yo +9 -8
  76. package/std/fs/dir.yo +34 -33
  77. package/std/fs/file.yo +52 -51
  78. package/std/fs/metadata.yo +10 -9
  79. package/std/fs/temp.yo +24 -13
  80. package/std/fs/walker.yo +10 -9
  81. package/std/gc.yo +1 -0
  82. package/std/glob.yo +7 -7
  83. package/std/http/client.yo +15 -14
  84. package/std/http/http.yo +6 -6
  85. package/std/http/index.yo +1 -1
  86. package/std/imm/list.yo +33 -0
  87. package/std/imm/map.yo +2 -1
  88. package/std/imm/set.yo +1 -0
  89. package/std/imm/sorted_map.yo +1 -0
  90. package/std/imm/sorted_set.yo +1 -0
  91. package/std/imm/string.yo +27 -23
  92. package/std/imm/vec.yo +18 -2
  93. package/std/io/reader.yo +2 -1
  94. package/std/io/writer.yo +3 -2
  95. package/std/libc/assert.yo +1 -0
  96. package/std/libc/ctype.yo +1 -0
  97. package/std/libc/dirent.yo +1 -0
  98. package/std/libc/errno.yo +1 -0
  99. package/std/libc/fcntl.yo +1 -0
  100. package/std/libc/float.yo +1 -0
  101. package/std/libc/limits.yo +1 -0
  102. package/std/libc/math.yo +1 -0
  103. package/std/libc/signal.yo +1 -0
  104. package/std/libc/stdatomic.yo +1 -0
  105. package/std/libc/stdint.yo +1 -0
  106. package/std/libc/stdio.yo +1 -0
  107. package/std/libc/stdlib.yo +1 -0
  108. package/std/libc/string.yo +1 -0
  109. package/std/libc/sys/stat.yo +1 -0
  110. package/std/libc/time.yo +1 -0
  111. package/std/libc/unistd.yo +1 -0
  112. package/std/libc/wctype.yo +1 -0
  113. package/std/libc/windows.yo +2 -0
  114. package/std/log.yo +7 -6
  115. package/std/net/addr.yo +5 -4
  116. package/std/net/dns.yo +7 -6
  117. package/std/net/errors.yo +8 -8
  118. package/std/net/tcp.yo +19 -18
  119. package/std/net/udp.yo +13 -12
  120. package/std/os/signal.yo +3 -3
  121. package/std/path.yo +1 -0
  122. package/std/prelude.yo +353 -182
  123. package/std/process/command.yo +40 -23
  124. package/std/process/index.yo +2 -1
  125. package/std/regex/compiler.yo +10 -9
  126. package/std/regex/index.yo +41 -41
  127. package/std/regex/match.yo +2 -2
  128. package/std/regex/parser.yo +21 -21
  129. package/std/regex/vm.yo +42 -41
  130. package/std/string/string.yo +95 -40
  131. package/std/string/string_builder.yo +9 -9
  132. package/std/string/unicode.yo +50 -49
  133. package/std/sync/channel.yo +2 -1
  134. package/std/sync/cond.yo +5 -4
  135. package/std/sync/mutex.yo +4 -3
  136. package/std/sys/advise.yo +1 -0
  137. package/std/sys/bufio/buf_reader.yo +17 -16
  138. package/std/sys/bufio/buf_writer.yo +10 -9
  139. package/std/sys/clock.yo +1 -0
  140. package/std/sys/copy.yo +1 -0
  141. package/std/sys/dir.yo +10 -9
  142. package/std/sys/dns.yo +6 -5
  143. package/std/sys/errors.yo +11 -11
  144. package/std/sys/events.yo +1 -0
  145. package/std/sys/externs.yo +38 -37
  146. package/std/sys/file.yo +17 -16
  147. package/std/sys/future.yo +4 -3
  148. package/std/sys/iov.yo +1 -0
  149. package/std/sys/mmap.yo +1 -0
  150. package/std/sys/path.yo +1 -0
  151. package/std/sys/perm.yo +2 -1
  152. package/std/sys/pipe.yo +1 -0
  153. package/std/sys/process.yo +5 -4
  154. package/std/sys/signal.yo +1 -0
  155. package/std/sys/socketpair.yo +1 -0
  156. package/std/sys/sockinfo.yo +1 -0
  157. package/std/sys/statfs.yo +2 -1
  158. package/std/sys/statx.yo +1 -0
  159. package/std/sys/sysinfo.yo +1 -0
  160. package/std/sys/tcp.yo +15 -14
  161. package/std/sys/temp.yo +1 -0
  162. package/std/sys/time.yo +2 -1
  163. package/std/sys/timer.yo +6 -6
  164. package/std/sys/tty.yo +2 -1
  165. package/std/sys/udp.yo +13 -12
  166. package/std/sys/unix.yo +12 -11
  167. package/std/testing/bench.yo +4 -3
  168. package/std/thread.yo +7 -6
  169. package/std/time/datetime.yo +18 -15
  170. package/std/time/duration.yo +11 -10
  171. package/std/time/instant.yo +4 -4
  172. package/std/time/sleep.yo +1 -0
  173. package/std/url/index.yo +3 -3
  174. package/std/worker.yo +4 -3
@@ -9,7 +9,7 @@
9
9
  //! { Command } :: import "std/process/command";
10
10
  //! { Exception, AnyError } :: import "std/error";
11
11
  //!
12
- //! main :: (fn(io : IO, exn : Exception) -> unit)({
12
+ //! main :: (fn(io : Io, exn : Exception) -> unit)({
13
13
  //! cmd := Command.new(`echo`);
14
14
  //! cmd.arg(`hello`);
15
15
  //! cmd.arg(`world`);
@@ -17,10 +17,11 @@
17
17
  //! assert(out.status.success(), "echo should succeed");
18
18
  //! });
19
19
  //! ```
20
+ pragma(Pragma.AllowUnsafe);
20
21
  open(import("../collections/array_list"));
21
22
  open(import("../string"));
22
- { Exception, IOErr } :: import("../error");
23
- { IOError } :: import("../sys/errors");
23
+ { Exception, IoExn } :: import("../error");
24
+ { IoError } :: import("../sys/errors");
24
25
  IO_process :: import("../sys/process");
25
26
  IO_file :: import("../sys/file");
26
27
  IO_pipe :: import("../sys/pipe");
@@ -96,12 +97,12 @@ impl(
96
97
  )
97
98
  ),
98
99
  /// Append a single argument to the argv list.
99
- arg : (fn(self : *(Self), a : String) -> unit)({
100
+ arg : (fn(ref(self) : Self, a : String) -> unit)({
100
101
  self._args.push(a);
101
102
  ()
102
103
  }),
103
104
  /// Append multiple arguments to the argv list.
104
- args : (fn(self : *(Self), more : ArrayList(String)) -> unit)({
105
+ args : (fn(ref(self) : Self, more : ArrayList(String)) -> unit)({
105
106
  n := more.len();
106
107
  i := usize(0);
107
108
  while(runtime(i < n), {
@@ -122,7 +123,7 @@ impl(
122
123
  // Convert each entry of `(program + args)` into an owned NUL-terminated
123
124
  // `ArrayList(u8)`. The returned list owns the C-string storage; callers
124
125
  // extract the raw `*(u8)` pointers separately.
125
- _build_cstr_storage :: (fn(self : *(Command)) -> ArrayList(ArrayList(u8)))({
126
+ _build_cstr_storage :: (fn(self : Command) -> ArrayList(ArrayList(u8)))({
126
127
  storage := ArrayList(ArrayList(u8)).new();
127
128
  storage.push(self._program.to_cstr());
128
129
  n := self._args.len();
@@ -145,15 +146,20 @@ _build_cstr_storage :: (fn(self : *(Command)) -> ArrayList(ArrayList(u8)))({
145
146
  // returns the pid (since the kernel reads argv synchronously inside the syscall).
146
147
  _spawn_with_fds :: (
147
148
  fn(
148
- self : *(Command),
149
+ self : Command,
149
150
  stdin_fd : i32,
150
151
  stdout_fd : i32,
151
152
  stderr_fd : i32,
152
- io : IO
153
- ) -> Impl(Future(i32, IOErr))
154
- )(
153
+ io : Io
154
+ ) -> Impl(Future(i32, IoExn))
155
+ )({
156
+ // Build the C-string storage BEFORE entering the async closure so the
157
+ // closure doesn't have to capture `self` directly. `self : Command` is an
158
+ // object/ref binding that can't be safely captured across an async
159
+ // boundary; the resulting `storage` ArrayList is Rc/heap-allocated and
160
+ // can be moved into the closure's capture struct.
161
+ storage := _build_cstr_storage(self);
155
162
  io.async((e) => {
156
- storage := _build_cstr_storage(self);
157
163
  argc := storage.len();
158
164
  // Allocate argv buffer: argc entries + 1 null terminator.
159
165
  argv_bytes := (sizeof(?*(u8)) * (argc + usize(1)));
@@ -185,12 +191,12 @@ _spawn_with_fds :: (
185
191
  pid := e.io.await(IO_process.spawn(program_cstr, argv_buf,.None, stdin_fd, stdout_fd, stderr_fd), e.io);
186
192
  // Free argv buffer (storage is dropped naturally at scope end).
187
193
  free(.Some(argv_raw));
188
- IOError.check(pid, e.exn)
194
+ IoError.check(pid, e.exn)
189
195
  })
190
- );
196
+ });
191
197
  // Read all available bytes from `fd` into a freshly returned ArrayList(u8)
192
198
  // until EOF (read returns 0).
193
- _drain_fd :: (fn(fd : i32, io : IO) -> Impl(Future(ArrayList(u8), IOErr)))(
199
+ _drain_fd :: (fn(fd : i32, io : Io) -> Impl(Future(ArrayList(u8), IoExn)))(
194
200
  io.async((e) => {
195
201
  buf_size := usize(4096);
196
202
  buf := *(u8)(malloc(buf_size).unwrap());
@@ -200,7 +206,7 @@ _drain_fd :: (fn(fd : i32, io : IO) -> Impl(Future(ArrayList(u8), IOErr)))(
200
206
  cond(
201
207
  (n < i32(0)) => {
202
208
  free(.Some(*(void)(buf)));
203
- e.exn.throw(dyn(IOError.from_errno(i32(0) - n)));
209
+ e.exn.throw(dyn(IoError.from_errno(i32(0) - n)));
204
210
  },
205
211
  (n == i32(0)) => break,
206
212
  true => {
@@ -223,24 +229,32 @@ impl(
223
229
  Command,
224
230
  /// Spawn the child with stdio inherited from the parent, wait for it to
225
231
  /// exit, and return its `ExitStatus`.
226
- status : (fn(self : *(Self), io : IO) -> Impl(Future(ExitStatus, IOErr)))(
232
+ status : (fn(self : Self, io : Io) -> Impl(Future(ExitStatus, IoExn)))(
233
+ // `self : Self` is a value-copy of the Rc-counted Command object, so the
234
+ // closure can freely capture it. (Was `ref(self)` previously, which is a
235
+ // second-class reference and can't be captured across an async boundary.)
227
236
  io.async((e) => {
228
- pid := e.io.await(_spawn_with_fds(self, i32(-(1)), i32(-(1)), i32(-(1)), io), e);
237
+ pid := e.io.await(
238
+ _spawn_with_fds(self, i32(-(1)), i32(-(1)), i32(-(1)), io),
239
+ e
240
+ );
229
241
  raw := e.io.await(IO_process.waitpid(pid, i32(0)), e.io);
230
- IOError.check(raw, e.exn);
242
+ IoError.check(raw, e.exn);
231
243
  ExitStatus(raw : raw)
232
244
  })
233
245
  ),
234
246
  /// Spawn the child with stdout and stderr captured through pipes. Waits for
235
247
  /// the child to exit and returns the exit status plus the captured bytes.
236
- output : (fn(self : *(Self), io : IO) -> Impl(Future(Output, IOErr)))(
248
+ output : (fn(self : Self, io : Io) -> Impl(Future(Output, IoExn)))(
249
+ // `self : Self` is a value-copy of the Rc-counted Command object; the
250
+ // closure can freely capture it instead of needing `ref(self)`.
237
251
  io.async((e) => {
238
252
  // Create stdout and stderr pipes.
239
253
  out_fd_buf := MaybeUninit(Array(i32, usize(2))).new();
240
254
  out_fd := *(i32)(out_fd_buf.as_ptr());
241
255
  pr1 := IO_pipe.pipe(out_fd);
242
256
  cond(
243
- (pr1 < i32(0)) => e.exn.throw(dyn(IOError.from_errno(i32(0) - pr1))),
257
+ (pr1 < i32(0)) => e.exn.throw(dyn(IoError.from_errno(i32(0) - pr1))),
244
258
  true => ()
245
259
  );
246
260
  out_read := (out_fd &+ usize(0)).*;
@@ -252,14 +266,17 @@ impl(
252
266
  (pr2 < i32(0)) => {
253
267
  e.io.await(IO_file.close(out_read), e.io);
254
268
  e.io.await(IO_file.close(out_write), e.io);
255
- e.exn.throw(dyn(IOError.from_errno(i32(0) - pr2)));
269
+ e.exn.throw(dyn(IoError.from_errno(i32(0) - pr2)));
256
270
  },
257
271
  true => ()
258
272
  );
259
273
  err_read := (err_fd &+ usize(0)).*;
260
274
  err_write := (err_fd &+ usize(1)).*;
261
275
  // Spawn child with the write ends of both pipes.
262
- pid := e.io.await(_spawn_with_fds(self, i32(-(1)), out_write, err_write, io), e);
276
+ pid := e.io.await(
277
+ _spawn_with_fds(self, i32(-(1)), out_write, err_write, io),
278
+ e
279
+ );
263
280
  // Close write ends in parent so reads see EOF when child exits.
264
281
  e.io.await(IO_file.close(out_write), e.io);
265
282
  e.io.await(IO_file.close(err_write), e.io);
@@ -269,7 +286,7 @@ impl(
269
286
  e.io.await(IO_file.close(out_read), e.io);
270
287
  e.io.await(IO_file.close(err_read), e.io);
271
288
  raw := e.io.await(IO_process.waitpid(pid, i32(0)), e.io);
272
- IOError.check(raw, e.exn);
289
+ IoError.check(raw, e.exn);
273
290
  Output(
274
291
  status : ExitStatus(raw : raw),
275
292
  stdout : stdout_buf,
@@ -2,6 +2,7 @@
2
2
  //!
3
3
  //! Environment variables, command-line arguments, and current working
4
4
  //! directory live in `std/env`.
5
+ pragma(Pragma.AllowUnsafe);
5
6
  /// Current target platform as a compile-time string.
6
7
  /// One of: "linux", "macos", "windows", "freebsd", "emscripten", "wasi".
7
8
  platform :: __yo_process_platform();
@@ -19,7 +20,7 @@ export(Arch);
19
20
  /// Exit the process with the given status code.
20
21
  exit :: (fn(code : usize) -> unit)({
21
22
  { exit : _exit } :: import("../libc/stdlib");
22
- _exit(int(code));
23
+ unsafe(_exit(int(code)));
23
24
  });
24
25
  export(exit);
25
26
  _command :: import("./command.yo");
@@ -1,5 +1,6 @@
1
1
  //! NFA compiler — compiles a `RegexNode` AST into a flat list of NFA instructions
2
2
  //! using Thompson's construction algorithm.
3
+ pragma(Pragma.AllowUnsafe);
3
4
  open(import("std/collections/array_list"));
4
5
  open(import("std/string"));
5
6
  { RegexNode, NodeKind, CharRange, AnchorKind, GroupNameEntry } :: import("./node.yo");
@@ -269,13 +270,13 @@ impl(
269
270
  .Sequence => {
270
271
  i := usize(0);
271
272
  while(i < node.children.len(), i = (i + usize(1)), {
272
- child := node.children.get(i).unwrap();
273
+ child := node.children(i);
273
274
  recur(self, child);
274
275
  });
275
276
  },
276
277
  .Alternation => {
277
- left := node.children.get(usize(0)).unwrap();
278
- right := node.children.get(usize(1)).unwrap();
278
+ left := node.children(usize(0));
279
+ right := node.children(usize(1));
279
280
  split_pc := self._emit(Instr.split_instr(usize(0), usize(0)));
280
281
  left_start := self._current_pc();
281
282
  &(self._program.instructions(split_pc)).* = Instr.split_instr(left_start, usize(0));
@@ -288,7 +289,7 @@ impl(
288
289
  &(self._program.instructions(jump_pc)).* = Instr.jump_instr(end_pc);
289
290
  },
290
291
  .Quantifier => {
291
- child := node.children.get(usize(0)).unwrap();
292
+ child := node.children(usize(0));
292
293
  min_val := node.q_min;
293
294
  max_val := node.q_max;
294
295
  greedy := node.q_greedy;
@@ -352,7 +353,7 @@ impl(
352
353
  );
353
354
  },
354
355
  .Group => {
355
- child := node.children.get(usize(0)).unwrap();
356
+ child := node.children(usize(0));
356
357
  start_slot := (node.group_index * usize(2));
357
358
  end_slot := ((node.group_index * usize(2)) + usize(1));
358
359
  self._emit(Instr.save_instr(start_slot));
@@ -360,14 +361,14 @@ impl(
360
361
  self._emit(Instr.save_instr(end_slot));
361
362
  },
362
363
  .NonCapturingGroup => {
363
- child := node.children.get(usize(0)).unwrap();
364
+ child := node.children(usize(0));
364
365
  recur(self, child);
365
366
  },
366
367
  .Backreference => {
367
368
  self._emit(Instr.backref_instr(node.group_index));
368
369
  },
369
370
  .Lookahead => {
370
- child := node.children.get(usize(0)).unwrap();
371
+ child := node.children(usize(0));
371
372
  positive := (!(node.negated));
372
373
  // Emit lookahead instruction with placeholder sub_end
373
374
  la_pc := self._emit(Instr.lookahead_instr(usize(0), usize(0), positive));
@@ -378,7 +379,7 @@ impl(
378
379
  &(self._program.instructions(la_pc)).* = Instr.lookahead_instr(sub_start, sub_end, positive);
379
380
  },
380
381
  .Lookbehind => {
381
- child := node.children.get(usize(0)).unwrap();
382
+ child := node.children(usize(0));
382
383
  positive := (!(node.negated));
383
384
  lb_pc := self._emit(Instr.lookbehind_instr(usize(0), usize(0), positive));
384
385
  sub_start := self._current_pc();
@@ -401,7 +402,7 @@ impl(
401
402
  instrs := self._program.instructions;
402
403
  (done : bool) = false;
403
404
  while((pc < instrs.len()) && (!(done)), {
404
- instr := instrs.get(pc).unwrap();
405
+ instr := instrs(pc);
405
406
  match(
406
407
  instr.kind,
407
408
  .Save => {
@@ -61,7 +61,7 @@ impl(
61
61
  result_bytes := ArrayList(u8).with_capacity(end_pos - start);
62
62
  i := start;
63
63
  while(i < end_pos, i = (i + usize(1)), {
64
- result_bytes.push(bytes.get(i).unwrap());
64
+ result_bytes.push(bytes(i));
65
65
  });
66
66
  String.from_bytes(result_bytes)
67
67
  }),
@@ -69,7 +69,7 @@ impl(
69
69
  char_idx := usize(0);
70
70
  i := usize(0);
71
71
  while(i < byte_pos, {
72
- b := bytes.get(i).unwrap();
72
+ b := bytes(i);
73
73
  char_len := cond(
74
74
  (b < u8(0x80)) => usize(1),
75
75
  ((b >= u8(0xC0)) && (b < u8(0xE0))) => usize(2),
@@ -91,18 +91,18 @@ impl(
91
91
  (prefix_len == usize(0)) => from_byte,
92
92
  (input_len < prefix_len) => (input_len + usize(1)),
93
93
  true => {
94
- first_byte := prefix.get(usize(0)).unwrap();
94
+ first_byte := prefix(usize(0));
95
95
  (pos : usize) = from_byte;
96
96
  (found : bool) = false;
97
97
  while((pos <= (input_len - prefix_len)) && (!(found)), {
98
98
  cond(
99
- (input_bytes.get(pos).unwrap() == first_byte) => {
99
+ (input_bytes(pos) == first_byte) => {
100
100
  // Check remaining prefix bytes
101
101
  (match_ok : bool) = true;
102
102
  pi := usize(1);
103
103
  while((pi < prefix_len) && match_ok, pi = (pi + usize(1)), {
104
104
  cond(
105
- (input_bytes.get(pos + pi).unwrap() != prefix.get(pi).unwrap()) => {
105
+ (input_bytes(pos + pi) != prefix(pi)) => {
106
106
  match_ok = false;
107
107
  },
108
108
  true => ()
@@ -136,8 +136,8 @@ impl(
136
136
  _build_match : (fn(self : Self, slots : ArrayList(usize), input : String) -> RegexMatch)({
137
137
  bytes := input.as_bytes();
138
138
  unset := usize.MAX;
139
- match_start_byte := slots.get(usize(0)).unwrap();
140
- match_end_byte := slots.get(usize(1)).unwrap();
139
+ match_start_byte := slots(usize(0));
140
+ match_end_byte := slots(usize(1));
141
141
  match_text := self._extract_substring(bytes, match_start_byte, match_end_byte);
142
142
  match_char_index := self._byte_to_char_index(bytes, match_start_byte);
143
143
  groups := ArrayList(Option(String)).new();
@@ -147,8 +147,8 @@ impl(
147
147
  end_slot := ((g * usize(2)) + usize(1));
148
148
  cond(
149
149
  ((start_slot < slots.len()) && (end_slot < slots.len())) => {
150
- gs := slots.get(start_slot).unwrap();
151
- ge := slots.get(end_slot).unwrap();
150
+ gs := slots(start_slot);
151
+ ge := slots(end_slot);
152
152
  cond(
153
153
  ((gs != unset) && (ge != unset)) => {
154
154
  group_text := self._extract_substring(bytes, gs, ge);
@@ -203,7 +203,7 @@ impl(
203
203
  break;
204
204
  },
205
205
  true => {
206
- b := bytes.get(byte_pos).unwrap();
206
+ b := bytes(byte_pos);
207
207
  char_len := cond(
208
208
  (b < u8(0x80)) => usize(1),
209
209
  ((b >= u8(0xC0)) && (b < u8(0xE0))) => usize(2),
@@ -237,8 +237,8 @@ impl(
237
237
  result.matched => {
238
238
  m := self._build_match(result.slots, input);
239
239
  matches.push(m);
240
- match_start := result.slots.get(usize(0)).unwrap();
241
- match_end := result.slots.get(usize(1)).unwrap();
240
+ match_start := result.slots(usize(0));
241
+ match_end := result.slots(usize(1));
242
242
  cond(
243
243
  (match_end == match_start) => {
244
244
  // Empty match: advance one char to avoid infinite loop
@@ -247,7 +247,7 @@ impl(
247
247
  break;
248
248
  },
249
249
  true => {
250
- b := bytes.get(byte_pos).unwrap();
250
+ b := bytes(byte_pos);
251
251
  char_len := cond(
252
252
  (b < u8(0x80)) => usize(1),
253
253
  ((b >= u8(0xC0)) && (b < u8(0xE0))) => usize(2),
@@ -281,8 +281,8 @@ impl(
281
281
  result.matched => {
282
282
  m := self._build_match(result.slots, input);
283
283
  matches.push(m);
284
- match_start := result.slots.get(usize(0)).unwrap();
285
- match_end := result.slots.get(usize(1)).unwrap();
284
+ match_start := result.slots(usize(0));
285
+ match_end := result.slots(usize(1));
286
286
  cond(
287
287
  (match_end == match_start) => {
288
288
  cond(
@@ -290,7 +290,7 @@ impl(
290
290
  break;
291
291
  },
292
292
  true => {
293
- b := bytes.get(byte_pos).unwrap();
293
+ b := bytes(byte_pos);
294
294
  char_len := cond(
295
295
  (b < u8(0x80)) => usize(1),
296
296
  ((b >= u8(0xC0)) && (b < u8(0xE0))) => usize(2),
@@ -319,7 +319,7 @@ impl(
319
319
  break;
320
320
  },
321
321
  true => {
322
- b := bytes.get(byte_pos).unwrap();
322
+ b := bytes(byte_pos);
323
323
  char_len := cond(
324
324
  (b < u8(0x80)) => usize(1),
325
325
  ((b >= u8(0xC0)) && (b < u8(0xE0))) => usize(2),
@@ -368,11 +368,11 @@ impl(
368
368
  result := ArrayList(u8).new();
369
369
  i := usize(0);
370
370
  while(i < rep_len, {
371
- b := rep_bytes.get(i).unwrap();
371
+ b := rep_bytes(i);
372
372
  cond(
373
373
  ((b == u8(36)) && ((i + usize(1)) < rep_len)) => {
374
374
  // '$' character — check next char
375
- next_b := rep_bytes.get(i + usize(1)).unwrap();
375
+ next_b := rep_bytes(i + usize(1));
376
376
  cond(
377
377
  (next_b == u8(36)) => {
378
378
  // $$ → literal $
@@ -384,7 +384,7 @@ impl(
384
384
  match_bytes := m.value().as_bytes();
385
385
  mi := usize(0);
386
386
  while(mi < match_bytes.len(), mi = (mi + usize(1)), {
387
- result.push(match_bytes.get(mi).unwrap());
387
+ result.push(match_bytes(mi));
388
388
  });
389
389
  i = (i + usize(2));
390
390
  },
@@ -396,7 +396,7 @@ impl(
396
396
  byte_idx := usize(0);
397
397
  ci := usize(0);
398
398
  while(ci < char_idx, {
399
- cb := input_bytes.get(byte_idx).unwrap();
399
+ cb := input_bytes(byte_idx);
400
400
  cbl := cond(
401
401
  (cb < u8(0x80)) => usize(1),
402
402
  ((cb >= u8(0xC0)) && (cb < u8(0xE0))) => usize(2),
@@ -408,7 +408,7 @@ impl(
408
408
  });
409
409
  pi := usize(0);
410
410
  while(pi < byte_idx, pi = (pi + usize(1)), {
411
- result.push(input_bytes.get(pi).unwrap());
411
+ result.push(input_bytes(pi));
412
412
  });
413
413
  i = (i + usize(2));
414
414
  },
@@ -420,7 +420,7 @@ impl(
420
420
  byte_idx := usize(0);
421
421
  ci := usize(0);
422
422
  while(ci < char_idx, {
423
- cb := input_bytes.get(byte_idx).unwrap();
423
+ cb := input_bytes(byte_idx);
424
424
  cbl := cond(
425
425
  (cb < u8(0x80)) => usize(1),
426
426
  ((cb >= u8(0xC0)) && (cb < u8(0xE0))) => usize(2),
@@ -435,7 +435,7 @@ impl(
435
435
  byte_idx = (byte_idx + match_bytes.len());
436
436
  pi := byte_idx;
437
437
  while(pi < input_bytes.len(), pi = (pi + usize(1)), {
438
- result.push(input_bytes.get(pi).unwrap());
438
+ result.push(input_bytes(pi));
439
439
  });
440
440
  i = (i + usize(2));
441
441
  },
@@ -449,7 +449,7 @@ impl(
449
449
  g_bytes := g.as_bytes();
450
450
  gi := usize(0);
451
451
  while(gi < g_bytes.len(), gi = (gi + usize(1)), {
452
- result.push(g_bytes.get(gi).unwrap());
452
+ result.push(g_bytes(gi));
453
453
  });
454
454
  },
455
455
  .None => ()
@@ -462,7 +462,7 @@ impl(
462
462
  (name_end : usize) = name_start;
463
463
  (found_close : bool) = false;
464
464
  while(name_end < rep_len, {
465
- nb := rep_bytes.get(name_end).unwrap();
465
+ nb := rep_bytes(name_end);
466
466
  cond(
467
467
  (nb == u8(125)) => {
468
468
  found_close = true;
@@ -478,7 +478,7 @@ impl(
478
478
  name_bytes := ArrayList(u8).with_capacity(name_end - name_start);
479
479
  ni := name_start;
480
480
  while(ni < name_end, ni = (ni + usize(1)), {
481
- name_bytes.push(rep_bytes.get(ni).unwrap());
481
+ name_bytes.push(rep_bytes(ni));
482
482
  });
483
483
  name := String.from_bytes(name_bytes);
484
484
  grp := m.named_group(name);
@@ -488,7 +488,7 @@ impl(
488
488
  g_bytes := g.as_bytes();
489
489
  gi := usize(0);
490
490
  while(gi < g_bytes.len(), gi = (gi + usize(1)), {
491
- result.push(g_bytes.get(gi).unwrap());
491
+ result.push(g_bytes(gi));
492
492
  });
493
493
  },
494
494
  .None => ()
@@ -533,7 +533,7 @@ impl(
533
533
  (match_start_byte : usize) = usize(0);
534
534
  ci := usize(0);
535
535
  while(ci < char_idx, {
536
- cb := input_bytes.get(match_start_byte).unwrap();
536
+ cb := input_bytes(match_start_byte);
537
537
  cbl := cond(
538
538
  (cb < u8(0x80)) => usize(1),
539
539
  ((cb >= u8(0xC0)) && (cb < u8(0xE0))) => usize(2),
@@ -548,17 +548,17 @@ impl(
548
548
  out := ArrayList(u8).new();
549
549
  pi := usize(0);
550
550
  while(pi < match_start_byte, pi = (pi + usize(1)), {
551
- out.push(input_bytes.get(pi).unwrap());
551
+ out.push(input_bytes(pi));
552
552
  });
553
553
  rep := self._apply_replacement(replacement, m);
554
554
  rep_bytes := rep.as_bytes();
555
555
  ri := usize(0);
556
556
  while(ri < rep_bytes.len(), ri = (ri + usize(1)), {
557
- out.push(rep_bytes.get(ri).unwrap());
557
+ out.push(rep_bytes(ri));
558
558
  });
559
559
  pi = match_end_byte;
560
560
  while(pi < input_bytes.len(), pi = (pi + usize(1)), {
561
- out.push(input_bytes.get(pi).unwrap());
561
+ out.push(input_bytes(pi));
562
562
  });
563
563
  String.from_bytes(out)
564
564
  }
@@ -574,13 +574,13 @@ impl(
574
574
  (last_end_byte : usize) = usize(0);
575
575
  mi := usize(0);
576
576
  while(mi < all_matches.len(), mi = (mi + usize(1)), {
577
- m := all_matches.get(mi).unwrap();
577
+ m := all_matches(mi);
578
578
  // Convert char index to byte index for match start
579
579
  char_idx := m.index();
580
580
  (match_start_byte : usize) = usize(0);
581
581
  ci := usize(0);
582
582
  while(ci < char_idx, {
583
- cb := input_bytes.get(match_start_byte).unwrap();
583
+ cb := input_bytes(match_start_byte);
584
584
  cbl := cond(
585
585
  (cb < u8(0x80)) => usize(1),
586
586
  ((cb >= u8(0xC0)) && (cb < u8(0xE0))) => usize(2),
@@ -594,21 +594,21 @@ impl(
594
594
  // Copy text between last match end and this match start
595
595
  pi := last_end_byte;
596
596
  while(pi < match_start_byte, pi = (pi + usize(1)), {
597
- out.push(input_bytes.get(pi).unwrap());
597
+ out.push(input_bytes(pi));
598
598
  });
599
599
  // Apply replacement
600
600
  rep := self._apply_replacement(replacement, m);
601
601
  rep_bytes := rep.as_bytes();
602
602
  ri := usize(0);
603
603
  while(ri < rep_bytes.len(), ri = (ri + usize(1)), {
604
- out.push(rep_bytes.get(ri).unwrap());
604
+ out.push(rep_bytes(ri));
605
605
  });
606
606
  last_end_byte = match_end_byte;
607
607
  });
608
608
  // Copy remaining text after last match
609
609
  pi := last_end_byte;
610
610
  while(pi < input_bytes.len(), pi = (pi + usize(1)), {
611
- out.push(input_bytes.get(pi).unwrap());
611
+ out.push(input_bytes(pi));
612
612
  });
613
613
  String.from_bytes(out)
614
614
  }
@@ -626,13 +626,13 @@ impl(
626
626
  (last_end_byte : usize) = usize(0);
627
627
  mi := usize(0);
628
628
  while(mi < all_matches.len(), mi = (mi + usize(1)), {
629
- m := all_matches.get(mi).unwrap();
629
+ m := all_matches(mi);
630
630
  // Convert char index to byte index for match start
631
631
  char_idx := m.index();
632
632
  (match_start_byte : usize) = usize(0);
633
633
  ci := usize(0);
634
634
  while(ci < char_idx, {
635
- cb := input_bytes.get(match_start_byte).unwrap();
635
+ cb := input_bytes(match_start_byte);
636
636
  cbl := cond(
637
637
  (cb < u8(0x80)) => usize(1),
638
638
  ((cb >= u8(0xC0)) && (cb < u8(0xE0))) => usize(2),
@@ -647,7 +647,7 @@ impl(
647
647
  part_bytes := ArrayList(u8).new();
648
648
  pi := last_end_byte;
649
649
  while(pi < match_start_byte, pi = (pi + usize(1)), {
650
- part_bytes.push(input_bytes.get(pi).unwrap());
650
+ part_bytes.push(input_bytes(pi));
651
651
  });
652
652
  parts.push(String.from_bytes(part_bytes));
653
653
  // Include capture groups in split result (like JS)
@@ -670,7 +670,7 @@ impl(
670
670
  remaining := ArrayList(u8).new();
671
671
  pi := last_end_byte;
672
672
  while(pi < input_bytes.len(), pi = (pi + usize(1)), {
673
- remaining.push(input_bytes.get(pi).unwrap());
673
+ remaining.push(input_bytes(pi));
674
674
  });
675
675
  parts.push(String.from_bytes(remaining));
676
676
  }
@@ -42,7 +42,7 @@ impl(
42
42
  true => {
43
43
  actual_idx := (idx - usize(1));
44
44
  cond(
45
- (actual_idx < self._groups.len()) => self._groups.get(actual_idx).unwrap(),
45
+ (actual_idx < self._groups.len()) => self._groups(actual_idx),
46
46
  true =>.None
47
47
  )
48
48
  }
@@ -52,7 +52,7 @@ impl(
52
52
  named_group : (fn(self : Self, name : String) -> Option(String))({
53
53
  i := usize(0);
54
54
  while(i < self._group_names.len(), i = (i + usize(1)), {
55
- entry := self._group_names.get(i).unwrap();
55
+ entry := self._group_names(i);
56
56
  cond(
57
57
  (entry.name == name) => {
58
58
  return(self.group(entry.index));