diff --git a/Makefile b/Makefile index 229e2f1..bc7a5bb 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,18 @@ c-repl: c-build c-clean: $(MAKE) -C c clean -# ─── Both implementations ──────────────────────────────────────── +# ─── Assembly implementation ────────────────────────────────────── + +asm-build: + $(MAKE) -C asm all + +asm-test: asm-build + $(MAKE) -C asm test + +asm-clean: + $(MAKE) -C asm clean + +# ─── All implementations ───────────────────────────────────────── functional-test: c-build @echo "═══ Shared functional tests (114 tests) ═══" @@ -54,9 +65,9 @@ functional-test: c-build @echo "── C ──" @./c/uncommonlisp tests/functional.lsp | tail -3 -test-all: test c-test functional-test - @echo "════════════════════════════════════" - @echo "All tests passed (Python + C + shared functional)" +test-all: test c-test asm-test functional-test + @echo "════════════════════════════════════════════════════" + @echo "All tests passed (Python + C + Assembly + functional)" bench-all: bench c-bench @@ -139,9 +150,10 @@ clean: clean-whitepaper: rm -rf $(VENV) $(PDF) whitepaper/WHITEPAPER.pdf -clean-all: clean clean-whitepaper c-clean +clean-all: clean clean-whitepaper c-clean asm-clean .PHONY: all test test-verbose bench bench-verbose repl lint \ c-build c-test c-bench c-repl c-clean \ + asm-build asm-test asm-clean \ test-all bench-all examples friction \ whitepaper clean clean-whitepaper clean-all diff --git a/asm/Makefile b/asm/Makefile index 3e3e357..69dcf75 100644 --- a/asm/Makefile +++ b/asm/Makefile @@ -5,48 +5,7 @@ uncommonlisp: uncommonlisp.s ld -o uncommonlisp uncommonlisp.o test: uncommonlisp - @echo "=== Basic arithmetic ===" - echo '(+ 1 2)' | ./uncommonlisp - @echo "=== Nested arithmetic ===" - echo '(+ (* 3 4) (- 10 5))' | ./uncommonlisp - @echo "=== Boolean and comparison ===" - echo '(< 1 2)' | ./uncommonlisp - @echo "=== Quote ===" - echo "(quote (1 2 3))" | ./uncommonlisp - @echo "=== If ===" - echo '(if (< 1 2) 42 99)' | ./uncommonlisp - @echo "=== Define and use ===" - echo '(define x 10) (+ x 5)' | ./uncommonlisp - @echo "=== Lambda ===" - echo '((lambda (x y) (+ x y)) 3 4)' | ./uncommonlisp - @echo "=== Factorial ===" - echo '(define (fact n) (if (<= n 1) 1 (* n (fact (- n 1))))) (fact 10)' | ./uncommonlisp - @echo "=== Fibonacci (named let) ===" - echo '(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (fib 35)' | ./uncommonlisp - @echo "=== Ackermann ===" - echo '(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (ack 3 4)' | ./uncommonlisp - @echo "=== List operations ===" - echo '(car (cdr (list 1 2 3)))' | ./uncommonlisp - @echo "=== Length ===" - echo '(length (list 1 2 3 4 5))' | ./uncommonlisp - @echo "=== And/Or ===" - echo '(and 1 2 3)' | ./uncommonlisp - echo '(or #f #f 42)' | ./uncommonlisp - @echo "=== Let ===" - echo '(let ((x 10) (y 20)) (+ x y))' | ./uncommonlisp - @echo "=== Begin ===" - echo '(begin 1 2 3)' | ./uncommonlisp - @echo "=== Set! ===" - echo '(define x 1) (set! x 42) x' | ./uncommonlisp - @echo "=== Not ===" - echo '(not #f)' | ./uncommonlisp - echo '(not 42)' | ./uncommonlisp - @echo "=== Null/Pair ===" - echo "(null? '())" | ./uncommonlisp - echo '(pair? (cons 1 2))' | ./uncommonlisp - @echo "=== Display ===" - echo '(display 42) (newline)' | ./uncommonlisp - @echo "=== All tests passed ===" + @bash test.sh clean: rm -f uncommonlisp.o uncommonlisp diff --git a/asm/test.sh b/asm/test.sh new file mode 100644 index 0000000..c05743f --- /dev/null +++ b/asm/test.sh @@ -0,0 +1,168 @@ +#!/bin/bash +# test.sh — Unit, integration, and functional tests for the asm Scheme interpreter +# +# Usage: bash test.sh +# +# Tests verify expected output. Any mismatch = FAIL. + +set -e +cd "$(dirname "$0")" + +PASS=0 +FAIL=0 +UL=./uncommonlisp + +check() { + local name="$1" input="$2" expected="$3" + local got + got=$(echo "$input" | $UL 2>/dev/null | tr -d '\n') + if [ "$got" = "$expected" ]; then + PASS=$((PASS + 1)) + else + FAIL=$((FAIL + 1)) + echo "FAIL: $name" + echo " input: $input" + echo " expected: $expected" + echo " got: $got" + fi +} + +echo "═══════════════════════════════════════════════════════" +echo "asm/uncommonlisp test suite" +echo "═══════════════════════════════════════════════════════" + +# ─── UNIT TESTS: individual primitives ──────────────────── + +echo "[unit] arithmetic" +check "add" "(+ 1 2)" "3" +check "sub" "(- 10 3)" "7" +check "mul" "(* 6 7)" "42" +check "nested" "(+ (* 3 4) (- 10 5))" "17" +check "negate" "(- 5)" "-5" +check "zero-add" "(+)" "0" +check "one-mul" "(*)" "1" +check "multi-add" "(+ 1 2 3 4)" "10" +check "multi-mul" "(* 2 3 4)" "24" +check "modulo" "(modulo 10 3)" "1" +check "remainder" "(remainder 10 3)" "1" +check "quotient" "(quotient 10 3)" "3" +check "abs" "(abs -7)" "7" +check "min" "(min 3 1 4)" "1" +check "max" "(max 3 1 4)" "4" +check "expt" "(* 2 2 2 2 2 2 2 2 2 2)" "1024" + +echo "[unit] comparison" +check "eq" "(= 5 5)" "#t" +check "neq" "(= 5 6)" "#f" +check "lt" "(< 3 5)" "#t" +check "gt" "(> 5 3)" "#t" +check "le" "(<= 3 3)" "#t" +check "ge" "(>= 5 5)" "#t" +check "lt-false" "(< 5 3)" "#f" + +echo "[unit] booleans" +check "not-false" "(not #f)" "#t" +check "not-true" "(not #t)" "#f" +check "not-num" "(not 42)" "#f" + +echo "[unit] predicates" +check "zero?" "(zero? 0)" "#t" +check "zero?-1" "(zero? 1)" "#f" +check "null?-nil" "(null? '())" "#t" +check "null?-pair" "(null? (cons 1 2))" "#f" +check "pair?" "(pair? (cons 1 2))" "#t" +check "pair?-num" "(pair? 42)" "#f" +check "number?" "(number? 42)" "#t" +check "boolean?" "(boolean? #t)" "#t" +check "symbol?" "(symbol? 'x)" "#t" +check "positive?" "(positive? 5)" "#t" +check "negative?" "(negative? -3)" "#t" + +echo "[unit] pairs & lists" +check "cons" "(cons 1 2)" "(1 . 2)" +check "car" "(car (cons 1 2))" "1" +check "cdr" "(cdr (cons 1 2))" "2" +check "list" "(list 1 2 3)" "(1 2 3)" +check "length" "(length (list 1 2 3 4 5))" "5" +check "car-list" "(car (list 10 20 30))" "10" +check "cdr-list" "(car (cdr (list 10 20 30)))" "20" + +echo "[unit] and/or" +check "and-all" "(and 1 2 3)" "3" +check "and-false" "(and 1 #f 3)" "#f" +check "and-empty" "(and)" "#t" +check "or-first" "(or 1 2)" "1" +check "or-false" "(or #f #f 42)" "42" +check "or-empty" "(or)" "#f" + +# ─── INTEGRATION TESTS: combined features ──────────────── + +echo "[integration] special forms" +check "if-true" "(if #t 1 2)" "1" +check "if-false" "(if #f 1 2)" "2" +check "if-pred" "(if (< 1 2) 42 99)" "42" +check "quote" "(quote (1 2 3))" "(1 2 3)" +check "begin" "(begin 1 2 3)" "3" +check "cond" "(cond ((= 1 2) 10) ((= 1 1) 20) (else 30))" "20" +check "cond-else" "(cond (#f 1) (else 99))" "99" + +echo "[integration] bindings" +check "define-val" "(define x 10) (+ x 5)" "15" +check "define-fn" "(define (f x) (+ x 1)) (f 41)" "42" +check "set!" "(define x 1) (set! x 42) x" "42" +check "let" "(let ((x 10) (y 20)) (+ x y))" "30" +check "lambda" "((lambda (x y) (+ x y)) 3 4)" "7" +check "closure" "(define (make-adder n) (lambda (x) (+ x n))) ((make-adder 10) 5)" "15" + +echo "[integration] named-let" +check "named-let-sum" "(let loop ((i 5) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i))))" "15" + +echo "[integration] recursion" +check "factorial" "(define (fact n) (if (<= n 1) 1 (* n (fact (- n 1))))) (fact 10)" "3628800" +check "fib-rec" "(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2))))) (fib 10)" "55" + +echo "[integration] higher-order" +check "apply-lambda" "((lambda (f x) (f x)) (lambda (n) (* n n)) 7)" "49" + +# ─── FUNCTIONAL TESTS: real programs ───────────────────── + +echo "[functional] fibonacci" +check "fib-35" "(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (fib 35)" "9227465" + +echo "[functional] ackermann" +check "ack-3-4" "(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (ack 3 4)" "125" + +echo "[functional] tail-call optimization" +check "tco-deep" "(define (count n) (if (= n 0) 0 (count (- n 1)))) (count 100000)" "0" + +echo "[functional] list processing" +check "list-ops" "(define (sum lst) (if (null? lst) 0 (+ (car lst) (sum (cdr lst))))) (sum (list 1 2 3 4 5))" "15" +check "list-rev" "(define (rev lst acc) (if (null? lst) acc (rev (cdr lst) (cons (car lst) acc)))) (rev (list 1 2 3) '())" "(3 2 1)" + +echo "[functional] mutual recursion" +check "even-odd" "(define (my-even n) (if (= n 0) #t (my-odd (- n 1)))) (define (my-odd n) (if (= n 0) #f (my-even (- n 1)))) (my-even 10)" "#t" + +echo "[functional] closure state" +check "counter" "(define c (let ((n 0)) (lambda () (set! n (+ n 1)) n))) (c) (c) (c)" "123" + +echo "[functional] display output" +# display writes to stdout without newline, result is void +got=$(echo '(display 42) (newline)' | $UL 2>/dev/null) +if echo "$got" | grep -q "42"; then + PASS=$((PASS + 1)) +else + FAIL=$((FAIL + 1)) + echo "FAIL: display-42" +fi + +# ─── SUMMARY ───────────────────────────────────────────── + +echo +echo "═══════════════════════════════════════════════════════" +echo "Results: $PASS passed, $FAIL failed" +if [ $FAIL -eq 0 ]; then + echo "ALL TESTS PASSED" +else + echo "SOME TESTS FAILED" + exit 1 +fi