8 let MalExceptionObj = ""
15 return SequentialQ(a:obj) && !EmptyQ(a:obj)
18 function Quasiquote(ast)
20 return ListNew([SymbolNew("quote"), a:ast])
22 let a0 = ListFirst(a:ast)
23 if SymbolQ(a0) && ObjValue(a0) == "unquote"
24 return ListNth(a:ast, 1)
25 elseif PairQ(a0) && SymbolQ(ListFirst(a0)) && ObjValue(ListFirst(a0)) == "splice-unquote"
26 return ListNew([SymbolNew("concat"), ListNth(a0, 1), Quasiquote(ListRest(a:ast))])
28 return ListNew([SymbolNew("cons"), Quasiquote(a0), Quasiquote(ListRest(a:ast))])
32 function IsMacroCall(ast, env)
36 let a0 = ListFirst(a:ast)
40 let macroname = ObjValue(a0)
41 if empty(a:env.find(macroname))
44 return MacroQ(a:env.get(macroname))
47 function MacroExpand(ast, env)
49 while IsMacroCall(ast, a:env)
50 let macroobj = a:env.get(ObjValue(ListFirst(ast)))
51 let macroargs = ListRest(ast)
52 let ast = FuncInvoke(macroobj, macroargs)
57 function EvalAst(ast, env)
59 let varname = ObjValue(a:ast)
60 return a:env.get(varname)
63 for e in ObjValue(a:ast)
64 call add(ret, EVAL(e, a:env))
69 for e in ObjValue(a:ast)
70 call add(ret, EVAL(e, a:env))
75 for [k,v] in items(ObjValue(a:ast))
76 let keyobj = HashParseKey(k)
77 let newkey = EVAL(keyobj, a:env)
78 let newval = EVAL(v, a:env)
79 let keystring = HashMakeKey(newkey)
80 let ret[keystring] = newval
88 function GetCatchClause(ast)
89 if ListCount(a:ast) < 3
92 let catch_clause = ListNth(a:ast, 2)
93 if ListFirst(catch_clause) == SymbolNew("catch*")
100 function EVAL(ast, env)
106 return EvalAst(ast, env)
109 let ast = MacroExpand(ast, env)
111 return EvalAst(ast, env)
114 let first = ListFirst(ast)
115 let first_symbol = SymbolQ(first) ? ObjValue(first) : ""
116 if first_symbol == "def!"
117 let a1 = ObjValue(ast)[1]
118 let a2 = ObjValue(ast)[2]
119 return env.set(ObjValue(a1), EVAL(a2, env))
120 elseif first_symbol == "let*"
121 let a1 = ObjValue(ast)[1]
122 let a2 = ObjValue(ast)[2]
123 let env = NewEnv(env)
124 let let_binds = ObjValue(a1)
126 while i < len(let_binds)
127 call env.set(ObjValue(let_binds[i]), EVAL(let_binds[i+1], env))
132 elseif first_symbol == "quote"
133 return ListNth(ast, 1)
134 elseif first_symbol == "quasiquote"
135 let ast = Quasiquote(ListNth(ast, 1))
137 elseif first_symbol == "defmacro!"
138 let a1 = ListNth(ast, 1)
139 let a2 = ListNth(ast, 2)
140 let macro = MarkAsMacro(EVAL(a2, env))
141 return env.set(ObjValue(a1), macro)
142 elseif first_symbol == "macroexpand"
143 return MacroExpand(ListNth(ast, 1), env)
144 elseif first_symbol == "if"
145 let condvalue = EVAL(ObjValue(ast)[1], env)
146 if FalseQ(condvalue) || NilQ(condvalue)
147 if len(ObjValue(ast)) < 4
150 let ast = ObjValue(ast)[3]
153 let ast = ObjValue(ast)[2]
156 elseif first_symbol == "try*"
158 return EVAL(ListNth(ast, 1), env)
160 let catch_clause = GetCatchClause(ast)
161 if empty(catch_clause)
165 let exc_var = ObjValue(ListNth(catch_clause, 1))
166 if v:exception == "__MalException__"
167 let exc_value = g:MalExceptionObj
169 let exc_value = StringNew(v:exception)
171 let catch_env = NewEnvWithBinds(env, ListNew([SymbolNew(exc_var)]), ListNew([exc_value]))
172 return EVAL(ListNth(catch_clause, 2), catch_env)
174 elseif first_symbol == "do"
175 let astlist = ObjValue(ast)
176 call EvalAst(ListNew(astlist[1:-2]), env)
177 let ast = astlist[-1]
179 elseif first_symbol == "fn*"
180 let fn = NewFn(ListNth(ast, 2), env, ListNth(ast, 1))
182 elseif first_symbol == "eval"
183 let ast = EVAL(ListNth(ast, 1), env)
188 let el = EvalAst(ast, env)
189 let funcobj = ListFirst(el)
190 let args = ListRest(el)
191 if NativeFunctionQ(funcobj)
192 return NativeFuncInvoke(funcobj, args)
193 elseif FunctionQ(funcobj)
194 let fn = ObjValue(funcobj)
196 let env = NewEnvWithBinds(fn.env, fn.params, args)
199 throw "Not a function"
206 return PrStr(a:exp, 1)
209 function RE(str, env)
210 return EVAL(READ(a:str), a:env)
213 function REP(str, env)
214 return PRINT(EVAL(READ(a:str), a:env))
217 function GetArgvList()
221 call add(list, StringNew(arg))
226 set maxfuncdepth=10000
227 let repl_env = NewEnv("")
229 for [k, v] in items(CoreNs)
230 call repl_env.set(k, v)
233 call repl_env.set("*ARGV*", GetArgvList())
235 call RE("(def! not (fn* (a) (if a false true)))", repl_env)
236 call RE("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env)
237 call 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)))))))", repl_env)
238 call RE("(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))))))))", repl_env)
242 call RE('(load-file "' . argv(0) . '")', repl_env)
244 call PrintLn("Error: " . v:exception)
250 let [eof, line] = Readline("user> ")
258 call PrintLn(REP(line, repl_env))
260 call PrintLn("Error: " . v:exception)