17 (define-condition invalid-function
(types:mal-error
)
18 ((form :initarg
:form
:reader form
)
19 (context :initarg
:context
:reader context
))
20 (:report
(lambda (condition stream
)
22 "Invalid function '~a' provided while ~a"
23 (printer:pr-str
(form condition
))
24 (if (string= (context condition
) "apply")
28 (defvar *repl-env
* (make-instance 'env
:mal-environment
))
30 (dolist (binding core
:ns
)
31 (env:set-env
*repl-env
*
35 (env:set-env
*repl-env
*
36 (types:make-mal-symbol
'|eval|
)
37 (types:make-mal-builtin-fn
(lambda (ast)
38 (mal-eval ast
*repl-env
*))))
40 (defun eval-sequence (sequence env
)
42 (lambda (ast) (mal-eval ast env
))
43 (mal-value sequence
)))
45 (defun eval-hash-map (hash-map env
)
46 (let ((hash-map-value (mal-value hash-map
))
47 (new-hash-table (make-hash-table :test
'types
:mal-value
=)))
49 for key being the hash-keys of hash-map-value
50 do
(setf (gethash (mal-eval key env
) new-hash-table
)
51 (mal-eval (gethash key hash-map-value
) env
)))
52 (make-mal-hash-map new-hash-table
)))
54 (defun eval-ast (ast env
)
56 (types:symbol
(env:get-env env ast
))
57 (types:list
(eval-sequence ast env
))
58 (types:vector
(make-mal-vector (apply 'vector
(eval-sequence ast env
))))
59 (types:hash-map
(eval-hash-map ast env
))
62 (defun is-pair (value)
63 (and (or (mal-list-p value
)
65 (not (zerop (length (mal-value value
))))))
67 (defun quasiquote (ast)
68 (if (not (is-pair ast
))
69 (types:make-mal-list
(list (types:make-mal-symbol
'|quote|
)
71 (let ((forms (map 'list
#'identity
(mal-value ast
))))
73 ((mal-value= (make-mal-symbol '|unquote|
) (first forms
))
76 ((and (is-pair (first forms
))
77 (mal-value= (make-mal-symbol '|splice-unquote|
)
78 (first (mal-value (first forms
)))))
79 (types:make-mal-list
(list (types:make-mal-symbol
'|concat|
)
80 (second (mal-value (first forms
)))
81 (quasiquote (make-mal-list (cdr forms
))))))
83 (t (types:make-mal-list
(list (types:make-mal-symbol
'|cons|
)
84 (quasiquote (first forms
))
85 (quasiquote (make-mal-list (cdr forms
))))))))))
87 (defun is-macro-call (ast env
)
88 (when (and (types:mal-list-p ast
)
89 (not (zerop (length (mal-value ast
)))))
90 (let* ((func-symbol (first (mal-value ast
)))
91 (func (when (types:mal-symbol-p func-symbol
)
92 (ignore-errors (env:get-env env func-symbol
)))))
95 (cdr (assoc 'is-macro
(types:mal-attrs func
)))))))
97 (defun mal-macroexpand (ast env
)
99 while
(is-macro-call ast env
)
100 do
(let* ((forms (types:mal-value ast
))
101 (func (env:get-env env
(first forms
))))
102 (setf ast
(apply (mal-value func
)
106 (defun mal-eval (ast env
)
108 do
(setf ast
(mal-macroexpand ast env
))
110 ((null ast
) (return (make-mal-nil nil
)))
111 ((not (types:mal-list-p ast
)) (return (eval-ast ast env
)))
112 ((zerop (length (mal-value ast
))) (return ast
))
113 (t (let ((forms (mal-value ast
)))
115 ((mal-value= (make-mal-symbol '|quote|
) (first forms
))
116 (return (second forms
)))
118 ((mal-value= (make-mal-symbol '|quasiquote|
) (first forms
))
119 (setf ast
(quasiquote (second forms
))))
121 ((mal-value= (make-mal-symbol '|macroexpand|
) (first forms
))
122 (return (mal-macroexpand (second forms
) env
)))
124 ((mal-value= (make-mal-symbol '|def
!|
) (first forms
))
125 (return (env:set-env env
(second forms
) (mal-eval (third forms
) env
))))
127 ((mal-value= (make-mal-symbol '|defmacro
!|
) (first forms
))
128 (let ((value (mal-eval (third forms
) env
)))
129 (return (if (types:mal-fn-p value
)
133 (setf (cdr (assoc 'is-macro
(types:mal-attrs value
))) t
)
135 (error 'invalid-function
137 :context
"macro")))))
139 ((mal-value= (make-mal-symbol '|let
*|
) (first forms
))
140 (let ((new-env (make-instance 'env
:mal-environment
142 ;; Convert a potential vector to a list
145 (mal-value (second forms
)))))
147 (mapcar (lambda (binding)
150 (mal-eval (or (cdr binding
)
151 (types:make-mal-nil nil
))
154 for
(symbol value
) on bindings
156 collect
(cons symbol value
)))
157 (setf ast
(third forms
)
160 ((mal-value= (make-mal-symbol '|do|
) (first forms
))
161 (mapc (lambda (form) (mal-eval form env
))
162 (butlast (cdr forms
)))
163 (setf ast
(car (last forms
))))
165 ((mal-value= (make-mal-symbol '|if|
) (first forms
))
166 (let ((predicate (mal-eval (second forms
) env
)))
167 (setf ast
(if (or (mal-value= predicate
(types:make-mal-nil nil
))
168 (mal-value= predicate
(types:make-mal-boolean nil
)))
172 ((mal-value= (make-mal-symbol '|fn
*|
) (first forms
))
173 (return (let ((arglist (second forms
))
174 (body (third forms
)))
175 (types:make-mal-fn
(lambda (&rest args
)
176 (mal-eval body
(make-instance 'env
:mal-environment
182 :attrs
(list (cons 'params arglist
)
185 (cons 'is-macro nil
))))))
187 (t (let* ((evaluated-list (eval-ast ast env
))
188 (function (car evaluated-list
)))
189 ;; If first element is a mal function unwrap it
190 (cond ((types:mal-fn-p function
)
191 (let* ((attrs (types:mal-attrs function
)))
192 (setf ast
(cdr (assoc 'ast attrs
))
193 env
(make-instance 'env
:mal-environment
194 :parent
(cdr (assoc 'env attrs
))
197 (mal-value (cdr (assoc 'params attrs
))))
198 :exprs
(cdr evaluated-list
)))))
199 ((types:mal-builtin-fn-p function
)
200 (return (apply (mal-value function
)
201 (cdr evaluated-list
))))
202 (t (error 'invalid-function
204 :context
"apply")))))))))))
206 (defun mal-read (string)
207 (reader:read-str string
))
209 (defun mal-print (expression)
210 (printer:pr-str expression
))
214 (mal-print (mal-eval (mal-read string
)
216 (types:mal-error
(condition)
225 (rep "(def! not (fn* (a) (if a false true)))")
226 (rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
227 (rep "(def! *ARGV* (list))")
228 (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)))))))")
229 (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))))))))")
231 (defun readline (prompt &optional
(in-stream *standard-input
*) (out-stream *standard-output
*))
232 (format out-stream prompt
)
233 (force-output out-stream
)
234 (read-line in-stream nil
))
236 (defun writeline (string)
238 (write-line string
)))
241 (loop do
(let ((line (readline "user> ")))
242 (if line
(writeline (rep line
)) (return)))))
244 (env:set-env
*repl-env
*
245 (types:make-mal-symbol
'|
*ARGV
*|
)
246 (types:wrap-value
(cdr common-lisp-user
::*args
*)
249 (if (null common-lisp-user
::*args
*)
253 (car common-lisp-user
::*args
*))))