4 READ
:= method(str
, MalReader
read_str(str
))
7 obj ?isSequential
and(obj isEmpty not
)
10 quasiquote
:= method(ast
,
11 if(isPair(ast
) not
, return(MalList
with(list(MalSymbol
with("quote"), ast
))))
13 if(a0
== MalSymbol
with("unquote"), return(ast
at(1)))
14 if(isPair(a0
) and (a0
at(0) == MalSymbol
with("splice-unquote")),
15 return(MalList
with(list(MalSymbol
with("concat"), a0
at(1), quasiquote(ast rest
)))),
16 return(MalList
with(list(MalSymbol
with("cons"), quasiquote(a0
), quasiquote(ast rest
)))))
19 isMacroCall
:= method(ast
, env
,
20 if(ast
type != "MalList", return false
)
22 if(a0
type != "MalSymbol", return false
)
23 if(env
find(a0
) isNil, return false
)
25 (f
type == "MalFunc") and (f isMacro
)
28 macroexpand
:= method(ast
, env
,
29 while(isMacroCall(ast
, env
),
30 macro
:= env
get(ast
at(0))
31 ast
= macro blk
call(ast rest
)
36 eval_ast
:= method(ast
, env
,
38 "MalSymbol", env
get(ast
),
39 "MalList", MalList
with(ast
map(a
, EVAL(a
, env
))),
40 "MalVector", MalVector
with(ast
map(a
, EVAL(a
, env
))),
44 keyObj
:= MalMap
keyToObj(k
)
45 m
atPut(MalMap
objToKey(EVAL(keyObj
, env
)), EVAL(v
, env
))
52 EVAL
:= method(ast
, env
,
54 if(ast
type != "MalList", return(eval_ast(ast
, env
)))
56 ast
= macroexpand(ast
, env
)
57 if(ast
type != "MalList", return(eval_ast(ast
, env
)))
58 if(ast isEmpty
, return ast
)
60 if(ast
at(0) type == "MalSymbol",
63 return(env
set(ast
at(1), EVAL(ast
at(2), env
))),
65 eval_ast(ast
slice(1,-1), env
)
69 ast
= if(EVAL(ast
at(1), env
), ast
at(2), ast
at(3))
72 return(MalFunc
with(ast
at(2), ast
at(1), env
, block(a
, EVAL(ast
at(2), Env
with(env
, ast
at(1), a
))))),
74 letEnv
:= Env
with(env
)
76 ast
at(1) foreach(i
, e
,
79 letEnv
set(varName
, EVAL(e
, letEnv
))
88 ast
= quasiquote(ast
at(1))
91 return(env
set(ast
at(1), EVAL(ast
at(2), env
) clone setIsMacro(true
))),
93 return(macroexpand(ast
at(1), env
))
98 el
:= eval_ast(ast
, env
)
103 return(f
call(args
)),
106 env
= Env
with(f env
, f params
, args
)
108 Exception raise("Unknown function type")
113 PRINT
:= method(exp
, exp
malPrint(true
))
115 repl_env
:= Env
with(nil
)
117 RE
:= method(str
, EVAL(READ(str
), repl_env
))
119 REP
:= method(str
, PRINT(RE(str
)))
121 MalCore NS
foreach(k
, v
, repl_env
set(MalSymbol
with(k
), v
))
122 repl_env
set(MalSymbol
with("eval"), block(a
, EVAL(a
at(0), repl_env
)))
123 repl_env
set(MalSymbol
with("*ARGV*"), MalList
with(System args
slice(2)))
125 // core
.mal
: defined using the language itself
126 RE("(def! not (fn* (a) (if a false true)))")
127 RE("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))")
128 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)))))))")
130 if(System args size
> 1,
131 REP("(load-file \"" .. (System args
at(1)) .. "\")")
136 line
:= MalReadline
readLine("user> ")
137 if(line
isNil, break)
138 if(line isEmpty
, continue)
139 e
:= try(REP(line
) println
)
141 if(e
type == "MalException",
142 ("Error: " .. ((e val
) malPrint(true
))) println
,
143 ("Error: " .. (e error
)) println