DocsGetting started
Debugging.
Set breakpoints, step through Fango source, and inspect bindings in the REPL or a compiled program.
Fango has two debuggers that share one set of commands: one inside the REPL, and one for compiled programs. Both stop on Fango source lines, show the expression about to run, and let you inspect bindings by their source names.
Debug at the REPL.
Start the REPL with --debug:
fango repl --debug
The flag applies to the whole session, including imports and reloads. It keeps source bindings around and turns off the optimizations that would hide them. Set a breakpoint with :break FILE:LINE, then evaluate an expression as usual:
> import Geometry
> :break Geometry.fango:12
> Geometry.area shape
When evaluation reaches line 12, the REPL prints where it stopped, with the expression underlined, and switches to a debug> prompt. To step through an expression from its start without a breakpoint, use :step EXPR.
Paths are relative to the source root, such as Geometry/Point.fango, or use <stdlib>/List.fango for the standard library. A breakpoint applies only to lines with executable code: a blank line, comment, or type signature stays unresolved, and the debugger doesn’t move it to a nearby line. A breakpoint in a module you haven’t imported yet waits until you import it.
Stops happen before the underlined expression runs. A binding becomes visible once its initializer has finished.
Commands at a stop.
At debug> the leading colon is optional, so next, :next, and n all do the same thing. A blank line repeats the last command.
| Command | Alias | What it does |
|---|---|---|
continue |
c |
Run until the next breakpoint or the end |
step |
s |
Stop at the next Fango source location, entering calls |
next |
n |
Step over calls |
finish |
f |
Run until the current function returns |
stack |
List the frames | |
frame INDEX |
Select a frame to inspect | |
locals |
Show the selected frame’s parameters, locals, and captures | |
print NAME |
Show one binding | |
expand HANDLE [OFFSET] |
Page through a large value’s children | |
break FILE:LINE |
b |
Set another breakpoint |
breaks, delete ID |
List or remove breakpoints | |
quit |
q |
End the session |
help |
h |
List the supported commands |
At the REPL, stop cancels the paused input and goes back to the ordinary prompt, keeping your handler levels.
Bindings show as name : Type = value. The debugger prints values from their structure, as in Just 42 or { name = "Ada", age = 42 }, without calling Show or any other code of yours. print takes a name, not an expression. Large values are cut off after a few levels or 50 children and get a handle you can pass to expand. Functions show as <function>, and resources as an opaque value.
Debug a compiled program.
fango debug builds a program with the debug profile and launches it under the debugger:
fango debug mandelbrot.fango
fango debug mandelbrot.fango -- first second
It uses Delve, on macOS or Linux; the Fango repository’s Nix shell includes it. The program stops at the first Fango line in main, and the same debug> commands apply. Native programs also have args, and raw versions of stack, args, locals, and print that inspect the generated Go. Ctrl-C interrupts the running program, and quit ends it.
To keep a debuggable executable, build it with fango build --debug -o mandelbrot-debug mandelbrot.fango, then run fango debug ./mandelbrot-debug. The build writes a companion mandelbrot-debug.fango-debug.json holding the source snapshot and locations, so keep the two files together. Excerpts come from that snapshot, so the debugger shows the source as it was when you built it.
What the debugger can’t see.
Stepping treats a native Go sidecar as a single step and doesn’t enter its Go code. A function that tail-calls itself keeps one frame, so next may stop on the next iteration, while finish runs until the whole loop returns. Compile-time splices run before the debugger is involved.
At the REPL, debug sessions are sequential: starting a task with Async.spawn or a parallel map fails while debugging. Breakpoints belong to the source you checked. After you change and reload a file, set its breakpoints again.
