tests: make throw of non-strings optional/soft.
[jackhill/mal.git] / vimscript / step3_env.vim
CommitLineData
50a964ce
DM
1source readline.vim
2source types.vim
3source reader.vim
4source printer.vim
5source env.vim
6
7function READ(str)
8 return ReadStr(a:str)
9endfunction
10
11function EvalAst(ast, env)
12 if SymbolQ(a:ast)
13 let varname = ObjValue(a:ast)
14 return a:env.get(varname)
15 elseif ListQ(a:ast)
16 let ret = []
17 for e in ObjValue(a:ast)
18 call add(ret, EVAL(e, a:env))
19 endfor
20 return ListNew(ret)
21 elseif VectorQ(a:ast)
22 let ret = []
23 for e in ObjValue(a:ast)
24 call add(ret, EVAL(e, a:env))
25 endfor
26 return VectorNew(ret)
27 elseif HashQ(a:ast)
28 let ret = {}
29 for [k,v] in items(ObjValue(a:ast))
30 let keyobj = HashParseKey(k)
31 let newkey = EVAL(keyobj, a:env)
32 let newval = EVAL(v, a:env)
33 let keystring = HashMakeKey(newkey)
34 let ret[keystring] = newval
35 endfor
36 return HashNew(ret)
37 else
38 return a:ast
39 end
40endfunction
41
42function EVAL(ast, env)
43 if !ListQ(a:ast)
44 return EvalAst(a:ast, a:env)
45 end
8f27005f
DM
46 if EmptyQ(a:ast)
47 return a:ast
48 endif
50a964ce
DM
49
50 let first_symbol = ObjValue(ObjValue(a:ast)[0])
51 if first_symbol == "def!"
52 let a1 = ObjValue(a:ast)[1]
53 let a2 = ObjValue(a:ast)[2]
54 return a:env.set(ObjValue(a1), EVAL(a2, a:env))
55 elseif first_symbol == "let*"
56 let a1 = ObjValue(a:ast)[1]
57 let a2 = ObjValue(a:ast)[2]
58 let let_env = NewEnv(a:env)
59 let let_binds = ObjValue(a1)
60 let i = 0
61 while i < len(let_binds)
62 call let_env.set(ObjValue(let_binds[i]), EVAL(let_binds[i+1], let_env))
63 let i = i + 2
64 endwhile
65 return EVAL(a2, let_env)
66 else
67 " apply list
68 let el = EvalAst(a:ast, a:env)
69 let Fn = ObjValue(el)[0]
70 return Fn(ObjValue(el)[1:-1])
71 endif
72
73endfunction
74
75function PRINT(exp)
76 return PrStr(a:exp, 1)
77endfunction
78
79function REP(str, env)
80 return PRINT(EVAL(READ(a:str), a:env))
81endfunction
82
83function MalAdd(args)
84 return IntegerNew(ObjValue(a:args[0]) + ObjValue(a:args[1]))
85endfunction
86
87function MalSub(args)
88 return IntegerNew(ObjValue(a:args[0]) - ObjValue(a:args[1]))
89endfunction
90
91function MalMul(args)
92 return IntegerNew(ObjValue(a:args[0]) * ObjValue(a:args[1]))
93endfunction
94
95function MalDiv(args)
96 return IntegerNew(ObjValue(a:args[0]) / ObjValue(a:args[1]))
97endfunction
98
99let repl_env = NewEnv("")
100call repl_env.set("+", function("MalAdd"))
101call repl_env.set("-", function("MalSub"))
102call repl_env.set("*", function("MalMul"))
103call repl_env.set("/", function("MalDiv"))
104
105while 1
106 let [eof, line] = Readline("user> ")
107 if eof
108 break
109 endif
110 if line == ""
111 continue
112 endif
113 try
114 call PrintLn(REP(line, repl_env))
115 catch
116 call PrintLn("Error: " . v:exception)
117 endtry
118endwhile
119qall!