Merge pull request #378 from asarhaddon/test-macro-not-changing-function
[jackhill/mal.git] / swift / core.swift
CommitLineData
2539e6af
KR
1//******************************************************************************
2// MAL - core
3//******************************************************************************
4
5import Foundation
6
425305df
KR
7// This is a simple type distinct from all MalVal types so that we can pass a
8// sequence to a function and be able to distinguish between those functions
9// that want a sequence as a parameter and those that want a sequence that holds
10// the rest of the function parameters.
11//
12final class MalVarArgs {
13 init(_ value: MalSequence) { self.value = value }
14 init(_ value: MalVal) { self.value = as_sequence(value) }
15 let value: MalSequence
16}
2539e6af 17
425305df 18private func fn_eq(obj1: MalVal, obj2: MalVal) throws -> Bool {
2539e6af
KR
19 return obj1 == obj2
20}
21
425305df
KR
22private func fn_throw(exception: MalVal) throws -> MalVal {
23 try throw_error(exception)
2539e6af
KR
24}
25
425305df 26private func fn_nilQ(obj: MalVal) throws -> Bool {
2539e6af
KR
27 return is_nil(obj)
28}
29
425305df 30private func fn_trueQ(obj: MalVal) throws -> Bool {
2539e6af
KR
31 return is_true(obj)
32}
33
425305df 34private func fn_falseQ(obj: MalVal) throws -> Bool {
2539e6af
KR
35 return is_false(obj)
36}
37
c391c80c
JM
38private func fn_stringQ(obj: MalVal) throws -> Bool {
39 return is_string(obj)
40}
41
425305df
KR
42private func fn_symbol(s: String) throws -> MalVal {
43 return make_symbol(s)
2539e6af
KR
44}
45
425305df 46private func fn_symbolQ(obj: MalVal) throws -> Bool {
2539e6af
KR
47 return is_symbol(obj)
48}
49
425305df 50private func fn_keyword(s: MalVal) throws -> MalVal {
2539e6af
KR
51 if is_keyword(s) {
52 return s
53 }
54 if is_string(s) {
425305df 55 return make_keyword(as_string(s))
2539e6af 56 }
425305df 57 try throw_error("expected string or keyword")
2539e6af
KR
58}
59
425305df 60private func fn_keywordQ(obj: MalVal) throws -> Bool {
2539e6af
KR
61 return is_keyword(obj)
62}
63
c3c9f348
JM
64private func fn_numberQ(obj: MalVal) throws -> Bool {
65 return is_integer(obj) || is_float(obj)
66}
67
68private func fn_functionQ(obj: MalVal) throws -> Bool {
69 return is_function(obj)
70}
71
72private func fn_macroQ(obj: MalVal) throws -> Bool {
73 return is_macro(obj)
74}
75
425305df
KR
76private func fn_prstr(args: MalVarArgs) throws -> String {
77 let args_str_array = args.value.map { pr_str($0, true) }
78 return args_str_array.joinWithSeparator(" ")
2539e6af
KR
79}
80
425305df
KR
81private func fn_str(args: MalVarArgs) throws -> String {
82 let args_str_array = args.value.map { pr_str($0, false) }
83 return args_str_array.joinWithSeparator("")
2539e6af
KR
84}
85
425305df
KR
86private func fn_prn(args: MalVarArgs) {
87 let args_str_array = args.value.map { pr_str($0, true) }
88 let args_str = args_str_array.joinWithSeparator(" ")
89 print(args_str)
2539e6af
KR
90}
91
425305df
KR
92private func fn_println(args: MalVarArgs) {
93 let args_str_array = args.value.map { pr_str($0, false) }
94 let args_str = args_str_array.joinWithSeparator(" ")
95 print(args_str)
2539e6af
KR
96}
97
425305df
KR
98private func fn_readstring(s: String) throws -> MalVal {
99 return try read_str(s)
2539e6af
KR
100}
101
425305df 102private func fn_readline(s: String) throws -> String? {
2539e6af
KR
103 return _readline(s)
104}
105
425305df
KR
106private func fn_slurp(s: String) throws -> MalVal {
107 do {
108 let result = try String(contentsOfFile: s, encoding: NSUTF8StringEncoding)
109 return make_string(result)
110 } catch let error as NSError {
111 try throw_error("unknown error reading file \(error)")
2539e6af 112 }
2539e6af
KR
113}
114
425305df 115private func fn_lt(arg1: MalIntType, arg2: MalIntType) throws -> Bool {
2539e6af
KR
116 return arg1 < arg2
117}
118
425305df 119private func fn_lte(arg1: MalIntType, arg2: MalIntType) throws -> Bool {
2539e6af
KR
120 return arg1 <= arg2
121}
122
425305df 123private func fn_gt(arg1: MalIntType, arg2: MalIntType) throws -> Bool {
2539e6af
KR
124 return arg1 > arg2
125}
126
425305df 127private func fn_gte(arg1: MalIntType, arg2: MalIntType) throws -> Bool {
2539e6af
KR
128 return arg1 >= arg2
129}
130
425305df 131private func fn_add(arg1: MalIntType, arg2: MalIntType) throws -> MalIntType {
2539e6af
KR
132 return arg1 + arg2
133}
134
425305df 135private func fn_subtract(arg1: MalIntType, arg2: MalIntType) throws -> MalIntType {
2539e6af
KR
136 return arg1 - arg2
137}
138
425305df 139private func fn_multiply(arg1: MalIntType, arg2: MalIntType) throws -> MalIntType {
2539e6af
KR
140 return arg1 * arg2
141}
142
425305df 143private func fn_divide(arg1: MalIntType, arg2: MalIntType) throws -> MalIntType {
2539e6af
KR
144 return arg1 / arg2
145}
146
425305df
KR
147private func fn_timems() throws -> MalIntType {
148 var time = timeval(tv_sec: 0, tv_usec: 0)
2539e6af
KR
149 let res = gettimeofday(&time, nil)
150 if res == 0 {
425305df 151 return (MalIntType(time.tv_sec) * 1_000_000 + MalIntType(time.tv_usec)) / 1000
2539e6af
KR
152 }
153 return -1
154}
155
425305df
KR
156private func fn_list(args: MalVarArgs) throws -> MalVal {
157 return make_list(args.value)
2539e6af
KR
158}
159
425305df 160private func fn_listQ(obj: MalVal) throws -> Bool {
2539e6af
KR
161 return is_list(obj)
162}
163
425305df
KR
164private func fn_vector(args: MalVarArgs) throws -> MalVal {
165 return make_vector(args.value)
2539e6af
KR
166}
167
425305df 168private func fn_vectorQ(obj: MalVal) throws -> Bool {
2539e6af
KR
169 return is_vector(obj)
170}
171
425305df
KR
172private func fn_hashmap(args: MalVarArgs) throws -> MalVal {
173 return make_hashmap(args.value)
2539e6af
KR
174}
175
425305df 176private func fn_hashmapQ(obj: MalVal) throws -> Bool {
2539e6af
KR
177 return is_hashmap(obj)
178}
179
425305df
KR
180private func fn_assoc(hash: MalHashMap, args: MalVarArgs) throws -> MalVal {
181 guard args.value.count % 2 == 0 else {
182 try throw_error("expected even number of elements, got \(args.value.count)")
2539e6af
KR
183 }
184 var new_dictionary = hash.hash
425305df
KR
185 for var index: MalIntType = 0; index < args.value.count; index += 2 {
186 new_dictionary[try! args.value.nth(index)] = try! args.value.nth(index + 1)
2539e6af 187 }
425305df 188 return make_hashmap(new_dictionary)
2539e6af
KR
189}
190
425305df
KR
191private func fn_dissoc(hash: MalHashMap, args: MalVarArgs) throws -> MalVal {
192 var new_dictionary = hash.hash
193 for value in args.value {
194 new_dictionary.removeValueForKey(value)
195 }
196 return make_hashmap(new_dictionary)
2539e6af
KR
197}
198
425305df
KR
199private func fn_get(obj: MalVal, key: MalVal) throws -> MalVal {
200 if let as_vec = as_vectorQ(obj) {
201 guard let index = as_integerQ(key) else {
202 try throw_error("expected integer key for get(vector), got \(key)")
203 }
204 let n = as_inttype(index)
205 guard n >= as_vec.count else { try throw_error("index out of range: \(n) >= \(as_vec.count)") }
206 return try! as_vec.nth(n)
2539e6af 207 }
425305df
KR
208 if let as_hash = as_hashmapQ(obj) {
209 if let value = as_hash.value_for(key) { return value }
210 return make_nil()
2539e6af
KR
211 }
212 if is_nil(obj) {
213 return obj
214 }
425305df 215 try throw_error("get called on unsupported type: \(obj)")
2539e6af
KR
216}
217
425305df
KR
218private func fn_containsQ(obj: MalVal, key: MalVal) throws -> MalVal {
219 if let as_vec = as_vectorQ(obj) {
220 guard let index = as_integerQ(key) else {
221 try throw_error("expected integer key for contains(vector), got \(key)")
222 }
223 let n = as_inttype(index)
224 return n < as_vec.count ? make_true() : make_false()
2539e6af 225 }
425305df
KR
226 if let as_hash = as_hashmapQ(obj) {
227 return as_hash.value_for(key) != nil ? make_true() : make_false()
2539e6af 228 }
425305df 229 try throw_error("contains? called on unsupported type: \(obj)")
2539e6af
KR
230}
231
425305df
KR
232private func fn_keys(hash: MalHashMap) throws -> MalVal {
233 return hash.keys
2539e6af
KR
234}
235
425305df
KR
236private func fn_values(hash: MalHashMap) throws -> MalVal {
237 return hash.values
2539e6af
KR
238}
239
425305df 240private func fn_sequentialQ(obj: MalVal) throws -> Bool {
2539e6af
KR
241 return is_sequence(obj)
242}
243
425305df
KR
244private func fn_cons(first: MalVal, rest: MalSequence) throws -> MalVal {
245 return rest.cons(first)
2539e6af
KR
246}
247
425305df
KR
248private func fn_concat(args: MalVarArgs) throws -> MalVal {
249 var result = make_list()
250 for arg in args.value {
251 guard let arg_as_seq = as_sequenceQ(arg) else {
252 try throw_error("expected list, got \(arg)")
253 }
254 result = try! as_sequence(result).concat(arg_as_seq)
2539e6af 255 }
425305df 256 return result
2539e6af
KR
257}
258
425305df
KR
259private func fn_nth(list: MalSequence, index: MalIntType) throws -> MalVal {
260 return try list.nth(index)
2539e6af
KR
261}
262
425305df 263private func fn_first(arg: MalVal) throws -> MalVal {
2539e6af
KR
264 if is_nil(arg) {
265 return arg
266 }
425305df 267 if let list = as_sequenceQ(arg) {
2539e6af
KR
268 return list.first()
269 }
425305df 270 try throw_error("expected list, got \(arg)")
2539e6af
KR
271}
272
b5f4363f
DM
273private func fn_rest(arg: MalVal) throws -> MalVal {
274 if is_nil(arg) {
275 return make_list()
276 }
277 if let seq = as_sequenceQ(arg) {
278 return seq.rest()
279 }
280 try throw_error("expected sequence, got \(arg)")
2539e6af
KR
281}
282
425305df
KR
283private func fn_emptyQ(obj: MalVal) throws -> Bool {
284 if let list = as_sequenceQ(obj) {
2539e6af
KR
285 return list.isEmpty
286 }
287 return true
288}
289
425305df 290private func fn_count(obj: MalVal) throws -> MalIntType {
2539e6af
KR
291 if is_nil(obj) {
292 return 0
293 }
425305df
KR
294 if let as_seq = as_sequenceQ(obj) {
295 return as_seq.count
2539e6af 296 }
425305df
KR
297 if let as_hash = as_hashmapQ(obj) {
298 return as_hash.count
2539e6af 299 }
425305df
KR
300 if let as_str = as_stringQ(obj) {
301 return MalIntType(as_stringtype(as_str).characters.count)
2539e6af
KR
302 }
303 return 0
304}
305
425305df
KR
306private func fn_apply(args: MalVarArgs) throws -> MalVal {
307 guard args.value.count >= 2 else {
308 try throw_error("expected at least 2 arguments to apply, got \(args.value.count)")
309 }
310
311 let first = args.value.first()
312 let middle = args.value.range_from(1, to: args.value.count - 1)
313 let last = args.value.last()
314
315 guard let fn = as_functionQ(first) else {
316 try throw_error("expected function for first argument to apply, got \(first)")
317 }
318 guard let seq = as_sequenceQ(last) else {
319 try throw_error("expected sequence for last argument to apply, got \(last)")
320 }
321 let exprs = try! as_sequence(middle).concat(seq)
322 return try fn.apply(as_sequence(exprs))
2539e6af
KR
323}
324
425305df 325private func fn_map(fn: MalFunction, list: MalSequence) throws -> MalVal {
2539e6af 326 var result = [MalVal]()
425305df
KR
327 result.reserveCapacity(Int(list.count))
328 for var index: MalIntType = 0; index < list.count; ++index {
329 let apply_res = try fn.apply(as_sequence(make_list_from(try! list.nth(index))))
2539e6af
KR
330 result.append(apply_res)
331 }
425305df 332 return make_list(result)
2539e6af
KR
333}
334
425305df
KR
335private func fn_conj(first: MalSequence, rest: MalVarArgs) throws -> MalVal {
336 return try first.conj(rest.value)
2539e6af
KR
337}
338
c391c80c
JM
339private func fn_seq(seq: MalVal) throws -> MalVal {
340 if let list = as_listQ(seq) {
341 return list.count > 0 ? list : make_nil()
342 } else if let vector = as_vectorQ(seq) {
343 return vector.count > 0 ? make_list(vector) : make_nil()
344 } else if let str = as_stringQ(seq) {
345 if str.string.characters.count == 0 { return make_nil() }
346 return make_list(str.string.characters.map { make_string(String($0)) })
347 } else if is_nil(seq) {
348 return make_nil()
349 } else {
350 try throw_error("seq: called with non-sequence")
351 }
352 return seq
353}
354
425305df
KR
355private func fn_meta(obj: MalVal) throws -> MalVal {
356 if let meta = get_meta(obj) {
357 return meta
358 }
359
360 return make_nil()
2539e6af
KR
361}
362
425305df
KR
363private func fn_withmeta(form: MalVal, meta: MalVal) throws -> MalVal {
364 return with_meta(form, meta)
2539e6af
KR
365}
366
425305df
KR
367private func fn_atom(obj: MalVal) throws -> MalVal {
368 return make_atom(obj)
2539e6af
KR
369}
370
425305df 371private func fn_atomQ(obj: MalVal) throws -> Bool {
2539e6af
KR
372 return is_atom(obj)
373}
374
425305df
KR
375private func fn_deref(atom: MalAtom) throws -> MalVal {
376 return atom.object
2539e6af
KR
377}
378
425305df
KR
379private func fn_resetBang(atom: MalAtom, obj: MalVal) throws -> MalVal {
380 return atom.set_object(obj)
2539e6af
KR
381}
382
425305df
KR
383private func fn_swapBang(let atom: MalAtom, fn: MalFunction, rest: MalVarArgs) throws -> MalVal {
384 var new_args = make_list_from(atom.object)
385 new_args = try as_sequence(new_args).concat(rest.value)
386 let result = try fn.apply(as_sequence(new_args))
387 return atom.set_object(result)
2539e6af
KR
388}
389
390//******************************************************************************
391//
392// The facility for invoking built-in functions makes use of a name ->
393// function-pointer table (defined down below). The function-pointers accept a
394// sequence of MalVals and return a MalVal as a result. Each built-in function
395// that does actual work, on the other hand, may expect a different set of
396// parameters of different types, and may naturally return a result of any type.
397// In order to convert between these two types of interfaces, we have these
425305df 398// unwrap_args functions. These functions implement the (MalSequence) -> MalVal
2539e6af
KR
399// interface expected by EVAL, and convert that information into Ints, Strings,
400// etc. expected by the built-in functions.
401//
402//******************************************************************************
403
425305df
KR
404private func with_one_parameter(args: MalSequence, @noescape fn: (MalVal) throws -> MalVal) throws -> MalVal {
405 guard args.count >= 1 else { try throw_error("expected at least 1 parameter, got \(args.count)") }
406 let arg1 = try! args.nth(0)
407 return try fn(arg1)
2539e6af
KR
408}
409
425305df
KR
410private func with_two_parameters(args: MalSequence, @noescape fn: (MalVal, MalVal) throws -> MalVal) throws -> MalVal {
411 guard args.count >= 2 else { try throw_error("expected at least 2 parameter, got \(args.count)") }
412 let arg1 = try! args.nth(0)
413 let arg2 = try! args.nth(1)
414 return try fn(arg1, arg2)
2539e6af
KR
415}
416
417// ========== 0-parameter functions ==========
418
425305df 419// () -> MalIntType
2539e6af 420
425305df
KR
421private func unwrap_args(args: MalSequence, @noescape forFunction fn: () throws -> MalIntType) throws -> MalVal {
422 return make_integer(try fn())
2539e6af
KR
423}
424
425// () -> MalVal
426
425305df
KR
427private func unwrap_args(args: MalSequence, @noescape forFunction fn: () throws -> MalVal) throws -> MalVal {
428 return try fn()
2539e6af
KR
429}
430
431// ========== 1-parameter functions ==========
432
425305df
KR
433// (MalAtom) -> MalVal
434
435private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalAtom) throws -> MalVal) throws -> MalVal {
436 return try with_one_parameter(args) { (arg1) -> MalVal in
437 guard let atom = as_atomQ(arg1) else {
438 try throw_error("expected atom, got \(arg1)")
439 }
440 return try fn(atom)
441 }
442}
443
2539e6af
KR
444// (MalHashMap) -> MalVal
445
425305df
KR
446private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalHashMap) throws -> MalVal) throws -> MalVal {
447 return try with_one_parameter(args) { (arg1) -> MalVal in
448 guard let hash = as_hashmapQ(arg1) else {
449 try throw_error("expected hashmap, got \(arg1)")
450 }
451 return try fn(hash)
2539e6af
KR
452 }
453}
454
455// (MalSequence) -> MalVal
456
425305df
KR
457private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalSequence) throws -> MalVal) throws -> MalVal {
458 return try with_one_parameter(args) { (arg1) -> MalVal in
459 guard let seq = as_sequenceQ(arg1) else {
460 try throw_error("expected list, got \(arg1)")
461 }
462 return try fn(seq)
2539e6af
KR
463 }
464}
465
466// (MalVal) -> Bool
467
425305df
KR
468private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVal) throws -> Bool) throws -> MalVal {
469 return try with_one_parameter(args) { (arg1) -> MalVal in
470 return try fn(arg1) ? make_true() : make_false()
2539e6af
KR
471 }
472}
473
425305df 474// (MalVal) -> MalIntType
2539e6af 475
425305df
KR
476private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVal) throws -> MalIntType) throws -> MalVal {
477 return try with_one_parameter(args) { (arg1) -> MalVal in
478 return make_integer(try fn(arg1))
2539e6af
KR
479 }
480}
481
482// (MalVal) -> MalVal
483
425305df
KR
484func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVal) throws -> MalVal) throws -> MalVal {
485 return try with_one_parameter(args) { (arg1) -> MalVal in
486 return try fn(arg1)
2539e6af
KR
487 }
488}
489
490// (String) -> MalVal
491
425305df
KR
492private func unwrap_args(args: MalSequence, @noescape forFunction fn: (String) throws -> MalVal) throws -> MalVal {
493 return try with_one_parameter(args) { (arg1) -> MalVal in
494 guard let str = as_stringQ(arg1) else {
495 try throw_error("expected string, got \(arg1)")
496 }
497 return try fn(as_stringtype(str))
2539e6af
KR
498 }
499}
500
501// (String) -> MalVal?
502
425305df
KR
503private func unwrap_args(args: MalSequence, @noescape forFunction fn: (String) throws -> MalVal?) throws -> MalVal {
504 return try with_one_parameter(args) { (arg1) -> MalVal in
505 guard let str = as_stringQ(arg1) else {
506 try throw_error("expected string, got \(arg1)")
507 }
508 let res = try fn(as_stringtype(str))
509 return res != nil ? res! : make_nil()
2539e6af
KR
510 }
511}
512
513// (String) -> String
514
425305df
KR
515private func unwrap_args(args: MalSequence, @noescape forFunction fn: (String) throws -> String) throws -> MalVal {
516 return try with_one_parameter(args) { (arg1) -> MalVal in
517 guard let str = as_stringQ(arg1) else {
518 try throw_error("expected string, got \(arg1)")
519 }
520 return make_string(try fn(as_stringtype(str)))
2539e6af
KR
521 }
522}
523
524// (String) -> String?
525
425305df
KR
526private func unwrap_args(args: MalSequence, @noescape forFunction fn: (String) throws -> String?) throws -> MalVal {
527 return try with_one_parameter(args) { (arg1) -> MalVal in
528 guard let str = as_stringQ(arg1) else {
529 try throw_error("expected string, got \(arg1)")
530 }
531 let res = try fn(as_stringtype(str))
532 return res != nil ? make_string(res!) : make_nil()
2539e6af
KR
533 }
534}
535
536// ========== 2-parameter functions ==========
537
425305df 538// (MalIntType, MalIntType) -> Bool
2539e6af 539
425305df
KR
540private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalIntType, MalIntType) throws -> Bool) throws -> MalVal {
541 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
542 guard let int1 = as_integerQ(arg1) else {
543 try throw_error("expected number, got \(arg1)")
544 }
545 guard let int2 = as_integerQ(arg2) else {
546 try throw_error("expected number, got \(arg2)")
547 }
548 return try fn(as_inttype(int1), as_inttype(int2)) ? make_true() : make_false()
2539e6af
KR
549 }
550}
551
425305df 552// (MalIntType, MalIntType) -> MalIntType
2539e6af 553
425305df
KR
554private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalIntType, MalIntType) throws -> MalIntType) throws -> MalVal {
555 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
556 guard let int1 = as_integerQ(arg1) else {
557 try throw_error("expected number, got \(arg1)")
558 }
559 guard let int2 = as_integerQ(arg2) else {
560 try throw_error("expected number, got \(arg2)")
561 }
562 return make_integer(try fn(as_inttype(int1), as_inttype(int2)))
2539e6af
KR
563 }
564}
565
566// (MalAtom, MalVal) -> MalVal
567
425305df
KR
568private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalAtom, MalVal) throws -> MalVal) throws -> MalVal {
569 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
570 guard let atom = as_atomQ(arg1) else {
571 try throw_error("expected atom, got \(arg1)")
572 }
573 return try fn(atom, arg2)
2539e6af
KR
574 }
575}
576
577// (MalFunction, MalSequence) -> MalVal
578
425305df
KR
579private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalFunction, MalSequence) throws -> MalVal) throws -> MalVal {
580 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
581 guard let fn1 = as_functionQ(arg1) else {
582 try throw_error("expected function, got \(arg1)")
583 }
584 guard let seq2 = as_sequenceQ(arg2) else {
585 try throw_error("expected sequence, got \(arg2)")
586 }
587 return try fn(fn1, seq2)
2539e6af
KR
588 }
589}
590
425305df 591// (MalSequence, MalIntType) -> MalVal
2539e6af 592
425305df
KR
593private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalSequence, MalIntType) throws -> MalVal) throws -> MalVal {
594 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
595 guard let seq = as_sequenceQ(arg1) else {
596 try throw_error("expected sequence, got \(arg1)")
597 }
598 guard let int = as_integerQ(arg2) else {
599 try throw_error("expected number, got \(arg2)")
600 }
601 return try fn(seq, as_inttype(int))
2539e6af
KR
602 }
603}
604
605// (MalVal, MalSequence) -> MalVal
606
425305df
KR
607private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVal, MalSequence) throws -> MalVal) throws -> MalVal {
608 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
609 guard let seq = as_sequenceQ(arg2) else {
610 try throw_error("expected sequence, got \(arg2)")
611 }
612 return try fn(arg1, seq)
2539e6af
KR
613 }
614}
615
616// (MalVal, MalVal) -> Bool
617
425305df
KR
618private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVal, MalVal) throws -> Bool) throws -> MalVal {
619 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
620 return try fn(arg1, arg2) ? make_true() : make_false()
2539e6af
KR
621 }
622}
623
624// (MalVal, MalVal) -> MalVal
625
425305df
KR
626private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVal, MalVal) throws -> MalVal) throws -> MalVal {
627 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
628 return try fn(arg1, arg2)
2539e6af
KR
629 }
630}
631
632// ========== Variadic functions ==========
633
634// (MalVarArgs) -> ()
635
425305df
KR
636private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVarArgs) throws -> ()) throws -> MalVal {
637 try fn(MalVarArgs(args))
638 return make_nil()
2539e6af
KR
639}
640
641// (MalVarArgs) -> String
642
425305df
KR
643private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVarArgs) throws -> String) throws -> MalVal {
644 return make_string(try fn(MalVarArgs(args)))
2539e6af
KR
645}
646
647// (MalVarArgs) -> MalVal
648
425305df
KR
649private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalVarArgs) throws -> MalVal) throws -> MalVal {
650 return try fn(MalVarArgs(args))
2539e6af
KR
651}
652
653// (MalAtom, MalFunction, MalVarArgs) -> MalVal
654
425305df
KR
655private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalAtom, MalFunction, MalVarArgs) throws -> MalVal) throws -> MalVal {
656 return try with_two_parameters(args) { (arg1, arg2) -> MalVal in
657 guard let atom = as_atomQ(arg1) else {
658 try throw_error("expected atom, got \(arg1)")
659 }
660 guard let fn2 = as_functionQ(arg2) else {
661 try throw_error("expected function, got \(arg2)")
662 }
663 return try fn(atom, fn2, MalVarArgs(as_sequence(args.rest()).rest()))
2539e6af
KR
664 }
665}
666
667// (MalHashMap, MalVarArgs) -> MalVal
668
425305df
KR
669private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalHashMap, MalVarArgs) throws -> MalVal) throws -> MalVal {
670 return try with_one_parameter(args) { (arg1) -> MalVal in
671 guard let hash = as_hashmapQ(arg1) else {
672 try throw_error("expected hashmap, got \(arg1)")
673 }
674 return try fn(hash, MalVarArgs(args.rest()))
2539e6af
KR
675 }
676}
677
678// (MalSequence, MalVarArgs) -> MalVal
679
425305df
KR
680private func unwrap_args(args: MalSequence, @noescape forFunction fn: (MalSequence, MalVarArgs) throws -> MalVal) throws -> MalVal {
681 return try with_one_parameter(args) { (arg1) -> MalVal in
682 guard let seq = as_sequenceQ(arg1) else {
683 try throw_error("expected sequence, got \(arg1)")
684 }
685 return try fn(seq, MalVarArgs(args.rest()))
2539e6af
KR
686 }
687}
688
689// *o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*o*
690
425305df
KR
691let ns: [String: MalBuiltin.Signature] = [
692 "=": { try unwrap_args($0, forFunction: fn_eq) },
693 "throw": { try unwrap_args($0, forFunction: fn_throw) },
694
695 "nil?": { try unwrap_args($0, forFunction: fn_nilQ) },
696 "true?": { try unwrap_args($0, forFunction: fn_trueQ) },
697 "false?": { try unwrap_args($0, forFunction: fn_falseQ) },
c391c80c 698 "string?": { try unwrap_args($0, forFunction: fn_stringQ) },
425305df
KR
699 "symbol": { try unwrap_args($0, forFunction: fn_symbol) },
700 "symbol?": { try unwrap_args($0, forFunction: fn_symbolQ) },
701 "keyword": { try unwrap_args($0, forFunction: fn_keyword) },
702 "keyword?": { try unwrap_args($0, forFunction: fn_keywordQ) },
c3c9f348
JM
703 "number?": { try unwrap_args($0, forFunction: fn_numberQ) },
704 "fn?": { try unwrap_args($0, forFunction: fn_functionQ) },
705 "macro?": { try unwrap_args($0, forFunction: fn_macroQ) },
425305df
KR
706
707 "pr-str": { try unwrap_args($0, forFunction: fn_prstr) },
708 "str": { try unwrap_args($0, forFunction: fn_str) },
709 "prn": { try unwrap_args($0, forFunction: fn_prn) },
710 "println": { try unwrap_args($0, forFunction: fn_println) },
711 "read-string": { try unwrap_args($0, forFunction: fn_readstring) },
712 "readline": { try unwrap_args($0, forFunction: fn_readline) },
713 "slurp": { try unwrap_args($0, forFunction: fn_slurp) },
714
715 "<": { try unwrap_args($0, forFunction: fn_lt) },
716 "<=": { try unwrap_args($0, forFunction: fn_lte) },
717 ">": { try unwrap_args($0, forFunction: fn_gt) },
718 ">=": { try unwrap_args($0, forFunction: fn_gte) },
719 "+": { try unwrap_args($0, forFunction: fn_add) },
720 "-": { try unwrap_args($0, forFunction: fn_subtract) },
721 "*": { try unwrap_args($0, forFunction: fn_multiply) },
722 "/": { try unwrap_args($0, forFunction: fn_divide) },
723 "time-ms": { try unwrap_args($0, forFunction: fn_timems) },
724
725 "list": { try unwrap_args($0, forFunction: fn_list) },
726 "list?": { try unwrap_args($0, forFunction: fn_listQ) },
727 "vector": { try unwrap_args($0, forFunction: fn_vector) },
728 "vector?": { try unwrap_args($0, forFunction: fn_vectorQ) },
729 "hash-map": { try unwrap_args($0, forFunction: fn_hashmap) },
730 "map?": { try unwrap_args($0, forFunction: fn_hashmapQ) },
731 "assoc": { try unwrap_args($0, forFunction: fn_assoc) },
732 "dissoc": { try unwrap_args($0, forFunction: fn_dissoc) },
733 "get": { try unwrap_args($0, forFunction: fn_get) },
734 "contains?": { try unwrap_args($0, forFunction: fn_containsQ) },
735 "keys": { try unwrap_args($0, forFunction: fn_keys) },
736 "vals": { try unwrap_args($0, forFunction: fn_values) },
737
738 "sequential?": { try unwrap_args($0, forFunction: fn_sequentialQ) },
739 "cons": { try unwrap_args($0, forFunction: fn_cons) },
740 "concat": { try unwrap_args($0, forFunction: fn_concat) },
741 "nth": { try unwrap_args($0, forFunction: fn_nth) },
742 "first": { try unwrap_args($0, forFunction: fn_first) },
743 "rest": { try unwrap_args($0, forFunction: fn_rest) },
744 "empty?": { try unwrap_args($0, forFunction: fn_emptyQ) },
745 "count": { try unwrap_args($0, forFunction: fn_count) },
746 "apply": { try unwrap_args($0, forFunction: fn_apply) },
747 "map": { try unwrap_args($0, forFunction: fn_map) },
c391c80c 748
425305df 749 "conj": { try unwrap_args($0, forFunction: fn_conj) },
c391c80c 750 "seq": { try unwrap_args($0, forFunction: fn_seq) },
425305df
KR
751
752 "meta": { try unwrap_args($0, forFunction: fn_meta) },
753 "with-meta": { try unwrap_args($0, forFunction: fn_withmeta) },
754 "atom": { try unwrap_args($0, forFunction: fn_atom) },
755 "atom?": { try unwrap_args($0, forFunction: fn_atomQ) },
756 "deref": { try unwrap_args($0, forFunction: fn_deref) },
757 "reset!": { try unwrap_args($0, forFunction: fn_resetBang) },
758 "swap!": { try unwrap_args($0, forFunction: fn_swapBang) },
2539e6af
KR
759]
760
761func load_builtins(env: Environment) {
762 for (name, fn) in ns {
425305df 763 env.set(as_symbol(make_symbol(name)), make_builtin(fn))
2539e6af
KR
764 }
765}