Merge pull request #358 from bjh21/bjh21-extra-tests
[jackhill/mal.git] / elisp / step8_macros.el
CommitLineData
1249126b
VS
1;; -*- lexical-binding: t; -*-
2
c2b12e5b
VS
3(require 'mal/types)
4(require 'mal/func)
5(require 'mal/env)
6(require 'mal/reader)
7(require 'mal/printer)
8(require 'mal/core)
1249126b
VS
9
10(defvar repl-env (mal-env))
11
12(dolist (binding core-ns)
13 (let ((symbol (car binding))
14 (fn (cdr binding)))
15 (mal-env-set repl-env symbol fn)))
16
17(defun mal-pair-p (mal-object)
18 (let ((type (mal-type mal-object))
19 (value (mal-value mal-object)))
20 (if (and (or (eq type 'list) (eq type 'vector))
21 (not (zerop (length value))))
22 t
23 nil)))
24
25(defun quasiquote (ast)
26 (if (not (mal-pair-p ast))
27 (mal-list (list (mal-symbol 'quote) ast))
4e1479b2 28 (let* ((a (mal-listify ast))
1249126b
VS
29 (a0 (car a))
30 (a0... (cdr a))
31 (a1 (cadr a)))
32 (cond
33 ((eq (mal-value a0) 'unquote)
34 a1)
35 ((and (mal-pair-p a0)
36 (eq (mal-value (car (mal-value a0)))
37 'splice-unquote))
38 (mal-list (list (mal-symbol 'concat)
39 (cadr (mal-value a0))
40 (quasiquote (mal-list a0...)))))
41 (t
42 (mal-list (list (mal-symbol 'cons)
43 (quasiquote a0)
44 (quasiquote (mal-list a0...)))))))))
45
46(defun macro-call-p (ast env)
47 (when (mal-list-p ast)
48 (let ((a0 (car (mal-value ast))))
49 (when (mal-symbol-p a0)
50 (let ((value (mal-env-find env (mal-value a0))))
51 (when (and (mal-func-p value)
52 (mal-func-macro-p value))
53 t))))))
54
55(defun MACROEXPAND (ast env)
56 (while (macro-call-p ast env)
57 (let* ((a (mal-value ast))
58 (a0* (mal-value (car a)))
59 (a0... (cdr a))
60 (macro (mal-env-find env a0*)))
61 (setq ast (apply (mal-value (mal-func-fn macro)) a0...))))
62 ast)
63
64(defun READ (input)
65 (read-str input))
66
67(defun EVAL (ast env)
68 (catch 'return
69 (while t
70 (when (not (mal-list-p ast))
71 (throw 'return (eval-ast ast env)))
72
73 (setq ast (MACROEXPAND ast env))
ecb8de2d 74 (when (or (not (mal-list-p ast)) (not (mal-value ast)))
1249126b
VS
75 (throw 'return (eval-ast ast env)))
76
77 (let* ((a (mal-value ast))
78 (a0 (car a))
79 (a0* (mal-value a0))
80 (a1 (cadr a))
81 (a2 (nth 2 a))
82 (a3 (nth 3 a)))
83 (cond
84 ((eq a0* 'def!)
85 (let* ((identifier (mal-value a1))
86 (value (EVAL a2 env)))
87 (throw 'return (mal-env-set env identifier value))))
88 ((eq a0* 'let*)
89 (let* ((env* (mal-env env))
90 (bindings (mal-value a1))
91 (form a2))
92 (when (vectorp bindings)
93 (setq bindings (append bindings nil)))
94 (while bindings
95 (let ((key (mal-value (pop bindings)))
96 (value (EVAL (pop bindings) env*)))
97 (mal-env-set env* key value)))
98 (setq env env*
99 ast form))) ; TCO
100 ((eq a0* 'quote)
101 (throw 'return a1))
102 ((eq a0* 'quasiquote)
103 (setq ast (quasiquote a1))) ; TCO
104 ((eq a0* 'defmacro!)
105 (let ((identifier (mal-value a1))
106 (value (EVAL a2 env)))
107 (setf (aref (aref value 1) 4) t)
108 (throw 'return (mal-env-set env identifier value))))
109 ((eq a0* 'macroexpand)
110 (throw 'return (MACROEXPAND a1 env)))
111 ((eq a0* 'do)
112 (let* ((a0... (cdr a))
113 (butlast (butlast a0...))
114 (last (car (last a0...))))
115 (when butlast
116 (eval-ast (mal-list butlast) env))
117 (setq ast last))) ; TCO
118 ((eq a0* 'if)
119 (let* ((condition (EVAL a1 env))
120 (condition-type (mal-type condition))
121 (then a2)
122 (else a3))
123 (if (and (not (eq condition-type 'false))
124 (not (eq condition-type 'nil)))
125 (setq ast then) ; TCO
126 (if else
127 (setq ast else) ; TCO
c347c874 128 (throw 'return mal-nil)))))
1249126b
VS
129 ((eq a0* 'fn*)
130 (let* ((binds (mapcar 'mal-value (mal-value a1)))
131 (body a2)
132 (fn (mal-fn
133 (lambda (&rest args)
134 (let ((env* (mal-env env binds args)))
135 (EVAL body env*))))))
136 (throw 'return (mal-func body binds env fn))))
137 (t
138 ;; not a special form
139 (let* ((ast* (mal-value (eval-ast ast env)))
140 (fn (car ast*))
141 (args (cdr ast*)))
142 (if (mal-func-p fn)
143 (let ((env* (mal-env (mal-func-env fn)
144 (mal-func-params fn)
145 args)))
146 (setq env env*
147 ast (mal-func-ast fn))) ; TCO
148 ;; built-in function
149 (let ((fn* (mal-value fn)))
150 (throw 'return (apply fn* args)))))))))))
151
152(defun eval-ast (ast env)
153 (let ((type (mal-type ast))
154 (value (mal-value ast)))
155 (cond
156 ((eq type 'symbol)
157 (let ((definition (mal-env-get env value)))
158 (or definition (error "Definition not found"))))
159 ((eq type 'list)
160 (mal-list (mapcar (lambda (item) (EVAL item env)) value)))
161 ((eq type 'vector)
162 (mal-vector (vconcat (mapcar (lambda (item) (EVAL item env)) value))))
163 ((eq type 'map)
164 (let ((map (copy-hash-table value)))
165 (maphash (lambda (key value)
166 (puthash key (EVAL value env) map))
167 map)
168 (mal-map map)))
169 (t
170 ;; return as is
171 ast))))
172
173(mal-env-set repl-env 'eval (mal-fn (let ((env repl-env)) (lambda (form) (EVAL form env)))))
7bc8987a 174(mal-env-set repl-env '*ARGV* (mal-list (mapcar 'mal-string (cdr argv))))
1249126b
VS
175
176(defun PRINT (input)
177 (pr-str input t))
178
179(defun rep (input)
180 (PRINT (EVAL (READ input) repl-env)))
181
182(rep "(def! not (fn* (a) (if a false true)))")
183(rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
184
185(rep "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
186(rep "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))")
187
188(defun readln (prompt)
189 ;; C-d throws an error
190 (ignore-errors (read-from-minibuffer prompt)))
191
192(defun println (format-string &rest args)
193 (if (not args)
194 (princ format-string)
195 (princ (apply 'format format-string args)))
196 (terpri))
197
198(defmacro with-error-handling (&rest body)
199 `(condition-case err
200 (progn ,@body)
201 (end-of-token-stream
202 ;; empty input, carry on
203 )
204 (unterminated-sequence
205 (let* ((type (cadr err))
206 (end
207 (cond
208 ((eq type 'string) ?\")
209 ((eq type 'list) ?\))
210 ((eq type 'vector) ?\])
211 ((eq type 'map) ?}))))
212 (princ (format "Expected '%c', got EOF\n" end))))
213 (error ; catch-all
214 (println (error-message-string err)))))
215
216(defun main ()
217 (if argv
218 (with-error-handling
219 (rep (format "(load-file \"%s\")" (car argv))))
220 (let (eof)
221 (while (not eof)
222 (let ((input (readln "user> ")))
223 (if input
224 (with-error-handling
225 (println (rep input)))
226 (setq eof t)
227 ;; print final newline
228 (terpri)))))))
229
230(main)