1 ;; -*- lexical-binding: t; -*-
11 (defvar repl-env
(mal-env))
13 (dolist (binding core-ns
)
14 (let ((symbol (car binding
))
16 (mal-env-set repl-env symbol fn
)))
18 (defun starts-with-p (ast sym
)
19 (let ((s (car (mal-value ast
))))
21 (eq (mal-value s
) sym
))))
23 (defun qq-reducer (elt acc
)
24 (mal-list (if (and (mal-list-p elt
)
25 (starts-with-p elt
'splice-unquote
))
26 (list (mal-symbol 'concat
) (cadr (mal-value elt
)) acc
)
27 (list (mal-symbol 'cons
) (quasiquote elt
) acc
))))
30 (cl-reduce 'qq-reducer elts
:from-end t
:initial-value
(mal-list nil
)))
32 (defun quasiquote (ast)
33 (cl-case (mal-type ast
)
34 (list (if (starts-with-p ast
'unquote
)
35 (cadr (mal-value ast
))
36 (qq-iter (mal-value ast
))))
37 (vector (mal-list (list (mal-symbol 'vec
) (qq-iter (mal-value ast
)))))
38 ((map symbol
) (mal-list (list (mal-symbol 'quote
) ast
)))
41 (defun MACROEXPAND (ast env
)
43 (while (and (mal-list-p ast
)
44 (setq a
(mal-value ast
))
47 (setq macro
(mal-env-find env
(mal-value a0
)))
49 (mal-func-macro-p macro
))
50 (setq ast
(apply (mal-value (mal-func-fn macro
)) (cdr a
)))))
59 (when (not (mal-list-p ast
))
60 (throw 'return
(eval-ast ast env
)))
62 (setq ast
(MACROEXPAND ast env
))
63 (when (or (not (mal-list-p ast
)) (not (mal-value ast
)))
64 (throw 'return
(eval-ast ast env
)))
66 (let* ((a (mal-value ast
))
70 (cl-case (mal-value (car a
))
72 (let ((identifier (mal-value a1
))
73 (value (EVAL a2 env
)))
74 (throw 'return
(mal-env-set env identifier value
))))
76 (let ((env* (mal-env env
))
77 (bindings (mal-listify a1
))
80 (let ((key (mal-value (pop bindings
)))
81 (value (EVAL (pop bindings
) env
*)))
82 (mal-env-set env
* key value
)))
88 (throw 'return
(quasiquote a1
)))
90 (setq ast
(quasiquote a1
))) ; TCO
92 (let ((identifier (mal-value a1
))
93 (value (EVAL a2 env
)))
94 (setf (aref (aref value
1) 4) t
)
95 (throw 'return
(mal-env-set env identifier value
))))
97 (throw 'return
(MACROEXPAND a1 env
)))
100 (throw 'return
(EVAL a1 env
))
102 (if (and a2
(eq (mal-value (car (mal-value a2
))) 'catch
*))
103 (let* ((a2* (mal-value a2
))
104 (identifier (mal-value (cadr a2
*)))
106 (err* (if (eq (car err
) 'mal-custom
)
110 (mal-string (error-message-string err
))))
111 (env* (mal-env env
(list identifier
) (list err
*))))
112 (throw 'return
(EVAL form env
*)))
113 (signal (car err
) (cdr err
))))))
115 (let* ((a0...
(cdr a
))
116 (butlast (butlast a0...
))
117 (last (car (last a0...
))))
119 (eval-ast (mal-list butlast
) env
))
120 (setq ast last
))) ; TCO
122 (let* ((condition (EVAL a1 env
))
123 (condition-type (mal-type condition
))
126 (if (and (not (eq condition-type
'false
))
127 (not (eq condition-type
'nil
)))
128 (setq ast then
) ; TCO
130 (setq ast else
) ; TCO
131 (throw 'return mal-nil
)))))
133 (let* ((binds (mapcar 'mal-value
(mal-value a1
)))
137 (let ((env* (mal-env env binds args
)))
138 (EVAL body env
*))))))
139 (throw 'return
(mal-func body binds env fn
))))
141 ;; not a special form
142 (let* ((ast* (mal-value (eval-ast ast env
)))
146 (let ((env* (mal-env (mal-func-env fn
)
150 ast
(mal-func-ast fn
))) ; TCO
152 (let ((fn* (mal-value fn
)))
153 (throw 'return
(apply fn
* args
)))))))))))
155 (defun eval-ast (ast env
)
156 (let ((value (mal-value ast
)))
157 (cl-case (mal-type ast
)
159 (let ((definition (mal-env-get env value
)))
160 (or definition
(error "Definition not found"))))
162 (mal-list (mapcar (lambda (item) (EVAL item env
)) value
)))
164 (mal-vector (vconcat (mapcar (lambda (item) (EVAL item env
)) value
))))
166 (let ((map (copy-hash-table value
)))
167 (maphash (lambda (key val
)
168 (puthash key
(EVAL val env
) map
))
175 (mal-env-set repl-env
'eval
(mal-fn (let ((env repl-env
)) (lambda (form) (EVAL form env
)))))
176 (mal-env-set repl-env
'*ARGV
* (mal-list (mapcar 'mal-string
(cdr argv
))))
177 (mal-env-set repl-env
'*host-language
* (mal-string "elisp"))
183 (PRINT (EVAL (READ input
) repl-env
)))
185 (rep "(def! not (fn* (a) (if a false true)))")
186 (rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))")
187 (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)))))))")
189 (defun readln (prompt)
190 ;; C-d throws an error
191 (ignore-errors (read-from-minibuffer prompt
)))
193 (defun println (format-string &rest args
)
195 (princ format-string
)
196 (princ (apply 'format format-string args
)))
199 (defmacro with-error-handling
(&rest body
)
203 ;; empty input, carry on
205 (unterminated-sequence
206 (princ (format "Expected '%c', got EOF\n"
213 (println (error-message-string err
)))))
218 (rep (format "(load-file \"%s\")" (car argv
))))
220 (rep "(println (str \"Mal [\" *host-language* \"]\"))")
222 (let ((input (readln "user> ")))
225 (println (rep input
)))
227 ;; print final newline