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