Merge pull request #420 from asarhaddon/load-file-once
[jackhill/mal.git] / guile / core.scm
CommitLineData
be17d0a6
NG
1;; Copyright (C) 2015
2;; "Mu Lei" known as "NalaGinrut" <NalaGinrut@gmail.com>
3;; This file is free software: you can redistribute it and/or modify
4;; it under the terms of the GNU General Public License as published by
5;; the Free Software Foundation, either version 3 of the License, or
6;; (at your option) any later version.
7
8;; This file is distributed in the hope that it will be useful,
9;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11;; GNU General Public License for more details.
12
13;; You should have received a copy of the GNU General Public License
14;; along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16(library (core)
5835f45b 17 (export core.ns ->list)
9f3c0995 18 (import (guile) (rnrs) (types) (reader) (printer) (ice-9 match) (readline)))
5835f45b
NG
19
20(define (->list o) ((if (vector? o) vector->list identity) o))
be17d0a6
NG
21
22(define (_count obj)
23 (cond
24 ((_nil? obj) 0)
25 ((vector? obj) (vector-length obj))
26 (else (length obj))))
27
28(define (_empty? obj) (zero? (_count obj)))
29
dc656104
NG
30;; Well, strange spec...
31(define (_equal? o1 o2)
d5995c72
DM
32 (define (equal-lists? lst1 lst2)
33 (and (= (length lst1) (length lst2))
34 (for-all _equal? lst1 lst2)))
35 (define (equal-hash-tables? ht1 ht2)
36 (define (equal-values? k)
37 (_equal? (_get ht1 k) (_get ht2 k)))
38 (let ((keys1 (_keys ht1)))
39 (and (= (length keys1) (length (_keys ht2)))
40 (for-all equal-values? keys1))))
41 (cond
42 ((and (_sequential? o1) (_sequential? o2))
43 (equal-lists? (->list o1) (->list o2)))
44 ((and (hash-table? o1) (hash-table? o2))
45 (equal-hash-tables? o1 o2))
46 (else
47 (equal? o1 o2))))
dc656104 48
be17d0a6
NG
49(define (pr-str . args)
50 (define (pr x) (pr_str x #t))
51 (string-join (map pr args) " "))
52
dc656104
NG
53(define (str . args)
54 (define (pr x) (pr_str x #f))
55 (string-join (map pr args) ""))
56
57(define (prn . args)
58 (format #t "~a~%" (apply pr-str args))
98cd78e4 59 nil)
dc656104
NG
60
61(define (println . args)
62 (define (pr x) (pr_str x #f))
98cd78e4 63 (format #t "~{~a~^ ~}~%" (map pr args))
dc656104
NG
64 nil)
65
f040d9fb
NG
66(define (slurp filename)
67 (when (not (file-exists? filename))
0d9fb576 68 (throw 'mal-error (format #f "File/dir '~a' doesn't exist" filename)))
f040d9fb
NG
69 (call-with-input-file filename get-string-all))
70
5835f45b
NG
71(define (_cons x y)
72 (cons x (->list y)))
73
74(define (concat . args)
75 (apply append (map ->list args)))
76
e658ffd2
NG
77(define (_nth lst n)
78 (define ll (->list lst))
79 (when (>= n (length ll))
80 (throw 'mal-error "nth: index out of range"))
81 (list-ref ll n))
82
83(define (_first lst)
84 (define ll (->list lst))
75048743
DM
85 (cond
86 ((_nil? lst) nil)
87 ((null? ll) nil)
88 (else (car ll))))
e658ffd2
NG
89
90(define (_rest lst)
91 (define ll (->list lst))
75048743
DM
92 (cond
93 ((_nil? lst) '())
94 ((null? ll) '())
95 (else (cdr ll))))
e658ffd2 96
98cd78e4
NG
97(define (_map f lst) (map (callable-closure f) (->list lst)))
98
99(define (_apply f . args)
100 (define ll
10bc1bce 101 (let lp((next args) (ret '()))
98cd78e4
NG
102 (cond
103 ((null? next) (reverse ret))
104 (else
105 (let ((n (->list (car next))))
106 (lp (cdr next) (if (list? n)
107 (append (reverse n) ret)
108 (cons n ret))))))))
a6e59cf3 109 (callable-apply f ll))
98cd78e4
NG
110
111(define (->symbol x)
112 ((if (symbol? x) identity string->symbol) x))
113
114(define (->keyword x)
115 ((if (_keyword? x) identity string->keyword) x))
116
98cd78e4
NG
117(define (_hash-map . lst) (list->hash-map lst))
118
119(define (_assoc ht . lst) (list->hash-map lst (hash-table-clone ht)))
120
121(define (_get ht k)
122 (if (_nil? ht)
123 nil
124 (hash-ref ht k nil)))
125
126(define (_dissoc ht . lst)
127 (define ht2 (hash-table-clone ht))
128 (for-each (lambda (k) (hash-remove! ht2 k)) lst)
129 ht2)
130
131(define (_keys ht) (hash-map->list (lambda (k v) k) ht))
132
133(define (_vals ht) (hash-map->list (lambda (k v) v) ht))
134
1c90c506
NG
135(define (_contains? ht k)
136 (let ((v (hash-ref ht k '*mal-null*)))
137 (if (eq? v '*mal-null*)
138 #f
139 #t)))
98cd78e4
NG
140
141(define (_sequential? o) (or (list? o) (vector? o)))
142
9f3c0995
NG
143(define (_meta c)
144 (if (callable? c)
145 (callable-meta-info c)
2a80d367 146 (or (object-property c 'meta) nil)))
9f3c0995
NG
147
148(define (_with-meta c ht)
149 (cond
150 ((callable? c)
151 (let ((cc (make-callable ht
152 (callable-unbox c)
aac5cf7b 153 #f
9f3c0995
NG
154 (callable-closure c))))
155 cc))
156 (else
157 (let ((cc (box c)))
2a80d367 158 (set-object-property! cc 'meta ht)
9f3c0995
NG
159 cc))))
160
161;; Apply closure 'c' with atom-val as one of arguments, then
162;; set the result as the new val of atom.
163(define (_swap! atom c . rest)
164 (let* ((args (cons (atom-val atom) rest))
165 (val (callable-apply c args)))
166 (atom-val-set! atom val)
167 val))
168
169(define (_conj lst . args)
170 (cond
171 ((vector? lst)
172 (list->vector (append (->list lst) args)))
173 ((list? lst)
174 (append (reverse args) (->list lst)))
175 (else (throw 'mal-error (format #f "conj: '~a' is not list/vector" lst)))))
176
4e6ae3b7
DM
177(define (_seq obj)
178 (cond
179 ((_nil? obj) nil)
180 ((_string? obj)
181 (if (string-null? obj) nil (map string (string->list obj))))
182 ((_empty? obj) nil)
183 (else (->list obj))))
184
0d9fb576
NG
185(define (__readline prompt)
186 (let ((str (_readline prompt)))
187 (if (eof-object? str)
188 #f
189 str)))
190
2a80d367
NG
191(define (_true? x) (eq? x #t))
192(define (_false? x) (eq? x #f))
193
194;; We need regular named procedure for better debug
195(define (_atom x) (make-atom x))
196(define (_atom? x) (atom? x))
197(define (_deref x) (atom-val x))
198(define (_reset! x v) (atom-val-set! x v))
199
4b3eaa74
NG
200(define (time-ms)
201 (let ((t (gettimeofday)))
202 (round
203 (+ (* (car t) 1000.0) (/ (cdr t) 1000.0) 0.5))))
204
be17d0a6 205(define *primitives*
f040d9fb
NG
206 `((list ,list)
207 (list? ,list?)
208 (empty? ,_empty?)
209 (count ,_count)
210 (= ,_equal?)
211 (< ,<)
212 (<= ,<=)
213 (> ,>)
214 (>= ,>=)
215 (+ ,+)
216 (- ,-)
217 (* ,*)
218 (/ ,/)
f040d9fb
NG
219 (pr-str ,pr-str)
220 (str ,str)
221 (prn ,prn)
222 (println ,println)
223 (read-string ,read_str)
224 (slurp ,slurp)
5835f45b
NG
225 (cons ,_cons)
226 (concat ,concat)
e658ffd2
NG
227 (nth ,_nth)
228 (first ,_first)
229 (rest ,_rest)
98cd78e4
NG
230 (map ,_map)
231 (apply ,_apply)
232 (nil? ,_nil?)
2a80d367
NG
233 (true? ,_true?)
234 (false? ,_false?)
85657c96 235 (number? ,number?)
98cd78e4
NG
236 (symbol? ,symbol?)
237 (symbol ,->symbol)
4e6ae3b7 238 (string? ,_string?)
98cd78e4
NG
239 (keyword ,->keyword)
240 (keyword? ,_keyword?)
241 (vector? ,vector?)
242 (vector ,vector)
243 (hash-map ,_hash-map)
244 (map? ,hash-table?)
245 (assoc ,_assoc)
246 (get ,_get)
247 (dissoc ,_dissoc)
248 (keys ,_keys)
249 (vals ,_vals)
250 (contains? ,_contains?)
251 (sequential? ,_sequential?)
85657c96
VS
252 (fn? ,is-func?)
253 (macro? ,is-macro?)
0d9fb576 254 (readline ,__readline)
9f3c0995
NG
255 (meta ,_meta)
256 (with-meta ,_with-meta)
2a80d367
NG
257 (atom ,_atom)
258 (atom? ,_atom?)
259 (deref ,_deref)
260 (reset! ,_reset!)
9f3c0995 261 (swap! ,_swap!)
2f60d14c 262 (conj ,_conj)
4e6ae3b7 263 (seq ,_seq)
4b3eaa74 264 (time-ms ,time-ms)))
be17d0a6
NG
265
266;; Well, we have to rename it to this strange name...
267(define core.ns *primitives*)