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