diff --git a/lib/ocaml/runtime.sx b/lib/ocaml/runtime.sx index 29177685..52a27d08 100644 --- a/lib/ocaml/runtime.sx +++ b/lib/ocaml/runtime.sx @@ -274,6 +274,19 @@ match o with | None -> [] | Some x -> [x] + + let join oo = + match oo with + | None -> None + | Some inner -> inner + + let to_result none_v o = + match o with + | None -> Error none_v + | Some x -> Ok x + + let some x = Some x + let none = None end ;; module Result = struct @@ -316,6 +329,21 @@ match r with | Ok x -> Some x | Error _ -> None + + let value r default = + match r with + | Ok x -> x + | Error _ -> default + + let iter f r = + match r with + | Ok x -> f x + | Error _ -> () + + let fold ok_f err_f r = + match r with + | Ok x -> ok_f x + | Error e -> err_f e end ;; module String = struct @@ -334,6 +362,16 @@ let index_of s sub = _string_index_of s sub end ;; + module Bytes = struct + (* Thin alias of String — SX has no separate immutable byte type. *) + let length s = String.length s + let get s i = String.get s i + let of_string s = s + let to_string s = s + let concat sep xs = String.concat sep xs + let sub s i n = String.sub s i n + end ;; + module Char = struct let code c = _char_code c let chr n = _char_chr n diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 6d467482..404b707b 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1064,6 +1064,26 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 3604) (eval "(ocaml-run-program \"let q = Queue.create () ;; Queue.push 1 q ;; Queue.push 2 q ;; Queue.length q\")") +;; ── Option/Result/Bytes extensions ──────────────────────────── +(epoch 3700) +(eval "(ocaml-run \"Option.join (Some (Some 5))\")") +(epoch 3701) +(eval "(ocaml-run \"Option.join None\")") +(epoch 3702) +(eval "(ocaml-run \"Option.to_result \\\"missing\\\" None\")") +(epoch 3703) +(eval "(ocaml-run \"Option.to_result \\\"missing\\\" (Some 7)\")") +(epoch 3704) +(eval "(ocaml-run \"Result.value (Ok 5) 0\")") +(epoch 3705) +(eval "(ocaml-run \"Result.value (Error \\\"e\\\") 99\")") +(epoch 3706) +(eval "(ocaml-run \"Result.fold (fun x -> x * 10) (fun e -> 0) (Ok 5)\")") +(epoch 3707) +(eval "(ocaml-run \"Bytes.length \\\"hello\\\"\")") +(epoch 3708) +(eval "(ocaml-run \"Bytes.concat \\\"-\\\" [\\\"a\\\";\\\"b\\\";\\\"c\\\"]\")") + EPOCHS OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1684,6 +1704,17 @@ check 3602 "Stack.top" '1' check 3603 "Queue.pop FIFO" '1' check 3604 "Queue.length" '2' +# ── Option/Result/Bytes extensions ───────────────────────────── +check 3700 "Option.join nested" '("Some" 5)' +check 3701 "Option.join None" '("None")' +check 3702 "Option.to_result None" '("Error" "missing")' +check 3703 "Option.to_result Some" '("Ok" 7)' +check 3704 "Result.value Ok" '5' +check 3705 "Result.value Error fallback" '99' +check 3706 "Result.fold Ok" '50' +check 3707 "Bytes.length" '5' +check 3708 "Bytes.concat" '"a-b-c"' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL OCaml-on-SX tests passed" diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index dd4698bf..742efe40 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -399,6 +399,12 @@ _Newest first._ recognise `!` as the prefix-deref of an application argument, so `String.concat "" (List.rev !b)` parses as `(... (deref b))`. Buffer uses a ref holding a string list; contents reverses and concats. +- 2026-05-08 Phase 6 — Option/Result/Bytes extensions (+9 tests, 439 + total). Option: join, to_result, some, none. Result: value, iter, + fold. Bytes: length, get, of_string, to_string, concat, sub (thin + alias of String — SX has no separate immutable byte type). Ordering + fix: Bytes module placed after String so its closures capture String + in scope. - 2026-05-08 Phase 6 — `Stack` and `Queue` modules in OCaml (+5 tests, 430 total). Stack: ref-holding-list LIFO with push/pop/top/length/ is_empty/clear. Queue: amortised O(1) two-list `(front, back)` queue