Commit | Line | Data |
---|---|---|
1d20dc6b VS |
1 | (define-library (lib core) |
2 | ||
3 | (export ns) | |
4 | ||
5 | (import (scheme base)) | |
6 | (import (scheme write)) | |
663059ad | 7 | (import (scheme file)) |
8e53f705 | 8 | (import (scheme time)) |
a43528b9 VS |
9 | (import (scheme read)) |
10 | (import (scheme eval)) | |
49352c89 VS |
11 | ;; HACK: cyclone doesn't implement environments yet, but its eval |
12 | ;; behaves as if you were using the repl environment | |
13 | (cond-expand | |
14 | (cyclone) | |
15 | (else | |
16 | (import (scheme repl)))) | |
1d20dc6b VS |
17 | |
18 | (import (lib types)) | |
19 | (import (lib util)) | |
20 | (import (lib printer)) | |
663059ad | 21 | (import (lib reader)) |
1d20dc6b VS |
22 | |
23 | (begin | |
24 | ||
25 | (define (coerce x) | |
26 | (if x mal-true mal-false)) | |
27 | ||
28 | (define (->printed-string args print-readably sep) | |
29 | (let ((items (map (lambda (arg) (pr-str arg print-readably)) args))) | |
30 | (string-intersperse items sep))) | |
31 | ||
32 | (define (mal-equal? a b) | |
33 | (let ((a-type (and (mal-object? a) (mal-type a))) | |
34 | (a-value (and (mal-object? a) (mal-value a))) | |
35 | (b-type (and (mal-object? b) (mal-type b))) | |
36 | (b-value (and (mal-object? b) (mal-value b)))) | |
37 | (cond | |
38 | ((or (not a-type) (not b-type)) | |
39 | mal-false) | |
40 | ((and (memq a-type '(list vector)) | |
41 | (memq b-type '(list vector))) | |
42 | (mal-list-equal? (->list a-value) (->list b-value))) | |
43 | ((and (eq? a-type 'map) (eq? b-type 'map)) | |
1d117aaf | 44 | (mal-map-equal? a-value b-value)) |
1d20dc6b VS |
45 | (else |
46 | (and (eq? a-type b-type) | |
47 | (equal? a-value b-value)))))) | |
48 | ||
49 | (define (mal-list-equal? as bs) | |
50 | (let loop ((as as) | |
51 | (bs bs)) | |
52 | (cond | |
53 | ((and (null? as) (null? bs)) #t) | |
54 | ((or (null? as) (null? bs)) #f) | |
55 | (else | |
56 | (if (mal-equal? (car as) (car bs)) | |
57 | (loop (cdr as) (cdr bs)) | |
58 | #f))))) | |
59 | ||
1d117aaf VS |
60 | (define (mal-map-ref key m . default) |
61 | (if (pair? default) | |
62 | (alist-ref key m mal-equal? (car default)) | |
63 | (alist-ref key m mal-equal?))) | |
64 | ||
65 | (define (mal-map-equal? as bs) | |
66 | (if (not (= (length as) (length bs))) | |
67 | #f | |
68 | (let loop ((as as)) | |
69 | (if (pair? as) | |
70 | (let* ((item (car as)) | |
71 | (key (car item)) | |
72 | (value (cdr item))) | |
73 | (if (mal-equal? (mal-map-ref key bs) value) | |
74 | (loop (cdr as)) | |
75 | #f)) | |
76 | #t)))) | |
77 | ||
78 | (define (mal-map-dissoc m keys) | |
79 | (let loop ((items m) | |
80 | (acc '())) | |
81 | (if (pair? items) | |
82 | (let* ((item (car items)) | |
83 | (key (car item))) | |
84 | (if (contains? keys (lambda (x) (mal-equal? key x))) | |
85 | (loop (cdr items) acc) | |
86 | (loop (cdr items) (cons item acc)))) | |
87 | (reverse acc)))) | |
88 | ||
89 | (define (mal-map-assoc m kvs) | |
90 | (let ((kvs (list->alist kvs))) | |
91 | (append kvs (mal-map-dissoc m (map car kvs))))) | |
92 | ||
05414421 VS |
93 | (define (map-in-order proc items) |
94 | (let loop ((items items) | |
95 | (acc '())) | |
96 | (if (null? items) | |
97 | (reverse acc) | |
98 | (loop (cdr items) (cons (proc (car items)) acc))))) | |
99 | ||
663059ad VS |
100 | (define (slurp path) |
101 | (call-with-output-string | |
102 | (lambda (out) | |
103 | (call-with-input-file path | |
104 | (lambda (in) | |
105 | (let loop () | |
106 | (let ((chunk (read-string 1024 in))) | |
107 | (when (not (eof-object? chunk)) | |
108 | (display chunk out) | |
109 | (loop))))))))) | |
110 | ||
8e53f705 VS |
111 | (define (time-ms) |
112 | (* (/ (current-jiffy) (jiffies-per-second)) 1000.0)) | |
113 | ||
a43528b9 VS |
114 | (define (->mal-object x) |
115 | (cond | |
116 | ((boolean? x) (if x mal-true mal-false)) | |
117 | ((char? x) (mal-string (char->string x))) | |
118 | ((procedure? x) x) | |
119 | ((symbol? x) (mal-symbol x)) | |
120 | ((number? x) (mal-number x)) | |
121 | ((string? x) (mal-string x)) | |
122 | ((or (null? x) (pair? x)) | |
123 | (mal-list (map ->mal-object x))) | |
124 | ((vector? x) | |
125 | (mal-vector (vector-map ->mal-object x))) | |
126 | (else | |
127 | (error "unknown type")))) | |
128 | ||
129 | (define (scm-eval input) | |
130 | (call-with-input-string input | |
131 | (lambda (port) | |
49352c89 VS |
132 | (cond-expand |
133 | (cyclone | |
134 | (->mal-object (eval (read port)))) | |
135 | (else | |
2b9b1104 VS |
136 | (->mal-object (eval (read port) (environment '(scheme base) |
137 | '(scheme write))))))))) | |
a43528b9 | 138 | |
1d20dc6b VS |
139 | (define ns |
140 | `((+ . ,(lambda (a b) (mal-number (+ (mal-value a) (mal-value b))))) | |
141 | (- . ,(lambda (a b) (mal-number (- (mal-value a) (mal-value b))))) | |
142 | (* . ,(lambda (a b) (mal-number (* (mal-value a) (mal-value b))))) | |
143 | (/ . ,(lambda (a b) (mal-number (/ (mal-value a) (mal-value b))))) | |
144 | ||
145 | (list . ,(lambda args (mal-list args))) | |
663059ad | 146 | (list? . ,(lambda (x) (coerce (mal-instance-of? x 'list)))) |
1d20dc6b VS |
147 | (empty? . ,(lambda (lis) (coerce (null? (->list (mal-value lis)))))) |
148 | (count . ,(lambda (lis) (mal-number | |
149 | (if (eq? lis mal-nil) | |
150 | 0 | |
151 | (length (->list (mal-value lis))))))) | |
152 | ||
153 | (< . ,(lambda (a b) (coerce (< (mal-value a) (mal-value b))))) | |
154 | (<= . ,(lambda (a b) (coerce (<= (mal-value a) (mal-value b))))) | |
155 | (> . ,(lambda (a b) (coerce (> (mal-value a) (mal-value b))))) | |
156 | (>= . ,(lambda (a b) (coerce (>= (mal-value a) (mal-value b))))) | |
157 | (= . ,(lambda (a b) (coerce (mal-equal? a b)))) | |
158 | ||
159 | (pr-str . ,(lambda args (mal-string (->printed-string args #t " ")))) | |
160 | (str . ,(lambda args (mal-string (->printed-string args #f "")))) | |
161 | (prn . ,(lambda args | |
162 | (display (->printed-string args #t " ")) | |
163 | (newline) | |
164 | mal-nil)) | |
165 | (println . ,(lambda args | |
166 | (display (->printed-string args #f " ")) | |
167 | (newline) | |
168 | mal-nil)) | |
169 | ||
663059ad VS |
170 | (read-string . ,(lambda (string) (read-str (mal-value string)))) |
171 | (slurp . ,(lambda (path) (mal-string (slurp (mal-value path))))) | |
1d117aaf | 172 | (throw . ,(lambda (x) (raise (cons 'user-error x)))) |
8e53f705 VS |
173 | (readline . ,(lambda (prompt) (let ((output (readline (mal-value prompt)))) |
174 | (if output (mal-string output) mal-nil)))) | |
175 | (time-ms . ,(lambda () (mal-number (time-ms)))) | |
a43528b9 | 176 | (scm-eval . ,(lambda (input) (scm-eval (mal-value input)))) |
663059ad VS |
177 | |
178 | (atom . ,(lambda (x) (mal-atom x))) | |
179 | (atom? . ,(lambda (x) (coerce (mal-instance-of? x 'atom)))) | |
180 | (deref . ,(lambda (atom) (mal-value atom))) | |
181 | (reset! . ,(lambda (atom x) (mal-value-set! atom x) x)) | |
182 | (swap! . ,(lambda (atom fn . args) | |
183 | (let* ((fn (if (func? fn) (func-fn fn) fn)) | |
184 | (value (apply fn (cons (mal-value atom) args)))) | |
185 | (mal-value-set! atom value) | |
186 | value))) | |
187 | ||
7f0ce0f0 VS |
188 | (cons . ,(lambda (x xs) (mal-list (cons x (->list (mal-value xs)))))) |
189 | (concat . ,(lambda args (mal-list (apply append (map (lambda (arg) (->list (mal-value arg))) args))))) | |
0d6f8696 VS |
190 | (nth . ,(lambda (x n) (let ((items (->list (mal-value x))) |
191 | (index (mal-value n))) | |
192 | (if (< index (length items)) | |
193 | (list-ref items index) | |
194 | (error (str "Out of range: " index)))))) | |
195 | (first . ,(lambda (x) (if (eq? x mal-nil) | |
196 | mal-nil | |
197 | (let ((items (->list (mal-value x)))) | |
198 | (if (null? items) | |
199 | mal-nil | |
200 | (car items)))))) | |
201 | (rest . ,(lambda (x) (if (eq? x mal-nil) | |
202 | (mal-list '()) | |
203 | (let ((items (->list (mal-value x)))) | |
204 | (if (null? items) | |
205 | (mal-list '()) | |
206 | (mal-list (cdr items))))))) | |
8e53f705 VS |
207 | (conj . ,(lambda (coll . args) |
208 | (let ((items (mal-value coll))) | |
209 | (cond | |
210 | ((vector? items) | |
211 | (mal-vector (vector-append items (list->vector args)))) | |
212 | ((list? items) | |
213 | (mal-list (append (reverse args) items))) | |
214 | (else | |
215 | (error "invalid collection type")))))) | |
216 | (seq . ,(lambda (x) (if (eq? x mal-nil) | |
217 | mal-nil | |
218 | (let ((value (mal-value x))) | |
219 | (case (mal-type x) | |
220 | ((list) | |
221 | (if (null? value) | |
222 | mal-nil | |
223 | x)) | |
224 | ((vector) | |
225 | (if (zero? (vector-length value)) | |
226 | mal-nil | |
227 | (mal-list (vector->list value)))) | |
228 | ((string) | |
229 | (if (zero? (string-length value)) | |
230 | mal-nil | |
231 | (mal-list (map mal-string (explode value))))) | |
232 | (else | |
233 | (error "invalid collection type"))))))) | |
7f0ce0f0 | 234 | |
1d117aaf VS |
235 | (apply . ,(lambda (f . args) (apply (if (func? f) (func-fn f) f) |
236 | (if (pair? (cdr args)) | |
237 | (append (butlast args) | |
238 | (->list (mal-value (last args)))) | |
239 | (->list (mal-value (car args))))))) | |
05414421 VS |
240 | (map . ,(lambda (f items) (mal-list (map-in-order |
241 | (if (func? f) (func-fn f) f) | |
242 | (->list (mal-value items)))))) | |
1d117aaf VS |
243 | |
244 | (nil? . ,(lambda (x) (coerce (eq? x mal-nil)))) | |
245 | (true? . ,(lambda (x) (coerce (eq? x mal-true)))) | |
246 | (false? . ,(lambda (x) (coerce (eq? x mal-false)))) | |
7cabea4f | 247 | (number? . ,(lambda (x) (coerce (mal-instance-of? x 'number)))) |
8e53f705 | 248 | (string? . ,(lambda (x) (coerce (mal-instance-of? x 'string)))) |
1d117aaf VS |
249 | (symbol? . ,(lambda (x) (coerce (mal-instance-of? x 'symbol)))) |
250 | (symbol . ,(lambda (x) (mal-symbol (string->symbol (mal-value x))))) | |
251 | (keyword? . ,(lambda (x) (coerce (mal-instance-of? x 'keyword)))) | |
252 | (keyword . ,(lambda (x) (mal-keyword (string->symbol (mal-value x))))) | |
253 | (vector? . ,(lambda (x) (coerce (mal-instance-of? x 'vector)))) | |
254 | (vector . ,(lambda args (mal-vector (list->vector args)))) | |
255 | (map? . ,(lambda (x) (coerce (mal-instance-of? x 'map)))) | |
256 | (hash-map . ,(lambda args (mal-map (list->alist args)))) | |
257 | (sequential? . ,(lambda (x) (coerce (and (mal-object? x) | |
258 | (memq (mal-type x) | |
259 | '(list vector)))))) | |
7cabea4f VS |
260 | (fn? . ,(lambda (x) (coerce (or (procedure? x) |
261 | (and (func? x) (not (func-macro? x))))))) | |
262 | (macro? . ,(lambda (x) (coerce (and (func? x) (func-macro? x))))) | |
1d117aaf VS |
263 | |
264 | (assoc . ,(lambda (m . kvs) (mal-map (mal-map-assoc (mal-value m) kvs)))) | |
265 | (dissoc . ,(lambda (m . keys) (mal-map (mal-map-dissoc (mal-value m) keys)))) | |
266 | (get . ,(lambda (m key) (mal-map-ref key (mal-value m) mal-nil))) | |
267 | (contains? . ,(lambda (m key) (coerce (mal-map-ref key (mal-value m))))) | |
268 | (keys . ,(lambda (m) (mal-list (map car (mal-value m))))) | |
269 | (vals . ,(lambda (m) (mal-list (map cdr (mal-value m))))) | |
270 | ||
8e53f705 VS |
271 | (with-meta . ,(lambda (x meta) |
272 | (cond | |
273 | ((mal-object? x) | |
274 | (make-mal-object (mal-type x) (mal-value x) meta)) | |
275 | ((func? x) | |
276 | (let ((func (make-func (func-ast x) (func-params x) | |
277 | (func-env x) (func-fn x)))) | |
278 | (func-macro?-set! func (func-macro? x)) | |
279 | (func-meta-set! func meta) | |
280 | func)) | |
281 | (else | |
282 | (error "unsupported type"))))) | |
283 | (meta . ,(lambda (x) (cond | |
284 | ((mal-object? x) | |
285 | (or (mal-meta x) mal-nil)) | |
286 | ((func? x) | |
287 | (or (func-meta x) mal-nil)) | |
288 | (else | |
289 | mal-nil)))) | |
290 | ||
1d20dc6b VS |
291 | )) |
292 | ||
293 | ) | |
294 | ||
295 | ) |