Documentation
¶
Overview ¶
Package debug is the embedder-facing debugger: breakpoints, stepping, and the break-prompt command surface a REPL renders.
It sits between the VM and its consumers. Debugger wraps machine.Debugger so github.com/aalpar/wile/pkg/wile.Engine never exposes VM types, and DebugContext binds that same debugger to the comma-prefixed commands pkg/repl dispatches. Both live here so pkg/wile and pkg/repl carry no debugger-specific code beyond attaching one.
The break state a consumer reads is a snapshot frozen at the stop, not the live VM context: the context is pool-recycled and zeroed once the evaluation ends.
Index ¶
- func CanonicalDebugCommand(token string) (string, bool)
- type BreakAction
- type BreakpointInfo
- type CommandMeta
- type DebugCommandInfo
- type DebugContext
- type Debugger
- func (p *Debugger) Attach(mc *machine.MachineContext, closureEnv *environment.EnvironmentFrame)
- func (p *Debugger) Breakpoints() []BreakpointInfo
- func (p *Debugger) Continue()
- func (p *Debugger) CurrentState() values.DebugState
- func (p *Debugger) DisableBreakpoint(id int) bool
- func (p *Debugger) EnableBreakpoint(id int) bool
- func (p *Debugger) IsStepping() bool
- func (p *Debugger) OnBreak(fn func(state values.DebugState, bp *BreakpointInfo))
- func (p *Debugger) OnBreakSuspend(fn func(state values.DebugState, bp *BreakpointInfo) BreakAction)
- func (p *Debugger) RemoveBreakpoint(id int) bool
- func (p *Debugger) SetBreakpoint(file string, line, col int) int
- func (p *Debugger) StepInto()
- func (p *Debugger) StepOut()
- func (p *Debugger) StepOver()
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CanonicalDebugCommand ¶
CanonicalDebugCommand maps a typed token (comma already stripped) to the canonical debug command name, so alias handling lives in one table and the break prompt cannot drift from ,help.
Types ¶
type BreakAction ¶
type BreakAction int
BreakAction is a suspension handler's verdict: what the VM should do with the computation it stopped. It is returned by the callback registered with Debugger.OnBreakSuspend, which runs while the VM is suspended.
const ( // BreakContinue resumes the suspended computation with stepping off. BreakContinue BreakAction = iota // BreakStep resumes and stops at the next source line, entering calls. BreakStep // BreakNext resumes and stops at the next source line in the same or a // shallower frame, running nested calls to completion. BreakNext // BreakFinish resumes and stops once execution reaches a strictly // shallower frame than the one that was suspended. BreakFinish // BreakAbandon does not resume: the computation is discarded and the // evaluation returns void. dynamic-wind after-thunks between the break // point and the top level still run. BreakAbandon )
type BreakpointInfo ¶
BreakpointInfo holds read-only breakpoint state for display.
type CommandMeta ¶
CommandMeta is the static half of a debug command: everything but the bound handler. Separated from DebugCommandInfo so a help renderer can list the commands without allocating a DebugContext (and its Debugger).
func Commands ¶
func Commands() []CommandMeta
Commands returns the debug-command catalog with no handlers bound. Bind them by taking DebugContext.DebugCommands instead.
type DebugCommandInfo ¶
type DebugCommandInfo struct {
Name string
Aliases []string
Summary string
Detail string
Handler func(args []string, out io.Writer)
}
DebugCommandInfo describes a single debug command: its canonical name, aliases, summary text, detail text, and handler function.
type DebugContext ¶
type DebugContext struct {
// contains filtered or unexported fields
}
DebugContext holds the state for debug commands. The break state itself — a snapshot frozen at the most recent break, NOT a live VM context — is owned by the wrapped Debugger and read through p.debugger.CurrentState(). DebugContext deliberately keeps no parallel copy, so the two can never disagree. Handing back the live context instead is what made ,where and ,backtrace report "No source location available": it is pool-recycled and zeroed the moment the evaluation ends.
func NewDebugContext ¶
func NewDebugContext() *DebugContext
NewDebugContext creates a new debug context.
func (*DebugContext) DebugCommands ¶
func (p *DebugContext) DebugCommands() []DebugCommandInfo
DebugCommands returns the canonical list of debug commands with bound handlers.
func (*DebugContext) Debugger ¶
func (p *DebugContext) Debugger() *Debugger
Debugger returns the debugger instance.
func (*DebugContext) HandleDebugCommand ¶
func (p *DebugContext) HandleDebugCommand(line string, out io.Writer) bool
HandleDebugCommand processes a debug command starting with ','. Returns true if a command was handled, false otherwise.
type Debugger ¶
type Debugger struct {
// contains filtered or unexported fields
}
Debugger controls breakpoints and stepping for an Engine. It wraps the internal machine.Debugger to avoid exposing VM types.
func (*Debugger) Attach ¶
func (p *Debugger) Attach(mc *machine.MachineContext, closureEnv *environment.EnvironmentFrame)
Attach installs this debugger on mc for the run about to start, and arms the break boundary when — and only when — a suspension handler is registered AND the debugger has something that could stop this run. Otherwise a break falls back to the render-only callback and no prompt frame is pushed.
Both conditions are load-bearing, because the boundary is not free: it is a real continuation frame, so it costs one unit of the call-depth budget for the whole run and changes the tail-call shape at the top level. The REPL registers a suspension handler for its entire session, so without the second condition every evaluation typed at the prompt paid for a debugger nobody had armed.
closureEnv is the frame the break handler closes over — the caller's mutable runtime environment, or its compilation environment when there is none.
func (*Debugger) Breakpoints ¶
func (p *Debugger) Breakpoints() []BreakpointInfo
Breakpoints returns all breakpoints.
func (*Debugger) CurrentState ¶
func (p *Debugger) CurrentState() values.DebugState
CurrentState returns the DebugState from the most recent break, or nil if no break has occurred.
It is a snapshot taken at the break, not the live VM context. The context is pool-recycled and zeroed when the evaluation ends, so handing it back was how ,where and ,backtrace came to report "No source location available" and "Empty stack trace" on a breakpoint that had just printed its location.
func (*Debugger) DisableBreakpoint ¶
DisableBreakpoint disables a breakpoint by ID.
func (*Debugger) EnableBreakpoint ¶
EnableBreakpoint enables a breakpoint by ID.
func (*Debugger) IsStepping ¶
IsStepping returns true if the debugger is in step mode.
func (*Debugger) OnBreak ¶
func (p *Debugger) OnBreak(fn func(state values.DebugState, bp *BreakpointInfo))
OnBreak sets the render-only callback for a breakpoint hit or a completed step. The DebugState provides source location and stack trace access without exposing VM internals.
It is the fallback, not the general notification: a stop that SUSPENDS invokes Debugger.OnBreakSuspend instead and does not invoke this. With a suspension handler registered, the stops that still reach here are the ones that cannot suspend — breaks inside load and eval, and any run the boundary was not armed for.
func (*Debugger) OnBreakSuspend ¶
func (p *Debugger) OnBreakSuspend(fn func(state values.DebugState, bp *BreakpointInfo) BreakAction)
OnBreakSuspend installs the handler that runs while the VM is SUSPENDED at a breakpoint or step stop, and whose verdict decides what happens next.
nil means NONE: with no suspend handler the VM does not suspend at all and the render-only Debugger.OnBreak callback is invoked inline instead, which is the behaviour an embedder with a Go-only debugger has always had.
Breaks inside load and eval do not suspend. Their freshly compiled template runs on a sub-context whose own continuation chain does not carry the break prompt, so those stops fall back to OnBreak.
func (*Debugger) RemoveBreakpoint ¶
RemoveBreakpoint removes a breakpoint by ID.
func (*Debugger) SetBreakpoint ¶
SetBreakpoint adds a breakpoint at the given source location. Returns the breakpoint ID.