From d1a00562a4a605e372b8367e8738678735be4417 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 25 Apr 2026 19:27:54 +0000 Subject: [PATCH] =?UTF-8?q?spec:=20vector=20primitives=20=E2=80=94=20bound?= =?UTF-8?q?s-checked=20ref/set!,=20vector-copy=20start/end=20slice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vector-ref and vector-set! now raise Eval_error on out-of-bounds index instead of an OCaml array exception. vector-copy accepts optional start and end parameters for slicing (R7RS §6.8). spec/primitives.sx doc updated to reflect slice params. Co-Authored-By: Claude Sonnet 4.6 --- hosts/ocaml/lib/sx_primitives.ml | 26 ++++++++++++++++++++---- plans/agent-briefings/primitives-loop.md | 5 ++++- spec/primitives.sx | 6 ++++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/hosts/ocaml/lib/sx_primitives.ml b/hosts/ocaml/lib/sx_primitives.ml index 3e0768f4..aeada877 100644 --- a/hosts/ocaml/lib/sx_primitives.ml +++ b/hosts/ocaml/lib/sx_primitives.ml @@ -1227,11 +1227,19 @@ let () = | _ -> raise (Eval_error "vector-length: expected vector")); register "vector-ref" (fun args -> match args with - | [Vector arr; Number n] -> arr.(int_of_float n) + | [Vector arr; Number n] -> + let i = int_of_float n in + if i < 0 || i >= Array.length arr then + raise (Eval_error (Printf.sprintf "vector-ref: index %d out of bounds (length %d)" i (Array.length arr))); + arr.(i) | _ -> raise (Eval_error "vector-ref: expected (vector index)")); register "vector-set!" (fun args -> match args with - | [Vector arr; Number n; v] -> arr.(int_of_float n) <- v; Nil + | [Vector arr; Number n; v] -> + let i = int_of_float n in + if i < 0 || i >= Array.length arr then + raise (Eval_error (Printf.sprintf "vector-set!: index %d out of bounds (length %d)" i (Array.length arr))); + arr.(i) <- v; Nil | _ -> raise (Eval_error "vector-set!: expected (vector index value)")); register "vector->list" (fun args -> match args with [Vector arr] -> List (Array.to_list arr) @@ -1246,8 +1254,18 @@ let () = | [Vector arr; v] -> Array.fill arr 0 (Array.length arr) v; Nil | _ -> raise (Eval_error "vector-fill!: expected (vector value)")); register "vector-copy" (fun args -> - match args with [Vector arr] -> Vector (Array.copy arr) - | _ -> raise (Eval_error "vector-copy: expected vector")); + match args with + | [Vector arr] -> Vector (Array.copy arr) + | [Vector arr; Number s] -> + let start = int_of_float s in + let len = Array.length arr - start in + if len <= 0 then Vector [||] else Vector (Array.sub arr start len) + | [Vector arr; Number s; Number e] -> + let start = int_of_float s in + let stop = min (int_of_float e) (Array.length arr) in + let len = stop - start in + if len <= 0 then Vector [||] else Vector (Array.sub arr start len) + | _ -> raise (Eval_error "vector-copy: expected (vector) or (vector start) or (vector start end)")); (* Capability-based sandboxing — gate IO operations *) let cap_stack : string list ref = ref [] in diff --git a/plans/agent-briefings/primitives-loop.md b/plans/agent-briefings/primitives-loop.md index 32bb0521..84cbb654 100644 --- a/plans/agent-briefings/primitives-loop.md +++ b/plans/agent-briefings/primitives-loop.md @@ -50,8 +50,10 @@ Primitives to add: - `vector-copy` `v` `[start]` `[end]` → fresh copy of slice Steps: -- [ ] OCaml: add `SxVector of value array` to `hosts/ocaml/sx_types.ml`; implement all +- [x] OCaml: add `SxVector of value array` to `hosts/ocaml/sx_types.ml`; implement all primitives in `hosts/ocaml/sx_primitives.ml` (or equivalent); wire into evaluator. + Note: Vector type + most prims were already present; added bounds-checked vector-ref/set! + and optional start/end to vector-copy. 10/10 vector tests pass (r7rs suite). - [ ] Spec: add vector entries to `spec/primitives.sx` with type signatures and descriptions. - [ ] JS bootstrapper: implement vectors in `hosts/javascript/platform.js` (or equivalent); ensure `sx-browser.js` rebuild picks them up. @@ -194,4 +196,5 @@ Brief each language's loop agent (or do inline) after rebasing their branch onto _Newest first._ +- 2026-04-25: Phase 1 OCaml step done — bounds-checked vector-ref/set!, vector-copy now accepts optional start/end, spec/primitives.sx doc updated. 10/10 r7rs vector tests pass, 4747 total (394 pre-existing hs-upstream fails unchanged). - 2026-04-25: Phase 0 complete — stopped CL/APL/Ruby/Tcl loops (all 4 idle at shell); confirmed E38 (tokenizer :end/:line) and E39 (WebWorker stub) both have implementation commits. diff --git a/spec/primitives.sx b/spec/primitives.sx index 6f0ab489..ddbbaf60 100644 --- a/spec/primitives.sx +++ b/spec/primitives.sx @@ -227,9 +227,11 @@ (define-primitive "vector-copy" - :params ((v :as vector)) + :params ((v :as vector) + (start :as number :optional true) + (end :as number :optional true)) :returns "vector" - :doc "Independent shallow copy.") + :doc "Shallow copy of vector, optionally sliced from start (inclusive) to end (exclusive).") (define-primitive "min"