Complete C port of the Scheme interpreter. Same .lsp files run in both Python and C with identical output. Architecture: - NaN-boxed 64-bit values (zero-alloc numbers) - Hash-map environments with parent chain + global shortcut - Interned symbols - TCO via explicit loop (eval) and TAIL_CALL/SELF_TAIL_CALL (VM) - Bytecode compiler with all opcodes including superinstructions - 58 unit + integration tests Makefile targets: make test-all run Python (571) + C (58) tests make examples run examples in both, compare output make friction benchmark same .lsp in Python vs C make c-build build C interpreter make c-test run C tests make c-repl C REPL
597 lines
18 KiB
C
597 lines
18 KiB
C
/*
|
|
* test.c — Unit + integration tests for the C Scheme interpreter
|
|
*/
|
|
#include "uncommonlisp.h"
|
|
|
|
static int tests_run = 0;
|
|
static int tests_passed = 0;
|
|
static int tests_failed = 0;
|
|
|
|
#define TEST(name) \
|
|
static void test_##name(void); \
|
|
static void run_test_##name(void) { \
|
|
tests_run++; \
|
|
TRY(ctx) { \
|
|
test_##name(); \
|
|
tests_passed++; \
|
|
printf(" PASS: %s\n", #name); \
|
|
} CATCH { \
|
|
tests_failed++; \
|
|
printf(" FAIL: %s — %s\n", #name, ctx.message); \
|
|
} ENDTRY; \
|
|
} \
|
|
static void test_##name(void)
|
|
|
|
#define ASSERT(cond, msg) \
|
|
do { if (!(cond)) lisp_error("assertion failed: %s", msg); } while(0)
|
|
|
|
#define ASSERT_EQ_INT(a, b) \
|
|
do { int64_t _a = (a), _b = (b); \
|
|
if (_a != _b) lisp_error("expected %lld, got %lld", (long long)_b, (long long)_a); \
|
|
} while(0)
|
|
|
|
#define ASSERT_EQ_STR(a, b) \
|
|
do { if (strcmp(a, b) != 0) lisp_error("expected \"%s\", got \"%s\"", b, a); } while(0)
|
|
|
|
/* Helper: evaluate source and return result */
|
|
static Env *fresh_env(void) {
|
|
Env *g = make_global_env();
|
|
int count;
|
|
Value *exprs = read_all(PRELUDE, &count, false);
|
|
for (int i = 0; i < count; i++) leval(exprs[i], g);
|
|
ul_free(exprs);
|
|
return g;
|
|
}
|
|
|
|
static Value run(const char *src) {
|
|
Env *g = fresh_env();
|
|
int count;
|
|
Value *exprs = read_all(src, &count, false);
|
|
Value result = VAL_VOID;
|
|
for (int i = 0; i < count; i++) result = leval(exprs[i], g);
|
|
ul_free(exprs);
|
|
return result;
|
|
}
|
|
|
|
static char *run_show(const char *src) {
|
|
return show(run(src), false);
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
* Unit tests — Types
|
|
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
TEST(nan_boxing_int) {
|
|
Value v = VAL_INT(42);
|
|
ASSERT(IS_INT(v), "should be int");
|
|
ASSERT_EQ_INT(as_int(v), 42);
|
|
|
|
v = VAL_INT(-100);
|
|
ASSERT_EQ_INT(as_int(v), -100);
|
|
|
|
v = VAL_INT(0);
|
|
ASSERT_EQ_INT(as_int(v), 0);
|
|
}
|
|
|
|
TEST(nan_boxing_double) {
|
|
Value v = make_double(3.14);
|
|
ASSERT(IS_DOUBLE(v), "should be double");
|
|
double d = as_double(v);
|
|
ASSERT(fabs(d - 3.14) < 1e-10, "should be 3.14");
|
|
}
|
|
|
|
TEST(nan_boxing_special) {
|
|
ASSERT(IS_NIL(VAL_NIL), "NIL");
|
|
ASSERT(IS_VOID(VAL_VOID), "VOID");
|
|
ASSERT(IS_TRUE(VAL_TRUE), "TRUE");
|
|
ASSERT(IS_FALSE(VAL_FALSE), "FALSE");
|
|
ASSERT(IS_EOF(VAL_EOF), "EOF");
|
|
ASSERT(IS_TRUTHY(VAL_TRUE), "TRUE is truthy");
|
|
ASSERT(!IS_TRUTHY(VAL_FALSE), "FALSE is not truthy");
|
|
ASSERT(IS_TRUTHY(VAL_NIL), "NIL is truthy (Scheme semantics)");
|
|
}
|
|
|
|
TEST(symbol_interning) {
|
|
Value s1 = intern("foo");
|
|
Value s2 = intern("foo");
|
|
Value s3 = intern("bar");
|
|
ASSERT(s1 == s2, "same symbol should be identical");
|
|
ASSERT(s1 != s3, "different symbols should differ");
|
|
ASSERT_EQ_STR(sym_name(s1), "foo");
|
|
}
|
|
|
|
TEST(pair_creation) {
|
|
Value p = cons(VAL_INT(1), cons(VAL_INT(2), VAL_NIL));
|
|
ASSERT(IS_PAIR(p), "should be pair");
|
|
ASSERT_EQ_INT(as_int(CAR(p)), 1);
|
|
ASSERT_EQ_INT(as_int(CADR(p)), 2);
|
|
ASSERT(IS_NIL(CDDR(p)), "should end with NIL");
|
|
}
|
|
|
|
TEST(string_creation) {
|
|
Value s = make_string_from_cstr("hello");
|
|
ASSERT(IS_STRING(s), "should be string");
|
|
ASSERT_EQ_INT(AS_STRING(s)->len, 5);
|
|
ASSERT_EQ_STR(AS_STRING(s)->data, "hello");
|
|
}
|
|
|
|
TEST(vector_creation) {
|
|
Value v = make_vector(3, VAL_INT(0));
|
|
ASSERT(IS_VECTOR(v), "should be vector");
|
|
ASSERT_EQ_INT(AS_VECTOR(v)->len, 3);
|
|
AS_VECTOR(v)->data[1] = VAL_INT(42);
|
|
ASSERT_EQ_INT(as_int(AS_VECTOR(v)->data[1]), 42);
|
|
}
|
|
|
|
TEST(rational_creation) {
|
|
Value r = rational_normalize(6, 4);
|
|
ASSERT(IS_RATIONAL(r), "6/4 should be rational 3/2");
|
|
ASSERT_EQ_INT(AS_RATIONAL(r)->num, 3);
|
|
ASSERT_EQ_INT(AS_RATIONAL(r)->den, 2);
|
|
|
|
Value r2 = rational_normalize(4, 2);
|
|
ASSERT(IS_INT(r2), "4/2 should normalize to int 2");
|
|
ASSERT_EQ_INT(as_int(r2), 2);
|
|
}
|
|
|
|
TEST(environment) {
|
|
Env *g = make_env(NULL);
|
|
g->global = g;
|
|
Value sym = intern("x");
|
|
env_define(g, sym, VAL_INT(42));
|
|
ASSERT_EQ_INT(as_int(env_lookup(g, sym)), 42);
|
|
|
|
Env *c = make_env(g);
|
|
ASSERT_EQ_INT(as_int(env_lookup(c, sym)), 42);
|
|
env_define(c, sym, VAL_INT(99));
|
|
ASSERT_EQ_INT(as_int(env_lookup(c, sym)), 99);
|
|
ASSERT_EQ_INT(as_int(env_lookup(g, sym)), 42);
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
* Unit tests — Reader
|
|
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
TEST(read_integer) {
|
|
Value v = run("42");
|
|
ASSERT_EQ_INT(as_int(v), 42);
|
|
}
|
|
|
|
TEST(read_float) {
|
|
Value v = run("3.14");
|
|
ASSERT(IS_DOUBLE(v), "should be double");
|
|
}
|
|
|
|
TEST(read_string) {
|
|
Value v = run("\"hello\"");
|
|
ASSERT(IS_STRING(v), "should be string");
|
|
ASSERT_EQ_STR(AS_STRING(v)->data, "hello");
|
|
}
|
|
|
|
TEST(read_boolean) {
|
|
ASSERT(IS_TRUE(run("#t")), "#t");
|
|
ASSERT(IS_FALSE(run("#f")), "#f");
|
|
}
|
|
|
|
TEST(read_list) {
|
|
char *s = run_show("'(1 2 3)");
|
|
ASSERT_EQ_STR(s, "(1 2 3)");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(read_vector) {
|
|
char *s = run_show("#(1 2 3)");
|
|
ASSERT_EQ_STR(s, "#(1 2 3)");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(read_char) {
|
|
Value v = run("#\\space");
|
|
ASSERT(IS_CHAR(v), "should be char");
|
|
ASSERT_EQ_INT(AS_CHAR(v), ' ');
|
|
}
|
|
|
|
TEST(read_rational) {
|
|
Value v = run("1/3");
|
|
ASSERT(IS_RATIONAL(v), "should be rational");
|
|
ASSERT_EQ_INT(AS_RATIONAL(v)->num, 1);
|
|
ASSERT_EQ_INT(AS_RATIONAL(v)->den, 3);
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
* Unit tests — Evaluator
|
|
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
TEST(eval_arithmetic) {
|
|
ASSERT_EQ_INT(as_int(run("(+ 1 2)")), 3);
|
|
ASSERT_EQ_INT(as_int(run("(- 10 3)")), 7);
|
|
ASSERT_EQ_INT(as_int(run("(* 4 5)")), 20);
|
|
ASSERT_EQ_INT(as_int(run("(+ 1 2 3 4 5)")), 15);
|
|
}
|
|
|
|
TEST(eval_comparison) {
|
|
ASSERT(IS_TRUE(run("(= 3 3)")), "3 = 3");
|
|
ASSERT(IS_FALSE(run("(= 3 4)")), "3 != 4");
|
|
ASSERT(IS_TRUE(run("(< 1 2)")), "1 < 2");
|
|
ASSERT(IS_TRUE(run("(> 5 3)")), "5 > 3");
|
|
}
|
|
|
|
TEST(eval_if) {
|
|
ASSERT_EQ_INT(as_int(run("(if #t 1 2)")), 1);
|
|
ASSERT_EQ_INT(as_int(run("(if #f 1 2)")), 2);
|
|
}
|
|
|
|
TEST(eval_cond) {
|
|
ASSERT_EQ_INT(as_int(run("(cond (#f 1) (#t 2) (else 3))")), 2);
|
|
ASSERT_EQ_INT(as_int(run("(cond (else 42))")), 42);
|
|
}
|
|
|
|
TEST(eval_and_or) {
|
|
ASSERT(IS_TRUE(run("(and #t #t)")), "and true");
|
|
ASSERT(IS_FALSE(run("(and #t #f)")), "and false");
|
|
ASSERT(IS_TRUE(run("(or #f #t)")), "or true");
|
|
ASSERT(IS_FALSE(run("(or #f #f)")), "or false");
|
|
}
|
|
|
|
TEST(eval_define) {
|
|
ASSERT_EQ_INT(as_int(run("(define x 42) x")), 42);
|
|
}
|
|
|
|
TEST(eval_lambda) {
|
|
ASSERT_EQ_INT(as_int(run("((lambda (x) (+ x 1)) 41)")), 42);
|
|
}
|
|
|
|
TEST(eval_define_function) {
|
|
ASSERT_EQ_INT(as_int(run("(define (f x) (+ x 1)) (f 41)")), 42);
|
|
}
|
|
|
|
TEST(eval_let) {
|
|
ASSERT_EQ_INT(as_int(run("(let ((x 10) (y 20)) (+ x y))")), 30);
|
|
}
|
|
|
|
TEST(eval_let_star) {
|
|
ASSERT_EQ_INT(as_int(run("(let* ((x 10) (y (* x 2))) (+ x y))")), 30);
|
|
}
|
|
|
|
TEST(eval_named_let) {
|
|
char *s = run_show("(let loop ((n 5) (acc 1)) (if (= n 0) acc (loop (- n 1) (* acc n))))");
|
|
ASSERT_EQ_STR(s, "120");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_letrec) {
|
|
ASSERT_EQ_INT(as_int(run(
|
|
"(letrec ((f (lambda (n) (if (= n 0) 1 (* n (f (- n 1))))))) (f 5))"
|
|
)), 120);
|
|
}
|
|
|
|
TEST(eval_begin) {
|
|
ASSERT_EQ_INT(as_int(run("(begin 1 2 3)")), 3);
|
|
}
|
|
|
|
TEST(eval_quote) {
|
|
char *s = run_show("'(1 2 3)");
|
|
ASSERT_EQ_STR(s, "(1 2 3)");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_quasiquote) {
|
|
char *s = run_show("(let ((x 42)) `(a ,x b))");
|
|
ASSERT_EQ_STR(s, "(a 42 b)");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_list_ops) {
|
|
ASSERT_EQ_INT(as_int(run("(car '(1 2 3))")), 1);
|
|
char *s = run_show("(cdr '(1 2 3))");
|
|
ASSERT_EQ_STR(s, "(2 3)");
|
|
ul_free(s);
|
|
ASSERT_EQ_INT(as_int(run("(length '(1 2 3))")), 3);
|
|
}
|
|
|
|
TEST(eval_map) {
|
|
char *s = run_show("(map (lambda (x) (* x x)) '(1 2 3 4))");
|
|
ASSERT_EQ_STR(s, "(1 4 9 16)");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_filter) {
|
|
char *s = run_show("(filter (lambda (x) (> x 2)) '(1 2 3 4 5))");
|
|
ASSERT_EQ_STR(s, "(3 4 5)");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_string_ops) {
|
|
ASSERT_EQ_INT(as_int(run("(string-length \"hello\")")), 5);
|
|
char *s = run_show("(string-append \"hello\" \" \" \"world\")");
|
|
ASSERT_EQ_STR(s, "\"hello world\"");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_vector_ops) {
|
|
ASSERT_EQ_INT(as_int(run("(vector-ref #(10 20 30) 1)")), 20);
|
|
ASSERT_EQ_INT(as_int(run("(vector-length #(1 2 3))")), 3);
|
|
}
|
|
|
|
TEST(eval_rational_arithmetic) {
|
|
char *s = run_show("(+ 1/3 1/6)");
|
|
ASSERT_EQ_STR(s, "1/2");
|
|
ul_free(s);
|
|
|
|
s = run_show("(* 2/3 3/4)");
|
|
ASSERT_EQ_STR(s, "1/2");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_do) {
|
|
char *s = run_show(
|
|
"(do ((i 0 (+ i 1)) (acc 0 (+ acc i)))"
|
|
" ((= i 5) acc))");
|
|
ASSERT_EQ_STR(s, "10");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_set) {
|
|
ASSERT_EQ_INT(as_int(run("(define x 1) (set! x 42) x")), 42);
|
|
}
|
|
|
|
TEST(eval_closures) {
|
|
ASSERT_EQ_INT(as_int(run(
|
|
"(define (make-adder n) (lambda (x) (+ n x)))"
|
|
"(define add5 (make-adder 5))"
|
|
"(add5 37)"
|
|
)), 42);
|
|
}
|
|
|
|
TEST(eval_recursion) {
|
|
ASSERT_EQ_INT(as_int(run(
|
|
"(define (fact n) (if (= n 0) 1 (* n (fact (- n 1)))))"
|
|
"(fact 10)"
|
|
)), 3628800);
|
|
}
|
|
|
|
TEST(eval_tail_call) {
|
|
/* This would stack-overflow without TCO */
|
|
char *s = run_show(
|
|
"(define (loop n)"
|
|
" (if (= n 0) 'done (loop (- n 1))))"
|
|
"(loop 100000)");
|
|
ASSERT_EQ_STR(s, "done");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_macro) {
|
|
ASSERT_EQ_INT(as_int(run(
|
|
"(define-macro (my-add a b) `(+ ,a ,b))"
|
|
"(my-add 20 22)"
|
|
)), 42);
|
|
}
|
|
|
|
TEST(eval_case) {
|
|
ASSERT_EQ_INT(as_int(run(
|
|
"(case 2"
|
|
" ((1) 10)"
|
|
" ((2 3) 20)"
|
|
" (else 30))"
|
|
)), 20);
|
|
}
|
|
|
|
TEST(eval_when_unless) {
|
|
ASSERT_EQ_INT(as_int(run("(when #t 42)")), 42);
|
|
ASSERT(IS_VOID(run("(when #f 42)")), "when false should be void");
|
|
ASSERT_EQ_INT(as_int(run("(unless #f 42)")), 42);
|
|
}
|
|
|
|
TEST(eval_hash_table) {
|
|
ASSERT_EQ_INT(as_int(run(
|
|
"(define ht (make-hash-table))"
|
|
"(hash-table-set! ht 'x 42)"
|
|
"(hash-table-ref ht 'x)"
|
|
)), 42);
|
|
}
|
|
|
|
TEST(eval_guard) {
|
|
char *s = run_show(
|
|
"(guard (e (#t (error-object-message e)))"
|
|
" (error \"test error\"))");
|
|
ASSERT_EQ_STR(s, "\"test error\"");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_define_record_type) {
|
|
char *s = run_show(
|
|
"(define-record-type point (make-point x y) point? (x point-x) (y point-y))"
|
|
"(define p (make-point 3 4))"
|
|
"(list (point-x p) (point-y p))");
|
|
ASSERT_EQ_STR(s, "(3 4)");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_module) {
|
|
char *s = run_show(
|
|
"(module math (export square)"
|
|
" (define (square x) (* x x)))"
|
|
"(import math)"
|
|
"(square 7)");
|
|
ASSERT_EQ_STR(s, "49");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_string_port) {
|
|
char *s = run_show(
|
|
"(define p (open-input-string \"hello\"))"
|
|
"(define c (read-char p))"
|
|
"c");
|
|
ASSERT_EQ_STR(s, "#\\h");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(eval_fold) {
|
|
ASSERT_EQ_INT(as_int(run("(fold-left (lambda (x acc) (+ x acc)) 0 '(1 2 3 4 5))")), 15);
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
* Integration tests — matching fibonacci.lsp output
|
|
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
TEST(fibonacci_iterative) {
|
|
char *s = run_show(
|
|
"(define (fib-iter n)"
|
|
" (let loop ((a 0) (b 1) (i 0))"
|
|
" (if (= i n) a (loop b (+ a b) (+ i 1)))))"
|
|
"(fib-iter 30)");
|
|
ASSERT_EQ_STR(s, "832040");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(fibonacci_recursive) {
|
|
char *s = run_show(
|
|
"(define (fib-rec n)"
|
|
" (if (<= n 1) n (+ (fib-rec (- n 1)) (fib-rec (- n 2)))))"
|
|
"(fib-rec 20)");
|
|
ASSERT_EQ_STR(s, "6765");
|
|
ul_free(s);
|
|
}
|
|
|
|
TEST(fibonacci_map) {
|
|
char *s = run_show(
|
|
"(define (fib-iter n)"
|
|
" (let loop ((a 0) (b 1) (i 0))"
|
|
" (if (= i n) a (loop b (+ a b) (+ i 1)))))"
|
|
"(map fib-iter (iota 15))");
|
|
ASSERT_EQ_STR(s, "(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377)");
|
|
ul_free(s);
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
* VM / bytecode tests
|
|
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
TEST(vm_basic) {
|
|
/* Run with auto-compile enabled */
|
|
Env *g = fresh_env();
|
|
g_auto_compile = true;
|
|
int count;
|
|
Value *exprs = read_all("(define (add a b) (+ a b)) (add 20 22)", &count, false);
|
|
Value result = VAL_VOID;
|
|
for (int i = 0; i < count; i++) result = leval(exprs[i], g);
|
|
ASSERT_EQ_INT(as_int(result), 42);
|
|
g_auto_compile = false;
|
|
ul_free(exprs);
|
|
}
|
|
|
|
TEST(vm_fibonacci) {
|
|
Env *g = fresh_env();
|
|
g_auto_compile = true;
|
|
int count;
|
|
Value *exprs = read_all(
|
|
"(define (fib-iter n)"
|
|
" (let loop ((a 0) (b 1) (i 0))"
|
|
" (if (= i n) a (loop b (+ a b) (+ i 1)))))"
|
|
"(fib-iter 30)", &count, false);
|
|
Value result = VAL_VOID;
|
|
for (int i = 0; i < count; i++) result = leval(exprs[i], g);
|
|
ASSERT_EQ_INT(as_int(result), 832040);
|
|
g_auto_compile = false;
|
|
ul_free(exprs);
|
|
}
|
|
|
|
TEST(vm_tail_call) {
|
|
Env *g = fresh_env();
|
|
g_auto_compile = true;
|
|
int count;
|
|
Value *exprs = read_all(
|
|
"(define (loop n) (if (= n 0) 'done (loop (- n 1))))"
|
|
"(loop 100000)", &count, false);
|
|
Value result = VAL_VOID;
|
|
for (int i = 0; i < count; i++) result = leval(exprs[i], g);
|
|
char *s = show(result, false);
|
|
ASSERT_EQ_STR(s, "done");
|
|
ul_free(s);
|
|
g_auto_compile = false;
|
|
ul_free(exprs);
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
* Main
|
|
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
int main(void) {
|
|
init_symbols();
|
|
|
|
printf("Running uncommonlisp C tests...\n\n");
|
|
printf("[types]\n");
|
|
run_test_nan_boxing_int();
|
|
run_test_nan_boxing_double();
|
|
run_test_nan_boxing_special();
|
|
run_test_symbol_interning();
|
|
run_test_pair_creation();
|
|
run_test_string_creation();
|
|
run_test_vector_creation();
|
|
run_test_rational_creation();
|
|
run_test_environment();
|
|
|
|
printf("\n[reader]\n");
|
|
run_test_read_integer();
|
|
run_test_read_float();
|
|
run_test_read_string();
|
|
run_test_read_boolean();
|
|
run_test_read_list();
|
|
run_test_read_vector();
|
|
run_test_read_char();
|
|
run_test_read_rational();
|
|
|
|
printf("\n[evaluator]\n");
|
|
run_test_eval_arithmetic();
|
|
run_test_eval_comparison();
|
|
run_test_eval_if();
|
|
run_test_eval_cond();
|
|
run_test_eval_and_or();
|
|
run_test_eval_define();
|
|
run_test_eval_lambda();
|
|
run_test_eval_define_function();
|
|
run_test_eval_let();
|
|
run_test_eval_let_star();
|
|
run_test_eval_named_let();
|
|
run_test_eval_letrec();
|
|
run_test_eval_begin();
|
|
run_test_eval_quote();
|
|
run_test_eval_quasiquote();
|
|
run_test_eval_list_ops();
|
|
run_test_eval_map();
|
|
run_test_eval_filter();
|
|
run_test_eval_string_ops();
|
|
run_test_eval_vector_ops();
|
|
run_test_eval_rational_arithmetic();
|
|
run_test_eval_do();
|
|
run_test_eval_set();
|
|
run_test_eval_closures();
|
|
run_test_eval_recursion();
|
|
run_test_eval_tail_call();
|
|
run_test_eval_macro();
|
|
run_test_eval_case();
|
|
run_test_eval_when_unless();
|
|
run_test_eval_hash_table();
|
|
run_test_eval_guard();
|
|
run_test_eval_define_record_type();
|
|
run_test_eval_module();
|
|
run_test_eval_string_port();
|
|
run_test_eval_fold();
|
|
|
|
printf("\n[integration]\n");
|
|
run_test_fibonacci_iterative();
|
|
run_test_fibonacci_recursive();
|
|
run_test_fibonacci_map();
|
|
|
|
printf("\n[vm/bytecode]\n");
|
|
run_test_vm_basic();
|
|
run_test_vm_fibonacci();
|
|
run_test_vm_tail_call();
|
|
|
|
printf("\n═══════════════════════════════════════════\n");
|
|
printf("Results: %d/%d passed", tests_passed, tests_run);
|
|
if (tests_failed > 0) printf(" (%d failed)", tests_failed);
|
|
printf("\n");
|
|
|
|
return tests_failed > 0 ? 1 : 0;
|
|
}
|