about summary refs log tree commit diff stats
path: root/fff.read.ss
diff options
context:
space:
mode:
Diffstat (limited to 'fff.read.ss')
-rw-r--r--fff.read.ss166
1 files changed, 166 insertions, 0 deletions
diff --git a/fff.read.ss b/fff.read.ss new file mode 100644 index 0000000..fa1aec2 --- /dev/null +++ b/fff.read.ss
@@ -0,0 +1,166 @@
1;;; (fff read) --- read an fff file into a scheme structure
2;; (C) Case Duckworth <acdw@acdw.net>
3
4(import (scheme base)
5 (scheme case-lambda)
6
7 (fff parse)
8
9 (srfi 1)
10 (utf8))
11
12;;; Parameters
13
14(define chunk-size
15 (make-parameter 2048))
16
17(define ignore-comments?
18 (make-parameter #t))
19
20(define base-environment
21 (make-parameter '(("true" . #t)
22 ("false" . #f)
23 ("null" . null))))
24
25;;; Transforming parsed intermediate representation into fff
26
27(define (comment? it)
28 (eq? 'comment (car it)))
29
30(define (singleton it)
31 (if (pair? it)
32 (if (not (pair? (cdr it)))
33 #t
34 (and (eq? 'ref (cadr it))
35 (not (pair? (cddr it)))
36 'ref))
37 #f))
38
39(define (resolve-ref obj env)
40 (let ((ref (cddr obj)))
41 (if (assoc ref env)
42 (cons (car obj)
43 (cdr (assoc ref env)))
44 (error "Reference doesn't exist: " ref env))))
45
46(define (resolve-refs obj env)
47 ;;; Resolve references in OBJ using ENV.
48 (let loop ((items (cdr obj))
49 (new-obj (list (car obj)))
50 (resolved-refs '()))
51 (if (null? items)
52 (values (reverse new-obj)
53 resolved-refs)
54
55 (let ((this (car items)))
56 (if (and (pair? (cdr this))
57 (eq? 'ref (cadr this)))
58 (loop (cdr items)
59 (cons (resolve-ref this env) new-obj)
60 (cons (cddr this) resolved-refs))
61 (loop (cdr items)
62 (cons this new-obj)
63 resolved-refs))))))
64
65(define (maybe-vector obj)
66 (let loop ((items (cdr obj))
67 (type #f))
68 (cond
69 ((comment? obj)
70 (cons 'comment
71 (apply string-append
72 (map (lambda (s)
73 (string-append s "\n"))
74 (cdr obj)))))
75 ((and (null? items)
76 (eq? type 'object))
77 obj)
78 ((and (null? items)
79 (eq? type 'vector))
80 (cons (car obj)
81 (list->vector (map cdr (cdr obj)))))
82 ((not (pair? items))
83 obj)
84 (else
85 (loop (cdr items)
86 (if (caar items)
87 (if (eq? type 'vector)
88 (error "Item type mismatch" 'object type)
89 'object)
90 (if (eq? type 'object)
91 (error "Item type mismatch" 'vector type)
92 'vector)))))))
93
94(define (%fff->scm fff env acc dupes)
95 (if (null? fff)
96 (map maybe-vector
97 (reverse
98 (filter
99 (lambda (x) (not (member (car x) dupes)))
100 acc)))
101 (let ((this (car fff))
102 (rest (cdr fff)))
103 (cond
104 ((comment? this)
105 (if (ignore-comments?)
106 (%fff->scm (cdr fff) env acc dupes)
107 (%fff->scm rest env (cons this acc) dupes)))
108 ((singleton this) =>
109 (lambda (x)
110 (%fff->scm rest
111 (cons this env)
112 (cons (if (eq? 'ref x)
113 (resolve-ref this (append env fff))
114 this)
115 acc)
116 (if (eq? 'ref x)
117 (cons (cddr this) dupes)
118 dupes))))
119 (else
120 (let-values (((resolved references)
121 (resolve-refs this (append env fff))))
122 (%fff->scm rest
123 (cons this env)
124 (cons resolved acc)
125 (append references dupes))))))))
126
127(define fff->scm
128 (case-lambda
129 ((fff)
130 (%fff->scm fff (base-environment) '() '()))
131 ((fff env)
132 (%fff->scm fff env '() '()))))
133
134;;; Reading fff
135
136(define (read-port port)
137 (let loop ((next (read-string (chunk-size) port))
138 (blank? #f)
139 (acc '()))
140 (cond
141 ((or (eof-object? next)
142 (and blank? (equal? next "")))
143 (close-input-port port)
144 (apply string-append (reverse acc)))
145 ((equal? next "")
146 (loop (read-string (chunk-size) port)
147 #t
148 (cons next acc)))
149 (else
150 (loop (read-string (chunk-size) port)
151 blank?
152 (cons next acc))))))
153
154(define (%read-fff port)
155 (or (fff->scm (parse-fff (read-port port)))
156 (error "Invalid fff" port)))
157
158(define read-fff
159 (case-lambda
160 (()
161 (%read-fff (current-input-port)))
162 ((port)
163 (%read-fff port))))
164
165(define (read-fff-string str)
166 (call-with-port (open-input-string str) %read-fff))