;;; schmaltz --- render scheme forms in text ;; every effort has been made to make this portable code, or at least to hide ;; the unportability behind configuration. (define render (case-lambda (() (render (current-input-port) (render-environment))) ((in) (render in (render-environment))) ((in env) (let loop ((ch (read-char in)) (acc '())) (cond ((not ch) ; after an expansion (loop (read-char in) acc)) ((eof-object? ch) ; end of file (display (list->string (reverse acc)))) ((eq? ch #\#) ; expansion (let* ((next (peek-char in)) (proc (assq-ref next (render-specials)))) (cond ((eq? next #\\) ; escape character -- #\,( => #,( (read-char in) ; skip the \ (loop (read-char in) ; continue (cons ch acc))) ((not proc) ; this character isn't special (loop (read-char in) ; continue (cons ch acc))) (else ; look up the reader and run it (read-char in) ; skip the character (loop #f (append (let* ((ins (displayed (eval (proc in) env))) (out (assoc ins (render-unprintables)))) (if out ((cdr out) next) (reverse (string->list ins)))) acc)))))) (else (loop (read-char in) ; normal character (cons ch acc)))))))) (define render-string (case-lambda ((str) (render-string str (interaction-environment))) ((str env) (call-with-port (open-input-string str) (lambda (in) (render env in)))))) (define (render->string . args) (call-with-port (open-output-string) (lambda (out) (apply render args) (get-output-string out)))) (define (render-string->string str . args) (call-with-port (open-output-string) (lambda (out) (apply render-string args) (get-output-string out)))) ;;; Configuration (define render-environment (make-parameter (interaction-environment))) (define render-specials ;; Alist of (CHAR . PROCEDURE) mapping input characters to special reader ;; meanings. Each PROCEDURE should take one parameter, a port. (make-parameter (list (cons #\, (lambda (port) (eval (read port) ; standard scheme read (render-environment)))) #;(cons #\@ (lambda (port) ; wrap the next form in `sxml->html' `(sxml->html ,(list 'quasiquote (read port)))))))) (define render-unprintables (make-parameter (list #;(cons "#" (lambda _ '())) #;(cons "#!eof" (lambda (ch) (list ch #\#)))))) ;;;: Utilities (define (displayed x) (call-with-port (open-output-string) (lambda (port) (display x port) (get-output-string port)))) (define (assq-ref key lis) (let ((val (assq key lis))) (if val (cdr val) #f))) (define (unprintable/skip . _) '()) (define (unprintable/backtrack ch) (list ch #\#))