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 | if !ListQ(a:ast) | |
37 | return EvalAst(a:ast, a:env) | |
38 | end | |
8f27005f DM |
39 | if EmptyQ(a:ast) |
40 | return a:ast | |
41 | endif | |
50a964ce DM |
42 | |
43 | let first = ListFirst(a:ast) | |
82641edb | 44 | let first_symbol = SymbolQ(first) ? first.val : "" |
50a964ce | 45 | if first_symbol == "def!" |
82641edb DM |
46 | let a1 = a:ast.val[1] |
47 | let a2 = a:ast.val[2] | |
48 | let ret = a:env.set(a1.val, EVAL(a2, a:env)) | |
50a964ce DM |
49 | return ret |
50 | elseif first_symbol == "let*" | |
82641edb DM |
51 | let a1 = a:ast.val[1] |
52 | let a2 = a:ast.val[2] | |
50a964ce | 53 | let let_env = NewEnv(a:env) |
82641edb | 54 | let let_binds = a1.val |
50a964ce DM |
55 | let i = 0 |
56 | while i < len(let_binds) | |
82641edb | 57 | call let_env.set(let_binds[i].val, EVAL(let_binds[i+1], let_env)) |
50a964ce DM |
58 | let i = i + 2 |
59 | endwhile | |
60 | return EVAL(a2, let_env) | |
61 | elseif first_symbol == "if" | |
82641edb | 62 | let condvalue = EVAL(a:ast.val[1], a:env) |
50a964ce | 63 | if FalseQ(condvalue) || NilQ(condvalue) |
82641edb | 64 | if len(a:ast.val) < 4 |
50a964ce DM |
65 | return g:MalNil |
66 | else | |
82641edb | 67 | return EVAL(a:ast.val[3], a:env) |
50a964ce DM |
68 | endif |
69 | else | |
82641edb | 70 | return EVAL(a:ast.val[2], a:env) |
50a964ce DM |
71 | endif |
72 | elseif first_symbol == "do" | |
73 | let el = EvalAst(ListRest(a:ast), a:env) | |
82641edb | 74 | return el.val[-1] |
50a964ce DM |
75 | elseif first_symbol == "fn*" |
76 | let fn = NewFn(ListNth(a:ast, 2), a:env, ListNth(a:ast, 1)) | |
77 | return fn | |
78 | else | |
79 | " apply list | |
80 | let el = EvalAst(a:ast, a:env) | |
81 | let funcobj = ListFirst(el) | |
82 | let args = ListRest(el) | |
83 | if NativeFunctionQ(funcobj) | |
84 | return NativeFuncInvoke(funcobj, args) | |
85 | elseif FunctionQ(funcobj) | |
86 | return FuncInvoke(funcobj, args) | |
87 | else | |
88 | throw "Not a function" | |
89 | endif | |
90 | endif | |
91 | endfunction | |
92 | ||
93 | function PRINT(exp) | |
94 | return PrStr(a:exp, 1) | |
95 | endfunction | |
96 | ||
97 | function REP(str, env) | |
98 | return PRINT(EVAL(READ(a:str), a:env)) | |
99 | endfunction | |
100 | ||
101 | let repl_env = NewEnv("") | |
102 | ||
103 | for [k, Fn] in items(CoreNs) | |
104 | call repl_env.set(k, Fn) | |
105 | endfor | |
106 | ||
107 | call REP("(def! not (fn* (a) (if a false true)))", repl_env) | |
108 | ||
109 | while 1 | |
110 | let [eof, line] = Readline("user> ") | |
111 | if eof | |
112 | break | |
113 | endif | |
114 | if line == "" | |
115 | continue | |
116 | endif | |
117 | try | |
118 | call PrintLn(REP(line, repl_env)) | |
119 | catch | |
120 | call PrintLn("Error: " . v:exception) | |
121 | endtry | |
122 | endwhile | |
123 | qall! |