phase 22 ruby: Hash/Set/Regexp/StringIO/Bytevectors/Fiber in lib/ruby/runtime.sx (61 forms), 76/76 tests

This commit is contained in:
2026-05-01 23:18:04 +00:00
parent 912de5a274
commit 182e6f63ef
3 changed files with 621 additions and 0 deletions

352
lib/ruby/runtime.sx Normal file
View File

@@ -0,0 +1,352 @@
;; lib/ruby/runtime.sx — Ruby primitives on SX
;;
;; Provides Ruby-idiomatic wrappers over SX built-ins.
;; Primitives used:
;; call/cc (core evaluator)
;; make-set/set-add!/set-member?/set-remove!/set->list (Phase 18)
;; make-regexp/regexp-match/regexp-match-all/... (Phase 19)
;; make-bytevector/bytevector-u8-ref/... (Phase 20)
;; ---------------------------------------------------------------------------
;; 0. Internal list helpers
;; ---------------------------------------------------------------------------
(define
(rb-list-set-nth lst i newval)
(letrec
((go (fn (ps j) (if (= (len ps) 0) (list) (cons (if (= j i) newval (first ps)) (go (rest ps) (+ j 1)))))))
(go lst 0)))
(define
(rb-list-remove-nth lst i)
(letrec
((go (fn (ps j) (if (= (len ps) 0) (list) (if (= j i) (go (rest ps) (+ j 1)) (cons (first ps) (go (rest ps) (+ j 1))))))))
(go lst 0)))
;; ---------------------------------------------------------------------------
;; 1. Hash (mutable, any-key, dict-backed list-of-pairs)
;; ---------------------------------------------------------------------------
(define
(rb-hash-new)
(let
((h (dict)))
(dict-set! h "_rb_hash" true)
(dict-set! h "_pairs" (list))
(dict-set! h "_size" 0)
h))
(define (rb-hash? v) (and (dict? v) (dict-has? v "_rb_hash")))
(define (rb-hash-size h) (get h "_size"))
(define
(rb-hash-find-idx pairs k)
(letrec
((go (fn (ps i) (cond ((= (len ps) 0) -1) ((= (first (first ps)) k) i) (else (go (rest ps) (+ i 1)))))))
(go pairs 0)))
(define
(rb-hash-at h k)
(letrec
((go (fn (ps) (if (= (len ps) 0) nil (if (= (first (first ps)) k) (nth (first ps) 1) (go (rest ps)))))))
(go (get h "_pairs"))))
(define
(rb-hash-at-or h k default)
(if (rb-hash-has-key? h k) (rb-hash-at h k) default))
(define
(rb-hash-at-put! h k v)
(let
((pairs (get h "_pairs")) (idx (rb-hash-find-idx (get h "_pairs") k)))
(if
(= idx -1)
(begin
(dict-set! h "_pairs" (append pairs (list (list k v))))
(dict-set! h "_size" (+ (get h "_size") 1)))
(dict-set! h "_pairs" (rb-list-set-nth pairs idx (list k v)))))
h)
(define
(rb-hash-has-key? h k)
(not (= (rb-hash-find-idx (get h "_pairs") k) -1)))
(define
(rb-hash-delete! h k)
(let
((idx (rb-hash-find-idx (get h "_pairs") k)))
(when
(not (= idx -1))
(dict-set! h "_pairs" (rb-list-remove-nth (get h "_pairs") idx))
(dict-set! h "_size" (- (get h "_size") 1))))
h)
(define (rb-hash-keys h) (map first (get h "_pairs")))
(define
(rb-hash-values h)
(map (fn (p) (nth p 1)) (get h "_pairs")))
(define
(rb-hash-each h callback)
(for-each
(fn (p) (callback (first p) (nth p 1)))
(get h "_pairs")))
(define (rb-hash->list h) (get h "_pairs"))
(define
(rb-list->hash pairs)
(let
((h (rb-hash-new)))
(for-each
(fn (p) (rb-hash-at-put! h (first p) (nth p 1)))
pairs)
h))
(define
(rb-hash-merge h1 h2)
(let
((result (rb-hash-new)))
(for-each
(fn (p) (rb-hash-at-put! result (first p) (nth p 1)))
(get h1 "_pairs"))
(for-each
(fn (p) (rb-hash-at-put! result (first p) (nth p 1)))
(get h2 "_pairs"))
result))
;; ---------------------------------------------------------------------------
;; 2. Set (uniqueness collection backed by SX make-set)
;; Note: set-member?/set-add!/set-remove! take (set item) order.
;; ---------------------------------------------------------------------------
(define
(rb-set-new)
(let
((s (dict)))
(dict-set! s "_rb_set" true)
(dict-set! s "_set" (make-set))
(dict-set! s "_size" 0)
s))
(define (rb-set? v) (and (dict? v) (dict-has? v "_rb_set")))
(define (rb-set-size s) (get s "_size"))
(define
(rb-set-add! s v)
(let
((sx (get s "_set")))
(when
(not (set-member? sx v))
(set-add! sx v)
(dict-set! s "_size" (+ (get s "_size") 1))))
s)
(define (rb-set-include? s v) (set-member? (get s "_set") v))
(define
(rb-set-delete! s v)
(let
((sx (get s "_set")))
(when
(set-member? sx v)
(set-remove! sx v)
(dict-set! s "_size" (- (get s "_size") 1))))
s)
(define (rb-set->list s) (set->list (get s "_set")))
(define
(rb-set-each s callback)
(for-each callback (set->list (get s "_set"))))
(define
(rb-set-union s1 s2)
(let
((result (rb-set-new)))
(for-each (fn (v) (rb-set-add! result v)) (rb-set->list s1))
(for-each (fn (v) (rb-set-add! result v)) (rb-set->list s2))
result))
(define
(rb-set-intersection s1 s2)
(let
((result (rb-set-new)))
(for-each
(fn (v) (when (rb-set-include? s2 v) (rb-set-add! result v)))
(rb-set->list s1))
result))
(define
(rb-set-difference s1 s2)
(let
((result (rb-set-new)))
(for-each
(fn (v) (when (not (rb-set-include? s2 v)) (rb-set-add! result v)))
(rb-set->list s1))
result))
;; ---------------------------------------------------------------------------
;; 3. Regexp (thin wrappers over Phase-19 make-regexp primitives)
;; ---------------------------------------------------------------------------
(define
(rb-regexp-new pattern flags)
(make-regexp pattern (if (= flags nil) "" flags)))
(define (rb-regexp? v) (regexp? v))
(define (rb-regexp-match rx str) (regexp-match rx str))
(define (rb-regexp-match-all rx str) (regexp-match-all rx str))
(define (rb-regexp-match? rx str) (not (= (regexp-match rx str) nil)))
(define
(rb-regexp-replace rx str replacement)
(regexp-replace rx str replacement))
(define
(rb-regexp-replace-all rx str replacement)
(regexp-replace-all rx str replacement))
(define (rb-regexp-split rx str) (regexp-split rx str))
;; ---------------------------------------------------------------------------
;; 4. StringIO (write buffer + char-by-char read after rewind)
;; ---------------------------------------------------------------------------
(define
(rb-string-io-new)
(let
((io (dict)))
(dict-set! io "_rb_string_io" true)
(dict-set! io "_buf" "")
(dict-set! io "_chars" (list))
(dict-set! io "_pos" 0)
io))
(define (rb-string-io? v) (and (dict? v) (dict-has? v "_rb_string_io")))
(define
(rb-string-io-write! io s)
(dict-set! io "_buf" (str (get io "_buf") s))
io)
(define (rb-string-io-string io) (get io "_buf"))
(define
(rb-string-io-rewind! io)
(dict-set! io "_chars" (string->list (get io "_buf")))
(dict-set! io "_pos" 0)
io)
(define
(rb-string-io-eof? io)
(>= (get io "_pos") (len (get io "_chars"))))
(define
(rb-string-io-read-char io)
(if
(rb-string-io-eof? io)
nil
(let
((c (nth (get io "_chars") (get io "_pos"))))
(dict-set! io "_pos" (+ (get io "_pos") 1))
c)))
(define
(rb-string-io-read io)
(letrec
((go (fn (acc) (let ((c (rb-string-io-read-char io))) (if (= c nil) (list->string (reverse acc)) (go (cons c acc)))))))
(go (list))))
;; ---------------------------------------------------------------------------
;; 5. Bytevectors (thin wrappers over Phase-20 bytevector primitives)
;; ---------------------------------------------------------------------------
(define
(rb-bytes-new n fill)
(make-bytevector n (if (= fill nil) 0 fill)))
(define (rb-bytes? v) (bytevector? v))
(define (rb-bytes-length v) (bytevector-length v))
(define (rb-bytes-get v i) (bytevector-u8-ref v i))
(define (rb-bytes-set! v i b) (bytevector-u8-set! v i b) v)
(define (rb-bytes-copy v) (bytevector-copy v))
(define (rb-bytes-append v1 v2) (bytevector-append v1 v2))
(define (rb-bytes-to-string v) (utf8->string v))
(define (rb-bytes-from-string s) (string->utf8 s))
(define (rb-bytes->list v) (bytevector->list v))
(define (rb-list->bytes lst) (list->bytevector lst))
;; ---------------------------------------------------------------------------
;; 6. Fiber (call/cc coroutines)
;; Body wrapped so completion always routes through _resumer, ensuring
;; rb-fiber-resume always returns via the captured continuation.
;; ---------------------------------------------------------------------------
(define rb-current-fiber nil)
(define
(rb-fiber-new body)
(let
((f (dict)))
(dict-set! f "_rb_fiber" true)
(dict-set! f "_state" "new")
(dict-set! f "_cont" nil)
(dict-set! f "_resumer" nil)
(dict-set! f "_parent" nil)
(dict-set!
f
"_body"
(fn
()
(let
((result (body)))
(dict-set! f "_state" "dead")
(set! rb-current-fiber (get f "_parent"))
((get f "_resumer") result))))
f))
(define (rb-fiber? v) (and (dict? v) (dict-has? v "_rb_fiber")))
(define (rb-fiber-alive? f) (not (= (get f "_state") "dead")))
(define
(rb-fiber-yield val)
(call/cc
(fn
(resume-k)
(let
((cur rb-current-fiber))
(dict-set! cur "_cont" resume-k)
(dict-set! cur "_state" "suspended")
(set! rb-current-fiber (get cur "_parent"))
((get cur "_resumer") val)))))
(define
(rb-fiber-resume f)
(call/cc
(fn
(return-k)
(dict-set! f "_parent" rb-current-fiber)
(dict-set! f "_resumer" return-k)
(set! rb-current-fiber f)
(dict-set! f "_state" "running")
(if
(= (get f "_cont") nil)
((get f "_body"))
((get f "_cont") nil)))))