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