Merge branch 'master' into chuck-implementation
[jackhill/mal.git] / scala / step6_file.scala
1 import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
2 Func, MalFunction}
3 import env.Env
4
5 object step6_file {
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)
15 case v: MalVector => v.map(EVAL(_, env))
16 case l: MalList => l.map(EVAL(_, env))
17 case m: MalHashMap => {
18 m.map{case (k,v) => (k, EVAL(v, env))}
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))
29 if (!_list_Q(ast))
30 return eval_ast(ast, env)
31
32 // apply list
33 ast.asInstanceOf[MalList].value match {
34 case Nil => {
35 return ast
36 }
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)
42 for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
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 => {
49 eval_ast(_list(rest.slice(0,rest.length-1):_*), env)
50 ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO)
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 => {
62 return new MalFunction(a2, env, a1.asInstanceOf[MalList],
63 (args: List[Any]) => {
64 EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
65 }
66 )
67 }
68 case _ => {
69 // function call
70 eval_ast(ast, env).asInstanceOf[MalList].value match {
71 case f :: el => {
72 f match {
73 case fn: MalFunction => {
74 env = fn.gen_env(el)
75 ast = fn.ast // continue loop (TCO)
76 }
77 case fn: Func => {
78 return fn(el)
79 }
80 case _ => {
81 throw new Exception("attempt to call non-function: " + f)
82 }
83 }
84 }
85 case _ => throw new Exception("invalid apply")
86 }
87 }
88 }
89 }
90 }
91
92 // print
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
103 core.ns.map{case (k: String,v: Any) => {
104 repl_env.set(Symbol(k), new Func(v))
105 }}
106 repl_env.set(Symbol("eval"), new Func((a: List[Any]) => EVAL(a(0), repl_env)))
107 repl_env.set(Symbol("*ARGV*"), _list(args.slice(1,args.length):_*))
108
109 // core.mal: defined using the language itself
110 REP("(def! not (fn* (a) (if a false true)))")
111 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
112
113 if (args.length > 0) {
114 REP("(load-file \"" + args(0) + "\")")
115 System.exit(0)
116 }
117
118 // repl loop
119 var line:String = null
120 while ({line = readLine("user> "); line != null}) {
121 try {
122 println(REP(line))
123 } catch {
124 case e : Throwable => {
125 println("Error: " + e.getMessage)
126 println(" " + e.getStackTrace.mkString("\n "))
127 }
128 }
129 }
130 }
131 }
132
133 // vim: ts=2:sw=2