Commit | Line | Data |
---|---|---|
a816262a JM |
1 | import types.{MalList, _list, _list_Q, MalVector, MalHashMap, |
2 | Func, MalFunction} | |
3 | import env.Env | |
4 | ||
5 | object stepA_interop { | |
6 | // read | |
7 | def READ(str: String): Any = { | |
8 | reader.read_str(str) | |
9 | } | |
10 | ||
11 | // eval | |
12 | def is_pair(x: Any): Boolean = { | |
13 | types._sequential_Q(x) && x.asInstanceOf[MalList].value.length > 0 | |
14 | } | |
15 | ||
16 | def quasiquote(ast: Any): Any = { | |
17 | if (!is_pair(ast)) { | |
18 | return _list(Symbol("quote"), ast) | |
19 | } else { | |
20 | val a0 = ast.asInstanceOf[MalList](0) | |
21 | if (types._symbol_Q(a0) && | |
22 | a0.asInstanceOf[Symbol].name == "unquote") { | |
23 | return ast.asInstanceOf[MalList](1) | |
24 | } else if (is_pair(a0)) { | |
25 | val a00 = a0.asInstanceOf[MalList](0) | |
26 | if (types._symbol_Q(a00) && | |
27 | a00.asInstanceOf[Symbol].name == "splice-unquote") { | |
28 | return _list(Symbol("concat"), | |
29 | a0.asInstanceOf[MalList](1), | |
30 | quasiquote(ast.asInstanceOf[MalList].drop(1))) | |
31 | } | |
32 | } | |
33 | return _list(Symbol("cons"), | |
34 | quasiquote(a0), | |
35 | quasiquote(ast.asInstanceOf[MalList].drop(1))) | |
36 | } | |
37 | } | |
38 | ||
39 | def is_macro_call(ast: Any, env: Env): Boolean = { | |
40 | ast match { | |
41 | case ml: MalList => { | |
42 | if (types._symbol_Q(ml(0)) && | |
43 | env.find(ml(0).asInstanceOf[Symbol]) != null) { | |
44 | env.get(ml(0).asInstanceOf[Symbol]) match { | |
45 | case f: MalFunction => return f.ismacro | |
46 | case _ => return false | |
47 | } | |
48 | } | |
49 | return false | |
50 | } | |
51 | case _ => return false | |
52 | } | |
53 | } | |
54 | ||
55 | def macroexpand(orig_ast: Any, env: Env): Any = { | |
56 | var ast = orig_ast; | |
57 | while (is_macro_call(ast, env)) { | |
58 | ast.asInstanceOf[MalList].value match { | |
59 | case f :: args => { | |
60 | val mac = env.get(f.asInstanceOf[Symbol]) | |
61 | ast = mac.asInstanceOf[MalFunction](args) | |
62 | } | |
63 | case _ => throw new Exception("macroexpand: invalid call") | |
64 | } | |
65 | } | |
66 | ast | |
67 | } | |
68 | ||
69 | def eval_ast(ast: Any, env: Env): Any = { | |
70 | ast match { | |
71 | case s : Symbol => env.get(s) | |
72 | case v: MalVector => v.map(EVAL(_, env)) | |
73 | case l: MalList => l.map(EVAL(_, env)) | |
74 | case m: MalHashMap => { | |
75 | m.map{case (k: String,v: Any) => (k, EVAL(v, env))} | |
76 | } | |
77 | case _ => ast | |
78 | } | |
79 | } | |
80 | ||
81 | def EVAL(orig_ast: Any, orig_env: Env): Any = { | |
82 | var ast = orig_ast; var env = orig_env; | |
83 | while (true) { | |
84 | ||
85 | //println("EVAL: " + printer._pr_str(ast,true)) | |
86 | if (!_list_Q(ast)) | |
87 | return eval_ast(ast, env) | |
88 | ||
89 | // apply list | |
90 | ast = macroexpand(ast, env) | |
91 | if (!_list_Q(ast)) return ast | |
92 | ||
93 | ast.asInstanceOf[MalList].value match { | |
94 | case Symbol("def!") :: a1 :: a2 :: Nil => { | |
95 | return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env)) | |
96 | } | |
97 | case Symbol("let*") :: a1 :: a2 :: Nil => { | |
98 | val let_env = new Env(env) | |
99 | for (g <- a1.asInstanceOf[MalList].value.grouped(2)) { | |
100 | let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env)) | |
101 | } | |
102 | env = let_env | |
103 | ast = a2 // continue loop (TCO) | |
104 | } | |
105 | case Symbol("quote") :: a1 :: Nil => { | |
106 | return a1 | |
107 | } | |
108 | case Symbol("quasiquote") :: a1 :: Nil => { | |
109 | ast = quasiquote(a1) // continue loop (TCO) | |
110 | } | |
111 | case Symbol("defmacro!") :: a1 :: a2 :: Nil => { | |
112 | val f = EVAL(a2, env) | |
113 | f.asInstanceOf[MalFunction].ismacro = true | |
114 | return env.set(a1.asInstanceOf[Symbol], f) | |
115 | } | |
116 | case Symbol("macroexpand") :: a1 :: Nil => { | |
117 | return macroexpand(a1, env) | |
118 | } | |
119 | case Symbol("try*") :: a1 :: rest => { | |
120 | try { | |
121 | return EVAL(a1, env) | |
122 | } catch { | |
123 | case t: Throwable => { | |
124 | rest(0).asInstanceOf[MalList].value match { | |
125 | case List(Symbol("catch*"), a21, a22) => { | |
126 | val exc: Any = t match { | |
127 | case mex: types.MalException => mex.value | |
128 | case _ => t.getMessage | |
129 | } | |
130 | return EVAL(a22, new Env(env, | |
131 | List(a21).iterator, | |
132 | List(exc).iterator)) | |
133 | } | |
134 | } | |
135 | throw t | |
136 | } | |
137 | } | |
138 | } | |
139 | case Symbol("do") :: rest => { | |
140 | eval_ast(_list(rest.slice(0,rest.length-1):_*), env) | |
141 | ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO) | |
142 | } | |
143 | case Symbol("if") :: a1 :: a2 :: rest => { | |
144 | val cond = EVAL(a1, env) | |
145 | if (cond == null || cond == false) { | |
146 | if (rest.length == 0) return null | |
147 | ast = rest(0) // continue loop (TCO) | |
148 | } else { | |
149 | ast = a2 // continue loop (TCO) | |
150 | } | |
151 | } | |
152 | case Symbol("fn*") :: a1 :: a2 :: Nil => { | |
153 | return new MalFunction(a2, env, a1.asInstanceOf[MalList], | |
154 | (args: List[Any]) => { | |
155 | EVAL(a2, new Env(env, types._toIter(a1), args.iterator)) | |
156 | } | |
157 | ) | |
158 | } | |
159 | case _ => { | |
160 | // function call | |
161 | eval_ast(ast, env).asInstanceOf[MalList].value match { | |
162 | case f :: el => { | |
163 | f match { | |
164 | case fn: MalFunction => { | |
165 | env = fn.gen_env(el) | |
166 | ast = fn.ast // continue loop (TCO) | |
167 | } | |
168 | case fn: Func => { | |
169 | return fn(el) | |
170 | } | |
171 | case _ => { | |
172 | throw new Exception("attempt to call non-function: " + f) | |
173 | } | |
174 | } | |
175 | } | |
176 | case _ => throw new Exception("invalid apply") | |
177 | } | |
178 | } | |
179 | } | |
180 | } | |
181 | } | |
182 | ||
183 | ||
184 | def PRINT(exp: Any): String = { | |
185 | printer._pr_str(exp, true) | |
186 | } | |
187 | ||
188 | // repl | |
189 | def main(args: Array[String]) = { | |
190 | val repl_env: Env = new Env() | |
191 | val REP = (str: String) => PRINT(EVAL(READ(str), repl_env)) | |
192 | ||
193 | // core.scala: defined using scala | |
194 | core.ns.map{case (k: String,v: Any) => { | |
195 | repl_env.set(Symbol(k), new Func(v)) | |
196 | }} | |
197 | repl_env.set(Symbol("eval"), new Func((a: List[Any]) => EVAL(a(0), repl_env))) | |
198 | repl_env.set(Symbol("*ARGV*"), _list(args.slice(1,args.length):_*)) | |
199 | ||
200 | // core.mal: defined using the language itself | |
201 | REP("(def! *host-language* \"scala\")") | |
202 | REP("(def! not (fn* (a) (if a false true)))") | |
203 | REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") | |
204 | 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)))))))") | |
205 | 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))))))))") | |
206 | ||
207 | ||
208 | if (args.length > 0) { | |
209 | REP("(load-file \"" + args(0) + "\")") | |
210 | System.exit(0) | |
211 | } | |
212 | ||
213 | // repl loop | |
214 | REP("(println (str \"Mal [\" *host-language* \"]\"))") | |
215 | var line:String = null | |
216 | while ({line = readLine("user> "); line != null}) { | |
217 | try { | |
218 | println(REP(line)) | |
219 | } catch { | |
220 | case e : Throwable => { | |
221 | println("Error: " + e.getMessage) | |
222 | println(" " + e.getStackTrace.mkString("\n ")) | |
223 | } | |
224 | } | |
225 | } | |
226 | } | |
227 | } | |
228 | ||
229 | // vim: ts=2:sw=2 |