4 READ
:= method(str
, MalReader
read_str(str
))
7 xs
reverseReduce(acc
, elt
,
8 if((elt
type == "MalList") and (elt size
== 2) and (elt
at(0) == MalSymbol
with("splice-unquote")),
9 MalList
with(list(MalSymbol
with("concat"), elt
at(1), acc
)),
10 MalList
with(list(MalSymbol
with("cons"), quasiquote(elt
), acc
))),
11 MalList
with(list())))
13 quasiquote
:= method(ast
,
15 "MalSymbol", MalList
with(list(MalSymbol
with("quote"), ast
)),
16 "MalMap", MalList
with(list(MalSymbol
with("quote"), ast
)),
17 "MalVector", MalList
with(list(MalSymbol
with("vec"), qq_foldr(ast
))),
18 "MalList", if((ast size
== 2) and (ast
at(0) == MalSymbol
with("unquote")),
23 isMacroCall
:= method(ast
, env
,
24 if(ast
type != "MalList", return false
)
26 if(a0
type != "MalSymbol", return false
)
27 if(env
find(a0
) isNil, return false
)
29 (f
type == "MalFunc") and (f isMacro
)
32 macroexpand
:= method(ast
, env
,
33 while(isMacroCall(ast
, env
),
34 macro
:= env
get(ast
at(0))
35 ast
= macro blk
call(ast rest
)
40 eval_ast
:= method(ast
, env
,
42 "MalSymbol", env
get(ast
),
43 "MalList", MalList
with(ast
map(a
, EVAL(a
, env
))),
44 "MalVector", MalVector
with(ast
map(a
, EVAL(a
, env
))),
48 keyObj
:= MalMap
keyToObj(k
)
49 m
atPut(MalMap
objToKey(EVAL(keyObj
, env
)), EVAL(v
, env
))
56 EVAL
:= method(ast
, env
,
58 if(ast
type != "MalList", return(eval_ast(ast
, env
)))
60 ast
= macroexpand(ast
, env
)
61 if(ast
type != "MalList", return(eval_ast(ast
, env
)))
62 if(ast isEmpty
, return ast
)
64 if(ast
at(0) type == "MalSymbol",
67 return(env
set(ast
at(1), EVAL(ast
at(2), env
))),
69 eval_ast(ast
slice(1,-1), env
)
73 ast
= if(EVAL(ast
at(1), env
), ast
at(2), ast
at(3))
76 return(MalFunc
with(ast
at(2), ast
at(1), env
, block(a
, EVAL(ast
at(2), Env
with(env
, ast
at(1), a
))))),
78 letEnv
:= Env
with(env
)
80 ast
at(1) foreach(i
, e
,
83 letEnv
set(varName
, EVAL(e
, letEnv
))
92 return quasiquote(ast
at(1)),
94 ast
= quasiquote(ast
at(1))
97 return(env
set(ast
at(1), EVAL(ast
at(2), env
) clone setIsMacro(true
))),
99 return(macroexpand(ast
at(1), env
))
104 el
:= eval_ast(ast
, env
)
109 return(f
call(args
)),
112 env
= Env
with(f env
, f params
, args
)
114 Exception raise("Unknown function type")
119 PRINT
:= method(exp
, exp
malPrint(true
))
121 repl_env
:= Env
with(nil
)
123 RE
:= method(str
, EVAL(READ(str
), repl_env
))
125 REP
:= method(str
, PRINT(RE(str
)))
127 MalCore NS
foreach(k
, v
, repl_env
set(MalSymbol
with(k
), v
))
128 repl_env
set(MalSymbol
with("eval"), block(a
, EVAL(a
at(0), repl_env
)))
129 repl_env
set(MalSymbol
with("*ARGV*"), MalList
with(System args
slice(2)))
131 // core
.mal
: defined using the language itself
132 RE("(def! not (fn* (a) (if a false true)))")
133 RE("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))")
134 RE("(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)))))))")
136 if(System args size
> 1,
137 REP("(load-file \"" .. (System args
at(1)) .. "\")")
142 line
:= MalReadline
readLine("user> ")
143 if(line
isNil, break)
144 if(line isEmpty
, continue)
145 e
:= try(REP(line
) println
)
147 if(e
type == "MalException",
148 ("Error: " .. ((e val
) malPrint(true
))) println
,
149 ("Error: " .. (e error
)) println