Implement step 7
[jackhill/mal.git] / objc / core.m
1 #import <Foundation/Foundation.h>
2
3 #import "mal_readline.h"
4 #import "types.h"
5 #import "reader.h"
6 #import "printer.h"
7 #import "malfunc.h"
8 #import "core.h"
9
10 NSObject * wrap_tf(BOOL val) {
11 return val ? [MalTrue alloc] : [MalFalse alloc];
12 }
13
14 @implementation Core
15
16 + (NSDictionary *)ns {
17 return @{
18 @"=": ^(NSArray *args){
19 return wrap_tf(equal_Q(args[0], args[1]));
20 },
21 @"throw": ^(NSArray *args){
22 @throw args[0];
23 },
24
25 @"nil?": ^(NSArray *args){
26 return wrap_tf([args[0] isKindOfClass:[NSNull class]]);
27 },
28 @"true?": ^(NSArray *args){
29 return wrap_tf([args[0] isKindOfClass:[MalTrue class]]);
30 },
31 @"false?": ^(NSArray *args){
32 return wrap_tf([args[0] isKindOfClass:[MalFalse class]]);
33 },
34 @"string?": ^(NSArray *args){
35 return wrap_tf(string_Q(args[0]));
36 },
37 @"symbol": ^(NSArray *args){
38 return [MalSymbol stringWithString:args[0]];
39 },
40 @"symbol?": ^(NSArray *args){
41 return wrap_tf([args[0] isKindOfClass:[MalSymbol class]]);
42 },
43 @"keyword": ^(NSArray *args){
44 return [NSString stringWithFormat:@"\u029e%@", args[0]];
45 },
46 @"keyword?": ^(NSArray *args){
47 return wrap_tf([args[0] isKindOfClass:[NSString class]] &&
48 ![args[0] isKindOfClass:[MalSymbol class]] &&
49 !string_Q(args[0]));
50 },
51
52 @"pr-str": ^(NSArray *args){
53 NSMutableArray * res = [NSMutableArray array];
54 for (id e in args) { [res addObject:_pr_str(e,true)]; }
55 return [res componentsJoinedByString:@" "];
56 },
57 @"str": ^(NSArray *args){
58 NSMutableArray * res = [NSMutableArray array];
59 for (id e in args) { [res addObject:_pr_str(e,false)]; }
60 return [res componentsJoinedByString:@""];
61 },
62 @"prn": ^(NSArray *args){
63 NSMutableArray * res = [NSMutableArray array];
64 for (id e in args) { [res addObject:_pr_str(e,true)]; }
65 printf("%s\n", [[res componentsJoinedByString:@" "] UTF8String]);
66 fflush(stdout);
67 return [NSNull alloc];
68 },
69 @"println": ^(NSArray *args){
70 NSMutableArray * res = [NSMutableArray array];
71 for (id e in args) { [res addObject:_pr_str(e,false)]; }
72 printf("%s\n", [[res componentsJoinedByString:@" "] UTF8String]);
73 fflush(stdout);
74 return [NSNull alloc];
75 },
76 @"read-string": ^(NSArray *args){
77 return read_str(args[0]);
78 },
79 @"readline": ^(NSArray *args){
80 char * rawline = _readline((char *)[(NSString *)args[0] UTF8String]);
81 if (rawline) {
82 return (NSObject *)[NSString stringWithUTF8String:rawline];
83 } else {
84 return (NSObject *)[NSNull alloc];
85 }
86 },
87 @"slurp": ^(NSArray *args){
88 return [NSString stringWithContentsOfFile:args[0]
89 encoding: NSUTF8StringEncoding
90 error: NULL];
91 },
92
93 @"<": ^(NSArray *args){
94 return wrap_tf([args[0] intValue] < [args[1] intValue]);
95 },
96 @"<=": ^(NSArray *args){
97 return wrap_tf([args[0] intValue] <= [args[1] intValue]);
98 },
99 @">": ^(NSArray *args){
100 return wrap_tf([args[0] intValue] > [args[1] intValue]);
101 },
102 @">=": ^(NSArray *args){
103 return wrap_tf([args[0] intValue] >= [args[1] intValue]);
104 },
105 @"+": ^(NSArray *args){
106 return [NSNumber numberWithInt:[args[0] intValue] + [args[1] intValue]];
107 },
108 @"-": ^(NSArray *args){
109 return [NSNumber numberWithInt:[args[0] intValue] - [args[1] intValue]];
110 },
111 @"*": ^(NSArray *args){
112 return [NSNumber numberWithInt:[args[0] intValue] * [args[1] intValue]];
113 },
114 @"/": ^(NSArray *args){
115 return [NSNumber numberWithInt:[args[0] intValue] / [args[1] intValue]];
116 },
117 @"time-ms": ^(NSArray *args){
118 long long ms = [[NSDate date] timeIntervalSince1970] * 1000;
119 return [NSNumber numberWithUnsignedInteger:ms];
120 },
121
122 @"list": ^(NSArray *args){
123 return args;
124 },
125 @"list?": ^(NSArray *args){
126 return wrap_tf(list_Q(args[0]));
127 },
128 @"vector": ^(NSArray *args){
129 return [MalVector fromArray:args];
130 },
131 @"vector?": ^(NSArray *args){
132 return wrap_tf([args[0] isKindOfClass:[MalVector class]]);
133 },
134 @"hash-map": ^(NSArray *args){
135 return hash_map(args);
136 },
137 @"map?": ^(NSArray *args){
138 return wrap_tf([args[0] isKindOfClass:[NSDictionary class]]);
139 },
140 @"assoc": ^(NSArray *args){
141 NSDictionary * dict = args[0];
142 NSMutableDictionary * new_dict = [[NSMutableDictionary alloc]
143 initWithDictionary:dict
144 copyItems:NO];
145 return assoc_BANG(new_dict, _rest(args));
146 },
147 @"dissoc": ^(NSArray *args){
148 NSDictionary * dict = args[0];
149 NSMutableDictionary * new_dict = [[NSMutableDictionary alloc]
150 initWithDictionary:dict
151 copyItems:NO];
152 for (NSString * key in _rest(args)) {
153 [new_dict removeObjectForKey:key];
154 }
155 return new_dict;
156 },
157 @"get": ^(NSArray *args){
158 if ([args[0] isKindOfClass:[NSNull class]]) {
159 return (NSObject *)[NSNull alloc];
160 }
161 NSObject * res = ((NSDictionary *)args[0])[args[1]];
162 return res ? res : [NSNull alloc];
163 },
164 @"contains?": ^(NSArray *args){
165 if ([args[0] isKindOfClass:[NSNull class]]) {
166 return wrap_tf(false);
167 }
168 return wrap_tf(((NSDictionary *)args[0])[args[1]] != nil);
169 },
170 @"keys": ^(NSArray *args){
171 return [(NSDictionary *)args[0] allKeys];
172 },
173 @"vals": ^(NSArray *args){
174 return [(NSDictionary *)args[0] allValues];
175 },
176
177 @"sequential?": ^(NSArray *args){
178 return wrap_tf([args[0] isKindOfClass:[NSArray class]]);
179 },
180 @"cons": ^(NSArray *args){
181 NSMutableArray * res = [NSMutableArray array];
182 [res addObject:args[0]];
183 [res addObjectsFromArray:args[1]];
184 return res;
185 },
186 @"concat": ^(NSArray *args){
187 NSMutableArray * res = [NSMutableArray array];
188 for (NSArray * arr in args) {
189 [res addObjectsFromArray:arr];
190 }
191 return res;
192 },
193 @"nth": ^(NSArray *args){
194 NSArray * lst = (NSArray *)args[0];
195 int idx = [(NSNumber *)args[1] intValue];
196 if (idx < [lst count]) {
197 return lst[idx];
198 } else {
199 @throw @"nth: index out of range";
200 }
201 },
202 @"first": ^(NSArray *args){
203 if ([args[0] isKindOfClass:[NSNull class]]) {
204 return (NSObject *)[NSNull alloc];
205 }
206 NSArray * lst = (NSArray *)args[0];
207 if ([lst count] > 0) {
208 return (NSObject *)lst[0];
209 } else {
210 return (NSObject *)[NSNull alloc];
211 }
212 },
213 @"rest": ^(NSArray *args){
214 if ([args[0] isKindOfClass:[NSNull class]]) {
215 return @[];
216 }
217 NSArray * lst = (NSArray *)args[0];
218 if ([lst count] > 1) {
219 return _rest(lst);
220 } else {
221 return @[];
222 }
223 },
224 @"empty?": ^(NSArray *args){
225 if ([args[0] isKindOfClass:[NSNull class]]) {
226 return wrap_tf(true);
227 } else {
228 return wrap_tf([args[0] count] == 0);
229 }
230 },
231 @"count": ^(NSArray *args){
232 if ([args[0] isKindOfClass:[NSNull class]]) {
233 return @0;
234 } else {
235 return [NSNumber numberWithInt:[args[0] count]];
236 }
237 },
238 @"apply": ^(NSArray *args){
239 NSObject * (^ f)(NSArray *) = args[0];
240 NSMutableArray * fargs = [NSMutableArray array];
241 if ([args count] > 1) {
242 NSRange r = NSMakeRange(1, [args count]-2);
243 [fargs addObjectsFromArray:[args subarrayWithRange:r]];
244 }
245 [fargs addObjectsFromArray:(NSArray *)[args lastObject]];
246 return apply(f, fargs);
247 },
248 @"map": ^(NSArray *args){
249 NSObject * (^ f)(NSArray *) = args[0];
250 NSMutableArray * res = [NSMutableArray array];
251 for (NSObject * x in (NSArray *)args[1]) {
252 [res addObject:apply(f, @[x])];
253 }
254 return res;
255 },
256 @"conj": ^(NSArray *args){
257 NSMutableArray * res = [NSMutableArray array];
258 if ([args[0] isKindOfClass:[MalVector class]]) {
259 [res addObjectsFromArray:args[0]];
260 [res addObjectsFromArray:_rest(args)];
261 return (NSObject *)[MalVector arrayWithArray:res];
262 } else {
263 [res addObjectsFromArray:[[_rest(args) reverseObjectEnumerator]
264 allObjects]];
265 [res addObjectsFromArray:args[0]];
266 return (NSObject *)res;
267 }
268 },
269 @"seq": ^(NSArray *args){
270 if (list_Q(args[0])) {
271 if ([args[0] count] == 0) { return (NSObject *)[NSNull alloc]; }
272 return (NSObject *)args[0];
273 } else if ([args[0] isKindOfClass:[MalVector class]]) {
274 if ([args[0] count] == 0) { return (NSObject *)[NSNull alloc]; }
275 return (NSObject *)[NSArray arrayWithArray:args[0]];
276 } else if (string_Q(args[0])) {
277 NSString * str = args[0];
278 if ([str length] == 0) { return (NSObject *)[NSNull alloc]; }
279 NSMutableArray * res = [NSMutableArray array];
280 for (int i=0; i < [str length]; i++) {
281 char c = [str characterAtIndex:i];
282 [res addObject:[NSString stringWithFormat:@"%c", c]];
283 }
284 return (NSObject *)res;
285 } else if ([args[0] isKindOfClass:[NSNull class]]) {
286 return (NSObject *)args[0];
287 } else {
288 @throw @"seq: called on non-sequence";
289 }
290 },
291
292 @"meta": ^(NSArray *args){
293 if ([args[0] isKindOfClass:[MalFunc class]]) {
294 return [(MalFunc *)args[0] meta];
295 } else {
296 return (NSObject *)[NSNull alloc];
297 }
298 },
299 @"with-meta": ^(NSArray *args){
300 if ([args[0] isKindOfClass:[MalFunc class]]) {
301 MalFunc * cmf = [(MalFunc *)args[0] copy];
302 cmf.meta = args[1];
303 return cmf;
304 } else {
305 @throw @"with-meta: object type not supported";
306 }
307 },
308 @"atom": ^(NSArray *args){
309 return [MalAtom fromObject:args[0]];
310 },
311 @"atom?": ^(NSArray *args){
312 return wrap_tf(atom_Q(args[0]));
313 },
314 @"deref": ^(NSArray *args){
315 return [(MalAtom *)args[0] val];
316 },
317 @"reset!": ^(NSArray *args){
318 MalAtom * atm = (MalAtom *)args[0];
319 return atm.val = args[1];
320 },
321 @"swap!": ^(NSArray *args){
322 MalAtom * atm = (MalAtom *)args[0];
323 NSObject * (^ f)(NSArray *) = args[1];
324 NSMutableArray * fargs = [NSMutableArray array];
325 [fargs addObject:atm.val];
326 if ([args count] > 2) {
327 NSRange r = NSMakeRange(2, [args count]-2);
328 [fargs addObjectsFromArray:[args subarrayWithRange:r]];
329 }
330 return atm.val = apply(f, fargs);
331 },
332 };
333 }
334
335 @end