test(eval): add tail-call and call/cc tests
This commit is contained in:
1 parent
eede0d15ec
commit
a9c2ffc22a
2 files changed
+93
No files matched your search
@@ -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)")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user