1 import types
.{MalList
, _list
, _list_Q
, MalVector
, MalHashMap
,
7 def READ(str
: String
): Any
= {
12 def is_pair(x
: Any
): Boolean
= {
13 types
._sequential_Q(x
) && x
.asInstanceOf
[MalList
].value
.length
> 0
16 def quasiquote(ast
: Any
): Any
= {
18 return _list(Symbol("quote"), ast
)
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)))
33 return _list(Symbol("cons"),
35 quasiquote(ast
.asInstanceOf
[MalList
].drop(1)))
39 def is_macro_call(ast
: Any
, env
: Env
): Boolean
= {
42 if (ml
.value
.length
> 0 &&
43 types
._symbol_Q(ml(0)) &&
44 env
.find(ml(0).asInstanceOf
[Symbol
]) != null) {
45 env
.get(ml(0).asInstanceOf
[Symbol
]) match {
46 case f
: MalFunction
=> return f
.ismacro
47 case _
=> return false
52 case _
=> return false
56 def macroexpand(orig_ast
: Any
, env
: Env
): Any
= {
58 while (is_macro_call(ast
, env
)) {
59 ast
.asInstanceOf
[MalList
].value
match {
61 val mac
= env
.get(f
.asInstanceOf
[Symbol
])
62 ast
= mac
.asInstanceOf
[MalFunction
](args
)
64 case _
=> throw new Exception("macroexpand: invalid call")
70 def eval_ast(ast
: Any
, env
: Env
): Any
= {
72 case s
: Symbol
=> env
.get(s
)
73 case v
: MalVector
=> v
.map(EVAL(_
, env
))
74 case l
: MalList
=> l
.map(EVAL(_
, env
))
75 case m
: MalHashMap
=> {
76 m
.map
{case (k
,v
) => (k
, EVAL(v
, env
))}
82 def EVAL(orig_ast
: Any
, orig_env
: Env
): Any
= {
83 var ast
= orig_ast
; var env
= orig_env
;
86 //println("EVAL: " + printer._pr_str(ast,true))
88 return eval_ast(ast
, env
)
91 ast
= macroexpand(ast
, env
)
93 return eval_ast(ast
, env
)
95 ast
.asInstanceOf
[MalList
].value
match {
99 case Symbol("def!") :: a1
:: a2
:: Nil
=> {
100 return env
.set(a1
.asInstanceOf
[Symbol
], EVAL(a2
, env
))
102 case Symbol("let*") :: a1
:: a2
:: Nil
=> {
103 val let_env
= new Env(env
)
104 for (g
<- a1
.asInstanceOf
[MalList
].value
.grouped(2)) {
105 let_env
.set(g(0).asInstanceOf
[Symbol
],EVAL(g(1),let_env
))
108 ast
= a2
// continue loop (TCO)
110 case Symbol("quote") :: a1
:: Nil
=> {
113 case Symbol("quasiquote") :: a1
:: Nil
=> {
114 ast
= quasiquote(a1
) // continue loop (TCO)
116 case Symbol("defmacro!") :: a1
:: a2
:: Nil
=> {
117 val f
= EVAL(a2
, env
)
118 f
.asInstanceOf
[MalFunction
].ismacro
= true
119 return env
.set(a1
.asInstanceOf
[Symbol
], f
)
121 case Symbol("macroexpand") :: a1
:: Nil
=> {
122 return macroexpand(a1
, env
)
124 case Symbol("try*") :: a1
:: rest
=> {
128 case t
: Throwable
=> {
129 if (rest
.length
== 0) throw t
130 rest(0).asInstanceOf
[MalList
].value
match {
131 case List(Symbol("catch*"), a21
, a22
) => {
132 val exc
: Any
= t
match {
133 case mex
: types
.MalException
=> mex
.value
134 case _
=> t
.getMessage
136 return EVAL(a22
, new Env(env
,
145 case Symbol("do") :: rest
=> {
146 eval_ast(_list(rest
.slice(0,rest
.length
-1):_
*), env
)
147 ast
= ast
.asInstanceOf
[MalList
].value
.last
// continue loop (TCO)
149 case Symbol("if") :: a1
:: a2
:: rest
=> {
150 val cond
= EVAL(a1
, env
)
151 if (cond
== null || cond
== false) {
152 if (rest
.length
== 0) return null
153 ast
= rest(0) // continue loop (TCO)
155 ast
= a2
// continue loop (TCO)
158 case Symbol("fn*") :: a1
:: a2
:: Nil
=> {
159 return new MalFunction(a2
, env
, a1
.asInstanceOf
[MalList
],
160 (args
: List
[Any
]) => {
161 EVAL(a2
, new Env(env
, types
._toIter(a1
), args
.iterator
))
167 eval_ast(ast
, env
).asInstanceOf
[MalList
].value
match {
170 case fn
: MalFunction
=> {
172 ast
= fn
.ast
// continue loop (TCO)
178 throw new Exception("attempt to call non-function: " + f
)
182 case _
=> throw new Exception("invalid apply")
190 def PRINT(exp
: Any
): String
= {
191 printer
._pr_str(exp
, true)
195 def main(args
: Array
[String
]) = {
196 val repl_env
: Env
= new Env()
197 val REP
= (str
: String
) => PRINT(EVAL(READ(str
), repl_env
))
199 // core.scala: defined using scala
200 core
.ns
.map
{case (k
: String
,v
: Any
) => {
201 repl_env
.set(Symbol(k
), new Func(v
))
203 repl_env
.set(Symbol("eval"), new Func((a
: List
[Any
]) => EVAL(a(0), repl_env
)))
204 repl_env
.set(Symbol("*ARGV*"), _list(args
.slice(1,args
.length
):_
*))
206 // core.mal: defined using the language itself
207 REP("(def! *host-language* \"scala\")")
208 REP("(def! not (fn* (a) (if a false true)))")
209 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
210 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)))))))")
211 REP("(def! inc (fn* [x] (+ x 1)))")
212 REP("(def! gensym (let* [counter (atom 0)] (fn* [] (symbol (str \"G__\" (swap! counter inc))))))")
213 REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))")
216 if (args
.length
> 0) {
217 REP("(load-file \"" + args(0) + "\")")
222 REP("(println (str \"Mal [\" *host-language* \"]\"))")
223 var line
:String
= null
224 while ({line
= readLine("user> "); line
!= null}) {
228 case e
: Throwable
=> {
229 println("Error: " + e
.getMessage
)
230 println(" " + e
.getStackTrace
.mkString("\n "))