' Debug macros: TRACE, ENTER/EXIT, DCHECK, DUMP via MACRO
#COMPILE EXE
#DIM ALL

MACRO DCheck(cond)
    IF (cond) = 0 THEN
        PRINT "CHECK FAILED"
    END IF
END MACRO

MACRO DCheckMsg(cond, msg)
    IF (cond) = 0 THEN
        PRINT "CHECK FAILED: "; msg
    END IF
END MACRO

MACRO Trace(msg)
    PRINT "TRACE: "; msg
END MACRO

MACRO EnterProc(name)
    PRINT "ENTER: "; name
END MACRO

MACRO ExitProc(name)
    PRINT "EXIT: "; name
END MACRO

MACRO DumpVar(name, value)
    PRINT "  VAR "; name; " = "; value
END MACRO

MACRO DumpStr(name, value)
    PRINT "  STR "; name; " = "; value
END MACRO

MACRO CheckEq(a, b, msg)
    IF a <> b THEN
        PRINT "CHECK_EQ FAILED: "; msg
        PRINT "  left="; a; " right="; b
    END IF
END MACRO

MACRO CheckNe(a, b, msg)
    IF a = b THEN
        PRINT "CHECK_NE FAILED: "; msg
    END IF
END MACRO

SUB TestDCheck()
    EnterProc("TestDCheck")
    LOCAL x AS LONG
    x = 42
    DCheck(x = 42)
    DCheckMsg(x = 42, "x should be 42")
    DumpVar("x", x)
    ExitProc("TestDCheck")
END SUB

SUB TestTrace()
    EnterProc("TestTrace")
    LOCAL i AS LONG
    FOR i = 1 TO 3
        PRINT "TRACE: iteration "; i
    NEXT i
    ExitProc("TestTrace")
END SUB

SUB TestNested()
    EnterProc("TestNested")
    Trace("Beginning nested test")
    TestDCheck()
    TestTrace()
    Trace("Nested test complete")
    ExitProc("TestNested")
END SUB

SUB TestBoundary(BYVAL v AS LONG, BYVAL lo AS LONG, BYVAL hi AS LONG)
    EnterProc("TestBoundary")
    DumpVar("val", v)
    DCheckMsg(v >= lo, "below lower bound")
    DCheckMsg(v <= hi, "above upper bound")
    ExitProc("TestBoundary")
END SUB

FUNCTION Factorial(BYVAL n AS LONG) AS LONG
    EnterProc("Factorial")
    DumpVar("n", n)
    LOCAL r AS LONG
    IF n <= 1 THEN
        r = 1
    ELSE
        r = n * Factorial(n - 1)
    END IF
    DumpVar("result", r)
    ExitProc("Factorial")
    FUNCTION = r
END FUNCTION

FUNCTION Fibonacci(BYVAL n AS LONG) AS LONG
    EnterProc("Fibonacci")
    LOCAL r AS LONG
    IF n <= 1 THEN
        r = n
    ELSE
        r = Fibonacci(n - 1) + Fibonacci(n - 2)
    END IF
    ExitProc("Fibonacci")
    FUNCTION = r
END FUNCTION

SUB RunAll()
    EnterProc("RunAll")
    TestNested()
    TestBoundary(50, 0, 100)
    TestBoundary(150, 0, 100)
    LOCAL f AS LONG
    f = Factorial(5)
    PRINT "Factorial(5) = "; f
    DCheck(f = 120)
    f = Fibonacci(6)
    PRINT "Fibonacci(6) = "; f
    DCheck(f = 8)
    ExitProc("RunAll")
END SUB

FUNCTION PBMAIN() AS LONG
    PRINT "=== Debug Macros Demo ==="
    RunAll()
    CheckEq(5, 5, "five equals five")
    CheckNe(5, 3, "five not equal three")
    PRINT "=== End Debug Macros ==="
    FUNCTION = 0
END FUNCTION
