2 (import (scheme write))
3 (import (scheme process-context))
15 (define (eval-ast ast env)
16 (let ((type (and (mal-object? ast) (mal-type ast)))
17 (value (and (mal-object? ast) (mal-value ast))))
19 ((symbol) (env-get env value))
20 ((list) (mal-list (map (lambda (item) (EVAL item env)) value)))
21 ((vector) (mal-vector (vector-map (lambda (item) (EVAL item env)) value)))
22 ((map) (mal-map (alist-map (lambda (key value) (cons key (EVAL value env))) value)))
25 (define (is-pair? ast)
26 (let ((type (and (mal-object? ast) (mal-type ast))))
27 (if (memq type '(list vector))
28 (pair? (->list (mal-value ast)))
31 (define (QUASIQUOTE ast)
32 (if (not (is-pair? ast))
33 (mal-list (list (mal-symbol 'quote) ast))
34 (let* ((items (->list (mal-value ast)))
36 (if (and (mal-object? a0)
37 (eq? (mal-type a0) 'symbol)
38 (eq? (mal-value a0) 'unquote))
40 (if (and (is-pair? a0)
41 (mal-object? (car (mal-value a0)))
42 (eq? (mal-type (car (mal-value a0))) 'symbol)
43 (eq? (mal-value (car (mal-value a0))) 'splice-unquote))
44 (mal-list (list (mal-symbol 'concat)
46 (QUASIQUOTE (mal-list (cdr items)))))
47 (mal-list (list (mal-symbol 'cons)
49 (QUASIQUOTE (mal-list (cdr items))))))))))
51 (define (is-macro-call? ast env)
52 (if (mal-instance-of? ast 'list)
53 (let ((op (car-safe (mal-value ast))))
54 (if (mal-instance-of? op 'symbol)
55 (let ((x (env-find env (mal-value op))))
57 (if (and (func? x) (func-macro? x))
64 (define (macroexpand ast env)
66 (if (is-macro-call? ast env)
67 (let* ((items (mal-value ast))
70 (fn (func-fn (env-get env (mal-value op)))))
71 (loop (apply fn ops)))
74 (define (EVAL ast env)
75 (define (handle-catch value handler)
76 (let* ((symbol (mal-value (cadr handler)))
77 (form (list-ref handler 2))
78 (env* (make-env env (list symbol) (list value))))
80 (let ((type (and (mal-object? ast) (mal-type ast))))
81 (if (not (eq? type 'list))
83 (if (null? (mal-value ast))
85 (let* ((ast (macroexpand ast env))
86 (items (mal-value ast)))
87 (if (not (mal-instance-of? ast 'list))
89 (let ((a0 (car items)))
90 (case (and (mal-object? a0) (mal-value a0))
92 (let ((symbol (mal-value (cadr items)))
93 (value (EVAL (list-ref items 2) env)))
94 (env-set env symbol value)
97 (let ((symbol (mal-value (cadr items)))
98 (value (EVAL (list-ref items 2) env)))
100 (func-macro?-set! value #t))
101 (env-set env symbol value)
104 (macroexpand (cadr items) env))
106 (if (< (length items) 3)
107 (EVAL (cadr items) env)
108 (let* ((form (cadr items))
109 (handler (mal-value (list-ref items 2))))
111 (ex ((error-object? ex)
113 (mal-string (error-object-message ex))
115 ((and (pair? ex) (eq? (car ex) 'user-error))
116 (handle-catch (cdr ex) handler)))
119 (let ((env* (make-env env))
120 (binds (->list (mal-value (cadr items))))
121 (form (list-ref items 2)))
122 (let loop ((binds binds))
124 (let ((key (mal-value (car binds))))
125 (when (null? (cdr binds))
126 (error "unbalanced list"))
127 (let ((value (EVAL (cadr binds) env*)))
128 (env-set env* key value)
129 (loop (cddr binds))))))
130 (EVAL form env*))) ; TCO
132 (let ((forms (cdr items)))
135 ;; the evaluation order of map is unspecified
136 (let loop ((forms forms))
137 (let ((form (car forms))
140 (EVAL form env) ; TCO
145 (let* ((condition (EVAL (cadr items) env))
146 (type (and (mal-object? condition)
147 (mal-type condition))))
148 (if (memq type '(false nil))
149 (if (< (length items) 4)
151 (EVAL (list-ref items 3) env)) ; TCO
152 (EVAL (list-ref items 2) env)))) ; TCO
156 (EVAL (QUASIQUOTE (cadr items)) env)) ; TCO
158 (let* ((binds (->list (mal-value (cadr items))))
159 (binds (map mal-value binds))
160 (body (list-ref items 2))
162 (let ((env* (make-env env binds args)))
164 (make-func body binds env fn)))
166 (let* ((items (mal-value (eval-ast ast env)))
170 (let* ((outer (func-env op))
171 (binds (func-params op))
172 (env* (make-env outer binds ops)))
173 (EVAL (func-ast op) env*)) ; TCO
174 (apply op ops))))))))))))
179 (define repl-env (make-env #f))
180 (for-each (lambda (kv) (env-set repl-env (car kv) (cdr kv))) ns)
183 (PRINT (EVAL (READ input) repl-env)))
185 (define args (cdr (command-line)))
187 (env-set repl-env 'eval (lambda (ast) (EVAL ast repl-env)))
188 (env-set repl-env '*ARGV* (mal-list (map mal-string (cdr-safe args))))
190 (rep "(def! not (fn* (a) (if a false true)))")
191 (rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
193 (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)))))))")
194 (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))))))))")
199 (let ((input (readline "user> ")))
202 (ex ((error-object? ex)
203 (when (not (memv 'empty-input (error-object-irritants ex)))
205 (display (error-object-message ex))
207 ((and (pair? ex) (eq? (car ex) 'user-error))
209 (display (pr-str (cdr ex) #t))
211 (display (rep input))
218 (rep (string-append "(load-file \"" (car args) "\")")))