Commit | Line | Data |
---|---|---|
50a964ce DM |
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 | ||
50a964ce | 11 | function ObjHasMeta(obj) |
b628a220 | 12 | return has_key(a:obj, "meta") |
50a964ce DM |
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 | ||
50a964ce | 29 | function SymbolQ(obj) |
b628a220 | 30 | return a:obj.type == "symbol" |
50a964ce DM |
31 | endfunction |
32 | ||
33 | function StringQ(obj) | |
b628a220 | 34 | return a:obj.type == "string" |
50a964ce DM |
35 | endfunction |
36 | ||
37 | function KeywordQ(obj) | |
b628a220 | 38 | return a:obj.type == "keyword" |
50a964ce DM |
39 | endfunction |
40 | ||
41 | function AtomQ(obj) | |
b628a220 | 42 | return a:obj.type == "atom" |
50a964ce DM |
43 | endfunction |
44 | ||
45 | function NilQ(obj) | |
b628a220 | 46 | return a:obj.type == "nil" |
50a964ce DM |
47 | endfunction |
48 | ||
49 | function TrueQ(obj) | |
b628a220 | 50 | return a:obj.type == "true" |
50a964ce DM |
51 | endfunction |
52 | ||
53 | function FalseQ(obj) | |
b628a220 | 54 | return a:obj.type == "false" |
50a964ce DM |
55 | endfunction |
56 | ||
57 | function IntegerQ(obj) | |
b628a220 | 58 | return a:obj.type == "integer" |
50a964ce DM |
59 | endfunction |
60 | ||
61 | function FloatQ(obj) | |
b628a220 | 62 | return a:obj.type == "float" |
50a964ce DM |
63 | endfunction |
64 | ||
65 | function ListQ(obj) | |
b628a220 | 66 | return a:obj.type == "list" |
50a964ce DM |
67 | endfunction |
68 | ||
69 | function VectorQ(obj) | |
b628a220 | 70 | return a:obj.type == "vector" |
50a964ce DM |
71 | endfunction |
72 | ||
73 | function SequentialQ(obj) | |
b628a220 | 74 | return ListQ(a:obj) || VectorQ(a:obj) |
50a964ce DM |
75 | endfunction |
76 | ||
77 | function HashQ(obj) | |
b628a220 | 78 | return a:obj.type == "hash" |
50a964ce DM |
79 | endfunction |
80 | ||
81 | function FunctionQ(obj) | |
b628a220 | 82 | return a:obj.type == "function" && !a:obj.val.is_macro |
50a964ce DM |
83 | endfunction |
84 | ||
85 | function MacroQ(obj) | |
b628a220 | 86 | return a:obj.type == "function" && a:obj.val.is_macro |
50a964ce DM |
87 | endfunction |
88 | ||
89 | function NativeFunctionQ(obj) | |
b628a220 | 90 | return a:obj.type == "nativefunction" |
50a964ce DM |
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) | |
b0b1e169 | 147 | throw "expected hash-map key string, got: " . a:obj.type); |
50a964ce | 148 | endif |
b0b1e169 | 149 | return a:obj.type . "#" . a:obj.val |
50a964ce DM |
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) | |
82641edb | 177 | if len(a:x.val) != len(a:y.val) |
50a964ce DM |
178 | return 0 |
179 | endif | |
82641edb DM |
180 | for k in keys(a:x.val) |
181 | let vx = a:x.val[k] | |
182 | let vy = a:y.val[k] | |
50a964ce DM |
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) | |
82641edb | 191 | if len(a:x.val) != len(a:y.val) |
50a964ce DM |
192 | return 0 |
193 | endif | |
194 | let i = 0 | |
82641edb DM |
195 | while i < len(a:x.val) |
196 | let ex = a:x.val[i] | |
197 | let ey = a:y.val[i] | |
50a964ce DM |
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) | |
b0b1e169 | 211 | elseif a:x.type != a:y.type |
50a964ce DM |
212 | return 0 |
213 | else | |
82641edb | 214 | return a:x.val == a:y.val |
50a964ce DM |
215 | endif |
216 | endfunction | |
217 | ||
218 | function EmptyQ(list) | |
82641edb | 219 | return empty(a:list.val) |
50a964ce DM |
220 | endfunction |
221 | ||
222 | function ListCount(list) | |
82641edb | 223 | return len(a:list.val) |
50a964ce DM |
224 | endfunction |
225 | ||
226 | function ListNth(list, index) | |
82641edb | 227 | if a:index >= len(a:list.val) |
50a964ce DM |
228 | throw "nth: index out of range" |
229 | endif | |
82641edb | 230 | return a:list.val[a:index] |
50a964ce DM |
231 | endfunction |
232 | ||
233 | function ListFirst(list) | |
82641edb | 234 | return get(a:list.val, 0, g:MalNil) |
50a964ce DM |
235 | endfunction |
236 | ||
237 | function ListDrop(list, drop_elements) | |
82641edb | 238 | return ListNew(a:list.val[a:drop_elements :]) |
50a964ce DM |
239 | endfunction |
240 | ||
241 | function ListRest(list) | |
242 | return ListDrop(a:list, 1) | |
243 | endfunction | |
244 | ||
245 | function FuncInvoke(funcobj, args) | |
82641edb | 246 | let fn = a:funcobj.val |
50a964ce DM |
247 | let funcenv = NewEnvWithBinds(fn.env, fn.params, a:args) |
248 | return EVAL(fn.ast, funcenv) | |
249 | endfunction | |
250 | ||
251 | function NativeFuncInvoke(funcobj, argslist) | |
82641edb DM |
252 | let fn = a:funcobj.val |
253 | return fn.Func(a:argslist.val) | |
50a964ce DM |
254 | endfunction |
255 | ||
256 | function MarkAsMacro(funcobj) | |
82641edb | 257 | let fn = a:funcobj.val |
50a964ce DM |
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 | ||
aa62cbda DM |
272 | function NewNativeFnLambda(lambdaexpr) |
273 | let fn = {"Func": a:lambdaexpr, "name": "inline"} | |
274 | return ObjNewWithMeta("nativefunction", fn, g:MalNil) | |
275 | endfunction | |
276 | ||
50a964ce DM |
277 | let g:MalNil = NilNew() |
278 | let g:MalTrue = TrueNew() | |
279 | let g:MalFalse = FalseNew() |