Commit | Line | Data |
---|---|---|
a816262a JM |
1 | import types.{MalList, _list, _list_Q, MalVector, MalHashMap, |
2 | Func, MalFunction} | |
821930db JM |
3 | import env.Env |
4 | ||
5 | object step5_tco { | |
6 | // read | |
7 | def READ(str: String): Any = { | |
8 | reader.read_str(str) | |
9 | } | |
10 | ||
11 | // eval | |
12 | def eval_ast(ast: Any, env: Env): Any = { | |
13 | ast match { | |
14 | case s : Symbol => env.get(s) | |
a816262a JM |
15 | case v: MalVector => v.map(EVAL(_, env)) |
16 | case l: MalList => l.map(EVAL(_, env)) | |
17 | case m: MalHashMap => { | |
fef22d1c | 18 | m.map{case (k,v) => (k, EVAL(v, env))} |
821930db JM |
19 | } |
20 | case _ => ast | |
21 | } | |
22 | } | |
23 | ||
24 | def EVAL(orig_ast: Any, orig_env: Env): Any = { | |
25 | var ast = orig_ast; var env = orig_env; | |
26 | while (true) { | |
27 | ||
28 | //println("EVAL: " + printer._pr_str(ast,true)) | |
a816262a | 29 | if (!_list_Q(ast)) |
821930db JM |
30 | return eval_ast(ast, env) |
31 | ||
32 | // apply list | |
a816262a | 33 | ast.asInstanceOf[MalList].value match { |
eb243cd5 DM |
34 | case Nil => { |
35 | return ast | |
36 | } | |
821930db JM |
37 | case Symbol("def!") :: a1 :: a2 :: Nil => { |
38 | return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env)) | |
39 | } | |
40 | case Symbol("let*") :: a1 :: a2 :: Nil => { | |
41 | val let_env = new Env(env) | |
a816262a | 42 | for (g <- a1.asInstanceOf[MalList].value.grouped(2)) { |
821930db JM |
43 | let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env)) |
44 | } | |
45 | env = let_env | |
46 | ast = a2 // continue loop (TCO) | |
47 | } | |
48 | case Symbol("do") :: rest => { | |
a816262a JM |
49 | eval_ast(_list(rest.slice(0,rest.length-1):_*), env) |
50 | ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO) | |
821930db JM |
51 | } |
52 | case Symbol("if") :: a1 :: a2 :: rest => { | |
53 | val cond = EVAL(a1, env) | |
54 | if (cond == null || cond == false) { | |
55 | if (rest.length == 0) return null | |
56 | ast = rest(0) // continue loop (TCO) | |
57 | } else { | |
58 | ast = a2 // continue loop (TCO) | |
59 | } | |
60 | } | |
61 | case Symbol("fn*") :: a1 :: a2 :: Nil => { | |
a816262a | 62 | return new MalFunction(a2, env, a1.asInstanceOf[MalList], |
821930db JM |
63 | (args: List[Any]) => { |
64 | EVAL(a2, new Env(env, types._toIter(a1), args.iterator)) | |
65 | } | |
66 | ) | |
67 | } | |
68 | case _ => { | |
69 | // function call | |
a816262a | 70 | eval_ast(ast, env).asInstanceOf[MalList].value match { |
821930db JM |
71 | case f :: el => { |
72 | f match { | |
a816262a | 73 | case fn: MalFunction => { |
821930db JM |
74 | env = fn.gen_env(el) |
75 | ast = fn.ast // continue loop (TCO) | |
76 | } | |
a816262a | 77 | case fn: Func => { |
821930db JM |
78 | return fn(el) |
79 | } | |
80 | case _ => { | |
a816262a | 81 | throw new Exception("attempt to call non-function: " + f) |
821930db JM |
82 | } |
83 | } | |
84 | } | |
85 | case _ => throw new Exception("invalid apply") | |
86 | } | |
87 | } | |
88 | } | |
89 | } | |
90 | } | |
91 | ||
92 | ||
93 | def PRINT(exp: Any): String = { | |
94 | printer._pr_str(exp, true) | |
95 | } | |
96 | ||
97 | // repl | |
98 | def main(args: Array[String]) = { | |
99 | val repl_env: Env = new Env() | |
100 | val REP = (str: String) => PRINT(EVAL(READ(str), repl_env)) | |
101 | ||
102 | // core.scala: defined using scala | |
a816262a JM |
103 | core.ns.map{case (k: String,v: Any) => { |
104 | repl_env.set(Symbol(k), new Func(v)) | |
105 | }} | |
821930db JM |
106 | |
107 | // core.mal: defined using the language itself | |
108 | REP("(def! not (fn* (a) (if a false true)))") | |
109 | ||
110 | var line:String = null | |
111 | while ({line = readLine("user> "); line != null}) { | |
112 | try { | |
113 | println(REP(line)) | |
114 | } catch { | |
115 | case e : Throwable => { | |
116 | println("Error: " + e.getMessage) | |
117 | println(" " + e.getStackTrace.mkString("\n ")) | |
118 | } | |
119 | } | |
120 | } | |
121 | } | |
122 | } | |
123 | ||
124 | // vim: ts=2:sw=2 |