diff options
Diffstat (limited to 'schmaltz.sls')
-rw-r--r-- | schmaltz.sls | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/schmaltz.sls b/schmaltz.sls new file mode 100644 index 0000000..25d926b --- /dev/null +++ b/schmaltz.sls | |||
@@ -0,0 +1,79 @@ | |||
1 | ;;; schmaltz --- render scheme forms in text | ||
2 | ;; every effort has been made to make this portable code, or at least to hide | ||
3 | ;; the unportability behind configuration. | ||
4 | |||
5 | (define render | ||
6 | (case-lambda | ||
7 | (() | ||
8 | (render (current-input-port) (render-environment))) | ||
9 | ((port) | ||
10 | (render port (render-environment))) | ||
11 | ((port env) | ||
12 | (let loop ((ch (read-char port)) | ||
13 | (acc '())) | ||
14 | (cond | ||
15 | ((not ch) ; after an expansion | ||
16 | (loop (read-char port) acc)) | ||
17 | ((eof-object? ch) ; end of file | ||
18 | (list->string (reverse acc))) | ||
19 | ((eq? ch #\#) ; expansion | ||
20 | (let* ((next (peek-char port)) | ||
21 | (proc (assq-ref next (render-specials)))) | ||
22 | (cond | ||
23 | ((eq? next #\\) ; escape character -- #\,( => #,( | ||
24 | (read-char port) ; skip the \ | ||
25 | (loop (read-char port) ; continue | ||
26 | (cons ch acc))) | ||
27 | ((not proc) ; this character isn't special | ||
28 | (loop (read-char port) ; continue | ||
29 | (cons ch acc))) | ||
30 | (else ; look up the reader and run it | ||
31 | (read-char port) ; skip the character | ||
32 | (loop #f (append (let* ((ins (displayed (eval (proc port) env))) | ||
33 | (out (assoc ins (render-unprintables)))) | ||
34 | (if out | ||
35 | ((cdr out) next) | ||
36 | (reverse (string->list ins)))) | ||
37 | acc)))))) | ||
38 | (else (loop (read-char port) ; normal character | ||
39 | (cons ch acc)))))))) | ||
40 | |||
41 | (define render-string | ||
42 | (case-lambda | ||
43 | ((s) (render-string s (interaction-environment))) | ||
44 | ((s env) | ||
45 | (call-with-port (open-input-string s) | ||
46 | (lambda (port) | ||
47 | (render env port)))))) | ||
48 | |||
49 | ;;; Configuration | ||
50 | |||
51 | (define render-environment | ||
52 | (make-parameter | ||
53 | (interaction-environment))) | ||
54 | |||
55 | (define render-specials | ||
56 | ;; Alist of (CHAR . PROCEDURE) mapping input characters to special reader | ||
57 | ;; meanings. Each PROCEDURE should take one parameter, a port. | ||
58 | (make-parameter | ||
59 | (list (cons #\, (lambda (port) (eval (read port) ; standard scheme read | ||
60 | (interaction-environment)))) | ||
61 | #;(cons #\@ (lambda (port) ; wrap the next form in `sxml->html' | ||
62 | `(sxml->html ,(list 'quasiquote (read port)))))))) | ||
63 | |||
64 | (define render-unprintables | ||
65 | (make-parameter | ||
66 | (list #;(cons "#<unspecified>" (lambda _ '())) | ||
67 | #;(cons "#!eof" (lambda (ch) (list ch #\#)))))) | ||
68 | |||
69 | ;;;: Utilities | ||
70 | |||
71 | (define (displayed x) | ||
72 | (call-with-port (open-output-string) | ||
73 | (lambda (port) | ||
74 | (display x port) | ||
75 | (get-output-string port)))) | ||
76 | |||
77 | (define (assq-ref key lis) | ||
78 | (let ((val (assq key lis))) | ||
79 | (if val (cdr val) #f))) | ||