python: remove extraneous macroexpand call.
[jackhill/mal.git] / dart / core.dart
CommitLineData
3934e3f8
HT
1import 'dart:io';
2
3import 'printer.dart';
4import 'reader.dart' as reader;
5import 'types.dart';
6
7Map<MalSymbol, MalBuiltin> ns = <MalSymbol, MalBuiltin>{
8 new MalSymbol('+'): new MalBuiltin((List<MalType> args) {
9 var a = args[0] as MalInt;
10 var b = args[1] as MalInt;
11 return new MalInt(a.value + b.value);
12 }),
13 new MalSymbol('-'): new MalBuiltin((List<MalType> args) {
14 var a = args[0] as MalInt;
15 var b = args[1] as MalInt;
16 return new MalInt(a.value - b.value);
17 }),
18 new MalSymbol('*'): new MalBuiltin((List<MalType> args) {
19 var a = args[0] as MalInt;
20 var b = args[1] as MalInt;
21 return new MalInt(a.value * b.value);
22 }),
23 new MalSymbol('/'): new MalBuiltin((List<MalType> args) {
24 var a = args[0] as MalInt;
25 var b = args[1] as MalInt;
26 return new MalInt(a.value ~/ b.value);
27 }),
28 new MalSymbol('list'):
29 new MalBuiltin((List<MalType> args) => new MalList(args.toList())),
30 new MalSymbol('list?'): new MalBuiltin(
31 (List<MalType> args) => new MalBool(args.single is MalList)),
32 new MalSymbol('empty?'): new MalBuiltin((List<MalType> args) {
33 var a = args.single as MalIterable;
34 return new MalBool(a.elements.isEmpty);
35 }),
36 new MalSymbol('count'): new MalBuiltin((List<MalType> args) {
37 var a = args.first as MalIterable;
38 return new MalInt(a.elements.length);
39 }),
40 new MalSymbol('='): new MalBuiltin((List<MalType> args) {
41 var a = args[0];
42 var b = args[1];
43 return new MalBool(a == b);
44 }),
45 new MalSymbol('<'): new MalBuiltin((List<MalType> args) {
46 var a = args[0] as MalInt;
47 var b = args[1] as MalInt;
48 return new MalBool(a.value < b.value);
49 }),
50 new MalSymbol('<='): new MalBuiltin((List<MalType> args) {
51 var a = args[0] as MalInt;
52 var b = args[1] as MalInt;
53 return new MalBool(a.value <= b.value);
54 }),
55 new MalSymbol('>'): new MalBuiltin((List<MalType> args) {
56 var a = args[0] as MalInt;
57 var b = args[1] as MalInt;
58 return new MalBool(a.value > b.value);
59 }),
60 new MalSymbol('>='): new MalBuiltin((List<MalType> args) {
61 var a = args[0] as MalInt;
62 var b = args[1] as MalInt;
63 return new MalBool(a.value >= b.value);
64 }),
65 new MalSymbol('pr-str'): new MalBuiltin((List<MalType> args) {
66 return new MalString(
67 args.map((a) => pr_str(a, print_readably: true)).join(' '));
68 }),
69 new MalSymbol('str'): new MalBuiltin((List<MalType> args) {
70 return new MalString(
71 args.map((a) => pr_str(a, print_readably: false)).join());
72 }),
73 new MalSymbol('prn'): new MalBuiltin((List<MalType> args) {
74 print(args.map((a) => pr_str(a, print_readably: true)).join(' '));
75 return new MalNil();
76 }),
77 new MalSymbol('println'): new MalBuiltin((List<MalType> args) {
78 print(args.map((a) => pr_str(a, print_readably: false)).join(' '));
79 return new MalNil();
80 }),
81 new MalSymbol('read-string'): new MalBuiltin((List<MalType> args) {
82 var code = args.single as MalString;
83 return reader.read_str(code.value);
84 }),
85 new MalSymbol('slurp'): new MalBuiltin((List<MalType> args) {
86 var fileName = args.single as MalString;
87 var file = new File(fileName.value);
88 return new MalString(file.readAsStringSync());
89 }),
90 new MalSymbol('atom'): new MalBuiltin((List<MalType> args) {
91 var value = args.single;
92 return new MalAtom(value);
93 }),
94 new MalSymbol('atom?'): new MalBuiltin((List<MalType> args) {
95 var value = args.single;
96 return new MalBool(value is MalAtom);
97 }),
98 new MalSymbol('deref'): new MalBuiltin((List<MalType> args) {
99 var atom = args.single as MalAtom;
100 return atom.value;
101 }),
102 new MalSymbol('reset!'): new MalBuiltin((List<MalType> args) {
103 var atom = args[0] as MalAtom;
104 var newValue = args[1];
105 atom.value = newValue;
106 return newValue;
107 }),
108 new MalSymbol('swap!'): new MalBuiltin((List<MalType> args) {
109 var atom = args[0] as MalAtom;
110 var func = args[1] as MalCallable;
111 var fnArgs = [atom.value]..addAll(args.sublist(2));
112 var result = func.call(fnArgs);
113 atom.value = result;
114 return result;
115 }),
116 new MalSymbol('cons'): new MalBuiltin((List<MalType> args) {
117 var x = args[0];
118 var xs = args[1] as MalIterable;
119 return new MalList([x]..addAll(xs));
120 }),
121 new MalSymbol('concat'): new MalBuiltin((List<MalType> args) {
122 var results = <MalType>[];
123 for (MalIterable element in args) {
124 results.addAll(element);
125 }
126 return new MalList(results);
127 }),
128 new MalSymbol('nth'): new MalBuiltin((List<MalType> args) {
129 var indexable = args[0] as MalIterable;
130 var index = args[1] as MalInt;
131 try {
132 return indexable[index.value];
133 } on RangeError catch (e) {
134 throw new MalNativeException(e);
135 }
136 }),
137 new MalSymbol('first'): new MalBuiltin((List<MalType> args) {
138 var list = args.first as MalIterable;
139 if (list.isEmpty) return new MalNil();
140 return list.first;
141 }),
142 new MalSymbol('rest'): new MalBuiltin((List<MalType> args) {
143 var list = args.first as MalIterable;
144 if (list.isEmpty) return new MalList(<MalType>[]);
145 return new MalList(list.sublist(1));
146 }),
147 new MalSymbol('throw'): new MalBuiltin((List<MalType> args) {
148 throw new MalException(args.first);
149 }),
150 new MalSymbol('nil?'): new MalBuiltin((List<MalType> args) {
151 return new MalBool(args.first is MalNil);
152 }),
153 new MalSymbol('true?'): new MalBuiltin((List<MalType> args) {
154 return new MalBool(args.first is MalBool && (args.first as MalBool).value);
155 }),
156 new MalSymbol('false?'): new MalBuiltin((List<MalType> args) {
157 return new MalBool(args.first is MalBool && !(args.first as MalBool).value);
158 }),
159 new MalSymbol('symbol'): new MalBuiltin((List<MalType> args) {
160 return new MalSymbol((args.first as MalString).value);
161 }),
162 new MalSymbol('symbol?'): new MalBuiltin((List<MalType> args) {
163 return new MalBool(args.first is MalSymbol);
164 }),
165 new MalSymbol('keyword'): new MalBuiltin((List<MalType> args) {
166 if (args.first is MalKeyword) return args.first;
167 return new MalKeyword((args.first as MalString).value);
168 }),
169 new MalSymbol('keyword?'): new MalBuiltin((List<MalType> args) {
170 return new MalBool(args.first is MalKeyword);
171 }),
172 new MalSymbol('vector'): new MalBuiltin((List<MalType> args) {
173 return new MalVector(args);
174 }),
175 new MalSymbol('vector?'): new MalBuiltin((List<MalType> args) {
176 return new MalBool(args.first is MalVector);
177 }),
178 new MalSymbol('hash-map'): new MalBuiltin((List<MalType> args) {
179 return new MalHashMap.fromSequence(args);
180 }),
181 new MalSymbol('map?'): new MalBuiltin((List<MalType> args) {
182 return new MalBool(args.first is MalHashMap);
183 }),
184 new MalSymbol('assoc'): new MalBuiltin((List<MalType> args) {
185 var map = args.first as MalHashMap;
186 var assoc = new MalHashMap.fromSequence(args.skip(1).toList());
187 var newMap = new Map<MalType, MalType>.from(map.value);
188 newMap.addAll(assoc.value);
189 return new MalHashMap(newMap);
190 }),
191 new MalSymbol('dissoc'): new MalBuiltin((List<MalType> args) {
192 var map = args.first as MalHashMap;
193 var newMap = new Map<MalType, MalType>.from(map.value);
194 for (var key in args.skip(1)) {
195 newMap.remove(key);
196 }
197 return new MalHashMap(newMap);
198 }),
199 new MalSymbol('get'): new MalBuiltin((List<MalType> args) {
200 if (args[0] is MalNil) return new MalNil();
201 var map = args[0] as MalHashMap;
202 var key = args[1];
203 return map.value[key] ?? new MalNil();
204 }),
205 new MalSymbol('contains?'): new MalBuiltin((List<MalType> args) {
206 var map = args[0] as MalHashMap;
207 var key = args[1];
208 return new MalBool(map.value.containsKey(key));
209 }),
210 new MalSymbol('keys'): new MalBuiltin((List<MalType> args) {
211 return new MalList((args.first as MalHashMap).value.keys.toList());
212 }),
213 new MalSymbol('vals'): new MalBuiltin((List<MalType> args) {
214 return new MalList((args.first as MalHashMap).value.values.toList());
215 }),
216 new MalSymbol('sequential?'): new MalBuiltin((List<MalType> args) {
217 return new MalBool(args.first is MalList || args.first is MalVector);
218 }),
219 new MalSymbol('readline'): new MalBuiltin((List<MalType> args) {
220 var message = args.first as MalString;
221 stdout.write(message.value);
222 var input = stdin.readLineSync();
223 if (input == null) return new MalNil();
224 return new MalString(input);
225 }),
226 new MalSymbol('time-ms'): new MalBuiltin((List<MalType> args) {
227 assert(args.isEmpty);
228 return new MalInt(new DateTime.now().millisecondsSinceEpoch);
229 }),
230 new MalSymbol('conj'): new MalBuiltin((List<MalType> args) {
231 var collection = args.first;
232 var elements = args.sublist(1);
233 if (collection is MalList) {
234 return new MalList(
235 elements.reversed.toList()..addAll(collection.elements));
236 }
237 if (collection is MalVector) {
238 return new MalVector(collection.elements.toList()..addAll(elements));
239 }
240 throw new MalException(new MalString('"conj" takes a list or vector'));
241 }),
242 new MalSymbol('string?'): new MalBuiltin((List<MalType> args) {
243 return new MalBool(args.first is MalString);
244 }),
245 new MalSymbol('seq'): new MalBuiltin((List<MalType> args) {
246 var arg = args.first;
247 if (arg is MalIterable && arg.isEmpty) return new MalNil();
248 if (arg is MalString && arg.value.isEmpty) return new MalNil();
249
250 if (arg is MalNil || arg is MalList) return arg;
251 if (arg is MalVector) return new MalList(arg.elements.toList());
252 if (arg is MalString) {
253 var chars = <MalString>[];
254 for (var i = 0; i < arg.value.length; i++) {
255 chars.add(new MalString(arg.value[i]));
256 }
257 return new MalList(chars);
258 }
259 throw new MalException(new MalString('bad argument to "seq"'));
260 }),
261 new MalSymbol('map'): new MalBuiltin((List<MalType> args) {
262 var fn = args[0] as MalCallable;
263 var list = args[1] as MalIterable;
264 var newList = <MalType>[];
265 for (var element in list) {
266 newList.add(fn.call([element]));
267 }
268 return new MalList(newList);
269 }),
270 new MalSymbol('apply'): new MalBuiltin((List<MalType> args) {
271 var func = args.first as MalCallable;
272 var argList = args.last as MalIterable;
273 var newArgs = args.sublist(1, args.length - 1);
274 newArgs.addAll(argList);
275 return func.call(newArgs);
276 }),
277 new MalSymbol('meta'): new MalBuiltin((List<MalType> args) {
278 var arg = args.first;
279 return arg.meta ?? new MalNil();
280 }),
281 new MalSymbol('with-meta'): new MalBuiltin((List<MalType> args) {
282 var evaled = args.first;
283 var evaledWithMeta = evaled.clone();
284 evaledWithMeta.meta = args[1];
285 return evaledWithMeta;
286 }),
287};