#lang scheme/base
(require "../tools.ss"
(for-syntax
scheme/base
syntax/stx))
(provide make-word
word-behaviour!
word?
make-parameter-word
parameter-word?
word-parameter
word-swap!
word-parameter!
upgrade-to-parameter-word!
)
(define (word-run w state)
((word-ref w 0) w state))
(define (word-print word port write?)
(let* ((props (word-ref word 1)))
(write-string
(format "#<word>") port)))
(define-values
(struct:word make-word-internal word? word-ref word-set!)
(begin
(make-struct-type
'word #f 2 0 #f (list (cons prop:custom-write word-print))
#f word-run
)))
(define (make-word fn [props '()])
(make-word-internal
(lambda (w state) (fn state))
props))
(define (word-behaviour! word fn)
(word-set! word 0 (lambda (w state) (fn state))))
(define (run-pw pw state)
(((word-ref pw 1)) state))
(define (parameter-word? pw)
(and (word? pw)
(eq? (word-ref pw 0) run-pw)))
(define (word->parameter-word w)
(when (parameter-word? w)
(error 'recursive-parameter-word))
(make-word-internal
run-pw (make-parameter w)))
(define (make-parameter-word . args)
(word->parameter-word
(apply make-word args)))
(define (word-parameter w)
(unless (parameter-word? w)
(raise
(make-exn:fail:contract
"Not a parameter word."
(current-continuation-marks))))
(word-ref w 1))
(define (upgrade-to-parameter-word! w)
(define inner #f)
(define outer #f)
(set! inner (make-word #f))
(word-swap! w inner)
(set! outer (word->parameter-word inner))
(word-swap! w outer))
(define (word-parameter! w)
(unless (parameter-word? w)
(upgrade-to-parameter-word! w))
(word-parameter w))
(define (word-swap! w1 w2)
(define (swap n)
(let ((tmp (word-ref w1 n)))
(word-set! w1 n (word-ref w2 n))
(word-set! w2 n tmp)))
(swap 0)
(swap 1))