;; Phase 2 — colon definitions + compile mode + variables/values/fetch/store. (define forth-p2-passed 0) (define forth-p2-failed 0) (define forth-p2-failures (list)) (define forth-p2-assert (fn (label expected actual) (if (= expected actual) (set! forth-p2-passed (+ forth-p2-passed 1)) (begin (set! forth-p2-failed (+ forth-p2-failed 1)) (set! forth-p2-failures (concat forth-p2-failures (list (str label ": expected " (str expected) " got " (str actual))))))))) (define forth-p2-check-stack (fn (label src expected) (let ((r (forth-run src))) (forth-p2-assert label expected (nth r 2))))) (define forth-p2-check-output (fn (label src expected) (let ((r (forth-run src))) (forth-p2-assert label expected (nth r 1))))) (define forth-p2-colon-tests (fn () (forth-p2-check-stack "simple colon" ": DOUBLE 2 * ; 7 DOUBLE" (list 14)) (forth-p2-check-stack "three-op body" ": ADD3 + + ; 1 2 3 ADD3" (list 6)) (forth-p2-check-stack "nested call" ": SQR DUP * ; : SOS SQR SWAP SQR + ; 3 4 SOS" (list 25)) (forth-p2-check-stack "deep chain" ": D 2 ; : B D ; : A B D * ; A" (list 4)) (forth-p2-check-stack "colon uses literal" ": FOO 1 2 + ; FOO FOO +" (list 6)) (forth-p2-check-stack "case-insensitive def" ": BAR 9 ; bar" (list 9)) (forth-p2-check-stack "redefinition picks newest" ": F 1 ; : F 2 ; F" (list 2)) (forth-p2-check-stack "negative literal in def" ": NEG5 -5 ; NEG5" (list -5)) (forth-p2-check-stack "hex literal in def" ": X $10 ; X" (list 16)))) (define forth-p2-var-tests (fn () (forth-p2-check-stack "VARIABLE + !, @" "VARIABLE X 42 X ! X @" (list 42)) (forth-p2-check-stack "uninitialised @ is 0" "VARIABLE Y Y @" (list 0)) (forth-p2-check-stack "two variables" "VARIABLE A VARIABLE B 1 A ! 2 B ! A @ B @ +" (list 3)) (forth-p2-check-stack "+! increments" "VARIABLE X 10 X ! 5 X +! X @" (list 15)) (forth-p2-check-stack "+! multiple" "VARIABLE X 0 X ! 1 X +! 2 X +! 3 X +! X @" (list 6)))) (define forth-p2-const-tests (fn () (forth-p2-check-stack "CONSTANT" "100 CONSTANT C C" (list 100)) (forth-p2-check-stack "CONSTANT used twice" "5 CONSTANT FIVE FIVE FIVE *" (list 25)) (forth-p2-check-stack "CONSTANT in colon" "3 CONSTANT T : TRIPLE T * ; 7 TRIPLE" (list 21)))) (define forth-p2-value-tests (fn () (forth-p2-check-stack "VALUE initial" "50 VALUE V V" (list 50)) (forth-p2-check-stack "TO overwrites" "50 VALUE V 99 TO V V" (list 99)) (forth-p2-check-stack "TO twice" "1 VALUE V 2 TO V 3 TO V V" (list 3)) (forth-p2-check-stack "VALUE in arithmetic" "7 VALUE V V 3 +" (list 10)))) (define forth-p2-io-tests (fn () (forth-p2-check-output "colon prints" ": HELLO 72 EMIT 73 EMIT ; HELLO" "HI") (forth-p2-check-output "colon CR" ": LINE 42 . CR ; LINE" "42 \n"))) (define forth-p2-mode-tests (fn () (forth-p2-check-stack "empty colon body" ": NOP ; 5 NOP" (list 5)) (forth-p2-check-stack "colon using DUP" ": TWICE DUP ; 9 TWICE" (list 9 9)) (forth-p2-check-stack "IMMEDIATE NOP" ": X ; X" (list)))) (define forth-p2-run-all (fn () (set! forth-p2-passed 0) (set! forth-p2-failed 0) (set! forth-p2-failures (list)) (forth-p2-colon-tests) (forth-p2-var-tests) (forth-p2-const-tests) (forth-p2-value-tests) (forth-p2-io-tests) (forth-p2-mode-tests) (dict "passed" forth-p2-passed "failed" forth-p2-failed "failures" forth-p2-failures)))