2 (:require [mal.readline :as readline]
3 #?(:clj [clojure.repl])
4 [mal.reader :as reader]
5 [mal.printer :as printer]
11 (defn READ [& [strng]]
12 (reader/read-string strng))
18 (defn starts_with [ast sym]
25 acc (qq-iter (rest seq))]
26 (if (starts_with elt 'splice-unquote)
27 (list 'concat (second elt) acc)
28 (list 'cons (quasiquote elt) acc)))))
29 (defn quasiquote [ast]
30 (cond (starts_with ast 'unquote) (second ast)
31 (seq? ast) (qq-iter ast)
32 (vector? ast) (list 'vec (qq-iter ast))
33 (or (symbol? ast) (map? ast)) (list 'quote ast)
36 (defn eval-ast [ast env]
38 (symbol? ast) (env/env-get env ast)
40 (seq? ast) (doall (map #(EVAL % env) ast))
42 (vector? ast) (vec (doall (map #(EVAL % env) ast)))
44 (map? ast) (apply hash-map (doall (map #(EVAL % env)
45 (mapcat identity ast))))
52 ;;(prn "EVAL" ast (keys @env)) (flush)
57 ;; indented to match later steps
58 (let [[a0 a1 a2 a3] ast]
64 (env/env-set env a1 (EVAL a2 env))
67 (let [let-env (env/env env)]
68 (doseq [[b e] (partition 2 a1)]
69 (env/env-set let-env b (EVAL e let-env)))
79 (recur (quasiquote a1) env)
82 (do (eval-ast (->> ast (drop-last) (drop 1)) env)
83 (recur (last ast) env))
86 (let [cond (EVAL a1 env)]
87 (if (or (= cond nil) (= cond false))
96 (EVAL a2 (env/env env a1 (or args '()))))
102 (let [el (eval-ast ast env)
105 {:keys [expression environment parameters]} (meta f)]
107 (recur expression (env/env environment parameters args))
108 (apply f args))))))))
111 (defn PRINT [exp] (printer/pr-str exp))
114 (def repl-env (env/env))
117 (PRINT (EVAL (READ strng) repl-env)))
119 ;; core.clj: defined using Clojure
120 (doseq [[k v] core/core_ns] (env/env-set repl-env k v))
121 (env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
122 (env/env-set repl-env '*ARGV* ())
124 ;; core.mal: defined using the language itself
125 (rep "(def! not (fn* [a] (if a false true)))")
126 (rep "(def! load-file (fn* [f] (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))")
130 (let [line (readline/readline "user> ")]
132 (when-not (re-seq #"^\s*$|^\s*;.*$" line) ; blank/comment
135 #?(:clj (catch Throwable e (clojure.repl/pst e))
136 :cljs (catch js/Error e (println (.-stack e))))))
140 (env/env-set repl-env '*ARGV* (rest args))
142 (rep (str "(load-file \"" (first args) "\")"))