12 function StartsWith(ast, sym)
16 let fst = ListFirst(a:ast)
17 return SymbolQ(fst) && fst.val == a:sym
20 function QuasiquoteLoop(xs)
21 let revlist = reverse(copy(a:xs))
24 if ListQ(elt) && StartsWith(elt, "splice-unquote")
25 let acc = ListNew([SymbolNew("concat"), ListNth(elt, 1), acc])
27 let acc = ListNew([SymbolNew("cons"), Quasiquote(elt), acc])
33 function Quasiquote(ast)
35 return ListNew([SymbolNew("vec"), QuasiquoteLoop(a:ast.val)])
36 elseif SymbolQ(a:ast) || HashQ(a:ast)
37 return ListNew([SymbolNew("quote"), a:ast])
40 elseif StartsWith(a:ast, "unquote")
41 return ListNth(a:ast, 1)
43 return QuasiquoteLoop(a:ast.val)
47 function EvalAst(ast, env)
49 let varname = a:ast.val
50 return a:env.get(varname)
52 return ListNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
54 return VectorNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
57 for [k,v] in items(a:ast.val)
58 let keyobj = HashParseKey(k)
59 let newkey = EVAL(keyobj, a:env)
60 let newval = EVAL(v, a:env)
61 let keystring = HashMakeKey(newkey)
62 let ret[keystring] = newval
70 function EVAL(ast, env)
76 return EvalAst(ast, env)
82 let first = ListFirst(ast)
83 let first_symbol = SymbolQ(first) ? first.val : ""
84 if first_symbol == "def!"
87 let ret = env.set(a1.val, EVAL(a2, env))
89 elseif first_symbol == "let*"
93 let let_binds = a1.val
95 while i < len(let_binds)
96 call env.set(let_binds[i].val, EVAL(let_binds[i+1], env))
101 elseif first_symbol == "quote"
102 return ListNth(ast, 1)
103 elseif first_symbol == "quasiquoteexpand"
104 return Quasiquote(ListNth(ast, 1))
105 elseif first_symbol == "quasiquote"
106 let ast = Quasiquote(ListNth(ast, 1))
108 elseif first_symbol == "if"
109 let condvalue = EVAL(ast.val[1], env)
110 if FalseQ(condvalue) || NilQ(condvalue)
120 elseif first_symbol == "do"
121 let astlist = ast.val
122 call EvalAst(ListNew(astlist[1:-2]), env)
123 let ast = astlist[-1]
125 elseif first_symbol == "fn*"
126 let fn = NewFn(ListNth(ast, 2), env, ListNth(ast, 1))
128 elseif first_symbol == "eval"
129 let ast = EVAL(ListNth(ast, 1), env)
134 let el = EvalAst(ast, env)
135 let funcobj = ListFirst(el)
136 let args = ListRest(el)
137 if NativeFunctionQ(funcobj)
138 return NativeFuncInvoke(funcobj, args)
139 elseif FunctionQ(funcobj)
142 let env = NewEnvWithBinds(fn.env, fn.params, args)
145 throw "Not a function"
152 return PrStr(a:exp, 1)
155 function RE(str, env)
156 return EVAL(READ(a:str), a:env)
159 function REP(str, env)
160 return PRINT(EVAL(READ(a:str), a:env))
163 function GetArgvList()
164 return ListNew(map(copy(argv()[1:]), {_, arg -> StringNew(arg)}))
167 set maxfuncdepth=10000
168 let repl_env = NewEnv("")
170 for [k, v] in items(CoreNs)
171 call repl_env.set(k, v)
174 call repl_env.set("*ARGV*", GetArgvList())
176 call RE("(def! not (fn* (a) (if a false true)))", repl_env)
177 call RE("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", repl_env)
180 call RE('(load-file "' . argv(0) . '")', repl_env)
185 let [eof, line] = Readline("user> ")
193 call PrintLn(REP(line, repl_env))
195 call PrintLn("Error: " . v:exception)