All: add keywords.
[jackhill/mal.git] / cs / core.cs
CommitLineData
afdf531e 1using System;
8cb5cda4 2using System.IO;
afdf531e 3using System.Collections.Generic;
b18969c0 4using MalVal = Mal.types.MalVal;
afdf531e 5using MalConstant = Mal.types.MalConstant;
c3b508af 6using MalInt = Mal.types.MalInt;
faee4d12 7using MalSymbol = Mal.types.MalSymbol;
afdf531e 8using MalString = Mal.types.MalString;
b18969c0 9using MalList = Mal.types.MalList;
faee4d12
JM
10using MalVector = Mal.types.MalVector;
11using MalHashMap = Mal.types.MalHashMap;
17ae845e 12using MalAtom = Mal.types.MalAtom;
c3b508af 13using MalFunc = Mal.types.MalFunc;
b18969c0
JM
14
15namespace 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}