Commit | Line | Data |
---|---|---|
50a964ce DM |
1 | source readline.vim |
2 | source types.vim | |
3 | source reader.vim | |
4 | source printer.vim | |
5 | source env.vim | |
6 | source core.vim | |
7 | ||
8 | function READ(str) | |
9 | return ReadStr(a:str) | |
10 | endfunction | |
11 | ||
12 | function EvalAst(ast, env) | |
13 | if SymbolQ(a:ast) | |
82641edb | 14 | let varname = a:ast.val |
50a964ce DM |
15 | return a:env.get(varname) |
16 | elseif ListQ(a:ast) | |
4fbbe571 | 17 | return ListNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)})) |
50a964ce | 18 | elseif VectorQ(a:ast) |
4fbbe571 | 19 | return VectorNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)})) |
50a964ce DM |
20 | elseif HashQ(a:ast) |
21 | let ret = {} | |
82641edb | 22 | for [k,v] in items(a:ast.val) |
50a964ce DM |
23 | let keyobj = HashParseKey(k) |
24 | let newkey = EVAL(keyobj, a:env) | |
25 | let newval = EVAL(v, a:env) | |
26 | let keystring = HashMakeKey(newkey) | |
27 | let ret[keystring] = newval | |
28 | endfor | |
29 | return HashNew(ret) | |
30 | else | |
31 | return a:ast | |
32 | end | |
33 | endfunction | |
34 | ||
35 | function EVAL(ast, env) | |
36 | let ast = a:ast | |
37 | let env = a:env | |
38 | ||
39 | while 1 | |
40 | if !ListQ(ast) | |
41 | return EvalAst(ast, env) | |
42 | end | |
8f27005f DM |
43 | if EmptyQ(ast) |
44 | return ast | |
45 | endif | |
50a964ce DM |
46 | |
47 | let first = ListFirst(ast) | |
82641edb | 48 | let first_symbol = SymbolQ(first) ? first.val : "" |
50a964ce | 49 | if first_symbol == "def!" |
82641edb DM |
50 | let a1 = ast.val[1] |
51 | let a2 = ast.val[2] | |
52 | let ret = env.set(a1.val, EVAL(a2, env)) | |
50a964ce DM |
53 | return ret |
54 | elseif first_symbol == "let*" | |
82641edb DM |
55 | let a1 = ast.val[1] |
56 | let a2 = ast.val[2] | |
50a964ce | 57 | let env = NewEnv(env) |
82641edb | 58 | let let_binds = a1.val |
50a964ce DM |
59 | let i = 0 |
60 | while i < len(let_binds) | |
82641edb | 61 | call env.set(let_binds[i].val, EVAL(let_binds[i+1], env)) |
50a964ce DM |
62 | let i = i + 2 |
63 | endwhile | |
64 | let ast = a2 | |
65 | " TCO | |
66 | elseif first_symbol == "if" | |
82641edb | 67 | let condvalue = EVAL(ast.val[1], env) |
50a964ce | 68 | if FalseQ(condvalue) || NilQ(condvalue) |
82641edb | 69 | if len(ast.val) < 4 |
50a964ce DM |
70 | return g:MalNil |
71 | else | |
82641edb | 72 | let ast = ast.val[3] |
50a964ce DM |
73 | endif |
74 | else | |
82641edb | 75 | let ast = ast.val[2] |
50a964ce DM |
76 | endif |
77 | " TCO | |
78 | elseif first_symbol == "do" | |
82641edb | 79 | let astlist = ast.val |
50a964ce DM |
80 | call EvalAst(ListNew(astlist[1:-2]), env) |
81 | let ast = astlist[-1] | |
82 | " TCO | |
83 | elseif first_symbol == "fn*" | |
84 | let fn = NewFn(ListNth(ast, 2), env, ListNth(ast, 1)) | |
85 | return fn | |
86 | elseif first_symbol == "eval" | |
87 | let ast = EVAL(ListNth(ast, 1), env) | |
88 | let env = env.root() | |
89 | " TCO | |
90 | else | |
91 | " apply list | |
92 | let el = EvalAst(ast, env) | |
93 | let funcobj = ListFirst(el) | |
94 | let args = ListRest(el) | |
95 | if NativeFunctionQ(funcobj) | |
96 | return NativeFuncInvoke(funcobj, args) | |
97 | elseif FunctionQ(funcobj) | |
82641edb | 98 | let fn = funcobj.val |
50a964ce DM |
99 | let ast = fn.ast |
100 | let env = NewEnvWithBinds(fn.env, fn.params, args) | |
101 | " TCO | |
102 | else | |
103 | throw "Not a function" | |
104 | endif | |
105 | endif | |
106 | endwhile | |
107 | endfunction | |
108 | ||
109 | function PRINT(exp) | |
110 | return PrStr(a:exp, 1) | |
111 | endfunction | |
112 | ||
113 | function RE(str, env) | |
114 | return EVAL(READ(a:str), a:env) | |
115 | endfunction | |
116 | ||
117 | function REP(str, env) | |
118 | return PRINT(EVAL(READ(a:str), a:env)) | |
119 | endfunction | |
120 | ||
121 | function GetArgvList() | |
43d17539 | 122 | return ListNew(map(copy(argv()[1:]), {_, arg -> StringNew(arg)})) |
50a964ce DM |
123 | endfunction |
124 | ||
125 | set maxfuncdepth=10000 | |
126 | let repl_env = NewEnv("") | |
127 | ||
128 | for [k, v] in items(CoreNs) | |
129 | call repl_env.set(k, v) | |
130 | endfor | |
131 | ||
132 | call repl_env.set("*ARGV*", GetArgvList()) | |
133 | ||
134 | call RE("(def! not (fn* (a) (if a false true)))", repl_env) | |
e6d41de4 | 135 | call RE("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", repl_env) |
50a964ce DM |
136 | |
137 | if !empty(argv()) | |
138 | call RE('(load-file "' . argv(0) . '")', repl_env) | |
139 | qall! | |
140 | endif | |
141 | ||
142 | while 1 | |
143 | let [eof, line] = Readline("user> ") | |
144 | if eof | |
145 | break | |
146 | endif | |
147 | if line == "" | |
148 | continue | |
149 | endif | |
150 | try | |
151 | call PrintLn(REP(line, repl_env)) | |
152 | catch | |
153 | call PrintLn("Error: " . v:exception) | |
154 | endtry | |
155 | endwhile | |
156 | qall! |