353 lines
9.2 KiB
Plaintext
353 lines
9.2 KiB
Plaintext
;; 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)))))
|