DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / vimscript / step4_if_fn_do.vim
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)
14 let varname = a:ast.val
15 return a:env.get(varname)
16 elseif ListQ(a:ast)
17 return ListNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
18 elseif VectorQ(a:ast)
19 return VectorNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
20 elseif HashQ(a:ast)
21 let ret = {}
22 for [k,v] in items(a:ast.val)
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
39 if EmptyQ(a:ast)
40 return a:ast
41 endif
42
43 let first = ListFirst(a:ast)
44 let first_symbol = SymbolQ(first) ? first.val : ""
45 if first_symbol == "def!"
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))
49 return ret
50 elseif first_symbol == "let*"
51 let a1 = a:ast.val[1]
52 let a2 = a:ast.val[2]
53 let let_env = NewEnv(a:env)
54 let let_binds = a1.val
55 let i = 0
56 while i < len(let_binds)
57 call let_env.set(let_binds[i].val, EVAL(let_binds[i+1], let_env))
58 let i = i + 2
59 endwhile
60 return EVAL(a2, let_env)
61 elseif first_symbol == "if"
62 let condvalue = EVAL(a:ast.val[1], a:env)
63 if FalseQ(condvalue) || NilQ(condvalue)
64 if len(a:ast.val) < 4
65 return g:MalNil
66 else
67 return EVAL(a:ast.val[3], a:env)
68 endif
69 else
70 return EVAL(a:ast.val[2], a:env)
71 endif
72 elseif first_symbol == "do"
73 let el = EvalAst(ListRest(a:ast), a:env)
74 return el.val[-1]
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!