All: *ARGV* and *host-language*. Misc syncing/fixes.
[jackhill/mal.git] / clojure / src / step6_file.clj
CommitLineData
31690700
JM
1(ns step6-file
2 (:require [clojure.repl]
31690700 3 [readline]
ea81a808
JM
4 [reader]
5 [printer]
6 [env]
7 [core]))
31690700
JM
8
9;; read
10(defn READ [& [strng]]
11 (let [line (if strng strng (read-line))]
12 (reader/read-string strng)))
13
14;; eval
ea81a808 15(declare EVAL)
31690700
JM
16(defn eval-ast [ast env]
17 (cond
ea81a808 18 (symbol? ast) (env/env-get env ast)
31690700
JM
19
20 (seq? ast) (doall (map #(EVAL % env) ast))
21
22 (vector? ast) (vec (doall (map #(EVAL % env) ast)))
23
24 (map? ast) (apply hash-map (doall (map #(EVAL % env)
25 (mapcat identity ast))))
26
27 :else ast))
28
29(defn EVAL [ast env]
30 (loop [ast ast
31 env env]
32 ;;(prn "EVAL" ast (keys @env)) (flush)
33 (if (not (seq? ast))
34 (eval-ast ast env)
35
36 ;; apply list
37 (let [[a0 a1 a2 a3] ast]
38 (condp = a0
39 'def!
ea81a808 40 (env/env-set env a1 (EVAL a2 env))
31690700
JM
41
42 'let*
ea81a808 43 (let [let-env (env/env env)]
31690700 44 (doseq [[b e] (partition 2 a1)]
ea81a808 45 (env/env-set let-env b (EVAL e let-env)))
31690700
JM
46 (EVAL a2 let-env))
47
48 'do
49 (do (eval-ast (->> ast (drop-last) (drop 1)) env)
50 (recur (last ast) env))
51
52 'if
53 (let [cond (EVAL a1 env)]
54 (if (or (= cond nil) (= cond false))
55 (if (> (count ast) 2)
56 (recur a3 env)
57 nil)
58 (recur a2 env)))
59
60 'fn*
a34b0200
JM
61 (with-meta
62 (fn [& args]
63 (EVAL a2 (env/env env a1 args)))
64 {:expression a2
65 :environment env
66 :parameters a1})
31690700
JM
67
68 ;; apply
69 (let [el (eval-ast ast env)
70 f (first el)
71 args (rest el)
72 {:keys [expression environment parameters]} (meta f)]
73 (if expression
ea81a808 74 (recur expression (env/env environment parameters args))
31690700
JM
75 (apply f args))))))))
76
77;; print
78(defn PRINT [exp] (pr-str exp))
79
80;; repl
ea81a808 81(def repl-env (env/env))
31690700
JM
82(defn rep
83 [strng]
ea81a808 84 (PRINT (EVAL (READ strng) repl-env)))
31690700 85
8cb5cda4
JM
86;; core.clj: defined using Clojure
87(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
88(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
86b689f3 89(env/env-set repl-env '*ARGV* ())
31690700 90
8cb5cda4 91;; core.mal: defined using the language itself
31690700 92(rep "(def! not (fn* [a] (if a false true)))")
1617910a 93(rep "(def! load-file (fn* [f] (eval (read-string (str \"(do \" (slurp f) \")\")))))")
31690700 94
86b689f3
JM
95;; repl loop
96(defn repl-loop []
97 (let [line (readline/readline "user> ")]
98 (when line
99 (when-not (re-seq #"^\s*$|^\s*;.*$" line) ; blank/comment
100 (try
101 (println (rep line))
102 (catch Throwable e
103 (clojure.repl/pst e))))
104 (recur))))
105
31690700 106(defn -main [& args]
86b689f3 107 (env/env-set repl-env '*ARGV* (rest args))
31690700
JM
108 (if args
109 (rep (str "(load-file \"" (first args) "\")"))
86b689f3 110 (repl-loop)))