1 ;; -*- lexical-binding: t; -*-
3 (defun load-relative (file)
4 (let* ((current-file (or load-file-name buffer-file-name
))
5 (current-file-directory (file-name-directory current-file
)))
6 (load (expand-file-name file current-file-directory
) nil t
)))
8 (load-relative "types.el")
9 (load-relative "env.el")
10 (load-relative "func.el")
11 (load-relative "reader.el")
12 (load-relative "printer.el")
13 (load-relative "core.el")
15 (defvar repl-env
(mal-env))
17 (dolist (binding core-ns
)
18 (let ((symbol (car binding
))
20 (mal-env-set repl-env symbol fn
)))
22 (defun mal-pair-p (mal-object)
23 (let ((type (mal-type mal-object
))
24 (value (mal-value mal-object
)))
25 (if (and (or (eq type
'list
) (eq type
'vector
))
26 (not (zerop (length value
))))
30 (defun quasiquote (ast)
31 (if (not (mal-pair-p ast
))
32 (mal-list (list (mal-symbol 'quote
) ast
))
33 (let* ((a (mal-listify ast
))
38 ((eq (mal-value a0
) 'unquote
)
41 (eq (mal-value (car (mal-value a0
)))
43 (mal-list (list (mal-symbol 'concat
)
45 (quasiquote (mal-list a0...
)))))
47 (mal-list (list (mal-symbol 'cons
)
49 (quasiquote (mal-list a0...
)))))))))
51 (defun macro-call-p (ast env
)
52 (when (mal-list-p ast
)
53 (let ((a0 (car (mal-value ast
))))
54 (when (mal-symbol-p a0
)
55 (let ((value (mal-env-find env
(mal-value a0
))))
56 (when (and (mal-func-p value
)
57 (mal-func-macro-p value
))
60 (defun MACROEXPAND (ast env
)
61 (while (macro-call-p ast env
)
62 (let* ((a (mal-value ast
))
63 (a0* (mal-value (car a
)))
65 (macro (mal-env-find env a0
*)))
66 (setq ast
(apply (mal-value (mal-func-fn macro
)) a0...
))))
75 (when (not (mal-list-p ast
))
76 (throw 'return
(eval-ast ast env
)))
78 (setq ast
(MACROEXPAND ast env
))
79 (when (or (not (mal-list-p ast
)) (not (mal-value ast
)))
80 (throw 'return
(eval-ast ast env
)))
82 (let* ((a (mal-value ast
))
90 (let* ((identifier (mal-value a1
))
91 (value (EVAL a2 env
)))
92 (throw 'return
(mal-env-set env identifier value
))))
94 (let* ((env* (mal-env env
))
95 (bindings (mal-value a1
))
97 (when (vectorp bindings
)
98 (setq bindings
(append bindings nil
)))
100 (let ((key (mal-value (pop bindings
)))
101 (value (EVAL (pop bindings
) env
*)))
102 (mal-env-set env
* key value
)))
107 ((eq a0
* 'quasiquote
)
108 (setq ast
(quasiquote a1
))) ; TCO
110 (let ((identifier (mal-value a1
))
111 (value (EVAL a2 env
)))
112 (setf (aref (aref value
1) 4) t
)
113 (throw 'return
(mal-env-set env identifier value
))))
114 ((eq a0
* 'macroexpand
)
115 (throw 'return
(MACROEXPAND a1 env
)))
118 (throw 'return
(EVAL a1 env
))
120 (if (and a2
(eq (mal-value (car (mal-value a2
))) 'catch
*))
121 (let* ((a2* (mal-value a2
))
122 (identifier (mal-value (cadr a2
*)))
124 (err* (if (eq (car err
) 'mal-custom
)
128 (mal-string (error-message-string err
))))
129 (env* (mal-env env
(list identifier
) (list err
*))))
130 (throw 'return
(EVAL form env
*)))
131 (apply 'signal err
)))))
133 (let* ((a0...
(cdr a
))
134 (butlast (butlast a0...
))
135 (last (car (last a0...
))))
137 (eval-ast (mal-list butlast
) env
))
138 (setq ast last
))) ; TCO
140 (let* ((condition (EVAL a1 env
))
141 (condition-type (mal-type condition
))
144 (if (and (not (eq condition-type
'false
))
145 (not (eq condition-type
'nil
)))
146 (setq ast then
) ; TCO
148 (setq ast else
) ; TCO
149 (throw 'return mal-nil
)))))
151 (let* ((binds (mapcar 'mal-value
(mal-value a1
)))
155 (let ((env* (mal-env env binds args
)))
156 (EVAL body env
*))))))
157 (throw 'return
(mal-func body binds env fn
))))
159 ;; not a special form
160 (let* ((ast* (mal-value (eval-ast ast env
)))
164 (let ((env* (mal-env (mal-func-env fn
)
168 ast
(mal-func-ast fn
))) ; TCO
170 (let ((fn* (mal-value fn
)))
171 (throw 'return
(apply fn
* args
)))))))))))
173 (defun eval-ast (ast env
)
174 (let ((type (mal-type ast
))
175 (value (mal-value ast
)))
178 (let ((definition (mal-env-get env value
)))
179 (or definition
(error "Definition not found"))))
181 (mal-list (mapcar (lambda (item) (EVAL item env
)) value
)))
183 (mal-vector (vconcat (mapcar (lambda (item) (EVAL item env
)) value
))))
185 (let ((map (copy-hash-table value
)))
186 (maphash (lambda (key value
)
187 (puthash key
(EVAL value env
) map
))
194 (mal-env-set repl-env
'eval
(mal-fn (let ((env repl-env
)) (lambda (form) (EVAL form env
)))))
195 (mal-env-set repl-env
'*ARGV
* (mal-list (mapcar 'mal-string
(cdr argv
))))
196 (mal-env-set repl-env
'*host-language
* (mal-string "elisp"))
202 (PRINT (EVAL (READ input
) repl-env
)))
204 (rep "(def! not (fn* (a) (if a false true)))")
205 (rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
207 (rep "(def! *gensym-counter* (atom 0))")
208 (rep "(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))")
210 (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)))))))")
211 (rep "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))")
213 (defun readln (prompt)
214 ;; C-d throws an error
215 (ignore-errors (read-from-minibuffer prompt
)))
217 (defun println (format-string &rest args
)
219 (princ format-string
)
220 (princ (apply 'format format-string args
)))
223 (defmacro with-error-handling
(&rest body
)
227 ;; empty input, carry on
229 (unterminated-sequence
230 (let* ((type (cadr err
))
233 ((eq type
'string
) ?
\")
234 ((eq type
'list
) ?\
))
235 ((eq type
'vector
) ?\
])
236 ((eq type
'map
) ?
}))))
237 (princ (format "Expected '%c', got EOF\n" end
))))
239 (println (error-message-string err
)))))
244 (rep (format "(load-file \"%s\")" (car argv
))))
246 (rep "(println (str \"Mal [\" *host-language* \"]\"))")
248 (let ((input (readln "user> ")))
251 (println (rep input
)))
253 ;; print final newline