Commit | Line | Data |
---|---|---|
57350ed7 JM |
1 | #import <Foundation/Foundation.h> |
2 | ||
7cae6e6f | 3 | #import "mal_readline.h" |
57350ed7 | 4 | #import "types.h" |
7cae6e6f | 5 | #import "reader.h" |
57350ed7 | 6 | #import "printer.h" |
7cae6e6f | 7 | #import "malfunc.h" |
57350ed7 JM |
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 | }, | |
7cae6e6f JM |
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 | }, | |
57350ed7 JM |
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 | }, | |
7cae6e6f JM |
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 | }, | |
57350ed7 JM |
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 | }, | |
7cae6e6f JM |
117 | @"time-ms": ^(NSArray *args){ |
118 | long long ms = [[NSDate date] timeIntervalSince1970] * 1000; | |
119 | return [NSNumber numberWithUnsignedInteger:ms]; | |
120 | }, | |
57350ed7 JM |
121 | |
122 | @"list": ^(NSArray *args){ | |
123 | return args; | |
124 | }, | |
125 | @"list?": ^(NSArray *args){ | |
126 | return wrap_tf(list_Q(args[0])); | |
127 | }, | |
7cae6e6f JM |
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 | }, | |
57350ed7 | 176 | |
7cae6e6f JM |
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 | }, | |
57350ed7 JM |
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 | }, | |
7cae6e6f JM |
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 | }, | |
57350ed7 | 291 | |
7cae6e6f JM |
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 | }, | |
57350ed7 JM |
332 | }; |
333 | } | |
334 | ||
335 | @end |