ocaml: phase 6 Hashtbl.keys/values/bindings/remove/clear (+4 tests, 545 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 23s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 23s
Two new host primitives:
_hashtbl_remove t k -> dissoc the key from the underlying dict
_hashtbl_clear t -> reset the cell to {}
Eight new OCaml-syntax helpers in runtime.sx Hashtbl module:
bindings t = _hashtbl_to_list t
keys t = List.map (fun (k, _) -> k) (...)
values t = List.map (fun (_, v) -> v) (...)
to_seq t = bindings t
to_seq_keys / to_seq_values
remove / clear / reset
The keys/values implementations use a 'fun pair -> match pair with
(k, _) -> k' indirection because parse-fun does not currently allow
tuple patterns directly on parameters. Same restriction we worked
around in iteration 98's let-pattern desugaring.
Also: a detour attempting to add top-level 'let (a, b) = expr'
support was started but reverted — parse-decl-let in the outer
ocaml-parse-program scope does not have access to parse-pattern
(which is local to ocaml-parse). Will need a slice + re-parse trick
later.
This commit is contained in:
@@ -171,6 +171,17 @@
|
|||||||
(fn (t) (fn (k) (has-key? (nth t 0) (str k)))))
|
(fn (t) (fn (k) (has-key? (nth t 0) (str k)))))
|
||||||
(list "_hashtbl_length"
|
(list "_hashtbl_length"
|
||||||
(fn (t) (len (keys (nth t 0)))))
|
(fn (t) (len (keys (nth t 0)))))
|
||||||
|
(list "_hashtbl_remove"
|
||||||
|
(fn (t) (fn (k)
|
||||||
|
(let ((d (nth t 0)))
|
||||||
|
(begin
|
||||||
|
(set-nth! t 0 (dissoc d (str k)))
|
||||||
|
nil)))))
|
||||||
|
(list "_hashtbl_clear"
|
||||||
|
(fn (t)
|
||||||
|
(begin
|
||||||
|
(set-nth! t 0 {})
|
||||||
|
nil)))
|
||||||
;; _lazy_force: evaluate the thunk on first force, cache result.
|
;; _lazy_force: evaluate the thunk on first force, cache result.
|
||||||
;; cell: one-elt list whose value is ("Thunk" expr env) or
|
;; cell: one-elt list whose value is ("Thunk" expr env) or
|
||||||
;; ("Forced" v).
|
;; ("Forced" v).
|
||||||
|
|||||||
@@ -774,6 +774,27 @@
|
|||||||
| (k, v) :: rest -> go rest (f k v a)
|
| (k, v) :: rest -> go rest (f k v a)
|
||||||
in
|
in
|
||||||
go (_hashtbl_to_list t) acc
|
go (_hashtbl_to_list t) acc
|
||||||
|
|
||||||
|
(* OCaml's Hashtbl doesn't expose `keys` directly — it offers
|
||||||
|
`to_seq_keys` etc. We provide both: a plain list snapshot and
|
||||||
|
the keys/values projections that are commonly useful. *)
|
||||||
|
let bindings t = _hashtbl_to_list t
|
||||||
|
|
||||||
|
let keys t =
|
||||||
|
List.map (fun pair -> match pair with (k, _) -> k)
|
||||||
|
(_hashtbl_to_list t)
|
||||||
|
|
||||||
|
let values t =
|
||||||
|
List.map (fun pair -> match pair with (_, v) -> v)
|
||||||
|
(_hashtbl_to_list t)
|
||||||
|
|
||||||
|
let to_seq t = _hashtbl_to_list t
|
||||||
|
let to_seq_keys = keys
|
||||||
|
let to_seq_values = values
|
||||||
|
|
||||||
|
let remove t k = _hashtbl_remove t k
|
||||||
|
let reset t = _hashtbl_clear t
|
||||||
|
let clear t = _hashtbl_clear t
|
||||||
end ;;
|
end ;;
|
||||||
|
|
||||||
module Map = struct
|
module Map = struct
|
||||||
|
|||||||
@@ -1350,6 +1350,16 @@ cat > "$TMPFILE" << 'EPOCHS'
|
|||||||
(epoch 5092)
|
(epoch 5092)
|
||||||
(eval "(ocaml-run \"let pair = (5, 7) in let (x, y) = pair in x * y\")")
|
(eval "(ocaml-run \"let pair = (5, 7) in let (x, y) = pair in x * y\")")
|
||||||
|
|
||||||
|
;; ── Hashtbl.keys / values / remove / clear ────────────────────
|
||||||
|
(epoch 5100)
|
||||||
|
(eval "(ocaml-run \"let t = Hashtbl.create 4 in Hashtbl.add t \\\"a\\\" 1; Hashtbl.add t \\\"b\\\" 2; List.length (Hashtbl.keys t)\")")
|
||||||
|
(epoch 5101)
|
||||||
|
(eval "(ocaml-run \"let t = Hashtbl.create 4 in Hashtbl.add t \\\"a\\\" 5; Hashtbl.add t \\\"b\\\" 7; List.fold_left (+) 0 (Hashtbl.values t)\")")
|
||||||
|
(epoch 5102)
|
||||||
|
(eval "(ocaml-run \"let t = Hashtbl.create 4 in Hashtbl.add t \\\"x\\\" 1; Hashtbl.add t \\\"y\\\" 2; Hashtbl.remove t \\\"x\\\"; Hashtbl.length t\")")
|
||||||
|
(epoch 5103)
|
||||||
|
(eval "(ocaml-run \"let t = Hashtbl.create 4 in Hashtbl.add t \\\"a\\\" 1; Hashtbl.clear t; Hashtbl.length t\")")
|
||||||
|
|
||||||
EPOCHS
|
EPOCHS
|
||||||
|
|
||||||
OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||||
@@ -2145,6 +2155,12 @@ check 5090 "let (a, b) = (1,2)" '3'
|
|||||||
check 5091 "let (a, b, c) = (10,20,30)" '60'
|
check 5091 "let (a, b, c) = (10,20,30)" '60'
|
||||||
check 5092 "let pair; let (x, y) = pair" '35'
|
check 5092 "let pair; let (x, y) = pair" '35'
|
||||||
|
|
||||||
|
# ── Hashtbl.keys/values/remove/clear ────────────────────────────
|
||||||
|
check 5100 "Hashtbl.keys length" '2'
|
||||||
|
check 5101 "Hashtbl.values sum" '12'
|
||||||
|
check 5102 "Hashtbl.remove + length" '1'
|
||||||
|
check 5103 "Hashtbl.clear + length" '0'
|
||||||
|
|
||||||
TOTAL=$((PASS + FAIL))
|
TOTAL=$((PASS + FAIL))
|
||||||
if [ $FAIL -eq 0 ]; then
|
if [ $FAIL -eq 0 ]; then
|
||||||
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
||||||
|
|||||||
@@ -407,6 +407,16 @@ _Newest first._
|
|||||||
binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree *
|
binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree *
|
||||||
'a tree`) with insert + in-order traversal. Tests parametric ADT,
|
'a tree`) with insert + in-order traversal. Tests parametric ADT,
|
||||||
recursive match, List.append, List.fold_left.
|
recursive match, List.append, List.fold_left.
|
||||||
|
- 2026-05-09 Phase 6 — Hashtbl.keys / values / bindings / remove /
|
||||||
|
clear / reset / to_seq / to_seq_keys / to_seq_values (+4 tests, 545
|
||||||
|
total). Two new host primitives `_hashtbl_remove` and
|
||||||
|
`_hashtbl_clear`; the rest are pure OCaml-syntax helpers in
|
||||||
|
runtime.sx that map over `_hashtbl_to_list`. `keys` and `values`
|
||||||
|
pattern-match the (k, v) tuples to extract one side. Note: a
|
||||||
|
detour to also support top-level `let (a, b) = expr` was reverted
|
||||||
|
— `parse-decl-let` lives in the outer ocaml-parse-program scope
|
||||||
|
which doesn't have access to parse-pattern; will need a slice +
|
||||||
|
inner-parse trick later.
|
||||||
- 2026-05-09 Phase 4 — `let PATTERN = expr in body` tuple
|
- 2026-05-09 Phase 4 — `let PATTERN = expr in body` tuple
|
||||||
destructuring (+3 tests, 541 total). When `let` is followed by `(`,
|
destructuring (+3 tests, 541 total). When `let` is followed by `(`,
|
||||||
parse-let now reads a full pattern, expects `=`, then `in`, and
|
parse-let now reads a full pattern, expects `=`, then `in`, and
|
||||||
|
|||||||
Reference in New Issue
Block a user