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 (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
51 case _
=> return false
55 def macroexpand(orig_ast
: Any
, env
: Env
): Any
= {
57 while (is_macro_call(ast
, env
)) {
58 ast
.asInstanceOf
[MalList
].value
match {
60 val mac
= env
.get(f
.asInstanceOf
[Symbol
])
61 ast
= mac
.asInstanceOf
[MalFunction
](args
)
63 case _
=> throw new Exception("macroexpand: invalid call")
69 def eval_ast(ast
: Any
, env
: Env
): Any
= {
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
,v
) => (k
, EVAL(v
, env
))}
81 def EVAL(orig_ast
: Any
, orig_env
: Env
): Any
= {
82 var ast
= orig_ast
; var env
= orig_env
;
85 //println("EVAL: " + printer._pr_str(ast,true))
87 return eval_ast(ast
, env
)
90 ast
= macroexpand(ast
, env
)
92 return eval_ast(ast
, env
)
94 ast
.asInstanceOf
[MalList
].value
match {
95 case Symbol("def!") :: a1
:: a2
:: Nil
=> {
96 return env
.set(a1
.asInstanceOf
[Symbol
], EVAL(a2
, env
))
98 case Symbol("let*") :: a1
:: a2
:: Nil
=> {
99 val let_env
= new Env(env
)
100 for (g
<- a1
.asInstanceOf
[MalList
].value
.grouped(2)) {
101 let_env
.set(g(0).asInstanceOf
[Symbol
],EVAL(g(1),let_env
))
104 ast
= a2
// continue loop (TCO)
106 case Symbol("quote") :: a1
:: Nil
=> {
109 case Symbol("quasiquote") :: a1
:: Nil
=> {
110 ast
= quasiquote(a1
) // continue loop (TCO)
112 case Symbol("defmacro!") :: a1
:: a2
:: Nil
=> {
113 val f
= EVAL(a2
, env
)
114 f
.asInstanceOf
[MalFunction
].ismacro
= true
115 return env
.set(a1
.asInstanceOf
[Symbol
], f
)
117 case Symbol("macroexpand") :: a1
:: Nil
=> {
118 return macroexpand(a1
, env
)
120 case Symbol("do") :: rest
=> {
121 eval_ast(_list(rest
.slice(0,rest
.length
-1):_
*), env
)
122 ast
= ast
.asInstanceOf
[MalList
].value
.last
// continue loop (TCO)
124 case Symbol("if") :: a1
:: a2
:: rest
=> {
125 val cond
= EVAL(a1
, env
)
126 if (cond
== null || cond
== false) {
127 if (rest
.length
== 0) return null
128 ast
= rest(0) // continue loop (TCO)
130 ast
= a2
// continue loop (TCO)
133 case Symbol("fn*") :: a1
:: a2
:: Nil
=> {
134 return new MalFunction(a2
, env
, a1
.asInstanceOf
[MalList
],
135 (args
: List
[Any
]) => {
136 EVAL(a2
, new Env(env
, types
._toIter(a1
), args
.iterator
))
142 eval_ast(ast
, env
).asInstanceOf
[MalList
].value
match {
145 case fn
: MalFunction
=> {
147 ast
= fn
.ast
// continue loop (TCO)
153 throw new Exception("attempt to call non-function: " + f
)
157 case _
=> throw new Exception("invalid apply")
165 def PRINT(exp
: Any
): String
= {
166 printer
._pr_str(exp
, true)
170 def main(args
: Array
[String
]) = {
171 val repl_env
: Env
= new Env()
172 val REP
= (str
: String
) => PRINT(EVAL(READ(str
), repl_env
))
174 // core.scala: defined using scala
175 core
.ns
.map
{case (k
: String
,v
: Any
) => {
176 repl_env
.set(Symbol(k
), new Func(v
))
178 repl_env
.set(Symbol("eval"), new Func((a
: List
[Any
]) => EVAL(a(0), repl_env
)))
179 repl_env
.set(Symbol("*ARGV*"), _list(args
.slice(1,args
.length
):_
*))
181 // core.mal: defined using the language itself
182 REP("(def! not (fn* (a) (if a false true)))")
183 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
184 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)))))))")
185 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))))))))")
188 if (args
.length
> 0) {
189 REP("(load-file \"" + args(0) + "\")")
194 var line
:String
= null
195 while ({line
= readLine("user> "); line
!= null}) {
199 case e
: Throwable
=> {
200 println("Error: " + e
.getMessage
)
201 println(" " + e
.getStackTrace
.mkString("\n "))