diff --git a/Tests/KiteCoreTests/CallCCTests.swift b/Tests/KiteCoreTests/CallCCTests.swift new file mode 100644 index 0000000..8db5f21 --- /dev/null +++ b/Tests/KiteCoreTests/CallCCTests.swift @@ -0,0 +1,47 @@ +import XCTest +@testable import KiteCore + +final class CallCCTests: XCTestCase { + private func evalShow(_ src: String) throws -> String { + displayString(try Interpreter().evalString(src)) + } + + func testEarlyExit() throws { + let program = """ + (define (product items) + (call/cc + (lambda (break) + (let loop ((xs items) (acc 1)) + (cond ((null? xs) acc) + ((= (car xs) 0) (break 0)) + (else (loop (cdr xs) (* acc (car xs))))))))) + (list (product '(1 2 3 4)) (product '(1 2 0 4))) + """ + XCTAssertEqual(try evalShow(program), "(24 0)") + } + + func testContinuationValueWhenNotInvoked() throws { + XCTAssertEqual(try evalShow("(+ 1 (call/cc (lambda (k) 10)))"), "11") + } + + func testReentrantContinuationLoop() throws { + let program = """ + (let ((sum 0) (i 0) (k #f)) + (call/cc (lambda (c) (set! k c))) + (set! i (+ i 1)) + (set! sum (+ sum i)) + (if (< i 5) (k #f) sum)) + """ + XCTAssertEqual(try evalShow(program), "15") + } + + func testMultiShotContinuationAccumulates() throws { + let program = """ + (let ((results '()) (k #f) (n 0)) + (set! n (+ 1 (call/cc (lambda (c) (set! k c) 0)))) + (set! results (cons n results)) + (if (< n 4) (k n) results)) + """ + XCTAssertEqual(try evalShow(program), "(4 3 2 1)") + } +} diff --git a/Tests/KiteCoreTests/TailCallTests.swift b/Tests/KiteCoreTests/TailCallTests.swift new file mode 100644 index 0000000..563ba05 --- /dev/null +++ b/Tests/KiteCoreTests/TailCallTests.swift @@ -0,0 +1,46 @@ +import XCTest +@testable import KiteCore + +final class TailCallTests: XCTestCase { + private func evalShow(_ src: String) throws -> String { + displayString(try Interpreter().evalString(src)) + } + + func testDeepNamedLetLoop() throws { + let program = """ + (define (count-up n) + (let loop ((i 0)) + (if (= i n) i (loop (+ i 1))))) + (count-up 1000000) + """ + XCTAssertEqual(try evalShow(program), "1000000") + } + + func testDeepTailRecursiveAccumulator() throws { + let program = """ + (define (sum-to n acc) + (if (= n 0) acc (sum-to (- n 1) (+ acc 1)))) + (sum-to 1000000 0) + """ + XCTAssertEqual(try evalShow(program), "1000000") + } + + func testMutualTailRecursion() throws { + let program = """ + (define (even? n) (if (= n 0) #t (odd? (- n 1)))) + (define (odd? n) (if (= n 0) #f (even? (- n 1)))) + (even? 500000) + """ + XCTAssertEqual(try evalShow(program), "#t") + } + + func testTailPositionInCond() throws { + let program = """ + (define (loop i n) + (cond ((= i n) 'done) + (else (loop (+ i 1) n)))) + (loop 0 500000) + """ + XCTAssertEqual(try evalShow(program), "done") + } +}