DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / vimscript / types.vim
1 " types module
2
3 function ObjNewWithMeta(obj_type, obj_val, obj_meta)
4 return {"type": a:obj_type, "val": a:obj_val, "meta": a:obj_meta}
5 endfunction
6
7 function ObjNew(obj_type, obj_val)
8 return {"type": a:obj_type, "val": a:obj_val}
9 endfunction
10
11 function ObjHasMeta(obj)
12 return has_key(a:obj, "meta")
13 endfunction
14
15 function ObjMeta(obj)
16 return ObjHasMeta(a:obj) ? a:obj["meta"] : g:MalNil
17 endfunction
18
19 function ObjSetValue(obj, newval)
20 let a:obj["val"] = a:newval
21 return a:newval
22 endfunction
23
24 function ObjSetMeta(obj, newmeta)
25 let a:obj["meta"] = a:newmeta
26 return a:newmeta
27 endfunction
28
29 function SymbolQ(obj)
30 return a:obj.type == "symbol"
31 endfunction
32
33 function StringQ(obj)
34 return a:obj.type == "string"
35 endfunction
36
37 function KeywordQ(obj)
38 return a:obj.type == "keyword"
39 endfunction
40
41 function AtomQ(obj)
42 return a:obj.type == "atom"
43 endfunction
44
45 function NilQ(obj)
46 return a:obj.type == "nil"
47 endfunction
48
49 function TrueQ(obj)
50 return a:obj.type == "true"
51 endfunction
52
53 function FalseQ(obj)
54 return a:obj.type == "false"
55 endfunction
56
57 function IntegerQ(obj)
58 return a:obj.type == "integer"
59 endfunction
60
61 function FloatQ(obj)
62 return a:obj.type == "float"
63 endfunction
64
65 function ListQ(obj)
66 return a:obj.type == "list"
67 endfunction
68
69 function VectorQ(obj)
70 return a:obj.type == "vector"
71 endfunction
72
73 function SequentialQ(obj)
74 return ListQ(a:obj) || VectorQ(a:obj)
75 endfunction
76
77 function HashQ(obj)
78 return a:obj.type == "hash"
79 endfunction
80
81 function FunctionQ(obj)
82 return a:obj.type == "function" && !a:obj.val.is_macro
83 endfunction
84
85 function MacroQ(obj)
86 return a:obj.type == "function" && a:obj.val.is_macro
87 endfunction
88
89 function NativeFunctionQ(obj)
90 return a:obj.type == "nativefunction"
91 endfunction
92
93 function NilNew()
94 return ObjNew("nil", "")
95 endfunction
96
97 function TrueNew()
98 return ObjNew("true", "")
99 endfunction
100
101 function FalseNew()
102 return ObjNew("false", "")
103 endfunction
104
105 function BoolNew(bool)
106 return a:bool ? g:MalTrue : g:MalFalse
107 endfunction
108
109 function KeywordNew(val)
110 return ObjNew("keyword", a:val)
111 endfunction
112
113 function AtomNew(val)
114 return ObjNewWithMeta("atom", a:val, g:MalNil)
115 endfunction
116
117 function SymbolNew(val)
118 return ObjNew("symbol", a:val)
119 endfunction
120
121 function StringNew(val)
122 return ObjNew("string", a:val)
123 endfunction
124
125 function IntegerNew(val)
126 return ObjNew("integer", a:val)
127 endfunction
128
129 function FloatNew(val)
130 return ObjNew("float", a:val)
131 endfunction
132
133 function ListNew(val)
134 return ObjNewWithMeta("list", a:val, g:MalNil)
135 endfunction
136
137 function VectorNew(val)
138 return ObjNewWithMeta("vector", a:val, g:MalNil)
139 endfunction
140
141 function HashNew(val)
142 return ObjNewWithMeta("hash", a:val, g:MalNil)
143 endfunction
144
145 function HashMakeKey(obj)
146 if !StringQ(a:obj) && !KeywordQ(a:obj)
147 throw "expected hash-map key string, got: " . a:obj.type);
148 endif
149 return a:obj.type . "#" . a:obj.val
150 endfunction
151
152 function HashParseKey(str)
153 if a:str =~ "^string#"
154 return StringNew(a:str[7:])
155 elseif a:str =~ "^keyword#"
156 return KeywordNew(a:str[8:])
157 endif
158 endfunction
159
160 function HashBuild(elements)
161 if (len(a:elements) % 2) != 0
162 throw "Odd number of hash-map arguments"
163 endif
164 let i = 0
165 let hash = {}
166 while i < len(a:elements)
167 let key = a:elements[i]
168 let val = a:elements[i + 1]
169 let keystring = HashMakeKey(key)
170 let hash[keystring] = val
171 let i = i + 2
172 endwhile
173 return HashNew(hash)
174 endfunction
175
176 function HashEqualQ(x, y)
177 if len(a:x.val) != len(a:y.val)
178 return 0
179 endif
180 for k in keys(a:x.val)
181 let vx = a:x.val[k]
182 let vy = a:y.val[k]
183 if empty(vy) || !EqualQ(vx, vy)
184 return 0
185 endif
186 endfor
187 return 1
188 endfunction
189
190 function SequentialEqualQ(x, y)
191 if len(a:x.val) != len(a:y.val)
192 return 0
193 endif
194 let i = 0
195 while i < len(a:x.val)
196 let ex = a:x.val[i]
197 let ey = a:y.val[i]
198 if !EqualQ(ex, ey)
199 return 0
200 endif
201 let i = i +1
202 endwhile
203 return 1
204 endfunction
205
206 function EqualQ(x, y)
207 if SequentialQ(a:x) && SequentialQ(a:y)
208 return SequentialEqualQ(a:x, a:y)
209 elseif HashQ(a:x) && HashQ(a:y)
210 return HashEqualQ(a:x, a:y)
211 elseif a:x.type != a:y.type
212 return 0
213 else
214 return a:x.val == a:y.val
215 endif
216 endfunction
217
218 function EmptyQ(list)
219 return empty(a:list.val)
220 endfunction
221
222 function ListCount(list)
223 return len(a:list.val)
224 endfunction
225
226 function ListNth(list, index)
227 if a:index >= len(a:list.val)
228 throw "nth: index out of range"
229 endif
230 return a:list.val[a:index]
231 endfunction
232
233 function ListFirst(list)
234 return get(a:list.val, 0, g:MalNil)
235 endfunction
236
237 function ListDrop(list, drop_elements)
238 return ListNew(a:list.val[a:drop_elements :])
239 endfunction
240
241 function ListRest(list)
242 return ListDrop(a:list, 1)
243 endfunction
244
245 function FuncInvoke(funcobj, args)
246 let fn = a:funcobj.val
247 let funcenv = NewEnvWithBinds(fn.env, fn.params, a:args)
248 return EVAL(fn.ast, funcenv)
249 endfunction
250
251 function NativeFuncInvoke(funcobj, argslist)
252 let fn = a:funcobj.val
253 return fn.Func(a:argslist.val)
254 endfunction
255
256 function MarkAsMacro(funcobj)
257 let fn = a:funcobj.val
258 let fn.is_macro = 1
259 return a:funcobj
260 endfunction
261
262 function NewFn(ast, env, params)
263 let fn = {"ast": a:ast, "env": a:env, "params": a:params, "is_macro": 0}
264 return ObjNewWithMeta("function", fn, g:MalNil)
265 endfunction
266
267 function NewNativeFn(funcname)
268 let fn = {"Func": function(a:funcname), "name": a:funcname}
269 return ObjNewWithMeta("nativefunction", fn, g:MalNil)
270 endfunction
271
272 function NewNativeFnLambda(lambdaexpr)
273 let fn = {"Func": a:lambdaexpr, "name": "inline"}
274 return ObjNewWithMeta("nativefunction", fn, g:MalNil)
275 endfunction
276
277 let g:MalNil = NilNew()
278 let g:MalTrue = TrueNew()
279 let g:MalFalse = FalseNew()