Commit | Line | Data |
---|---|---|
afdf531e | 1 | using System; |
8cb5cda4 | 2 | using System.IO; |
afdf531e | 3 | using System.Collections.Generic; |
b18969c0 | 4 | using MalVal = Mal.types.MalVal; |
afdf531e | 5 | using MalConstant = Mal.types.MalConstant; |
c3b508af | 6 | using MalInt = Mal.types.MalInt; |
faee4d12 | 7 | using MalSymbol = Mal.types.MalSymbol; |
afdf531e | 8 | using MalString = Mal.types.MalString; |
b18969c0 | 9 | using MalList = Mal.types.MalList; |
faee4d12 JM |
10 | using MalVector = Mal.types.MalVector; |
11 | using MalHashMap = Mal.types.MalHashMap; | |
17ae845e | 12 | using MalAtom = Mal.types.MalAtom; |
c3b508af | 13 | using MalFunc = Mal.types.MalFunc; |
b18969c0 JM |
14 | |
15 | namespace Mal { | |
16 | public class core { | |
afdf531e JM |
17 | static MalConstant Nil = Mal.types.Nil; |
18 | static MalConstant True = Mal.types.True; | |
19 | static MalConstant False = Mal.types.False; | |
20 | ||
faee4d12 | 21 | // Errors/Exceptions |
c3b508af | 22 | static public MalFunc mal_throw = new MalFunc( |
faee4d12 JM |
23 | a => { throw new Mal.types.MalException(a[0]); }); |
24 | ||
25 | // Scalar functions | |
c3b508af | 26 | static MalFunc nil_Q = new MalFunc( |
faee4d12 JM |
27 | a => a[0] == Nil ? True : False); |
28 | ||
c3b508af | 29 | static MalFunc true_Q = new MalFunc( |
faee4d12 JM |
30 | a => a[0] == True ? True : False); |
31 | ||
c3b508af | 32 | static MalFunc false_Q = new MalFunc( |
faee4d12 JM |
33 | a => a[0] == False ? True : False); |
34 | ||
c3b508af | 35 | static MalFunc symbol_Q = new MalFunc( |
faee4d12 JM |
36 | a => a[0] is MalSymbol ? True : False); |
37 | ||
b8ee29b2 JM |
38 | static MalFunc keyword = new MalFunc( |
39 | a => new MalString("\u029e" + ((MalString)a[0]).getValue())); | |
40 | ||
41 | static MalFunc keyword_Q = new MalFunc( | |
42 | a => { | |
43 | if (a[0] is MalString && | |
44 | ((MalString)a[0]).getValue()[0] == '\u029e') { | |
45 | return True; | |
46 | } else { | |
47 | return False; | |
48 | } | |
49 | } ); | |
50 | ||
faee4d12 | 51 | |
db4c329a | 52 | // Number functions |
c3b508af | 53 | static MalFunc time_ms = new MalFunc( |
aaba2493 | 54 | a => new MalInt(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond)); |
db4c329a | 55 | |
afdf531e | 56 | // String functions |
c3b508af | 57 | static public MalFunc pr_str = new MalFunc( |
afdf531e JM |
58 | a => new MalString(printer._pr_str_args(a, " ", true)) ); |
59 | ||
c3b508af | 60 | static public MalFunc str = new MalFunc( |
afdf531e JM |
61 | a => new MalString(printer._pr_str_args(a, "", false)) ); |
62 | ||
c3b508af | 63 | static public MalFunc prn = new MalFunc( |
afdf531e JM |
64 | a => { |
65 | Console.WriteLine(printer._pr_str_args(a, " ", true)); | |
66 | return Nil; | |
67 | } ); | |
68 | ||
c3b508af | 69 | static public MalFunc println = new MalFunc( |
afdf531e JM |
70 | a => { |
71 | Console.WriteLine(printer._pr_str_args(a, " ", false)); | |
72 | return Nil; | |
73 | } ); | |
74 | ||
c3b508af | 75 | static public MalFunc mal_readline = new MalFunc( |
8cb5cda4 JM |
76 | a => { |
77 | var line = readline.Readline(((MalString)a[0]).getValue()); | |
78 | if (line == null) { return types.Nil; } | |
79 | else { return new MalString(line); } | |
80 | } ); | |
81 | ||
c3b508af | 82 | static public MalFunc read_string = new MalFunc( |
8cb5cda4 JM |
83 | a => reader.read_str(((MalString)a[0]).getValue())); |
84 | ||
c3b508af | 85 | static public MalFunc slurp = new MalFunc( |
8cb5cda4 JM |
86 | a => new MalString(File.ReadAllText( |
87 | ((MalString)a[0]).getValue()))); | |
88 | ||
89 | ||
faee4d12 | 90 | // List/Vector functions |
c3b508af | 91 | static public MalFunc list_Q = new MalFunc( |
afdf531e JM |
92 | a => a[0].GetType() == typeof(MalList) ? True : False); |
93 | ||
c3b508af | 94 | static public MalFunc vector_Q = new MalFunc( |
faee4d12 JM |
95 | a => a[0].GetType() == typeof(MalVector) ? True : False); |
96 | ||
97 | // HashMap functions | |
c3b508af | 98 | static public MalFunc hash_map_Q = new MalFunc( |
faee4d12 JM |
99 | a => a[0].GetType() == typeof(MalHashMap) ? True : False); |
100 | ||
c3b508af | 101 | static MalFunc contains_Q = new MalFunc( |
faee4d12 JM |
102 | a => { |
103 | string key = ((MalString)a[1]).getValue(); | |
104 | var dict = ((MalHashMap)a[0]).getValue(); | |
105 | return dict.ContainsKey(key) ? True : False; | |
106 | }); | |
107 | ||
c3b508af | 108 | static MalFunc assoc = new MalFunc( |
faee4d12 JM |
109 | a => { |
110 | var new_hm = ((MalHashMap)a[0]).copy(); | |
111 | return new_hm.assoc_BANG((MalList)a.slice(1)); | |
112 | }); | |
113 | ||
c3b508af | 114 | static MalFunc dissoc = new MalFunc( |
faee4d12 JM |
115 | a => { |
116 | var new_hm = ((MalHashMap)a[0]).copy(); | |
117 | return new_hm.dissoc_BANG((MalList)a.slice(1)); | |
118 | }); | |
119 | ||
c3b508af | 120 | static MalFunc get = new MalFunc( |
faee4d12 JM |
121 | a => { |
122 | string key = ((MalString)a[1]).getValue(); | |
7e9a2883 JM |
123 | if (a[0] == Nil) { |
124 | return Nil; | |
125 | } else { | |
126 | var dict = ((MalHashMap)a[0]).getValue(); | |
127 | return dict.ContainsKey(key) ? dict[key] : Nil; | |
128 | } | |
faee4d12 JM |
129 | }); |
130 | ||
c3b508af | 131 | static MalFunc keys = new MalFunc( |
faee4d12 JM |
132 | a => { |
133 | var dict = ((MalHashMap)a[0]).getValue(); | |
134 | MalList key_lst = new MalList(); | |
135 | foreach (var key in dict.Keys) { | |
136 | key_lst.conj_BANG(new MalString(key)); | |
137 | } | |
138 | return key_lst; | |
139 | }); | |
140 | ||
c3b508af | 141 | static MalFunc vals = new MalFunc( |
faee4d12 JM |
142 | a => { |
143 | var dict = ((MalHashMap)a[0]).getValue(); | |
144 | MalList val_lst = new MalList(); | |
145 | foreach (var val in dict.Values) { | |
146 | val_lst.conj_BANG(val); | |
147 | } | |
148 | return val_lst; | |
149 | }); | |
150 | ||
151 | // Sequence functions | |
c3b508af | 152 | static public MalFunc sequential_Q = new MalFunc( |
faee4d12 | 153 | a => a[0] is MalList ? True : False); |
faa20db2 | 154 | |
c3b508af | 155 | static MalFunc cons = new MalFunc( |
5a159ae7 JM |
156 | a => { |
157 | var lst = new List<MalVal>(); | |
158 | lst.Add(a[0]); | |
159 | lst.AddRange(((MalList)a[1]).getValue()); | |
160 | return (MalVal)new MalList(lst); | |
161 | }); | |
162 | ||
c3b508af | 163 | static MalFunc concat = new MalFunc( |
5a159ae7 JM |
164 | a => { |
165 | if (a.size() == 0) { return new MalList(); } | |
166 | var lst = new List<MalVal>(); | |
167 | lst.AddRange(((MalList)a[0]).getValue()); | |
168 | for(int i=1; i<a.size(); i++) { | |
169 | lst.AddRange(((MalList)a[i]).getValue()); | |
170 | } | |
171 | return (MalVal)new MalList(lst); | |
172 | }); | |
173 | ||
c3b508af | 174 | static MalFunc nth = new MalFunc( |
b8ee29b2 JM |
175 | a => { |
176 | var idx = (int)((MalInt)a[1]).getValue(); | |
177 | if (idx < ((MalList)a[0]).size()) { | |
178 | return ((MalList)a[0])[idx]; | |
179 | } else { | |
180 | throw new Mal.types.MalException( | |
181 | "nth: index out of range"); | |
182 | } | |
183 | }); | |
faee4d12 | 184 | |
c3b508af | 185 | static MalFunc first = new MalFunc( |
faee4d12 JM |
186 | a => ((MalList)a[0])[0]); |
187 | ||
c3b508af | 188 | static MalFunc rest = new MalFunc( |
faee4d12 JM |
189 | a => ((MalList)a[0]).rest()); |
190 | ||
c3b508af | 191 | static MalFunc empty_Q = new MalFunc( |
faee4d12 JM |
192 | a => ((MalList)a[0]).size() == 0 ? True : False); |
193 | ||
c3b508af | 194 | static MalFunc count = new MalFunc( |
b8ee29b2 JM |
195 | a => { |
196 | return (a[0] == Nil) | |
197 | ? new MalInt(0) | |
198 | :new MalInt(((MalList)a[0]).size()); | |
199 | }); | |
faee4d12 | 200 | |
c3b508af | 201 | static MalFunc conj = new MalFunc( |
faee4d12 JM |
202 | a => { |
203 | var src_lst = ((MalList)a[0]).getValue(); | |
204 | var new_lst = new List<MalVal>(); | |
205 | new_lst.AddRange(src_lst); | |
206 | if (a[0] is MalVector) { | |
207 | for(int i=1; i<a.size(); i++) { | |
208 | new_lst.Add(a[i]); | |
209 | } | |
210 | return new MalVector(new_lst); | |
211 | } else { | |
212 | for(int i=1; i<a.size(); i++) { | |
213 | new_lst.Insert(0, a[i]); | |
214 | } | |
215 | return new MalList(new_lst); | |
216 | } | |
217 | }); | |
218 | ||
219 | ||
220 | // General list related functions | |
c3b508af | 221 | static MalFunc apply = new MalFunc( |
faee4d12 | 222 | a => { |
c3b508af | 223 | var f = (MalFunc)a[0]; |
faee4d12 JM |
224 | var lst = new List<MalVal>(); |
225 | lst.AddRange(a.slice(1,a.size()-1).getValue()); | |
226 | lst.AddRange(((MalList)a[a.size()-1]).getValue()); | |
227 | return f.apply(new MalList(lst)); | |
228 | }); | |
229 | ||
c3b508af | 230 | static MalFunc map = new MalFunc( |
faee4d12 | 231 | a => { |
c3b508af | 232 | MalFunc f = (MalFunc) a[0]; |
faee4d12 JM |
233 | var src_lst = ((MalList)a[1]).getValue(); |
234 | var new_lst = new List<MalVal>(); | |
235 | for(int i=0; i<src_lst.Count; i++) { | |
236 | new_lst.Add(f.apply(new MalList(src_lst[i]))); | |
237 | } | |
238 | return new MalList(new_lst); | |
239 | }); | |
240 | ||
5a159ae7 | 241 | |
17ae845e | 242 | // Metadata functions |
c3b508af | 243 | static MalFunc meta = new MalFunc( |
17ae845e JM |
244 | a => a[0].getMeta()); |
245 | ||
c3b508af | 246 | static MalFunc with_meta = new MalFunc( |
17ae845e JM |
247 | a => ((MalVal)a[0]).copy().setMeta(a[1])); |
248 | ||
249 | ||
250 | // Atom functions | |
c3b508af | 251 | static MalFunc atom_Q = new MalFunc( |
17ae845e JM |
252 | a => a[0] is MalAtom ? True : False); |
253 | ||
c3b508af | 254 | static MalFunc deref = new MalFunc( |
17ae845e JM |
255 | a => ((MalAtom)a[0]).getValue()); |
256 | ||
c3b508af | 257 | static MalFunc reset_BANG = new MalFunc( |
17ae845e JM |
258 | a => ((MalAtom)a[0]).setValue(a[1])); |
259 | ||
c3b508af | 260 | static MalFunc swap_BANG = new MalFunc( |
17ae845e JM |
261 | a => { |
262 | MalAtom atm = (MalAtom)a[0]; | |
c3b508af | 263 | MalFunc f = (MalFunc)a[1]; |
17ae845e JM |
264 | var new_lst = new List<MalVal>(); |
265 | new_lst.Add(atm.getValue()); | |
266 | new_lst.AddRange(((MalList)a.slice(2)).getValue()); | |
267 | return atm.setValue(f.apply(new MalList(new_lst))); | |
268 | }); | |
269 | ||
afdf531e JM |
270 | |
271 | ||
272 | static public Dictionary<string, MalVal> ns = | |
273 | new Dictionary<string, MalVal> { | |
c3b508af | 274 | {"=", new MalFunc( |
afdf531e | 275 | a => Mal.types._equal_Q(a[0], a[1]) ? True : False)}, |
faee4d12 JM |
276 | {"throw", mal_throw}, |
277 | {"nil?", nil_Q}, | |
278 | {"true?", true_Q}, | |
279 | {"false?", false_Q}, | |
c3b508af | 280 | {"symbol", new MalFunc(a => new MalSymbol((MalString)a[0]))}, |
faee4d12 | 281 | {"symbol?", symbol_Q}, |
b8ee29b2 JM |
282 | {"keyword", keyword}, |
283 | {"keyword?", keyword_Q}, | |
8cb5cda4 | 284 | |
afdf531e JM |
285 | {"pr-str", pr_str}, |
286 | {"str", str}, | |
287 | {"prn", prn}, | |
288 | {"println", println}, | |
8cb5cda4 JM |
289 | {"readline", mal_readline}, |
290 | {"read-string", read_string}, | |
291 | {"slurp", slurp}, | |
c3b508af JM |
292 | {"<", new MalFunc(a => (MalInt)a[0] < (MalInt)a[1])}, |
293 | {"<=", new MalFunc(a => (MalInt)a[0] <= (MalInt)a[1])}, | |
294 | {">", new MalFunc(a => (MalInt)a[0] > (MalInt)a[1])}, | |
295 | {">=", new MalFunc(a => (MalInt)a[0] >= (MalInt)a[1])}, | |
296 | {"+", new MalFunc(a => (MalInt)a[0] + (MalInt)a[1])}, | |
297 | {"-", new MalFunc(a => (MalInt)a[0] - (MalInt)a[1])}, | |
298 | {"*", new MalFunc(a => (MalInt)a[0] * (MalInt)a[1])}, | |
299 | {"/", new MalFunc(a => (MalInt)a[0] / (MalInt)a[1])}, | |
db4c329a | 300 | {"time-ms", time_ms}, |
afdf531e | 301 | |
c3b508af | 302 | {"list", new MalFunc(a => new MalList(a.getValue()))}, |
afdf531e | 303 | {"list?", list_Q}, |
c3b508af | 304 | {"vector", new MalFunc(a => new MalVector(a.getValue()))}, |
faee4d12 | 305 | {"vector?", vector_Q}, |
c3b508af | 306 | {"hash-map", new MalFunc(a => new MalHashMap(a))}, |
faee4d12 JM |
307 | {"map?", hash_map_Q}, |
308 | {"contains?", contains_Q}, | |
309 | {"assoc", assoc}, | |
310 | {"dissoc", dissoc}, | |
311 | {"get", get}, | |
312 | {"keys", keys}, | |
313 | {"vals", vals}, | |
5a159ae7 | 314 | |
faee4d12 | 315 | {"sequential?", sequential_Q}, |
5a159ae7 JM |
316 | {"cons", cons}, |
317 | {"concat", concat}, | |
faa20db2 | 318 | {"nth", nth}, |
faee4d12 JM |
319 | {"first", first}, |
320 | {"rest", rest}, | |
321 | {"empty?", empty_Q}, | |
322 | {"count", count}, | |
323 | {"conj", conj}, | |
324 | {"apply", apply}, | |
325 | {"map", map}, | |
17ae845e JM |
326 | |
327 | {"with-meta", with_meta}, | |
328 | {"meta", meta}, | |
c3b508af | 329 | {"atom", new MalFunc(a => new MalAtom(a[0]))}, |
17ae845e JM |
330 | {"atom?", atom_Q}, |
331 | {"deref", deref}, | |
332 | {"reset!", reset_BANG}, | |
333 | {"swap!", swap_BANG}, | |
afdf531e | 334 | }; |
b18969c0 JM |
335 | } |
336 | } |