Commit | Line | Data |
---|---|---|
31690700 | 1 | (load-file "../mal/env.mal") |
ea81a808 | 2 | (load-file "../mal/core.mal") |
31690700 JM |
3 | |
4 | ;; read | |
5 | (def! READ (fn* [strng] | |
6 | (read-string strng))) | |
7 | ||
8 | ||
9 | ;; eval | |
10 | (def! is-pair (fn* [x] | |
11 | (if (sequential? x) | |
12 | (if (> (count x) 0) | |
13 | true)))) | |
14 | ||
15 | (def! QUASIQUOTE (fn* [ast] | |
16 | (cond | |
17 | (not (is-pair ast)) | |
18 | (list 'quote ast) | |
19 | ||
20 | (= 'unquote (first ast)) | |
21 | (nth ast 1) | |
22 | ||
23 | (if (is-pair (first ast)) | |
24 | (if (= 'splice-unquote (first (first ast))) | |
25 | true)) | |
26 | (list 'concat (nth (first ast) 1) (QUASIQUOTE (rest ast))) | |
27 | ||
28 | "else" | |
29 | (list 'cons (QUASIQUOTE (first ast)) (QUASIQUOTE (rest ast)))))) | |
30 | ||
31 | (def! is-macro-call (fn* [ast env] | |
32 | (if (list? ast) | |
33 | (let* [a0 (first ast)] | |
34 | (if (symbol? a0) | |
35 | (if (env-find env a0) | |
36 | (let* [m (meta (env-get env a0))] | |
37 | (if m | |
38 | (if (get m "ismacro") | |
39 | true))))))))) | |
40 | ||
41 | (def! MACROEXPAND (fn* [ast env] | |
42 | (if (is-macro-call ast env) | |
43 | (let* [mac (env-get env (first ast))] | |
44 | (MACROEXPAND (apply mac (rest ast)) env)) | |
45 | ast))) | |
46 | ||
47 | (def! eval-ast (fn* [ast env] (do | |
48 | ;;(do (prn "eval-ast" ast "/" (keys env)) ) | |
49 | (cond | |
50 | (symbol? ast) (env-get env ast) | |
51 | ||
52 | (list? ast) (map (fn* [exp] (EVAL exp env)) ast) | |
53 | ||
54 | (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast)) | |
55 | ||
56 | (map? ast) (apply hash-map | |
57 | (apply concat | |
58 | (map (fn* [k] [k (EVAL (get ast k) env)]) | |
59 | (keys ast)))) | |
60 | ||
61 | "else" ast)))) | |
62 | ||
63 | (def! LET (fn* [env args] | |
64 | (if (> (count args) 0) | |
65 | (do | |
66 | (env-set env (nth args 0) (EVAL (nth args 1) env)) | |
67 | (LET env (rest (rest args))))))) | |
68 | ||
69 | (def! EVAL (fn* [ast env] (do | |
70 | ;;(do (prn "EVAL" ast "/" (keys @env)) ) | |
71 | (if (not (list? ast)) | |
72 | (eval-ast ast env) | |
73 | ||
74 | ;; apply list | |
75 | (let* [ast (MACROEXPAND ast env)] | |
76 | (if (not (list? ast)) | |
bfa3dd35 | 77 | (eval-ast ast env) |
31690700 JM |
78 | |
79 | (let* [a0 (first ast)] | |
80 | (cond | |
3178009c DM |
81 | (nil? a0) |
82 | ast | |
83 | ||
31690700 JM |
84 | (= 'def! a0) |
85 | (env-set env (nth ast 1) (EVAL (nth ast 2) env)) | |
a2849f89 | 86 | |
31690700 JM |
87 | (= 'let* a0) |
88 | (let* [let-env (new-env env)] | |
89 | (do | |
90 | (LET let-env (nth ast 1)) | |
91 | (EVAL (nth ast 2) let-env))) | |
a2849f89 | 92 | |
31690700 JM |
93 | (= 'quote a0) |
94 | (nth ast 1) | |
a2849f89 | 95 | |
31690700 JM |
96 | (= 'quasiquote a0) |
97 | (let* [a1 (nth ast 1)] | |
98 | (EVAL (QUASIQUOTE a1) env)) | |
a2849f89 | 99 | |
31690700 JM |
100 | (= 'defmacro! a0) |
101 | (let* [a1 (nth ast 1) | |
102 | a2 (nth ast 2) | |
103 | f (EVAL a2 env) | |
104 | m (or (meta f) {}) | |
105 | mac (with-meta f (assoc m "ismacro" true))] | |
106 | (env-set env a1 mac)) | |
a2849f89 | 107 | |
31690700 JM |
108 | (= 'macroexpand a0) |
109 | (let* [a1 (nth ast 1)] | |
110 | (MACROEXPAND a1 env)) | |
1617910a | 111 | |
31690700 JM |
112 | (= 'do a0) |
113 | (let* [el (eval-ast (rest ast) env)] | |
114 | (nth el (- (count el) 1))) | |
a2849f89 | 115 | |
31690700 JM |
116 | (= 'if a0) |
117 | (let* [cond (EVAL (nth ast 1) env)] | |
118 | (if (or (= cond nil) (= cond false)) | |
119 | (if (> (count ast) 3) | |
120 | (EVAL (nth ast 3) env) | |
121 | nil) | |
122 | (EVAL (nth ast 2) env))) | |
a2849f89 | 123 | |
31690700 JM |
124 | (= 'fn* a0) |
125 | (fn* [& args] | |
126 | (EVAL (nth ast 2) (new-env env (nth ast 1) args))) | |
a2849f89 | 127 | |
31690700 JM |
128 | "else" |
129 | (let* [el (eval-ast ast env) | |
130 | f (first el) | |
131 | args (rest el)] | |
132 | (apply f args)))))))))) | |
133 | ||
134 | ||
135 | ||
136 | (def! PRINT (fn* [exp] (pr-str exp))) | |
137 | ||
138 | ;; repl | |
139 | (def! repl-env (new-env)) | |
140 | (def! rep (fn* [strng] | |
141 | (PRINT (EVAL (READ strng) repl-env)))) | |
142 | ||
8cb5cda4 JM |
143 | ;; core.mal: defined directly using mal |
144 | (map (fn* [data] (env-set repl-env (nth data 0) (nth data 1))) core_ns) | |
145 | (env-set repl-env 'eval (fn* [ast] (EVAL ast repl-env))) | |
86b689f3 | 146 | (env-set repl-env '*ARGV* (rest *ARGV*)) |
31690700 | 147 | |
8cb5cda4 | 148 | ;; core.mal: defined using the new language itself |
31690700 | 149 | (rep "(def! not (fn* [a] (if a false true)))") |
1617910a | 150 | (rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") |
8cb5cda4 JM |
151 | (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)))))))") |
152 | (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))))))))") | |
31690700 | 153 | |
86b689f3 JM |
154 | ;; repl loop |
155 | (def! repl-loop (fn* [] | |
31690700 JM |
156 | (let* [line (readline "mal-user> ")] |
157 | (if line | |
158 | (do | |
159 | (if (not (= "" line)) | |
160 | (try* | |
86b689f3 | 161 | (println (rep line)) |
31690700 JM |
162 | (catch* exc |
163 | (println "Uncaught exception:" exc)))) | |
86b689f3 JM |
164 | (repl-loop)))))) |
165 | ||
166 | (def! -main (fn* [& args] | |
167 | (if (> (count args) 0) | |
168 | (rep (str "(load-file \"" (first args) "\")")) | |
169 | (repl-loop)))) | |
170 | (apply -main *ARGV*) |