Move implementations into impls/ dir
[jackhill/mal.git] / impls / vimscript / step7_quote.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 PairQ(obj)
13 return SequentialQ(a:obj) && !EmptyQ(a:obj)
14 endfunction
15
16 function Quasiquote(ast)
17 if !PairQ(a:ast)
18 return ListNew([SymbolNew("quote"), a:ast])
19 endif
20 let a0 = ListFirst(a:ast)
21 if SymbolQ(a0) && a0.val == "unquote"
22 return ListNth(a:ast, 1)
23 elseif PairQ(a0) && SymbolQ(ListFirst(a0)) && ListFirst(a0).val == "splice-unquote"
24 return ListNew([SymbolNew("concat"), ListNth(a0, 1), Quasiquote(ListRest(a:ast))])
25 else
26 return ListNew([SymbolNew("cons"), Quasiquote(a0), Quasiquote(ListRest(a:ast))])
27 end
28 endfunction
29
30 function EvalAst(ast, env)
31 if SymbolQ(a:ast)
32 let varname = a:ast.val
33 return a:env.get(varname)
34 elseif ListQ(a:ast)
35 return ListNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
36 elseif VectorQ(a:ast)
37 return VectorNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
38 elseif HashQ(a:ast)
39 let ret = {}
40 for [k,v] in items(a:ast.val)
41 let keyobj = HashParseKey(k)
42 let newkey = EVAL(keyobj, a:env)
43 let newval = EVAL(v, a:env)
44 let keystring = HashMakeKey(newkey)
45 let ret[keystring] = newval
46 endfor
47 return HashNew(ret)
48 else
49 return a:ast
50 end
51 endfunction
52
53 function EVAL(ast, env)
54 let ast = a:ast
55 let env = a:env
56
57 while 1
58 if !ListQ(ast)
59 return EvalAst(ast, env)
60 end
61 if EmptyQ(ast)
62 return ast
63 endif
64
65 let first = ListFirst(ast)
66 let first_symbol = SymbolQ(first) ? first.val : ""
67 if first_symbol == "def!"
68 let a1 = ast.val[1]
69 let a2 = ast.val[2]
70 let ret = env.set(a1.val, EVAL(a2, env))
71 return ret
72 elseif first_symbol == "let*"
73 let a1 = ast.val[1]
74 let a2 = ast.val[2]
75 let env = NewEnv(env)
76 let let_binds = a1.val
77 let i = 0
78 while i < len(let_binds)
79 call env.set(let_binds[i].val, EVAL(let_binds[i+1], env))
80 let i = i + 2
81 endwhile
82 let ast = a2
83 " TCO
84 elseif first_symbol == "quote"
85 return ListNth(ast, 1)
86 elseif first_symbol == "quasiquote"
87 let ast = Quasiquote(ListNth(ast, 1))
88 " TCO
89 elseif first_symbol == "if"
90 let condvalue = EVAL(ast.val[1], env)
91 if FalseQ(condvalue) || NilQ(condvalue)
92 if len(ast.val) < 4
93 return g:MalNil
94 else
95 let ast = ast.val[3]
96 endif
97 else
98 let ast = ast.val[2]
99 endif
100 " TCO
101 elseif first_symbol == "do"
102 let astlist = ast.val
103 call EvalAst(ListNew(astlist[1:-2]), env)
104 let ast = astlist[-1]
105 " TCO
106 elseif first_symbol == "fn*"
107 let fn = NewFn(ListNth(ast, 2), env, ListNth(ast, 1))
108 return fn
109 elseif first_symbol == "eval"
110 let ast = EVAL(ListNth(ast, 1), env)
111 let env = env.root()
112 " TCO
113 else
114 " apply list
115 let el = EvalAst(ast, env)
116 let funcobj = ListFirst(el)
117 let args = ListRest(el)
118 if NativeFunctionQ(funcobj)
119 return NativeFuncInvoke(funcobj, args)
120 elseif FunctionQ(funcobj)
121 let fn = funcobj.val
122 let ast = fn.ast
123 let env = NewEnvWithBinds(fn.env, fn.params, args)
124 " TCO
125 else
126 throw "Not a function"
127 endif
128 endif
129 endwhile
130 endfunction
131
132 function PRINT(exp)
133 return PrStr(a:exp, 1)
134 endfunction
135
136 function RE(str, env)
137 return EVAL(READ(a:str), a:env)
138 endfunction
139
140 function REP(str, env)
141 return PRINT(EVAL(READ(a:str), a:env))
142 endfunction
143
144 function GetArgvList()
145 return ListNew(map(copy(argv()[1:]), {_, arg -> StringNew(arg)}))
146 endfunction
147
148 set maxfuncdepth=10000
149 let repl_env = NewEnv("")
150
151 for [k, v] in items(CoreNs)
152 call repl_env.set(k, v)
153 endfor
154
155 call repl_env.set("*ARGV*", GetArgvList())
156
157 call RE("(def! not (fn* (a) (if a false true)))", repl_env)
158 call RE("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", repl_env)
159
160 if !empty(argv())
161 call RE('(load-file "' . argv(0) . '")', repl_env)
162 qall!
163 endif
164
165 while 1
166 let [eof, line] = Readline("user> ")
167 if eof
168 break
169 endif
170 if line == ""
171 continue
172 endif
173 try
174 call PrintLn(REP(line, repl_env))
175 catch
176 call PrintLn("Error: " . v:exception)
177 endtry
178 endwhile
179 qall!