Debugging
Langoost ships two debuggers: a terminal (TUI) debugger for quick command-line sessions, and a Debug Adapter Protocol (DAP) server for editors.
Terminal debugger
langoost debug <file.goost> opens an interactive TUI — a source viewer with
breakpoints and stepping, no editor required:
$ langoost debug app.goost
It pauses on the first line by default so you can set breakpoints; pass
--stop-on-entry=false to start running immediately.
Editor debugging (DAP)
Langoost also ships a Debug Adapter Protocol (DAP) server, so any DAP-aware
editor — VS Code, Neovim (nvim-dap), JetBrains, Helix, Zed — can debug .goost
programs with breakpoints, stepping, and variable inspection.
Running the adapter
$ langoost dap # speak DAP over stdin/stdout (editor default)
$ langoost dap --port 4711 # listen on a TCP port (long-running adapter)
Editors normally use stdio: the editor spawns langoost dap as a child process
and the framing handshake happens over the pipes automatically.
VS Code
Add a launch configuration in .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "langoost",
"name": "Run current Langoost file",
"request": "launch",
"program": "${file}",
"stopOnEntry": false
}
]
}
VS Code also needs a small extension shell that tells it how to spawn the
adapter — a package.json contributing a debuggers entry with
"program": "langoost", "args": ["dap"]. Package it with vsce package and
install the .vsix; then F5 debugs the active file.
Neovim (nvim-dap)
local dap = require('dap')
dap.adapters.langoost = {
type = 'executable',
command = 'langoost',
args = { 'dap' },
}
dap.configurations.langoost = {
{
type = 'langoost',
request = 'launch',
name = 'Run current file',
program = function() return vim.fn.expand('%:p') end,
stopOnEntry = false,
},
}
What works
| Capability | |
|---|---|
Set / unset breakpoints by file:line | ✅ |
| Continue, Step Over, Step Into, Step Out | ✅ |
Stop on entry (stopOnEntry: true) | ✅ |
| Stack trace with function names and source paths | ✅ |
Locals panel — function arguments and let bindings | ✅ |
Globals panel — top-level let declarations | ✅ |
| Stdout / stderr forwarded to the debug console | ✅ |
| Evaluate a single identifier in scope (watch / hover) | ✅ |
Not yet
Conditional breakpoints (the condition is accepted but ignored), log points,
evaluating arbitrary expressions (only bare identifiers today), and per-task
debugging of thread.core.spawn child VMs are planned but not yet implemented.
How it works
On launch, the adapter compiles the script, attaches DebugHooks to a fresh
VM, and runs it in a goroutine. Each iteration of the run loop checks the hooks:
if the next instruction’s line has a breakpoint (or you’re stepping), the VM
emits a stopped event and blocks until a resume command arrives. When no
debugger is attached the per-instruction cost is a single nil check. See
architecture for the VM internals.