All: fix get. All pass stepA tests.
[jackhill/mal.git] / python / core.py
1 import copy
2 from itertools import chain
3
4 import mal_types as types
5 from mal_types import List, Vector
6 import printer
7
8 # Errors/Exceptions
9 def throw(exc): raise Exception(exc)
10
11
12 # String functions
13 def pr_str(*args):
14 return " ".join(map(lambda exp: printer._pr_str(exp, True), args))
15
16 def do_str(*args):
17 return "".join(map(lambda exp: printer._pr_str(exp, False), args))
18
19 def prn(*args):
20 print " ".join(map(lambda exp: printer._pr_str(exp, True), args))
21 return None
22
23 def println(*args):
24 line = " ".join(map(lambda exp: printer._pr_str(exp, False), args))
25 print line.replace('\\n', '\n')
26 return None
27
28
29 # Hash map functions
30 def assoc(src_hm, *key_vals):
31 hm = copy.copy(src_hm)
32 for i in range(0,len(key_vals),2): hm[key_vals[i]] = key_vals[i+1]
33 return hm
34
35 def dissoc(src_hm, *keys):
36 hm = copy.copy(src_hm)
37 for key in keys:
38 if key in hm: del hm[key]
39 return hm
40
41 def get(hm, key):
42 if hm and key in hm:
43 return hm[key]
44 else:
45 return None
46
47 def contains_Q(hm, key): return key in hm
48
49 def keys(hm): return types._list(*hm.keys())
50
51 def vals(hm): return types._list(*hm.values())
52
53
54 # Sequence functions
55 def coll_Q(coll): return sequential_Q(coll) or hash_map_Q(coll)
56
57 def cons(x, seq): return List([x]) + List(seq)
58
59 def concat(*lsts): return List(chain(*lsts))
60
61 def nth(lst, idx): return lst[idx]
62
63 def first(lst): return lst[0]
64
65 def rest(lst): return List(lst[1:])
66
67 def empty_Q(lst): return len(lst) == 0
68
69 def count(lst): return len(lst)
70
71 # retains metadata
72 def conj(lst, *args):
73 if types._list_Q(lst):
74 new_lst = List(list(reversed(list(args))) + lst)
75 else:
76 new_lst = Vector(lst + list(args))
77 if hasattr(lst, "__meta__"):
78 new_lst.__meta__ = lst.__meta__
79 return new_lst
80
81 def apply(f, *args): return f(*(list(args[0:-1])+args[-1]))
82
83 def mapf(f, lst): return List(map(f, lst))
84
85
86 # Metadata functions
87 def with_meta(obj, meta):
88 if type(obj) == type(lambda x:x):
89 new_obj = obj.__copy__()
90 else:
91 new_obj = copy.copy(obj)
92 new_obj.__meta__ = meta
93 return new_obj
94
95 def meta(obj):
96 if hasattr(obj, "__meta__"): return obj.__meta__
97 else: return None
98
99
100 # Atoms functions
101 def deref(atm): return atm.val
102 def reset_BANG(atm,val):
103 atm.val = val
104 return atm.val
105 def swap_BANG(atm,f,*args):
106 atm.val = f(atm.val,*args)
107 return atm.val
108
109
110 ns = {
111 '=': types._equal_Q,
112 'throw': throw,
113 'nil?': types._nil_Q,
114 'true?': types._true_Q,
115 'false?': types._false_Q,
116 'symbol': types._symbol,
117 'symbol?': types._symbol_Q,
118 'pr-str': pr_str,
119 'str': do_str,
120 'prn': prn,
121 'println': println,
122 '<': lambda a,b: a<b,
123 '<=': lambda a,b: a<=b,
124 '>': lambda a,b: a>b,
125 '>=': lambda a,b: a>=b,
126 '+': lambda a,b: a+b,
127 '-': lambda a,b: a-b,
128 '*': lambda a,b: a*b,
129 '/': lambda a,b: a/b,
130
131 'list': types._list,
132 'list?': types._list_Q,
133 'vector': types._vector,
134 'vector?': types._vector_Q,
135 'hash-map': types._hash_map,
136 'map?': types._hash_map_Q,
137 'assoc': assoc,
138 'dissoc': dissoc,
139 'get': get,
140 'contains?': contains_Q,
141 'keys': keys,
142 'vals': vals,
143
144 'sequential?': types._sequential_Q,
145 'cons': cons,
146 'concat': concat,
147 'nth': nth,
148 'first': first,
149 'rest': rest,
150 'empty?': empty_Q,
151 'count': count,
152 'conj': conj,
153 'apply': apply,
154 'map': mapf,
155
156 'with-meta': with_meta,
157 'meta': meta,
158 'atom': types._atom,
159 'atom?': types._atom_Q,
160 'deref': deref,
161 'reset!': reset_BANG,
162 'swap!': swap_BANG}
163