RPython: add vector and hash-map support.
[jackhill/mal.git] / rpython / core.py
1 #import copy, time
2 import time
3
4 import mal_types as types
5 from mal_types import (MalType, nil, true, false,
6 MalInt, MalSym, MalStr,
7 MalList, MalVector, MalHashMap)
8 import mal_readline
9 import reader
10 import printer
11
12 # General functions
13 def wrap_tf(tf):
14 if tf: return true
15 else: return false
16
17 def do_equal(args): return wrap_tf(types._equal_Q(args[0], args[1]))
18
19 # Errors/Exceptions
20 def throw(args):
21 raise types.MalException(args[0])
22
23 # Scalar functions
24 def nil_Q(args): return wrap_tf(types._nil_Q(args[0]))
25 def true_Q(args): return wrap_tf(types._true_Q(args[0]))
26 def false_Q(args): return wrap_tf(types._false_Q(args[0]))
27 def symbol(args):
28 a0 = args[0]
29 if isinstance(a0, MalStr):
30 return types._symbol(a0.value)
31 elif isinstance(a0, MalSym):
32 return a0
33 else:
34 types.throw_str("symbol called on non-string/non-symbol")
35 def symbol_Q(args): return wrap_tf(types._symbol_Q(args[0]))
36 def keyword(args): return types._keyword(args[0])
37 def keyword_Q(args): return wrap_tf(types._keyword_Q(args[0]))
38
39
40 # String functions
41 def pr_str(args):
42 parts = []
43 for exp in args.values: parts.append(printer._pr_str(exp, True))
44 return MalStr(u" ".join(parts))
45
46 def do_str(args):
47 parts = []
48 for exp in args.values: parts.append(printer._pr_str(exp, False))
49 return MalStr(u"".join(parts))
50
51 def prn(args):
52 parts = []
53 for exp in args.values: parts.append(printer._pr_str(exp, True))
54 print(u" ".join(parts))
55 return nil
56
57 def println(args):
58 parts = []
59 for exp in args.values: parts.append(printer._pr_str(exp, False))
60 print(u" ".join(parts))
61 return nil
62
63 def do_readline(args):
64 prompt = args[0]
65 assert isinstance(prompt, MalStr)
66 return MalStr(unicode(mal_readline.readline(str(prompt.value))))
67
68 def read_str(args):
69 a0 = args[0]
70 assert isinstance(a0, MalStr)
71 return reader.read_str(str(a0.value))
72
73 def slurp(args):
74 a0 = args[0]
75 assert isinstance(a0, MalStr)
76 return MalStr(unicode(open(str(a0.value)).read()))
77
78 # Number functions
79 def lt(args):
80 a, b = args[0], args[1]
81 assert isinstance(a, MalInt)
82 assert isinstance(b, MalInt)
83 return wrap_tf(a.value < b.value)
84 def lte(args):
85 a, b = args[0], args[1]
86 assert isinstance(a, MalInt)
87 assert isinstance(b, MalInt)
88 return wrap_tf(a.value <= b.value)
89 def gt(args):
90 a, b = args[0], args[1]
91 assert isinstance(a, MalInt)
92 assert isinstance(b, MalInt)
93 return wrap_tf(a.value > b.value)
94 def gte(args):
95 a, b = args[0], args[1]
96 assert isinstance(a, MalInt)
97 assert isinstance(b, MalInt)
98 return wrap_tf(a.value >= b.value)
99
100 def plus(args):
101 a, b = args[0], args[1]
102 assert isinstance(a, MalInt)
103 assert isinstance(b, MalInt)
104 return MalInt(a.value+b.value)
105 def minus(args):
106 a, b = args[0], args[1]
107 assert isinstance(a, MalInt)
108 assert isinstance(b, MalInt)
109 return MalInt(a.value-b.value)
110 def multiply(args):
111 a, b = args[0], args[1]
112 assert isinstance(a, MalInt)
113 assert isinstance(b, MalInt)
114 return MalInt(a.value*b.value)
115 def divide(args):
116 a, b = args[0], args[1]
117 assert isinstance(a, MalInt)
118 assert isinstance(b, MalInt)
119 return MalInt(int(a.value/b.value))
120
121
122 # Hash map functions
123 def do_hash_map(ml):
124 assert isinstance(ml, MalList)
125 return types._hash_mapl(ml.values)
126
127 def hash_map_Q(args):
128 return wrap_tf(types._hash_map_Q(args[0]))
129
130 def assoc(args):
131 src_hm, key_vals = args[0], args.rest()
132 #new_dct = copy.copy(src_hm.dct)
133 new_dct = src_hm.dct.copy()
134 for i in range(0,len(key_vals),2):
135 k = key_vals[i]
136 assert isinstance(k, MalStr)
137 new_dct[k.value] = key_vals[i+1]
138 return MalHashMap(new_dct)
139
140 def dissoc(args):
141 src_hm, keys = args[0], args.rest()
142 #new_dct = copy.copy(src_hm.dct)
143 new_dct = src_hm.dct.copy()
144 for k in keys.values:
145 assert isinstance(k, MalStr)
146 if k.value in new_dct:
147 del new_dct[k.value]
148 return MalHashMap(new_dct)
149
150 def get(args):
151 obj, key = args[0], args[1]
152 if obj is nil:
153 return nil
154 elif isinstance(obj, MalHashMap):
155 assert isinstance(key, MalStr)
156 if obj and key.value in obj.dct:
157 return obj.dct[key.value]
158 else:
159 return nil
160 elif isinstance(obj, MalList):
161 assert isinstance(key, MalInt)
162 return obj.values[key.value]
163 else:
164 raise Exception("get called on invalid type")
165
166 def contains_Q(args):
167 hm, key = args[0], args[1]
168 assert isinstance(key, MalStr)
169 return wrap_tf(key.value in hm.dct)
170
171 def keys(args):
172 hm = args[0]
173 keys = []
174 for k in hm.dct.keys(): keys.append(MalStr(k))
175 return MalList(keys)
176
177 def vals(args):
178 hm = args[0]
179 return MalList(hm.dct.values())
180
181
182 # Sequence functions
183 def do_list(ml):
184 assert isinstance(ml, MalList)
185 return ml
186
187 def list_Q(args):
188 return wrap_tf(types._list_Q(args[0]))
189
190 def do_vector(ml):
191 assert isinstance(ml, MalList)
192 return MalVector(ml.values)
193
194 def vector_Q(args):
195 return wrap_tf(types._vector_Q(args[0]))
196
197 def empty_Q(args):
198 assert isinstance(args, MalType)
199 seq = args[0]
200 if isinstance(seq, MalList):
201 return wrap_tf(len(seq) == 0)
202 elif seq is nil:
203 return true
204 else:
205 types.throw_str("empty? called on non-sequence")
206
207 def count(args):
208 assert isinstance(args, MalType)
209 seq = args[0]
210 if isinstance(seq, MalList):
211 return MalInt(len(seq))
212 elif seq is nil:
213 return MalInt(0)
214 else:
215 types.throw_str("count called on non-sequence")
216
217 #def coll_Q(coll): return sequential_Q(coll) or hash_map_Q(coll)
218 #
219 def sequential_Q(args):
220 return wrap_tf(types._sequential_Q(args[0]))
221
222 def cons(args):
223 x, seq = args[0], args[1]
224 assert isinstance(seq, MalList)
225 return MalList([x] + seq.values)
226
227 def concat(args):
228 new_lst = []
229 for l in args.values:
230 assert isinstance(l, MalList)
231 new_lst = new_lst + l.values
232 return MalList(new_lst)
233
234 def nth(args):
235 lst, idx = args[0], args[1]
236 assert isinstance(lst, MalList)
237 assert isinstance(idx, MalInt)
238 if idx.value < len(lst): return lst[idx.value]
239 else: types.throw_str("nth: index out of range")
240
241 def first(args):
242 a0 = args[0]
243 assert isinstance(a0, MalList)
244 if len(a0) == 0: return nil
245 else: return a0[0]
246
247 def rest(args):
248 a0 = args[0]
249 assert isinstance(a0, MalList)
250 if len(a0) == 0: return MalList([])
251 else: return a0.rest()
252
253 ## retains metadata
254 #def conj(lst, *args):
255 # if types._list_Q(lst):
256 # new_lst = List(list(reversed(list(args))) + lst)
257 # else:
258 # new_lst = Vector(lst + list(args))
259 # if hasattr(lst, "__meta__"):
260 # new_lst.__meta__ = lst.__meta__
261 # return new_lst
262
263 def apply(args):
264 f, fargs = args[0], args.rest()
265 last_arg = fargs.values[-1]
266 assert isinstance(last_arg, MalList)
267 all_args = fargs.values[0:-1] + last_arg.values
268 return f.apply(MalList(all_args))
269
270 def mapf(args):
271 f, lst = args[0], args[1]
272 assert isinstance(lst, MalList)
273 res = []
274 for a in lst.values:
275 res.append(f.apply(MalList([a])))
276 return MalList(res)
277
278
279 ## Metadata functions
280 #def with_meta(obj, meta):
281 # new_obj = types._clone(obj)
282 # new_obj.__meta__ = meta
283 # return new_obj
284 #
285 #def meta(obj):
286 # if hasattr(obj, "__meta__"): return obj.__meta__
287 # else: return None
288 #
289 #
290 ## Atoms functions
291 #def deref(atm): return atm.val
292 #def reset_BANG(atm,val):
293 # atm.val = val
294 # return atm.val
295 #def swap_BANG(atm,f,*args):
296 # atm.val = f(atm.val,*args)
297 # return atm.val
298
299
300 ns = {
301 '=': do_equal,
302 'throw': throw,
303 'nil?': nil_Q,
304 'true?': true_Q,
305 'false?': false_Q,
306 'symbol': symbol,
307 'symbol?': symbol_Q,
308 'keyword': keyword,
309 'keyword?': keyword_Q,
310
311 'pr-str': pr_str,
312 'str': do_str,
313 'prn': prn,
314 'println': println,
315 'readline': do_readline,
316 'read-string': read_str,
317 'slurp': slurp,
318 '<': lt,
319 '<=': lte,
320 '>': gt,
321 '>=': gte,
322 '+': plus,
323 '-': minus,
324 '*': multiply,
325 '/': divide,
326 # 'time-ms': lambda : int(time.time() * 1000),
327 #
328 'list': do_list,
329 'list?': list_Q,
330 'vector': do_vector,
331 'vector?': vector_Q,
332 'hash-map': do_hash_map,
333 'map?': hash_map_Q,
334 'assoc': assoc,
335 'dissoc': dissoc,
336 'get': get,
337 'contains?': contains_Q,
338 'keys': keys,
339 'vals': vals,
340
341 'sequential?': sequential_Q,
342 'cons': cons,
343 'concat': concat,
344 'nth': nth,
345 'first': first,
346 'rest': rest,
347 'empty?': empty_Q,
348 'count': count,
349 # 'conj': conj,
350 'apply': apply,
351 'map': mapf,
352 #
353 # 'with-meta': with_meta,
354 # 'meta': meta,
355 # 'atom': types._atom,
356 # 'atom?': types._atom_Q,
357 # 'deref': deref,
358 # 'reset!': reset_BANG,
359 # 'swap!': swap_BANG
360 }
361