#include #include #include #include "lisp_api.h" #include "lisp.h" #include "lex.yy.h" #include "lisp.tab.h" static int tests_run = 0; static int tests_failed = 0; env *global_env = NULL; #define ASSERT(cond, msg) do { \ tests_run++; \ if (!(cond)) { \ tests_failed++; \ printf("FAIL: %s\n", msg); \ } else { \ printf("PASS: %s\n", msg); \ } \ } while (0) void test_make_int() { value *v = make_int(42); ASSERT(v->type == VT_INT, "make_int sets type"); ASSERT(v->as.i == 42, "make_int sets value"); } void test_cons_car_cdr() { value *a = make_int(1); value *b = make_int(2); value *p = cons(a, b); ASSERT(p->type == VT_PAIR, "cons creates pair"); ASSERT(car(p)->as.i == 1, "car works"); ASSERT(cdr(p)->as.i == 2, "cdr works"); } void test_env_define_lookup() { env *e = env_create(NULL); value *v = make_int(10); env_define(e, "x", v); value *found = env_lookup(e, "x"); ASSERT(found != NULL, "env_lookup finds symbol"); ASSERT(found->as.i == 10, "env_lookup returns correct value"); } void test_env_parent_lookup() { env *parent = env_create(NULL); env_define(parent, "x", make_int(5)); env *child = env_create(parent); value *found = env_lookup(child, "x"); ASSERT(found != NULL, "lookup finds parent symbol"); ASSERT(found->as.i == 5, "parent symbol value correct"); } void test_eval_literal() { env *e = env_create(NULL); value *v = make_int(7); value *r = eval(e, v); ASSERT(r->as.i == 7, "eval of int returns itself"); } void test_eval_symbol() { env *e = env_create(NULL); env_define(e, "x", make_int(99)); value *sym = make_symbol("x"); value *r = eval(e, sym); ASSERT(r->as.i == 99, "eval resolves symbol"); } void test_define() { env *e = env_create(NULL); value *expr =cons(make_symbol("define"), cons(make_symbol("x"), cons(make_int(3), make_nil()))); eval(e, expr); value *r = env_lookup(e, "x"); ASSERT(r != NULL, "define creates binding"); ASSERT(r->as.i == 3, "define sets correct value"); } void test_lambda_identity() { env *e = env_create(NULL); // ((lambda (x) x) 5) value *expr = cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons(make_symbol("x"), make_nil()) ) ), cons(make_int(5), make_nil()) ); value *r = eval(e, expr); ASSERT(r->type == VT_INT, "lambda identity returns int"); ASSERT(r->as.i == 5, "lambda identity returns argument"); } void test_lambda_add() { env *e = env_create(NULL); // install + procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons(make_int(1), make_nil()) ) ), make_nil() ) ) ), cons(make_int(4), make_nil()) ); value *r = eval(e, expr); ASSERT(r->as.i == 5, "lambda body with + works"); } void test_lambda_multiple_args() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), cons(make_symbol("y"), make_nil()) ), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons(make_symbol("y"), make_nil()) ) ), make_nil() ) ) ), cons(make_int(2), cons(make_int(3), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 5, "lambda with multiple parameters"); } void test_lambda_closure() { //(define x 10) //((lambda (y) (+ x y)) 5) env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); env_define(e, "x", make_int(10)); value *expr = cons( cons(make_symbol("lambda"), cons( cons(make_symbol("y"), make_nil()), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons(make_symbol("y"), make_nil()) ) ), make_nil() ) ) ), cons(make_int(5), make_nil()) ); value *r = eval(e, expr); ASSERT(r->as.i == 15, "lambda closes over outer environment"); } void test_nested_lambdas() { // (((lambda (x) (lambda (y) (+ x y))) 3) 4) env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons( cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("y"), make_nil()), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons(make_symbol("y"), make_nil()) ) ), make_nil() ) ) ), make_nil() ) ) ), cons(make_int(3), make_nil()) ), cons(make_int(4), make_nil()) ); value *r = eval(e, expr); ASSERT(r->as.i == 7, "nested lambdas capture variables"); } void test_lambda_does_not_modify_outer_env() { env *e = env_create(NULL); env_define(e, "x", make_int(1)); value *expr = cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons(make_symbol("x"), make_nil()) ) ), cons(make_int(99), make_nil()) ); value *r = eval(e, expr); value *outer = env_lookup(e, "x"); ASSERT(r->as.i == 99, "lambda returns inner x"); ASSERT(outer->as.i == 1, "outer x unchanged"); } void test_recursive_factorial() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); /* (define fact (lambda (n) (if (< n 2) 1 (* n (fact (- n 1)))))) */ value *fact_def = cons(make_symbol("define"), cons(make_symbol("fact"), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("n"), make_nil()), cons( cons(make_symbol("if"), cons( cons(make_symbol("<"), cons(make_symbol("n"), cons(make_int(2), make_nil()) ) ), cons( make_int(1), cons( cons(make_symbol("*"), cons(make_symbol("n"), cons( cons(make_symbol("fact"), cons( cons(make_symbol("-"), cons(make_symbol("n"), cons(make_int(1), make_nil()) ) ), make_nil() ) ), make_nil() ) ) ), make_nil() ) ) ) ), make_nil() ) ) ), make_nil() ) ) ); eval(e, fact_def); // (fact 5) value *call = cons(make_symbol("fact"), cons(make_int(5), make_nil()) ); value *r = eval(e, call); ASSERT(r->as.i == 120, "recursive factorial works"); } void test_eq_ints() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("equal?"), cons(make_int(3), cons(make_int(3), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->type == VT_INT, "eq returns true as int"); ASSERT(r->as.i == 1, "eq works on equal ints"); } void test_eq_ints_false() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("equal?"), cons(make_int(3), cons(make_int(4), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->type == VT_NIL, "eq returns nil on unequal ints"); } void test_eq_symbols() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("equal?"), cons(make_symbol("foo"), cons(make_symbol("foo"), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 1, "eq works on symbols"); } void test_eq_lists() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *list1 = cons(make_int(1), cons(make_int(2), make_nil()) ); value *list2 = cons(make_int(1), cons(make_int(2), make_nil()) ); value *expr = cons(make_symbol("equal?"), cons(list1, cons(list2, make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 1, "eq works on structurally equal lists"); } void test_null_true() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("null?"), cons(make_nil(), make_nil()) ); value *r = eval(e, expr); ASSERT(r->as.i == 1, "null? true on ()"); } void test_null_false() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("null?"), cons( cons(make_int(1), make_nil()), make_nil() ) ); value *r = eval(e, expr); ASSERT(r->type == VT_NIL, "null? false on non-empty list"); } void test_if_true() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("if"), cons( make_int(1), // true (non-nil) cons(make_int(42), cons(make_int(0), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 42, "if true branch evaluated"); } void test_if_false() { env *e = env_create(NULL); value *expr = cons(make_symbol("if"), cons( make_nil(), // false cons(make_int(1), cons(make_int(2), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 2, "if false branch evaluated"); } void test_if_short_circuit() { env *e = env_create(NULL); // (if 1 42 undefined-symbol) value *expr = cons(make_symbol("if"), cons( make_int(1), // true cons(make_int(42), cons(make_symbol("nope"), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 42, "if short-circuits unused branch"); } void test_add_multiple_args() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("+"), cons(make_int(1), cons(make_int(2), cons(make_int(3), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 6, "+ works with multiple args"); } void test_lt_chain() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("<"), cons(make_int(1), cons(make_int(2), cons(make_int(3), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 1, "< works as chain comparison"); } void test_partial_application_single_arg() { // ((lambda (x y) (+ x y)) 5) should return a lambda expecting y env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), cons(make_symbol("y"), make_nil()) ), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons(make_symbol("y"), make_nil()) ) ), make_nil() ) ) ), cons(make_int(5), make_nil()) ); value *r = eval(e, expr); ASSERT(r->type == VT_LAMBDA, "partial application returns lambda"); } void test_partial_application_then_complete() { // (((lambda (x y z) (+ x y z)) 1 2) 3) env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons( cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), cons(make_symbol("y"), cons(make_symbol("z"), make_nil()) ) ), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons(make_symbol("y"), cons(make_symbol("z"), make_nil()) ) ) ), make_nil() ) ) ), cons(make_int(1), cons(make_int(2), make_nil()) ) ), cons(make_int(3), make_nil()) ); value *r = eval(e, expr); ASSERT(r->as.i == 6, "partial application can be completed"); } // ============================================================================ // CURRYING TESTS // ============================================================================ void test_currying_manual() { // (((lambda (x) (lambda (y) (lambda (z) (+ x (+ y z))))) 1) 2) 3) env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons( cons( cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("y"), make_nil()), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("z"), make_nil()), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons( cons(make_symbol("+"), cons(make_symbol("y"), cons(make_symbol("z"), make_nil()) ) ), make_nil() ) ) ), make_nil() ) ) ), make_nil() ) ) ), make_nil() ) ) ), cons(make_int(1), make_nil()) ), cons(make_int(2), make_nil()) ), cons(make_int(3), make_nil()) ); value *r = eval(e, expr); ASSERT(r->as.i == 6, "curried functions work correctly"); } void test_currying_with_define() { // (define add (lambda (x) (lambda (y) (+ x y)))) // ((add 10) 5) env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *def = cons(make_symbol("define"), cons(make_symbol("add"), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("y"), make_nil()), cons( cons(make_symbol("+"), cons(make_symbol("x"), cons(make_symbol("y"), make_nil()) ) ), make_nil() ) ) ), make_nil() ) ) ), make_nil() ) ) ); eval(e, def); value *call = cons( cons(make_symbol("add"), cons(make_int(10), make_nil()) ), cons(make_int(5), make_nil()) ); value *r = eval(e, call); ASSERT(r->as.i == 15, "curried functions can be defined and called"); } // ============================================================================ // LAZY EVALUATION / THUNK TESTS // ============================================================================ void test_lazy_list_construction() { // Test that cdr of cons is not eagerly evaluated env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (car (cons 1 (cons 2 undefined-symbol))) // This should work because cdr is lazy value *expr = cons(make_symbol("car"), cons( cons(make_symbol("cons"), cons(make_int(1), cons( cons(make_symbol("cons"), cons(make_int(2), cons(make_symbol("undefined-here"), make_nil()) ) ), make_nil() ) ) ), make_nil() ) ); value *r = eval(e, expr); ASSERT(r->as.i == 1, "lazy evaluation prevents evaluation of unused cdr"); } void test_thunk_caching() { // Define a function that prints when called, then use it in a lazy context // to verify thunks cache their results env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (define x (cons 1 (cons 2 (cons 3 ())))) value *list_def = cons(make_symbol("define"), cons(make_symbol("x"), cons( cons(make_symbol("cons"), cons(make_int(1), cons( cons(make_symbol("cons"), cons(make_int(2), cons( cons(make_symbol("cons"), cons(make_int(3), cons(make_nil(), make_nil()) ) ), make_nil() ) ) ), make_nil() ) ) ), make_nil() ) ) ); eval(e, list_def); // (car (cdr x)) value *expr = cons(make_symbol("car"), cons( cons(make_symbol("cdr"), cons(make_symbol("x"), make_nil()) ), make_nil() ) ); value *r = eval(e, expr); ASSERT(r->as.i == 2, "lazy evaluation with thunks works"); } // ============================================================================ // SCOPING TESTS // ============================================================================ void test_lexical_scoping_shadowing() { // (define x 1) // (define f (lambda (x) x)) // (f 99) should return 99, not 1 env *e = env_create(NULL); env_define(e, "x", make_int(1)); value *f_def = cons(make_symbol("define"), cons(make_symbol("f"), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons(make_symbol("x"), make_nil()) ) ), make_nil() ) ) ); eval(e, f_def); value *call = cons(make_symbol("f"), cons(make_int(99), make_nil()) ); value *r = eval(e, call); value *outer_x = env_lookup(e, "x"); ASSERT(r->as.i == 99, "parameter shadows outer variable"); ASSERT(outer_x->as.i == 1, "outer variable unchanged by shadowing"); } void test_closure_captures_environment() { // (define make-adder (lambda (n) (lambda (x) (+ n x)))) // (define add5 (make-adder 5)) // (add5 10) should return 15 env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *maker_def = cons(make_symbol("define"), cons(make_symbol("make-adder"), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("n"), make_nil()), cons( cons(make_symbol("lambda"), cons( cons(make_symbol("x"), make_nil()), cons( cons(make_symbol("+"), cons(make_symbol("n"), cons(make_symbol("x"), make_nil()) ) ), make_nil() ) ) ), make_nil() ) ) ), make_nil() ) ) ); eval(e, maker_def); value *add5_def = cons(make_symbol("define"), cons(make_symbol("add5"), cons( cons(make_symbol("make-adder"), cons(make_int(5), make_nil()) ), make_nil() ) ) ); eval(e, add5_def); value *call = cons(make_symbol("add5"), cons(make_int(10), make_nil()) ); value *r = eval(e, call); ASSERT(r->as.i == 15, "closure captures and preserves environment"); } // ============================================================================ // QUOTE TESTS // ============================================================================ void test_quote_prevents_evaluation() { env *e = env_create(NULL); // (quote (+ 1 2)) should return the list, not 3 value *expr = cons(make_symbol("quote"), cons( cons(make_symbol("+"), cons(make_int(1), cons(make_int(2), make_nil()) ) ), make_nil() ) ); value *r = eval(e, expr); ASSERT(r->type == VT_PAIR, "quote returns unevaluated pair"); ASSERT(car(r)->type == VT_SYMBOL, "quote preserves symbols"); ASSERT(!strcmp(car(r)->as.sym, "+"), "quote preserves symbol value"); } void test_quote_with_tick_syntax() { env *e = env_create(NULL); // Parse '(1 2 3) which becomes (quote (1 2 3)) value *quoted_list = cons(make_symbol("quote"), cons( cons(make_int(1), cons(make_int(2), cons(make_int(3), make_nil()) ) ), make_nil() ) ); value *r = eval(e, quoted_list); ASSERT(r->type == VT_PAIR, "quoted list is a pair"); ASSERT(car(r)->as.i == 1, "quoted list preserves first element"); } // ============================================================================ // DOUBLE TYPE TESTS // ============================================================================ void test_double_arithmetic() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (+ 1.5 2.5) value *expr = cons(make_symbol("+"), cons(make_double(1.5), cons(make_double(2.5), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->type == VT_INT, "4.0 is represented as int"); ASSERT(r->as.i == 4, "double arithmetic works"); } void test_mixed_int_double_arithmetic() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (+ 1 2.5) value *expr = cons(make_symbol("+"), cons(make_int(1), cons(make_double(2.5), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->type == VT_DOUBLE, "mixed arithmetic returns double"); ASSERT(r->as.d == 3.5, "mixed int/double arithmetic works"); } // ============================================================================ // STRING TESTS // ============================================================================ void test_string_equality() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("equal?"), cons(make_string("hello"), cons(make_string("hello"), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 1, "string equality works"); } void test_string_inequality() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); value *expr = cons(make_symbol("equal?"), cons(make_string("hello"), cons(make_string("world"), make_nil()) ) ); value *r = eval(e, expr); ASSERT(r->type == VT_NIL, "string inequality works"); } // ============================================================================ // LIST CONSTRUCTION TESTS // ============================================================================ void test_list_function() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (list 1 2 3) value *expr = cons(make_symbol("list"), cons(make_int(1), cons(make_int(2), cons(make_int(3), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->type == VT_PAIR, "list creates a pair"); ASSERT(car(r)->as.i == 1, "list first element correct"); ASSERT(car(cdr(r))->as.i == 2, "list second element correct"); ASSERT(car(cdr(cdr(r)))->as.i == 3, "list third element correct"); } // ============================================================================ // REVERSE TESTS // ============================================================================ void test_reverse_list() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (reverse (list 1 2 3)) value *expr = cons(make_symbol("reverse"), cons( cons(make_symbol("list"), cons(make_int(1), cons(make_int(2), cons(make_int(3), make_nil()) ) ) ), make_nil() ) ); value *r = eval(e, expr); ASSERT(car(r)->as.i == 3, "reverse first element correct"); ASSERT(car(cdr(r))->as.i == 2, "reverse second element correct"); ASSERT(car(cdr(cdr(r)))->as.i == 1, "reverse third element correct"); } // ============================================================================ // ARITHMETIC CHAIN TESTS // ============================================================================ void test_subtraction_chain() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (- 10 3 2) value *expr = cons(make_symbol("-"), cons(make_int(10), cons(make_int(3), cons(make_int(2), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 5, "subtraction chains correctly"); } void test_multiplication_chain() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (* 2 3 4) value *expr = cons(make_symbol("*"), cons(make_int(2), cons(make_int(3), cons(make_int(4), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 24, "multiplication chains correctly"); } void test_division_chain() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (/ 24 2 3) value *expr = cons(make_symbol("/"), cons(make_int(24), cons(make_int(2), cons(make_int(3), make_nil()) ) ) ); value *r = eval(e, expr); ASSERT(r->as.i == 4, "division chains correctly"); } // ============================================================================ // ERROR HANDLING TESTS // ============================================================================ void test_undefined_symbol_error() { env *e = env_create(NULL); value *sym = make_symbol("undefined-var"); value *r = eval(e, sym); ASSERT(r->type == VT_ERROR, "undefined symbol returns error"); } void test_car_of_non_pair_error() { env *e = env_create(NULL); procedure_load_module(e, cons(make_string("modules/std_lib.so"), make_nil())); // (car 42) value *expr = cons(make_symbol("car"), cons(make_int(42), make_nil()) ); value *r = eval(e, expr); ASSERT(r->type == VT_ERROR, "car of non-pair returns error"); } int main(void) { test_make_int(); test_cons_car_cdr(); test_env_define_lookup(); test_env_parent_lookup(); test_eval_literal(); test_eval_symbol(); test_define(); test_lambda_identity(); test_lambda_add(); test_lambda_multiple_args(); test_lambda_closure(); test_nested_lambdas(); test_lambda_does_not_modify_outer_env(); test_recursive_factorial(); test_eq_ints(); test_eq_ints_false(); test_eq_symbols(); test_eq_lists(); test_null_true(); test_null_false(); test_if_true(); test_if_false(); test_if_short_circuit(); test_add_multiple_args(); test_lt_chain(); printf("=== PARTIAL APPLICATION TESTS ===\n"); test_partial_application_single_arg(); test_partial_application_then_complete(); printf("\n=== CURRYING TESTS ===\n"); test_currying_manual(); test_currying_with_define(); printf("\n=== LAZY EVALUATION TESTS ===\n"); test_lazy_list_construction(); test_thunk_caching(); printf("\n=== SCOPING TESTS ===\n"); test_lexical_scoping_shadowing(); test_closure_captures_environment(); printf("\n=== QUOTE TESTS ===\n"); test_quote_prevents_evaluation(); test_quote_with_tick_syntax(); printf("\n=== DOUBLE TYPE TESTS ===\n"); test_double_arithmetic(); test_mixed_int_double_arithmetic(); printf("\n=== STRING TESTS ===\n"); test_string_equality(); test_string_inequality(); printf("\n=== LIST TESTS ===\n"); test_list_function(); test_reverse_list(); printf("\n=== ARITHMETIC CHAIN TESTS ===\n"); test_subtraction_chain(); test_multiplication_chain(); test_division_chain(); printf("\n=== ERROR HANDLING TESTS ===\n"); test_undefined_symbol_error(); test_car_of_non_pair_error(); printf("\nTests run: %d\n", tests_run); printf("Tests failed: %d\n", tests_failed); return tests_failed ? 1 : 0; }