machine

package
v1.18.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

ADDING A NEW PROMOTED OP

Promoted ops inline hot primitives directly in the VM dispatch loop, bypassing arity check, arg binding, and indirect function call. Each promoted op has a non-tail and tail variant.

The 34 switch cases in Run() are deliberately hand-unrolled: Go compiles them to a jump table. A table-driven approach was benchmarked and rejected (~1.5% geo mean regression). See plans/2026-04-05-structural-reduction.md.

Edit sites (3 files):

  1. opcode.go — add OpXxx + OpXxxTail constants; add two opcodeTable entries with operandKind: OperandCachedBinding
  2. machine_context.go — add two case branches in Run() (non-tail + tail), each calling execPromoted(mc, instr, name, arity, tail, inlineFn)
  3. call_promoted.go — implement inlineXxx function; add case in promotedOpForName() (or call_promoted_arithmetic.go for numeric ops)

No changes needed in native_template.go or disassemble.go — both use opcodeTable[op].operandKind metadata to handle OperandCachedBinding generically. The peephole optimizer (peephole.go) also needs no changes — it uses promotedOpForName() to discover promoted ops generically.

Package machine implements the Scheme virtual machine, compiler, and macro expander.

The machine package is the core execution engine for Wile, providing:

Compilation Pipeline

Scheme source undergoes three phases:

  1. Expansion: macro-expand via [ExpanderTimeContinuation]
  2. Compilation: generate bytecode via [CompileTimeContinuation]
  3. Execution: run bytecode via MachineContext

Virtual Machine

The VM is a stack-based bytecode virtual machine with:

Continuations

Macro System

Implements R7RS hygienic macros with Flatt's "sets of scopes" model:

  • [ExpanderTimeContinuation]: macro expansion driver
  • syntax-rules pattern matching via internal/match
  • syntax-case with fenders and procedural macros

Foreign Functions

Go functions are exposed as ForeignFunction implementations:

type ForeignFunction func(CallContext) error

CallContext is the narrow interface (7 methods) that extensions depend on. The ForeignClosure type wraps these for the VM.

Index

Constants

This section is empty.

Variables

View Source
var DefaultPromptTag = NewPromptTag("default")

DefaultPromptTag is the default prompt tag installed at the top of execution.

View Source
var ErrBindingNotFound = werr.NewStaticError("binding not found")
View Source
var ErrInvalidGlobalIndex = werr.NewStaticError("literal is not a global index")
View Source
var ErrInvalidLiteralIndex = werr.NewStaticError("invalid literal index")
View Source
var ErrInvalidProgramCounter = werr.NewStaticError("invalid program counter")
View Source
var ErrLocalIndexOverflow = werr.NewStaticError("local index overflow")

ErrLocalIndexOverflow signals that a De Bruijn index slot or depth exceeds the int16 encoding range (-32768..32767). EncodeLocalIndex panics with this sentinel when the bytecode format cannot represent the index.

View Source
var ErrMachineDoNotAdvancePC = werr.NewStaticError("machine do not advance PC: operation did not advance program counter")
View Source
var ErrTimerExpired = werr.NewStaticError("timer expired")

ErrTimerExpired is the context cause set by with-timeout via context.WithTimeoutCause. Interrupt check sites compare against this to distinguish timer expiry from external cancellation (e.g. Ctrl+C).

Functions

func DecodeLocalIndex

func DecodeLocalIndex(arg int32) (slot, depth int)

DecodeLocalIndex unpacks slot and depth from a bit-packed Instruction.Arg.

func DisassembleString

func DisassembleString(tpl *NativeTemplate) string

DisassembleString produces a columnar human-readable listing from a NativeTemplate.

func EncodeLocalIndex

func EncodeLocalIndex(li *environment.LocalIndex) int32

EncodeLocalIndex packs a LocalIndex's slot and depth into a single int32 for storage in Instruction.Arg. Slot occupies the low 16 bits; depth occupies the high 16 bits. Both values must fit in int16 range (max 32767).

De Bruijn indices (de Bruijn 1972). Variables are addressed by numeric coordinates, eliminating name lookup at runtime.

addr(x) = (slot, depth), where:
  depth = number of enclosing λ-binders from use to definition
  slot  = index within the binding array at that depth

Encoding: Arg = (depth << 16) | (slot & 0xFFFF)

Invariant: the same variable always has the same (slot, depth)
  regardless of its name. Alpha-equivalence is a non-issue at runtime.
Constrains: GetLocalBindingBySlotDepth / SetLocalValueBySlotDepth
  (runtime access walks depth parent pointers, indexes by slot),
  linked closures (parent chain must match compile-time depth).
Constrained by: resolveLocal (compile-time computation of depth
  by walking the EnvironmentFrame parent chain).

See BIBLIOGRAPHY.md "De Bruijn Indices / Lexical Addressing".

func ErrorContextKey

func ErrorContextKey() values.Value

ErrorContextKey returns the continuation mark key for error context. Exposed for use by registry primitives that read the mark.

func ExceptionHandlerParam

func ExceptionHandlerParam() values.Value

ExceptionHandlerParam returns the canonical exception-handler parameter so the core registry can bind it to the Scheme global %exception-handlers. The return type is values.Value, not *Parameter: callers only need to bind the object, and narrowing keeps the mutating Parameter.SetValue out of reach so the shared singleton's base value (the immutability the cross-Engine safety argument rests on) can't be rewritten through this accessor. RaiseInPlace uses the package var directly.

func FieldMatches

func FieldMatches[T comparable, Op any](p, v *Op, ok bool, getField func(*Op) T) bool

FieldMatches is a helper for EqualTo methods on single-field operations. The caller must perform the type assertion and pass the result.

Usage:

func (p *OperationType) EqualTo(o values.Value) bool {
    v, ok := o.(*OperationType)
    return FieldMatches(p, v, ok, func(op *OperationType) int { return op.Field })
}

func FindCommonWindingPrefix

func FindCommonWindingPrefix(current, target WindingStack) int

FindCommonWindingPrefix finds the longest common prefix of two winding stacks. Returns the index where they diverge (0 means no common frames).

func GraftContinuation

func GraftContinuation(segment, target *MachineContinuation)

GraftContinuation walks the segment chain to its bottom frame and sets its parent to target, effectively splicing the segment onto the target chain.

func RaiseInPlace

func RaiseInPlace(mc *MachineContext, cond values.Value, continuable bool) error

RaiseInPlace invokes the current exception handler on cond, in the dynamic extent of the raise (R7RS §6.11), with the parent handler installed as current. It is the single implementation shared by raise, raise-continuable, error, and the Go-error bridge (applyCallableError).

  • continuable=false (raise / error / Go errors): the handler is expected to escape (e.g. via guard's captured continuation); if it returns, a secondary non-continuable exception escalates to the parent handler. The bridge only ever calls with continuable=false, so it never needs an in-place resume.
  • continuable=true (raise-continuable): the handler's return value becomes the value of the raise-continuable expression, resumed inline on mc.

When the handler stack is empty the condition is uncaught: a slim *ErrExceptionEscape carrier bubbles to RunWithEscapeHandling and surfaces to the embedder (engine.wrapRuntimeError) with the condition, source, and stack trace.

func ReleaseSubContext

func ReleaseSubContext(mc *MachineContext)

ReleaseSubContext zeros the MachineContext and returns it to the pool. Exported because call sites live in other packages (registry/, extensions/).

func ReleaseTopLevelContext

func ReleaseTopLevelContext(mc *MachineContext)

ReleaseTopLevelContext zeros the MachineContext and returns it to the pool. Exported because the primary call sites live in the root wile package (engine.go).

func SameType

func SameType[T any](p, v *T, ok bool) bool

SameType is a helper for EqualTo methods on zero-field operations. The caller must perform the type assertion and pass the result.

Usage:

func (p *OperationType) EqualTo(o values.Value) bool {
    v, ok := o.(*OperationType)
    return SameType(p, v, ok)
}

func SetCallCounting

func SetCallCounting(on bool)

SetCallCounting enables or disables per-callee call counting for MachineContexts created AFTER this call, independently of WILE_OPCODE_HITS. It is intended for measurement harnesses and embedders profiling call distribution; the counts are exposed via VMCounters.CallCounts. Existing contexts are unaffected.

func SliceMatches

func SliceMatches[T comparable, Op any](p, v *Op, ok bool, getField func(*Op) []T) bool

SliceMatches is a helper for EqualTo methods on operations with a single comparable-element slice field.

Usage:

func (p *OperationType) EqualTo(o values.Value) bool {
    v, ok := o.(*OperationType)
    return SliceMatches(p, v, ok, func(op *OperationType) []string { return op.Items })
}

func StackTraceToSchemeList

func StackTraceToSchemeList(st StackTrace) values.Tuple

StackTraceToSchemeList converts a StackTrace to a Scheme list of alists, one per frame. Each alist always carries name; file, line, and column are present only when source information is available. Lives here (not in the registry) because it converts machine types and is needed by both RaiseInPlace and the error-context primitives.

Types

type BarrierToken

type BarrierToken struct {
	// contains filtered or unexported fields
}

BarrierToken is an opaque identity for a with-continuation-barrier scope. Each call to call-with-continuation-barrier creates a fresh token. Barrier crossing is detected by pointer identity comparison: if the capture-time token differs from the invocation-time token, the continuation would cross a barrier boundary.

nil means "not inside any barrier."

The _ field ensures non-zero struct size. Go may return the same pointer for all zero-sized allocations (runtime.zerobase), which would defeat pointer identity comparison.

func NewBarrierToken

func NewBarrierToken() *BarrierToken

NewBarrierToken creates a fresh barrier identity token.

type Breakpoint

type Breakpoint struct {
	ID       BreakpointID
	File     string
	Line     int
	Column   int // 0 = any column on line
	Enabled  bool
	HitCount int
}

Breakpoint represents a source-level breakpoint.

type BreakpointID

type BreakpointID int

BreakpointID uniquely identifies a breakpoint.

type CallContext

type CallContext interface {
	// Arg returns the argument at the given positional index.
	// For variadic functions, the last parameter index holds the rest list.
	Arg(index int) values.Value

	// SetValue sets the single return value.
	SetValue(v values.Value)

	// SetValues sets multiple return values for R7RS values/call-with-values.
	SetValues(vs ...values.Value)

	// Authorizer returns the security authorizer for permission checks.
	Authorizer() security.Authorizer

	// Context returns the Go context for cancellation and timeout.
	Context() context.Context

	// EnvironmentFrame returns the current lexical environment frame.
	EnvironmentFrame() *environment.EnvironmentFrame

	// Thread returns the SRFI-18 thread object (nil for primordial thread).
	Thread() *values.Thread

	// ImmutableLiterals returns the engine-scoped set of immutable literal
	// pair/vector objects, or nil if the context has no namespace. The five
	// list/vector mutators consult it to enforce R7RS §4.1.2 constant
	// immutability.
	ImmutableLiterals() *environment.ImmutableLiterals
}

type CapturedContinuation

type CapturedContinuation struct {
	// contains filtered or unexported fields
}

CapturedContinuation is the value returned by call/cc to Scheme code. It is both callable (invoking it escapes to the captured point) and introspectable (continuation-marks can extract marks from its chain).

This replaces the opaque ForeignClosure that call/cc previously returned. The escape logic (thread check, barrier check, compose-then-abort) now lives in applyCapturedContinuation rather than inside a Go closure.

func NewCapturedContinuation

func NewCapturedContinuation(
	cc *ComposableContinuation,
	threadID uint64,
	barrierValid *BarrierToken,
) *CapturedContinuation

NewCapturedContinuation creates a captured continuation value from a composable continuation segment and the safety context at capture time.

func (*CapturedContinuation) AcceptsArity

func (*CapturedContinuation) AcceptsArity(int) bool

AcceptsArity reports whether this continuation can be called with n arguments. A continuation accepts ANY number of values (R7RS §6.10): it resumes the captured computation with however many values it is invoked with — zero, one, or several. Always true; there is no rejecting arity (n is an argument count, never negative).

func (*CapturedContinuation) ComposableContinuation

func (p *CapturedContinuation) ComposableContinuation() *ComposableContinuation

ComposableContinuation returns the underlying composable continuation, which carries the MachineContinuation chain for mark extraction.

func (*CapturedContinuation) EqualTo

func (p *CapturedContinuation) EqualTo(o values.Value) bool

func (*CapturedContinuation) IsVoid

func (p *CapturedContinuation) IsVoid() bool

func (*CapturedContinuation) SchemeString

func (p *CapturedContinuation) SchemeString() string

type CaseLambdaClosure

type CaseLambdaClosure struct {
	// contains filtered or unexported fields
}

CaseLambdaClosure dispatches to the first clause whose arity matches the argument count. Each clause is a MachineClosure with its own template and captured environment.

func NewCaseLambdaClosure

func NewCaseLambdaClosure(closures []*MachineClosure) *CaseLambdaClosure

func (*CaseLambdaClosure) AcceptsArity

func (p *CaseLambdaClosure) AcceptsArity(n int) bool

AcceptsArity reports whether any clause in this case-lambda can accept n arguments.

func (*CaseLambdaClosure) Clauses

func (p *CaseLambdaClosure) Clauses() []*MachineClosure

func (*CaseLambdaClosure) Doc

func (p *CaseLambdaClosure) Doc() string

Doc returns the documentation from the first clause's template, or "" if no clauses.

func (*CaseLambdaClosure) EqualTo

func (p *CaseLambdaClosure) EqualTo(o values.Value) bool

EqualTo implements Scheme equality for case-lambda closures. Two void closures (nil receivers) are considered equal to each other. Non-void closures are equal only if they have the same number of clauses and each corresponding clause is EqualTo its counterpart.

func (*CaseLambdaClosure) FindMatchingClause

func (p *CaseLambdaClosure) FindMatchingClause(argCount int) (*MachineClosure, bool)

FindMatchingClause finds the first clause that matches the given argument count. It returns the matching closure and true when a clause can accept exactly argCount arguments (for fixed-arity clauses) or at least argCount arguments (for variadic clauses). If the receiver is nil or no clause matches, it returns nil, false.

func (*CaseLambdaClosure) IsVoid

func (p *CaseLambdaClosure) IsVoid() bool

IsVoid reports whether this value represents the absence of a case-lambda closure. A nil receiver is treated as a distinguished "void" closure value, used as a sentinel to mean "no closure" rather than an error.

func (*CaseLambdaClosure) Name

func (p *CaseLambdaClosure) Name() string

Name returns the name from the first clause's template, or "" if no clauses.

func (*CaseLambdaClosure) SchemeString

func (p *CaseLambdaClosure) SchemeString() string

SchemeString returns the Scheme-readable representation of a case-lambda closure. Note that the void value (nil receiver) still prints as a case-lambda closure; callers must use IsVoid to distinguish the sentinel.

type Closure

type Closure interface {
	values.Callable
	NamedCallable
	// contains filtered or unexported methods
}

Closure is a callable that can be directly applied — either a compiled Scheme closure (*MachineClosure) or a Go foreign function (*ForeignClosure). Distinguished from other Callable types (CaseLambdaClosure, Parameter, ComposableContinuation) which have different application semantics.

type ComposableContinuation

type ComposableContinuation struct {
	// contains filtered or unexported fields
}

ComposableContinuation is a callable value wrapping a delimited continuation segment (a chain of MachineContinuation frames) plus the captured winding stack. When applied, it splices its frames onto the current continuation, effectively composing the captured computation with the current one.

This implements Racket-style composable continuations as described in Flatt, Yu, Findler, Felleisen "Adding Delimited and Composable Control to a Production Programming Environment" (ICFP 2007).

func NewComposableContinuation

func NewComposableContinuation(cont *MachineContinuation, windingStack WindingStack, threadID uint64, barrierValid *BarrierToken) *ComposableContinuation

NewComposableContinuation creates a composable continuation from a continuation chain segment and the winding stack captured at the point of capture. barrierValid is mc.BarrierValid() at capture time; nil means the capture happened outside any with-continuation-barrier.

func (*ComposableContinuation) AcceptsArity

func (*ComposableContinuation) AcceptsArity(int) bool

AcceptsArity reports whether this composable continuation can be called with n arguments. A continuation accepts ANY number of values (R7RS §6.10): it resumes with however many values it is invoked with — zero, one, or several. Always true; there is no rejecting arity (n is an argument count, never negative).

func (*ComposableContinuation) AcquireSegment

func (p *ComposableContinuation) AcquireSegment() *MachineContinuation

AcquireSegment returns the continuation segment for grafting.

First invocation marks the segment shared and returns it directly, avoiding a DeepCopy. Shared marking ensures RestoreAndRelease preserves frame evals for potential re-invocation.

Subsequent invocations reset the bottom frame's parent to nil (undoing GraftContinuation's mutation from the prior invocation) and deep-copy from the preserved shared frames.

This optimizes one-shot continuations (the common case in Schelog-style backtracking), eliminating O(depth) frame allocations per invocation.

func (*ComposableContinuation) BarrierValid

func (p *ComposableContinuation) BarrierValid() *BarrierToken

BarrierValid returns the barrier identity token captured when this continuation was created. Used by applyComposableContinuation to detect barrier crossings.

func (*ComposableContinuation) Cont

func (*ComposableContinuation) EqualTo

func (p *ComposableContinuation) EqualTo(o values.Value) bool

func (*ComposableContinuation) IsVoid

func (p *ComposableContinuation) IsVoid() bool

func (*ComposableContinuation) SchemeString

func (p *ComposableContinuation) SchemeString() string

func (*ComposableContinuation) ThreadID

func (p *ComposableContinuation) ThreadID() uint64

func (*ComposableContinuation) WindingStack

func (p *ComposableContinuation) WindingStack() WindingStack

type ContinuationMarkSet

type ContinuationMarkSet struct {
	// contains filtered or unexported fields
}

ContinuationMarkSet is an immutable snapshot of continuation marks collected from a walk of the continuation chain.

The frames slice contains per-frame mark slices, nearest frame first. Only frames with non-nil marks are included. Each frame is a []markEntry searched with values.EqIdentity (eq? semantics).

func CollectMarksFromContinuation

func CollectMarksFromContinuation(cont *MachineContinuation, tag *PromptTag) *ContinuationMarkSet

CollectMarksFromContinuation walks a captured MachineContinuation chain and builds a ContinuationMarkSet snapshot. Used by the (continuation-marks cont) primitive to extract marks from a continuation captured via call/cc.

Starts from cont (nearest frame) and walks parent links, stopping at the first frame whose promptTag matches tag (inclusive). Pass DefaultPromptTag for an unbounded walk.

func (*ContinuationMarkSet) EqualTo

func (p *ContinuationMarkSet) EqualTo(o values.Value) bool

func (*ContinuationMarkSet) First

func (p *ContinuationMarkSet) First(key, defaultVal values.Value) values.Value

First returns the value for key from the nearest frame, or defaultVal if no frame contains the key. Uses eq? semantics (values.EqIdentity) for key comparison.

func (*ContinuationMarkSet) IsVoid

func (p *ContinuationMarkSet) IsVoid() bool

func (*ContinuationMarkSet) SchemeString

func (p *ContinuationMarkSet) SchemeString() string

func (*ContinuationMarkSet) ToList

func (p *ContinuationMarkSet) ToList(key values.Value) values.Tuple

ToList returns a list of values for key across all frames, nearest first. Returns the empty list if no frame contains the key. Uses eq? semantics (values.EqIdentity) for key comparison.

func (*ContinuationMarkSet) ToListStar

func (p *ContinuationMarkSet) ToListStar(keys []values.Value, noneVal values.Value) values.Tuple

ToListStar returns a list of vectors for multiple keys across all frames. Each vector corresponds to a frame that has at least one of the requested keys. Vector positions correspond to the keys slice; noneVal fills missing keys. Uses eq? semantics (values.EqIdentity) for key comparison.

Racket §10.5: continuation-mark-set->list*

type Debugger

type Debugger struct {
	// contains filtered or unexported fields
}

Debugger manages breakpoints and stepping.

func NewDebugger

func NewDebugger() *Debugger

NewDebugger creates a new debugger.

func (*Debugger) Breakpoints

func (p *Debugger) Breakpoints() []*Breakpoint

Breakpoints returns all breakpoints.

func (*Debugger) CheckBreakpoint

func (p *Debugger) CheckBreakpoint(mc *MachineContext) *Breakpoint

CheckBreakpoint checks if execution should break at current location.

func (*Debugger) Continue

func (p *Debugger) Continue()

Continue resumes execution.

func (*Debugger) DisableBreakpoint

func (p *Debugger) DisableBreakpoint(id BreakpointID) bool

DisableBreakpoint disables a breakpoint.

func (*Debugger) EnableBreakpoint

func (p *Debugger) EnableBreakpoint(id BreakpointID) bool

EnableBreakpoint enables a breakpoint.

func (*Debugger) IsStepping

func (p *Debugger) IsStepping() bool

IsStepping returns whether the debugger is in stepping mode.

func (*Debugger) OnBreak

func (p *Debugger) OnBreak(fn func(mc *MachineContext, bp *Breakpoint))

OnBreak sets the callback for when a breakpoint is hit.

func (*Debugger) RemoveBreakpoint

func (p *Debugger) RemoveBreakpoint(id BreakpointID) bool

RemoveBreakpoint removes a breakpoint.

func (*Debugger) SetBreakpoint

func (p *Debugger) SetBreakpoint(file string, line, column int) BreakpointID

SetBreakpoint adds a breakpoint at the given source location.

func (*Debugger) ShouldStep

func (p *Debugger) ShouldStep(mc *MachineContext) bool

ShouldStep checks if we should break due to stepping.

func (*Debugger) StepInto

func (p *Debugger) StepInto()

StepInto enables step-into mode.

func (*Debugger) StepOut

func (p *Debugger) StepOut(mc *MachineContext)

StepOut enables step-out mode.

func (*Debugger) StepOver

func (p *Debugger) StepOver(mc *MachineContext)

StepOver enables step-over mode.

func (*Debugger) TriggerBreak

func (p *Debugger) TriggerBreak(mc *MachineContext, bp *Breakpoint)

TriggerBreak calls the break callback if set.

type DisassembledInstruction

type DisassembledInstruction struct {
	PC      int
	Op      string
	Arg     int32
	HasArg  bool   // true when Arg is meaningful (distinguishes unused from Arg=0)
	Slot    int    // decoded slot for local ops; -1 when not applicable
	Depth   int    // decoded depth for local ops; -1 when not applicable
	Target  int    // absolute PC for branch/save ops; -1 when not applicable
	Literal string // SchemeString() of resolved literal; "" when not applicable
	Binding string // name of cached binding's value; "" when not applicable
	SideOp  string // String() of InlinedOperation; "" when not applicable
	Source  string // "file:line:col" or ""
}

DisassembledInstruction holds the annotation for a single bytecode instruction.

type DisassembledTemplate

type DisassembledTemplate struct {
	Name         string
	ParamCount   int
	IsVariadic   bool
	Doc          string
	Literals     []string // SchemeString() of each literal
	Bindings     []string // name of each cached binding
	Instructions []DisassembledInstruction
}

DisassembledTemplate holds the annotated disassembly of a NativeTemplate.

func Disassemble

func Disassemble(tpl *NativeTemplate) DisassembledTemplate

Disassemble walks the template's bytecode and produces a DisassembledTemplate with annotations resolved per opcode category.

type DynamicWindFrame

type DynamicWindFrame struct {
	Before Closure // Called when entering this extent
	After  Closure // Called when exiting this extent
	ID     uint64  // Unique identifier for extent matching
	// contains filtered or unexported fields
}

DynamicWindFrame represents a single dynamic-wind extent. Each frame tracks the before/after thunks for one dynamic-wind call.

R7RS §6.10: dynamic-wind establishes a dynamic extent during which the before and after thunks are called whenever control enters or exits.

Continuation-wind interaction (Friedman & Haynes 1985, Clinger et al. 1999). The winding stack W is separate from continuation chain K.

W = [w₁, w₂, ...wₙ] where wᵢ = (before_i, after_i, id_i)

On continuation invocation from Wsrc to Wtgt:
  prefix = FindCommonWindingPrefix(Wsrc, Wtgt)
  UnwindTo(prefix):  call after_n, after_{n-1}, ... (innermost first)
  RewindTo(Wtgt):    call before_{prefix+1}, ... (outermost first)

Invariant: W is captured by value at call/cc time (copied into
  ComposableContinuation), NOT stored per continuation frame.
  W belongs to the dynamic extent, not the lexical continuation.
Constrains: RestoreWithWindingFrom (must compute prefix and run
  thunks in correct order). Sub-contexts inherit W from their parent
  via NewSubContext; NewSubContextWithWinding overrides for truncated
  stacks during unwind/exception cleanup.
Constrained by: CESK model (W is NOT part of K — it is orthogonal
  state). PushWind/PopWind opcodes maintain W during normal execution.

See BIBLIOGRAPHY.md "Dynamic-Wind" and "Continuation-Wind Interaction".

func NewDynamicWindFrame

func NewDynamicWindFrame(before, after Closure) *DynamicWindFrame

NewDynamicWindFrame creates a new winding frame with a unique ID.

type EditPlan

type EditPlan struct {
	// contains filtered or unexported fields
}

EditPlan collects non-overlapping bytecode edits for a NativeTemplate. Edits are applied in a single pass via Apply, which rewrites code, sourceRefs, and branch offsets, then garbage-collects unreferenced sideTable entries.

Apply remaps these Arg categories automatically:

  • PC offsets: Branch, BranchOnFalseValue, SaveContinuation
  • SideTable indices: Complex (unreferenced entries are GC'd)

These are stable across Apply and not touched:

  • Literal pool indices: LoadLiteral, LoadGlobal, StoreGlobal, PushLiteral, PushGlobal
  • Local indices: LoadLocal, StoreLocal, PushLocal
  • Stack offsets: PeekK

func NewEditPlan

func NewEditPlan(tpl *NativeTemplate) *EditPlan

NewEditPlan creates a new edit plan for the given template.

func (*EditPlan) AddLiteral

func (p *EditPlan) AddLiteral(v values.Value) int32

AddLiteral adds a value to the template's literal pool, with deduplication. Returns the index suitable for use in Instruction.Arg fields that reference the literal pool (OpLoadLiteral, OpLoadGlobal, OpStoreGlobal).

func (*EditPlan) Apply

func (p *EditPlan) Apply() int

Apply rewrites the template according to all accumulated edits:

  1. Sorts and validates edits (panics on overlap)
  2. Builds a PC remap from old positions to new positions
  3. Fixes branch offsets for surviving original instructions
  4. Rebuilds code + sourceRefs, splicing in replacements
  5. Garbage-collects unreferenced sideTable entries, remaps OpComplex.Arg

Returns the net change in instruction count (negative means code shrunk).

func (*EditPlan) Delete

func (p *EditPlan) Delete(start, end int)

Delete marks the range [start, end) for removal.

func (*EditPlan) HasEdits

func (p *EditPlan) HasEdits() bool

HasEdits reports whether any edits have been added.

func (*EditPlan) Insert

func (p *EditPlan) Insert(at int, instrs []Instruction, src uint32)

Insert inserts instrs before the instruction at position at.

func (*EditPlan) Replace

func (p *EditPlan) Replace(start, end int, instrs []Instruction, src uint32)

Replace marks the range [start, end) for replacement with instrs. src is the source reference for all inserted instructions.

type ErrExceptionEscape

type ErrExceptionEscape struct {
	Condition  values.Value          // The raised condition/object
	Source     *syntax.SourceContext // Source location where exception was raised
	StackTrace StackTrace            // VM stack trace at raise point
}

ErrExceptionEscape carries an UNCAUGHT Scheme exception out to the embedder. It is produced by RaiseInPlace when the exception-handler stack is empty (no handler caught the condition) and bubbles to RunWithEscapeHandling, where the public Engine turns it into a wile.RuntimeError (engine.wrapRuntimeError reads Condition / Source / StackTrace). Handler dispatch itself no longer flows through this type — handlers ride the %exception-handlers parameter and are invoked in place by RaiseInPlace (see exception_raise.go), so the old handler-machinery fields (Continuable / Continuation / Handled / WindingStack) are gone.

func (*ErrExceptionEscape) ConditionText

func (p *ErrExceptionEscape) ConditionText() string

ConditionText returns the raised condition's human-readable text alone — without the source-location prefix, the "error:"/"exception:" category word, or the stack trace that Error() adds. Callers that render their own prefix (the REPL's "Exception:", the CLI's "Error:", wile.RuntimeError's structured Source/StackTrace fields) use this to surface the message exactly once instead of embedding the whole Error() string and duplicating location and trace. A *NativeError yields its plain message; any other condition yields its SchemeString; a nil condition yields "<nil>".

Deliberately NOT shared with Error(): Error() gates a *NativeError's plain message on hasSource (a *NativeError with no source falls back to SchemeString there, for backward compatibility), whereas ConditionText always uses the plain message since it never pairs with a source prefix. The two ladders stay separate on purpose — do not "unify" them without preserving that divergence.

func (*ErrExceptionEscape) Error

func (p *ErrExceptionEscape) Error() string

Error implements the error interface.

When Source is present and the condition is a NativeError, produces clean human-readable output like "file:5:3: error: division by zero". For non-NativeError conditions with Source, produces "file:5:3: exception: foo". When no Source is set, falls back to the original format for backward compat.

func (*ErrExceptionEscape) Unwrap

func (p *ErrExceptionEscape) Unwrap() error

Unwrap returns the underlying error when the condition implements the error interface (e.g., *NativeError). This enables errors.Is/errors.As to traverse through ErrExceptionEscape into the wrapped error chain, supporting sentinel matching like errors.Is(err, werr.ErrDivisionByZero) from Go callers.

type ErrPromptAbort

type ErrPromptAbort struct {
	Tag    *PromptTag
	Values []values.Value
	// SourceWinding is a .Copy() of the winding stack live at the abort ORIGIN — the
	// escape point, which may be a deeper sub-context than the driver that catches the
	// abort. When set, the driver reconciles dynamic-wind from it (not from its own
	// p.windingStack) so the after-thunks between the escape point and the target
	// prompt fire exactly once: removing exitFn's own UnwindTo fixes the exit-path
	// double-fire (C2), and reconciling from the escape-point winding fixes the
	// after-thunk silently skipped when escaping through a deeper sub (C3). nil means
	// "reconcile from the driver's own winding" (the value-delivery aborts, e.g.
	// composable continuation, where the abort site and driver share a winding).
	SourceWinding WindingStack
}

ErrPromptAbort signals an abort to the nearest continuation prompt matching the given tag. It propagates up through Run() and is caught by RunWithEscapeHandling() or by call-with-continuation-prompt sub-contexts.

When caught, the handler finds the matching prompt frame, unwinds dynamic-wind extents, and invokes the prompt's handler with the abort values.

func (*ErrPromptAbort) Error

func (p *ErrPromptAbort) Error() string

type ErrResumeContinuation

type ErrResumeContinuation struct {
	Tag           *PromptTag
	Segment       *ComposableContinuation // carried UNRUN
	Values        []values.Value          // resume args, already copied off the eval stack
	SourceWinding WindingStack            // .Copy() of the winding live at the (k v) site
}

ErrResumeContinuation is the control signal that a call/cc-captured continuation is being invoked. It is NOT a value-delivery abort (that is ErrPromptAbort): it asks the nearest DefaultPromptTag driver loop to REINSTALL the carried segment into the live continuation and keep looping — the trampoline that replaces the per-resume nested sub.Run(). It implements error so it rides the existing return-err plumbing and errors.As matching across nested sub.Run() frames unchanged.

func (*ErrResumeContinuation) Error

func (p *ErrResumeContinuation) Error() string

type ErrTimerInterrupt

type ErrTimerInterrupt struct {
	Handler values.Callable
	// Tag identifies the with-timeout boundary (its finalizer frame) on the
	// continuation chain. A driver does FindPrompt(Tag) to locate that frame on the
	// chain the with-timeout actually installed — its OWN chain, even when the
	// with-timeout sits inside a surviving sub-context — and resolves the timer there.
	Tag *PromptTag
}

ErrTimerInterrupt signals that a wall-clock timer has expired. It propagates through the Go error return path and is handled by the with-timeout primitive or (as a safety net) by RunWithEscapeHandling.

This is a signal, not an exception. It is NOT caught by Scheme exception handlers — only by the VM infrastructure that installed the timer.

func (*ErrTimerInterrupt) Error

func (p *ErrTimerInterrupt) Error() string

type ErrorContext

type ErrorContext struct {
	// contains filtered or unexported fields
}

ErrorContext carries diagnostic information captured at a raise site. It is attached as a continuation mark during exception handler dispatch, enabling Scheme code to inspect source location, stack trace, and continuation marks at the point where the exception was raised.

func NewErrorContext

func NewErrorContext(
	source *syntax.SourceContext,
	stackTrace StackTrace,
	marks *ContinuationMarkSet,
) *ErrorContext

NewErrorContext creates an ErrorContext with the given diagnostics.

func (*ErrorContext) EqualTo

func (p *ErrorContext) EqualTo(other values.Value) bool

EqualTo uses pointer identity. ErrorContext values are not structurally comparable — each raise site produces a unique context.

func (*ErrorContext) IsVoid

func (p *ErrorContext) IsVoid() bool

IsVoid returns true if the receiver is nil.

func (*ErrorContext) Marks

func (p *ErrorContext) Marks() *ContinuationMarkSet

Marks returns the continuation mark set snapshot from the raise site, or nil if not captured.

func (*ErrorContext) SchemeString

func (p *ErrorContext) SchemeString() string

SchemeString returns the Scheme representation of the error context.

func (*ErrorContext) Source

func (p *ErrorContext) Source() *syntax.SourceContext

Source returns the source location at the raise site.

func (*ErrorContext) SourceLocation

func (p *ErrorContext) SourceLocation() string

SourceLocation returns the formatted source location string ("file:line:col"), or "" if unavailable.

func (*ErrorContext) StackTraceFrames

func (p *ErrorContext) StackTraceFrames() StackTrace

StackTraceFrames returns the stack trace captured at the raise site.

type ExpanderCtx

type ExpanderCtx interface {
	Env() *environment.EnvironmentFrame
	Expand(syntax.SyntaxValue) (syntax.SyntaxValue, error)
	ExpandOnce(syntax.SyntaxValue) (syntax.SyntaxValue, bool, error)
	IntroductionScope() *syntax.Scope
	SetIntroductionScope(*syntax.Scope)
	UseSiteScope() *syntax.Scope
	SetUseSiteScope(*syntax.Scope)
}

ExpanderCtx abstracts the macro expansion context so that code needing expansion capabilities can depend on this interface rather than the concrete ExpanderContext. This enables the future machine/compilation sub-package to provide ExpanderContext without circular imports back to machine/.

type ForeignClosure

type ForeignClosure struct {
	// contains filtered or unexported fields
}

ForeignClosure wraps a Go function as a directly-callable Scheme procedure. Unlike MachineClosure, it holds the ForeignFunction directly and bypasses the bytecode VM — no template, no opcodes, no VM loop iteration.

func NewForeignClosure

func NewForeignClosure(env *environment.EnvironmentFrame, pcnt int, variadic bool, fn ForeignFunction) *ForeignClosure

func (*ForeignClosure) AcceptsArity

func (p *ForeignClosure) AcceptsArity(n int) bool

AcceptsArity reports whether this closure can be called with n arguments.

func (*ForeignClosure) Doc

func (p *ForeignClosure) Doc() string

func (*ForeignClosure) Env

func (*ForeignClosure) EqualTo

func (p *ForeignClosure) EqualTo(o values.Value) bool

EqualTo uses identity semantics — two foreign closures are equal only if they are the same pointer.

func (*ForeignClosure) Fn

func (*ForeignClosure) IsVariadic

func (p *ForeignClosure) IsVariadic() bool

func (*ForeignClosure) IsVoid

func (p *ForeignClosure) IsVoid() bool

func (*ForeignClosure) Name

func (p *ForeignClosure) Name() string

func (*ForeignClosure) ParameterCount

func (p *ForeignClosure) ParameterCount() int

func (*ForeignClosure) SchemeString

func (p *ForeignClosure) SchemeString() string

func (*ForeignClosure) SetDoc

func (p *ForeignClosure) SetDoc(doc string)

func (*ForeignClosure) SetName

func (p *ForeignClosure) SetName(name string)

func (*ForeignClosure) SetValidator

func (p *ForeignClosure) SetValidator(v ForeignFunction)

SetValidator installs a contract validation function that runs before the implementation. Called during registration when contract enforcement is enabled.

func (*ForeignClosure) Validator

func (p *ForeignClosure) Validator() ForeignFunction

Validator returns the installed contract validator, or nil if none.

type ForeignFunction

type ForeignFunction func(mc CallContext) error

ForeignFunction is the signature for Go-implemented Scheme primitives. The CallContext provides access to arguments, the value register, and the cancellation context (via mc.Context()).

Most implementations only need CallContext methods (Arg, SetValue, SetValues, Authorizer, Context, EnvironmentFrame, Thread). Implementations that need full VM access (sub-context creation, continuation manipulation) should type-assert to *MachineContext.

type FreeList

type FreeList[T any] struct {
	// contains filtered or unexported fields
}

FreeList is a type-safe, observable object pool backed by a mutex-guarded slice instead of sync.Pool. Unlike sync.Pool, the freelist is NOT cleared by the garbage collector, so recycled objects (and any capacity they retain) persist across GC cycles.

Use FreeList when the GC feedback loop makes sync.Pool ineffective: high allocation rates trigger frequent GC, which clears sync.Pool, causing more allocations. FreeList breaks this loop at the cost of no automatic shrinkage.

func NewFreeList

func NewFreeList[T any](name string, newFn func() *T, resetFn func(*T)) *FreeList[T]

NewFreeList creates a FreeList[T] with the given name, constructor, and reset function. The freelist starts enabled.

func (*FreeList[T]) Acquire

func (p *FreeList[T]) Acquire() *T

Acquire returns a recycled object from the freelist. If the freelist is empty or disabled, it calls newFn to allocate a new object.

func (*FreeList[T]) Drain

func (p *FreeList[T]) Drain()

Drain clears all cached objects from the freelist.

func (*FreeList[T]) Name

func (p *FreeList[T]) Name() string

Name returns the freelist's name.

func (*FreeList[T]) Release

func (p *FreeList[T]) Release(v *T)

Release resets the object and appends it to the freelist. If disabled, the object is discarded after reset.

func (*FreeList[T]) SetEnabled

func (p *FreeList[T]) SetEnabled(on bool)

SetEnabled toggles the freelist on or off. When disabled, Acquire calls newFn directly and Release discards after reset.

func (*FreeList[T]) Stats

func (p *FreeList[T]) Stats() PoolSnapshot

Stats returns a point-in-time snapshot of the freelist's counters.

type InlinedOperation

type InlinedOperation interface {
	Operation
	Apply(mc *MachineContext) (*MachineContext, error)
}

InlinedOperation is the interface for operations dispatched through the side table via OpComplex. These operations carry their own Apply method because the Run() loop delegates to them rather than inlining the logic.

type Instruction

type Instruction struct {
	Op  OpCode
	Arg int32
}

Instruction is a single VM instruction for the switch-dispatch loop. Op selects the operation; Arg carries an immediate operand whose meaning depends on Op:

  • Zero-operand ops (Push, Pop, ...): Arg is unused (0).
  • Single-operand ops (Branch, LoadLiteral, ...): Arg is the offset, index, or depth.
  • Two-operand ops (LoadLocal, StoreLocal): Arg is bit-packed (slot in low 16, depth in high 16).
  • OpComplex: Arg is the index into the template's sideTable.

Size: 8 bytes (uint16 Op + 2 bytes padding + int32 Arg).

func (Instruction) String

func (instr Instruction) String() string

String returns a human-readable representation of the instruction.

type LiteralIndex

type LiteralIndex int

type MachineClosure

type MachineClosure struct {
	// contains filtered or unexported fields
}

Linked closure (Church 1936, Landin 1964, Cardelli 1983). A closure is a pair of compiled code and the lexical environment at definition time.

closure = ⟨λ, E⟩, where:
  λ = template  — compiled bytecode (NativeTemplate)
  E = env       — pointer to enclosing EnvironmentFrame

Access cost: O(1) creation (capture pointer), O(depth) free variable
  lookup (traverse parent chain). Flat closures invert this trade-off.

Invariant: E is a live pointer into the frame chain, not a copy.
  Mutations via set! are visible through the closure because the
  closure shares the frame, not a snapshot.
Constrains: OperationMakeClosure (must link E to runtime parent),
  Apply (always copies E to prevent aliasing and thread races).
Constrained by: de Bruijn addressing (free vars addressed by
  slot,depth in E's chain), CESK model (E is the environment component).

See BIBLIOGRAPHY.md "Linked Closure Representation".

func NewClosureWithTemplate

func NewClosureWithTemplate(tpl *NativeTemplate, env *environment.EnvironmentFrame) *MachineClosure

func NewVMForeignClosure

func NewVMForeignClosure(env *environment.EnvironmentFrame, pcnt int, variadic bool, fn ForeignFunction) *MachineClosure

NewVMForeignClosure creates a *MachineClosure backed by a ForeignFunction via a bytecode template (OpForeignFunctionCall + OpRestoreContinuation). Use this instead of NewForeignClosure for foreign functions that do nested VM execution (sub-context + Run), where the iterative VM loop prevents Go stack growth that applyForeign would cause.

func (*MachineClosure) AcceptsArity

func (p *MachineClosure) AcceptsArity(n int) bool

AcceptsArity reports whether this closure can be called with n arguments. Fixed-arity closures require exactly paramCount args; variadic closures require at least paramCount-1 (the rest parameter collects the remainder).

func (*MachineClosure) Copy

func (p *MachineClosure) Copy() *MachineClosure

func (*MachineClosure) Doc

func (p *MachineClosure) Doc() string

Doc returns the closure's documentation string from its compiled template.

func (*MachineClosure) Env

Env returns the closure's captured environment.

func (*MachineClosure) EqualTo

func (p *MachineClosure) EqualTo(o values.Value) bool

func (*MachineClosure) IsVoid

func (p *MachineClosure) IsVoid() bool

func (*MachineClosure) Name

func (p *MachineClosure) Name() string

Name returns the closure's name from its compiled template.

func (*MachineClosure) SchemeString

func (p *MachineClosure) SchemeString() string

func (*MachineClosure) Template

func (p *MachineClosure) Template() *NativeTemplate

type MachineContext

type MachineContext struct {
	// contains filtered or unexported fields
}

MachineContext represents the execution context of a virtual machine. It holds the current environment, values, evaluation stack, continuation, and program counter. It is created from a MachineContinuation and can be modified during execution.

func AcquireTopLevelContext

func AcquireTopLevelContext(ctx context.Context, tpl *NativeTemplate, env *environment.EnvironmentFrame) *MachineContext

AcquireTopLevelContext returns a pooled MachineContext initialized for top-level execution (no parent continuation). This eliminates the intermediate MachineContinuation allocation that NewMachineContinuation + NewMachineContext would otherwise perform when parent is nil.

The caller MUST call ReleaseTopLevelContext after Run returns.

func NewMachineContext

func NewMachineContext(ctx context.Context, cont *MachineContinuation) *MachineContext

NewMachineContext creates a new machine context with the given context and continuation. The context enables cancellation/timeout support in the VM loop. For callers that don't need cancellation, pass context.Background().

func NewThreadSubContext

func NewThreadSubContext(params SubContextParams, thread *values.Thread) *MachineContext

NewThreadSubContext creates a sub-context for a thread using previously captured parent state. Unlike NewSubContext, this doesn't access the parent MachineContext fields, making it safe to call from a different goroutine. The thread parameter should be the new thread object, which provides the thread identity for the new context.

This function is specifically designed for SRFI-18 thread creation. For other uses of sub-contexts (like map, for-each, dynamic-wind), use NewSubContext instead.

func RequireMachineContext

func RequireMachineContext(cc CallContext, name string) (*MachineContext, error)

RequireMachineContext asserts that cc is a *MachineContext, returning a wrapped ErrNotAMachineContext naming the primitive on failure. Foreign primitives that need full VM internals (eval, load, expand, syntax-local-*) share this prologue instead of repeating the checked type assertion.

func (*MachineContext) Apply

func (p *MachineContext) Apply(mcls *MachineClosure, vs ...values.Value) (*MachineContext, error)

func (*MachineContext) ApplyCallable

func (p *MachineContext) ApplyCallable(callable values.Value, args ...values.Value) (*MachineContext, error)

ApplyCallable dispatches a procedure call to the appropriate handler based on the callee's concrete type. This is the unified entry point for all Scheme procedure application, symmetric with OperationApply.

Supported callable types:

  • *MachineClosure: standard Scheme lambda
  • *ForeignClosure: Go foreign function (direct call, no bytecode)
  • *CaseLambdaClosure: R7RS case-lambda (§4.2.9)
  • *Parameter: R7RS parameter object (§4.2.6)
  • *ComposableContinuation: delimited continuation

Precondition: p.ctx must be set (always true for contexts created via NewMachineContext or NewSubContext).

func (*MachineContext) ApplyCaseLambda

func (p *MachineContext) ApplyCaseLambda(clcls *CaseLambdaClosure, vs ...values.Value) (*MachineContext, error)

ApplyCaseLambda applies a case-lambda closure by finding the matching clause.

func (*MachineContext) Arg

func (p *MachineContext) Arg(index int) values.Value

func (*MachineContext) Authorizer

func (p *MachineContext) Authorizer() security.Authorizer

Authorizer returns the security authorizer from this context's namespace, or nil if none is set.

func (*MachineContext) BarrierValid

func (p *MachineContext) BarrierValid() *BarrierToken

BarrierValid returns the barrier validity flag for the current context. Non-nil means execution is inside a with-continuation-barrier; the pointer identity distinguishes which barrier. Nil means no active barrier.

Escape closures and composable continuations use this to detect barrier crossings: if the capture-time pointer differs from the invocation-time pointer, the continuation would cross a barrier boundary.

func (*MachineContext) CallDepth

func (p *MachineContext) CallDepth() int

CallDepth returns the depth of the current continuation stack.

func (*MachineContext) CaptureInterruptContinuation

func (p *MachineContext) CaptureInterruptContinuation() *MachineContinuation

CaptureInterruptContinuation captures the full VM execution state at an interrupt point as a deep-copied continuation chain. Unlike SliceContinuationAt, this includes the live registers (template, pc, env, evals, value) that haven't been saved by a SaveContinuation instruction.

The MachineContext is not modified. The returned chain is a deep copy suitable for wrapping in a ComposableContinuation.

func (*MachineContext) CaptureInterruptContinuationAt

func (p *MachineContext) CaptureInterruptContinuationAt(boundary *MachineContinuation) *MachineContinuation

CaptureInterruptContinuationAt is CaptureInterruptContinuation delimited at boundary: it slices the live chain down to (but excluding) boundary, so a timer interrupt captures the suspended thunk DELIMITED at its with-timeout finalizer frame (boundary), not the whole chain — the correct composable continuation to hand the handler. boundary == nil captures the full chain (the original behavior).

It still pushes the synthetic live frame first, so the in-progress frame's registers (template, pc, env, evals, value) — which no SaveContinuation has saved — are captured. SliceContinuationAt deep-copies the eval stacks, so the returned segment is independent of p.evals.

func (*MachineContext) CaptureStackTrace

func (p *MachineContext) CaptureStackTrace(maxDepth int) StackTrace

CaptureStackTrace walks the continuation chain and builds a stack trace.

The walk spans sub-context boundaries via parentMC. When a trace is captured inside a sub-context — e.g. a parameter converter, eval/load, or an exception thunk that runs Scheme via NewSubContext — the inner frames alone would truncate at that sub-context's nil-rooted continuation chain. Hopping parentMC restores the full logical Scheme stack, inserting a foreignBoundaryName frame at each crossing.

This deliberately diverges from SliceContinuationAt, which walks the same cont.parent chain for *control* capture and MUST stop at the boundary to keep a captured continuation re-runnable (it cannot reproduce the Go residual between the inner and outer frames). A stack trace is read-only — it re-executes nothing — so spanning the boundary is both safe and desirable.

The walk stops at a context with isolatedMarks set (a re-invoked continuation running a grafted chain), mirroring findParameterInMarks: the trace then shows the continuation's own extent, not the invoker's.

func (*MachineContext) CaptureSubContextParams

func (p *MachineContext) CaptureSubContextParams() SubContextParams

CaptureSubContextParams extracts the state needed to create a sub-context in a different goroutine. This is used by thread creation to avoid race conditions when accessing the parent MachineContext from a child goroutine (T4 from architectural review).

Call this in the parent goroutine before creating the child goroutine, then pass the result to NewThreadSubContext in the child goroutine.

func (*MachineContext) CollectContinuationMarks

func (p *MachineContext) CollectContinuationMarks(tag *PromptTag) *ContinuationMarkSet

CollectContinuationMarks walks the continuation chain and builds a ContinuationMarkSet snapshot. Collects marks from the current frame and all continuation frames up to and including the nearest frame with a matching promptTag.

func (*MachineContext) Context

func (p *MachineContext) Context() context.Context

Context returns the context for this machine context.

func (*MachineContext) Counters

func (p *MachineContext) Counters() VMCounters

Counters returns a snapshot of the performance counters for this context.

func (*MachineContext) CurrentContinuation

func (p *MachineContext) CurrentContinuation() *MachineContinuation

func (*MachineContext) CurrentLocation

func (p *MachineContext) CurrentLocation() *values.DebugLocation

CurrentLocation returns the current source location as a values.DebugLocation, or nil if no source info is available. Implements values.DebugState.

func (*MachineContext) CurrentSource

func (p *MachineContext) CurrentSource() *syntax.SourceContext

CurrentSource returns the source location for the current execution point. When the current template has no source (e.g., inside a foreign function), walks up the continuation chain to find the nearest call site with source info. Continuation PCs are return addresses (one past the call), so pc-1 gives the call site.

func (*MachineContext) Debugger

func (p *MachineContext) Debugger() *Debugger

Debugger returns the attached debugger, or nil if none.

func (*MachineContext) DeleteMark

func (p *MachineContext) DeleteMark(key values.Value)

DeleteMark removes the continuation mark for key from the current frame. Nils the slice when empty to maintain the "nil = zero-cost" invariant. Uses eq? semantics for key comparison. Deletion uses swap-with-last for O(1) removal; insertion order is not preserved.

func (*MachineContext) EnvironmentFrame

func (p *MachineContext) EnvironmentFrame() *environment.EnvironmentFrame

func (*MachineContext) Error

func (p *MachineContext) Error(msg string) *SchemeError

Error creates a SchemeError with the current source location and stack trace but no sentinel cause, so errors.Is cannot match the result against any error family. Prefer WrapError(sentinel, msg) at any site whose failure has a sentinel — every production call site does (R9). Reach for Error only when no sentinel genuinely applies.

func (*MachineContext) EscapeCont

func (p *MachineContext) EscapeCont() *MachineContinuation

EscapeCont returns the escape continuation for this context. This is set by foreign functions (like dynamic-wind) that need call/cc inside their sub-contexts to know where to continue after completion.

func (*MachineContext) Evals

func (p *MachineContext) Evals() *Stack

Evals returns the eval stack for inspection (primarily for testing).

func (*MachineContext) ExpanderContext

func (p *MachineContext) ExpanderContext() ExpanderCtx

ExpanderContext returns the expander context, or nil if not in expansion context.

func (*MachineContext) FindPrompt

func (p *MachineContext) FindPrompt(tag *PromptTag) (*MachineContinuation, bool)

FindPrompt walks the continuation chain to find the nearest frame with a matching prompt tag. Also checks the context's own prompt tag (set by call-with-continuation-prompt on sub-contexts). Returns the matching frame and true, or nil and false.

When the prompt is on the context itself (not a continuation frame), returns nil and true — the caller should treat this as "prompt at the boundary of this sub-context" and slice the entire continuation chain.

func (*MachineContext) FormatStackTrace

func (p *MachineContext) FormatStackTrace(maxDepth int) string

FormatStackTrace returns a human-readable stack trace string. Implements values.DebugState.

func (*MachineContext) GetImmediateMark

func (p *MachineContext) GetImmediateMark(key values.Value) values.Value

GetImmediateMark returns the nearest mark for key, checking the current frame first, then the immediately saved continuation frame.

This is the correct lookup for call-with-immediate-continuation-mark: in tail position, with-continuation-mark sets the mark on the live frame (mc.marks); in non-tail position, SaveContinuation moves mc.marks to mc.cont and nils the live frame. Both cases are handled here.

func (*MachineContext) GetMark

func (p *MachineContext) GetMark(key values.Value) values.Value

GetMark returns the continuation mark for key on the current frame, or nil if no mark is set. Uses eq? semantics for key comparison. Invariant: nil is used exclusively as the "not found" sentinel. Mark values are always non-nil Scheme values (GetValue never returns nil); SetMark must never be called with a nil val, as nil would be indistinguishable from absent.

func (*MachineContext) GetValue

func (p *MachineContext) GetValue() values.Value

GetValue returns the first (or only) value from the value register. Returns Void if the register is empty.

func (*MachineContext) GetValues

func (p *MachineContext) GetValues() MultipleValues

GetValues returns all values from the value register as a MultipleValues slice. For the single-value case this allocates a one-element slice; callers on the hot path should use GetValue instead.

func (*MachineContext) ImmutableLiterals

func (p *MachineContext) ImmutableLiterals() *environment.ImmutableLiterals

ImmutableLiterals returns the engine-scoped immutable-literal set from this context's namespace, or nil if none is set. The five list/vector mutators consult it to enforce R7RS §4.1.2 constant immutability.

func (*MachineContext) IncrPC

func (p *MachineContext) IncrPC()

IncrPC increments the program counter by one.

func (*MachineContext) MaxCallDepth

func (p *MachineContext) MaxCallDepth() int

MaxCallDepth returns the maximum call depth limit. 0 means unlimited. The stored value is always non-negative; SetMaxCallDepth clamps negatives.

func (*MachineContext) MaxStackSize

func (p *MachineContext) MaxStackSize() uint64

MaxStackSize returns the maximum eval stack size limit. 0 means unlimited.

func (*MachineContext) NewSubContext

func (p *MachineContext) NewSubContext() *MachineContext

func (*MachineContext) NewSubContextWithTemplate

func (p *MachineContext) NewSubContextWithTemplate(
	tpl *NativeTemplate,
	env *environment.EnvironmentFrame,
) *MachineContext

NewSubContextWithTemplate creates a sub-context configured to execute the given template in the given environment. This is the correct way for primitives like eval and load to create execution contexts — it propagates all parent fields automatically via NewSubContext, preventing the "forgotten field" bug class that NewMachineContext + manual setters is vulnerable to.

The template and env override NewSubContext's defaults (nil template, parent's TopLevel env). pc starts at 0 (pool zero-value).

func (*MachineContext) NewSubContextWithWinding

func (p *MachineContext) NewSubContextWithWinding(windingStack WindingStack) *MachineContext

NewSubContextWithWinding creates a sub-context with an explicit winding stack instead of inheriting the parent's. Use this only when the sub-context must run with a winding stack that differs from the parent — for example, a truncated stack during unwind (machine_context_winding.go) or exception cleanup (prim_exceptions.go). All other sub-context creation should use NewSubContext.

func (*MachineContext) PC

func (p *MachineContext) PC() int

func (*MachineContext) Parent

func (p *MachineContext) Parent() *MachineContinuation

func (*MachineContext) ParentMC

func (p *MachineContext) ParentMC() *MachineContext

ParentMC returns the parent machine context (for sub-contexts), or nil for top-level contexts.

func (*MachineContext) PopContinuation

func (p *MachineContext) PopContinuation() (*MachineContinuation, error)

PopContinuation pops the current continuation from the machine context and returns it. It restores the machine context to the state saved in the popped continuation. Returns ErrContinuationUnderflow if callDepth would go below zero (compiler bug).

Note: Unlike Restore(), we do NOT copy evals here because PopContinuation is used for normal function return where the continuation is consumed once. Restore() is used for continuation re-entry (call/cc) where the same continuation may be invoked multiple times, requiring the copy to prevent stack corruption.

func (*MachineContext) PopWindingFrame

func (p *MachineContext) PopWindingFrame() *DynamicWindFrame

PopWindingFrame removes the innermost frame from the winding stack.

func (*MachineContext) PromptTag

func (p *MachineContext) PromptTag() *PromptTag

PromptTag returns the prompt tag for this context, or nil.

func (*MachineContext) PushValues

func (p *MachineContext) PushValues(v ...values.Value)

PushValues appends values to the value register. If the register currently holds a single value, it is promoted to the multi-value representation before appending. This promote-then-append pattern avoids losing the existing single value when transitioning to the multi-value path.

Order matters: we nil singleValue *before* installing the promoted MultipleValues so the mutual-exclusion invariant is never violated, even in the intra-method transient window.

func (*MachineContext) PushWindingFrame

func (p *MachineContext) PushWindingFrame(frame *DynamicWindFrame)

PushWindingFrame adds a frame to the winding stack.

func (*MachineContext) ReinstallSegment

func (p *MachineContext) ReinstallSegment(
	comp *ComposableContinuation,
	boundary *MachineContinuation,
	srcWinding WindingStack,
	vals []values.Value,
	isolate bool,
) (bool, error)

ReinstallSegment installs a captured/composable continuation segment into the current context. It is the single resume primitive shared by composable resume (boundary = p.cont, isolate = compose) and abortive call/cc resume (boundary = nil, isolate = true).

Returns wasEmpty = true when the captured continuation is empty (no chain to drive): the values are delivered and the CALLER performs its own post-delivery control transfer (composable: returnImmediate; the DefaultPromptTag driver: terminate or continue).

Order is load-bearing and matches the pre-refactor applyComposableContinuation:

  1. marks BEFORE the winding reconcile — RestoreWithWindingFrom runs dynamic-wind before/after thunks (arbitrary Scheme that may read marks / parameters), so the marks snapshot must already be installed.
  2. AcquireSegment BEFORE Restore — AcquireSegment marks the chain shared (first invoke) so a later normal return through a reinstalled frame takes RestoreAndRelease's copy-don't-pool branch (shared-bit safety; the tail-frame-recycling-unsound failure class hides here).

isolate is written unconditionally as a per-resume reset on the (now long-lived) driver context: a stale isolatedMarks from a prior resume must not leak into a later one (design guard #1). The broader stale-marks safety across separate top-level forms is discharged by the pool zeroing the whole *MachineContext on release (pool.go, via ReleaseTopLevelContext/ReleaseSubContext), not by this per-resume reset alone — if Acquire*Context ever stops zeroing, that guard breaks.

func (*MachineContext) ResolveParameterValue

func (p *MachineContext) ResolveParameterValue(param *Parameter) values.Value

ResolveParameterValue returns the effective value of a parameter, checking continuation marks (from parameterize) before falling back to the base value. This is the Go-side equivalent of calling the parameter with 0 args.

func (*MachineContext) Restore

func (p *MachineContext) Restore(cont *MachineContinuation)

func (*MachineContext) RestoreAndRelease

func (p *MachineContext) RestoreAndRelease(cont *MachineContinuation)

RestoreAndRelease is the fast path for normal function return. It transfers the continuation's state into the MachineContext (like Restore) but avoids copying evals — instead it transfers ownership directly and pools the consumed frame. This is safe because normal return consumes the frame exactly once; call/cc and escape paths must use Restore (which copies).

Shared frames (marked by MarkChainShared during call/cc capture) cannot be pooled because a captured continuation may re-invoke them. For shared frames, evals are copied (like Restore) and the frame is left for GC instead of pooling.

The sequence for unshared frames:

  1. Release mc's current evals to the stack pool (it's dead after restore)
  2. Transfer cont's evals directly to mc (no copy)
  3. Nil cont.evals so releaseContinuation won't double-release it
  4. Pool the consumed continuation frame

func (*MachineContext) RestoreWithWinding

func (p *MachineContext) RestoreWithWinding(cont *MachineContinuation, targetStack WindingStack) error

RestoreWithWinding restores a continuation with proper dynamic-wind handling. It unwinds from the current dynamic extent, rewinds to the target extent, then restores the machine state.

If cont is nil (continuation captured in a sub-context), we still perform the winding operations but don't restore machine state - the caller should handle continued execution appropriately.

func (*MachineContext) RestoreWithWindingFrom

func (p *MachineContext) RestoreWithWindingFrom(cont *MachineContinuation, sourceStack, targetStack WindingStack) error

RestoreWithWindingFrom restores a continuation with proper dynamic-wind handling, using an explicit source winding stack instead of the current context's stack.

This is needed when the escape originated from a sub-context that has a different winding stack than the context where RestoreWithWinding is called. For example, when call/cc captures inside a sub-context and the escape propagates up, the source winding stack (where the escape happened) may have frames that the top-level context doesn't know about.

Parameters:

  • cont: The continuation to restore to
  • sourceStack: The winding stack where the escape originated (for unwinding)
  • targetStack: The winding stack to restore to (for rewinding)

func (*MachineContext) RewindTo

func (p *MachineContext) RewindTo(target WindingStack, commonDepth int) error

RewindTo runs before thunks from common ancestor to target depth. Returns error if any before thunk fails.

func (*MachineContext) Run

func (p *MachineContext) Run() error

Run executes the VM loop starting from the current pc. The pc is NOT reset here - callers are responsible for ensuring the correct initial pc:

  • NewMachineContext copies pc from the continuation (typically 0 for fresh execution)
  • Apply sets pc = 0 for fresh closure invocation
  • Restore sets pc from the saved continuation for resumption

This design allows continuation resumption (e.g., raise-continuable) to work correctly by preserving the pc set by Restore rather than unconditionally resetting to 0.

Dispatch: Run always uses switch-dispatch over integer opcodes.

Context cancellation: The loop checks p.ctx.Done() every 1024 ops, allowing preemption via context.WithTimeout or context.WithCancel. This enables:

  • Test timeouts that actually stop execution
  • REPL interrupt support (Ctrl+C)
  • Resource management for long-running computations

Run executes the VM loop using switch-dispatch with integer opcodes. Hot-path operations (Wave 1-3) are inlined as switch cases; complex operations (closures, macros, FFI) are dispatched via OpComplex to the template's sideTable.

Set the context via SetContext() before calling Run().

func (*MachineContext) RunBodyUnderBarrier

func (p *MachineContext) RunBodyUnderBarrier(body values.Value, token *BarrierToken) (*MachineContext, error)

RunBodyUnderBarrier reifies with-continuation-barrier. It pushes a transparent chain frame carrying the OUTER barrier token (the restore target), flips the live barrier to `token` for the body, and inline-applies body on the live chain (no sub-context). On the body's normal return the transparent frame's restore reverts p.barrierValid to the outer token and forwards the body's value(s); a continuation captured inside the body spans the frame, so resume-out replays the same revert. An abort skips the frame and lands on an outer frame whose stamped barrierValid reverts via the driver's Restore. Because barrierValid is now a chain-carried register, the crossing check at the (k v) site (applyCapturedContinuation / applyComposableContinuation) is unchanged and correct at every transition: a continuation captured inside records `token`; one captured outside records the outer barrier; invoking across the boundary trips the pointer check.

func (*MachineContext) RunBodyUnderConsumer

func (p *MachineContext) RunBodyUnderConsumer(producer values.Value, consumer values.Value, args ...values.Value) (*MachineContext, error)

RunBodyUnderConsumer reifies a "run a body, then apply a consumer to its result" boundary on the live chain. It pushes a consumer apply-frame and inline-applies producer (to args) on the live chain, so a continuation captured inside producer spans the consumer frame and the rest of the program (fixing the sub-context producer truncation). On producer's normal return the consumer frame applies consumer to the produced values exactly once; a full call/cc continuation invoked inside producer aborts to DefaultPromptTag, discarding the chain-resident consumer frame (escape-past preserved).

call-with-values passes no args — its producer is a thunk. make-parameter passes the init value as the single arg to the user converter (the producer), with the consumer being a finalizer that wraps the converted value in a Parameter. The args path is the same one RunBodyUnderExitFrame already exercises.

func (*MachineContext) RunBodyUnderExitFrame

func (p *MachineContext) RunBodyUnderExitFrame(body values.Value, tag *PromptTag, finalizer values.Value, exitArg values.Value) (*MachineContext, error)

RunBodyUnderExitFrame reifies call-with-exit. It pushes a prompt apply-frame carrying tag whose literal is `finalizer`, then inline-applies body (proc) with exitArg (the one-shot exit closure). On proc's normal return the frame applies finalizer to proc's value(s) — clearing the one-shot and forwarding the value(s); an (exit v) abort to tag routes via the driver's FindPrompt to this frame (no handler), which delivers v and re-enters the same finalizer template (idempotent). The frame is NOT transparent (returnTemplate): the one-shot must be cleared on the normal-return path, which RunBodyUnderPrompt's returnTemplate cannot do.

func (*MachineContext) RunBodyUnderFrame

func (p *MachineContext) RunBodyUnderFrame(frame *MachineContinuation, body values.Value, args ...values.Value) (*MachineContext, error)

RunBodyUnderFrame pushes frame as mc.cont and inline-applies body on this context (no sub-context, no nested Run), so body runs ON THE LIVE CHAIN under frame: O(1) Go frames, and a continuation captured in body spans frame and everything below it. frame.parent MUST already be the current p.cont (the continuation constructors used by the callers below set it).

frame is either a transparent prompt frame (RunBodyUnderPrompt) or a plain continuation frame whose code runs on the body's normal return (RunBodyUnderConsumer). On normal completion the VM restores frame and executes its template; on abort to a frame-carried tag the driver's FindPrompt routes to it.

func (*MachineContext) RunBodyUnderPrompt

func (p *MachineContext) RunBodyUnderPrompt(body values.Value, tag *PromptTag, handler Closure, args ...values.Value) (*MachineContext, error)

RunBodyUnderPrompt installs a continuation-chain prompt frame on top of the current chain and applies body INLINE on this context, so the body runs on the live continuation. A continuation captured inside body spans the prompt frame and everything below it; an abort to tag routes through the chain (FindPrompt) to this frame's handler in RunResumable.

The frame is transparent on normal completion (returnTemplate). tag identifies the prompt for abort/capture. handler may be nil: nil means the abort values become the prompt's result delivered to the parent (call-with-continuation-prompt with a #f handler); a non-nil handler is invoked by the driver with the abort values (call-with-continuation-prompt). call-with-exit does NOT use this wrapper — it needs a non-transparent finalizer frame (RunBodyUnderExitFrame).

func (*MachineContext) RunBodyUnderTimer

func (p *MachineContext) RunBodyUnderTimer(
	timerCtx context.Context, cancel context.CancelFunc,
	thunk values.Value, handler values.Callable,
) (*MachineContext, error)

RunBodyUnderTimer reifies with-timeout. It installs a wall-clock timer for the duration of thunk and runs thunk INLINE on the live chain under a finalizer prompt frame (no sub-context), so a continuation captured inside thunk spans the finalizer frame and the rest of the program (the sub-context truncation is fixed). The frame carries a fresh tag so that a fired timer is routed to THIS with-timeout's frame by a driver's FindPrompt (resolveTimerInterrupt) — on whichever chain the with-timeout sits, top level or inside a surviving sub-context.

timerState is pushed as a LINKED stack (parent pointer) for nesting, and carries the tag plus the saved outer ctx. The finalizer does an IDEMPOTENT ABSOLUTE teardown — cancel the timer, restore the outer timer + ctx, forward the body's 0/1/N values — so it is correct on normal completion AND, run a second time, after the timer arm already tore the fired timer down (resolveTimerInterrupt restores the same outer state). This helper installs and restores p.timer directly: nesting requires pushing a child timer while the parent is still live, via the linked parent pointer.

func (*MachineContext) RunResumable

func (p *MachineContext) RunResumable() (rerr error)

RunResumable drives the VM loop under a DefaultPromptTag prompt, catching control bounces (ErrPromptAbort and ErrResumeContinuation — the trampoline resume signal) and looping. It is the single resume/abort driver shared by every DefaultPromptTag owner. It handles continuation escapes that weren't caught by an enclosing call/cc — used at the top level (REPL and file execution) to catch continuations invoked outside their original dynamic extent.

When a continuation captured inside a foreign function (like dynamic-wind's thunk) is invoked from outside, the escape error propagates up. This method catches it and restores the continuation with proper dynamic-wind handling.

For continuations captured inside sub-contexts (like dynamic-wind thunks):

  • Continuation: the inner state (inside the thunk)
  • EscapeCont: the outer continuation (after the original sub-context would have completed)

After the inner execution completes and unwinds, if there's a pending escape continuation, execution continues from there.

When execution completes normally (Run returns nil), any remaining frames on the winding stack are unwound (after thunks are called).

func (*MachineContext) RunWithEscapeHandling

func (p *MachineContext) RunWithEscapeHandling() error

RunWithEscapeHandling is the top-level entry point that runs the VM under the DefaultPromptTag prompt. It delegates to RunResumable, the shared abort/resume driver every DefaultPromptTag owner routes through.

func (*MachineContext) RunWithinBoundary

func (p *MachineContext) RunWithinBoundary() error

RunWithinBoundary drives this sub-context like Run, but resolves an ErrPromptAbort whose tag names a prompt ON THIS CONTEXT'S OWN CHAIN inline — the way RunResumable's abort arm does at the top level — instead of letting it escape to a Go-stack errors.As catch in the calling primitive.

It exists because the continuation cluster reifies call-with-exit / call-with-continuation-prompt as continuation-CHAIN prompt frames run inline. A reified boundary that appears INSIDE a surviving sub-context (a with-continuation-barrier thunk, a RaiseInPlace handler, a dynamic-wind thunk, a parameter converter, ...) lands its prompt frame on THAT sub-context's chain. When it aborts, FindPrompt(tag) on the sub's own chain finds the frame and this driver routes the abort here; without it the abort escapes to the top RunResumable, whose FindPrompt walks the PARENT chain and cannot see the frame ("no prompt found for tag").

It is a strict superset of Run for any NewSubContext: such a context has promptTag == nil (NewSubContext does not inherit it), so FindPrompt only matches a prompt FRAME pushed inside the sub by a reified boundary. An abort whose tag is NOT on this chain — a full call/cc to DefaultPromptTag, or an exit targeting an OUTER boundary — is re-raised unchanged so the enclosing driver owns it; and ErrResumeContinuation (the call/cc trampoline signal) is never an ErrPromptAbort, so it always re-raises to the top RunResumable. No DefaultPromptTag install, no timer or panic handling: those belong to the one top-level RunResumable.

func (*MachineContext) SaveContinuation

func (p *MachineContext) SaveContinuation(off int) error

SaveContinuation pushes a new continuation onto the machine context with the given offset to the current program counter. Returns ErrCallDepthExceeded if the call depth limit has been reached.

Note: callDepth is incremented BEFORE calling NewMachineContinuationFromMachineContext. The continuation's own callDepth is derived from mc.cont (the parent pointer), not from mc.callDepth, so this pre-increment does not affect the continuation's cached depth. See the comment on NewMachineContinuationFromMachineContext for why this matters.

func (*MachineContext) SetBarrierValid

func (p *MachineContext) SetBarrierValid(v *BarrierToken)

SetBarrierValid sets the barrier identity token on this context. Called by PrimCallWithContinuationBarrier to mark the sub-context as inside a barrier.

func (*MachineContext) SetContext

func (p *MachineContext) SetContext(ctx context.Context)

SetContext sets the context for this machine context. This should be called before Run() to enable context cancellation/timeout.

func (*MachineContext) SetDebugger

func (p *MachineContext) SetDebugger(d *Debugger)

SetDebugger attaches a debugger to this context.

func (*MachineContext) SetEnvPooled

func (p *MachineContext) SetEnvPooled(v bool)

SetEnvPooled controls whether the current environment frame will be recycled by RestoreAndRelease. Set to false after replacing env with a heap-allocated frame that must not be returned to envFramePool.

func (*MachineContext) SetEnvironmentFrame

func (p *MachineContext) SetEnvironmentFrame(env *environment.EnvironmentFrame)

SetEnvironmentFrame replaces the current environment frame. Used by operations that push new scopes (e.g., OperationBindPatternVars).

func (*MachineContext) SetEscapeCont

func (p *MachineContext) SetEscapeCont(cont *MachineContinuation)

SetEscapeCont sets the escape continuation for this context.

func (*MachineContext) SetExpanderContext

func (p *MachineContext) SetExpanderContext(ctx ExpanderCtx)

SetExpanderContext sets the expander context for this machine context. This is called when invoking macro transformers to enable syntax-local-* primitives. Lazy-allocates the expansion sub-record on first write.

func (*MachineContext) SetMark

func (p *MachineContext) SetMark(key, val values.Value)

SetMark sets a continuation mark on the current frame using eq? semantics. Updates an existing entry with the same key, or appends a new one.

func (*MachineContext) SetMaxCallDepth

func (p *MachineContext) SetMaxCallDepth(n int)

SetMaxCallDepth sets the maximum call depth limit. 0 means unlimited. Negative values are clamped to 0 (also unlimited).

func (*MachineContext) SetMaxStackSize

func (p *MachineContext) SetMaxStackSize(n uint64)

SetMaxStackSize sets the maximum eval stack size limit. 0 means unlimited.

func (*MachineContext) SetPC

func (p *MachineContext) SetPC(v int)

SetPC sets the program counter. Used by PrimCallCC for inline lambda execution.

func (*MachineContext) SetPromptTag

func (p *MachineContext) SetPromptTag(tag *PromptTag)

SetPromptTag sets the prompt tag on this context. Used by call-with-continuation-prompt to mark sub-contexts as prompt boundaries.

func (*MachineContext) SetSyntaxCaseState

func (p *MachineContext) SetSyntaxCaseState(v any)

SetSyntaxCaseState installs the syntax-case expansion state on the context, or nil to clear it. In production, the only legitimate concrete type is *compilation.syntaxCaseState; the constraint is enforced by encapsulation (unexported field, single-package consumer) rather than the type system. Lazy-allocates the expansion sub-record on first write.

func (*MachineContext) SetThread

func (p *MachineContext) SetThread(t *values.Thread)

SetThread sets the SRFI-18 thread identity on this context. Both the thread object and its ID are stored for efficient comparison.

func (*MachineContext) SetValue

func (p *MachineContext) SetValue(v values.Value)

SetValue stores a single value in the value register without allocating. This is the hot path: every LoadLocal, LoadGlobal, LoadLiteral, Pull, Pop, MakeClosure, etc. goes through here.

func (*MachineContext) SetValues

func (p *MachineContext) SetValues(vs ...values.Value)

SetValues sets the value register. Three paths:

  • len == 0: canonical empty state, both fields nil. Distinguishes the (nil, nil) empty register from (nil, []) which a naive 'multiValues = vs' would produce when vs is an empty-but-non-nil spread (e.g. SetValues(emptySlice...)).
  • len == 1: zero-allocation fast path via singleValue.
  • len > 1: fall back to the multiValues slice.

func (*MachineContext) SetWindingStack

func (p *MachineContext) SetWindingStack(stack WindingStack)

SetWindingStack sets the winding stack. Used by tests; production code should prefer NewSubContextWithWinding for override sites.

func (*MachineContext) SliceContinuationAt

func (p *MachineContext) SliceContinuationAt(prompt *MachineContinuation) *MachineContinuation

SliceContinuationAt deep-copies the continuation chain segment from p.cont down to (but not including) the prompt frame. The returned chain's bottom frame has parent = nil, making it a standalone segment suitable for composable continuation capture.

func (*MachineContext) SnapshotReachableMarksInto

func (p *MachineContext) SnapshotReachableMarksInto(comp *ComposableContinuation)

SnapshotReachableMarksInto attaches p's capture-time reachable marks to comp, so resuming comp restores the outer parameter/handler environment. Called at call/cc capture sites (PrimCallCC).

func (*MachineContext) SyntaxCaseState

func (p *MachineContext) SyntaxCaseState() any

SyntaxCaseState returns the per-context syntax-case expansion state, or nil when not in a syntax-case expansion. The concrete type is owned by machine/compilation/; callers within that subpackage type-assert to *syntaxCaseState. See the comment on expansionState for why this is any-typed.

func (*MachineContext) Template

func (p *MachineContext) Template() *NativeTemplate

func (*MachineContext) Thread

func (p *MachineContext) Thread() *values.Thread

Thread returns the SRFI-18 thread object for this context, or nil for the primordial thread.

func (*MachineContext) ThreadID

func (p *MachineContext) ThreadID() uint64

ThreadID returns the SRFI-18 thread ID for this context. 0 means the primordial thread (main goroutine).

func (*MachineContext) UnwindTo

func (p *MachineContext) UnwindTo(commonDepth int) error

UnwindTo runs after thunks from innermost to the common ancestor. Returns error if any after thunk fails.

func (*MachineContext) WindingStack

func (p *MachineContext) WindingStack() WindingStack

WindingStack returns the current winding stack.

func (*MachineContext) WrapError

func (p *MachineContext) WrapError(err error, msg string) *SchemeError

WrapError wraps an existing error with the current source location and stack trace.

type MachineContinuation

type MachineContinuation struct {
	// contains filtered or unexported fields
}

func NewMachineContinuation

func NewMachineContinuation(parent *MachineContinuation, tpl *NativeTemplate, env *environment.EnvironmentFrame) *MachineContinuation

NewMachineContinuation creates a new machine continuation with the given parent, template, environment frame, and initial values.

func NewMachineContinuationFromMachineContext

func NewMachineContinuationFromMachineContext(mc *MachineContext, off int) *MachineContinuation

NewMachineContinuationFromMachineContext creates a new machine continuation from the given machine context and an offset to the program counter. The new continuation inherits the environment, template, and evaluation stack from the machine context.

callDepth derivation: the new frame's parent is mc.cont, so its depth is derived from mc.cont's cached depth — NOT from mc.callDepth. These values differ because SaveContinuation pre-increments mc.callDepth before calling this function, but other callers do not:

  • SaveContinuation: mc.callDepth already incremented → mc.callDepth != chain length
  • PrimCallCC sub-context path (prim_control.go): mc.callDepth == 0, mc.cont == nil

Using mc.callDepth - 1 would underflow to -1 in the PrimCallCC case (mc.callDepth == 0). The parent-pointer formula is correct for all callers and immune to underflow.

func NewMachineContinuationWithPrompt

func NewMachineContinuationWithPrompt(parent *MachineContinuation, tpl *NativeTemplate, env *environment.EnvironmentFrame, tag *PromptTag, handler Closure) *MachineContinuation

NewMachineContinuationWithPrompt creates a continuation frame that acts as a continuation prompt. The tag identifies the prompt for abort/capture, and the handler is invoked when an abort reaches this prompt.

func (*MachineContinuation) CallDepth

func (p *MachineContinuation) CallDepth() int

CallDepth returns the depth of the continuation stack. The depth is cached in each frame at creation time, so this is O(1).

func (*MachineContinuation) Copy

func (*MachineContinuation) DeepCopy

DeepCopy creates a deep copy of the entire continuation chain. Each frame in the chain is copied, with parent pointers updated to point to the copied frames. This is needed for composable continuations which must be safely re-invoked multiple times.

func (*MachineContinuation) EnvironmentFrame

func (p *MachineContinuation) EnvironmentFrame() *environment.EnvironmentFrame

func (*MachineContinuation) EqualTo

func (p *MachineContinuation) EqualTo(o values.Value) bool

EqualTo compares by identity. A MachineContinuation is an internal continuation-chain node, never surfaced to Scheme equal?/eqv? (first-class continuations are *CapturedContinuation / *ComposableContinuation), so two distinct nodes are never "equal" in any observable sense. The former field-by-field comparison was structurally unsound (it mixed pointer-equal parent checks with value comparison of the rest) and effectively dead.

func (*MachineContinuation) GetValue

func (p *MachineContinuation) GetValue() values.Value

GetValue returns the first (or only) value from the value register. Returns Void if the register is empty.

func (*MachineContinuation) GetValues

func (p *MachineContinuation) GetValues() MultipleValues

GetValues returns all values from the value register as a MultipleValues slice. For the single-value case this allocates a one-element slice; callers on the hot path should use GetValue instead.

func (*MachineContinuation) IsVoid

func (p *MachineContinuation) IsVoid() bool

func (*MachineContinuation) MarkChainShared

func (p *MachineContinuation) MarkChainShared()

MarkChainShared marks every frame in the continuation chain as shared. Shared frames are not pooled by RestoreAndRelease — their evals are copied instead of transferred, preserving them for re-invocation.

Early-exits when a frame is already shared: all ancestors must already be shared from a prior capture (sharing propagates toward the root).

func (*MachineContinuation) PC

func (p *MachineContinuation) PC() int

func (*MachineContinuation) Parent

func (*MachineContinuation) PromptHandler

func (p *MachineContinuation) PromptHandler() Closure

func (*MachineContinuation) PromptTag

func (p *MachineContinuation) PromptTag() *PromptTag

func (*MachineContinuation) PushValues

func (p *MachineContinuation) PushValues(v ...values.Value)

PushValues appends values to the value register. If the register currently holds a single value, it is promoted to the multi-value representation before appending. This promote-then-append pattern avoids losing the existing single value when transitioning to the multi-value path.

Order matters: we nil singleValue *before* installing the promoted MultipleValues so the mutual-exclusion invariant is never violated, even in the intra-method transient window.

func (*MachineContinuation) SchemeString

func (p *MachineContinuation) SchemeString() string

func (*MachineContinuation) SetPC

func (p *MachineContinuation) SetPC(v int)

func (*MachineContinuation) SetPromptHandler

func (p *MachineContinuation) SetPromptHandler(h Closure)

func (*MachineContinuation) SetPromptTag

func (p *MachineContinuation) SetPromptTag(t *PromptTag)

func (*MachineContinuation) SetValue

func (p *MachineContinuation) SetValue(v values.Value)

SetValue stores a single value in the value register without allocating. This is the hot path: every LoadLocal, LoadGlobal, LoadLiteral, Pull, Pop, MakeClosure, etc. goes through here.

func (*MachineContinuation) SetValues

func (p *MachineContinuation) SetValues(vs ...values.Value)

SetValues sets the value register. Three paths:

  • len == 0: canonical empty state, both fields nil. Distinguishes the (nil, nil) empty register from (nil, []) which a naive 'multiValues = vs' would produce when vs is an empty-but-non-nil spread (e.g. SetValues(emptySlice...)).
  • len == 1: zero-allocation fast path via singleValue.
  • len > 1: fall back to the multiValues slice.

func (*MachineContinuation) Template

func (p *MachineContinuation) Template() *NativeTemplate

func (*MachineContinuation) ThreadID

func (p *MachineContinuation) ThreadID() uint64

type MacroEvaluator

type MacroEvaluator interface {
	// EvalTemplate evaluates a compiled template in the given environment
	// and returns the resulting value. Used by compileAndEvalLambdaTransformer
	// for define-syntax lambda transformers at compile time.
	EvalTemplate(ctx context.Context, tpl *NativeTemplate, env *environment.EnvironmentFrame) (values.Value, error)

	// InvokeTransformer calls a closure as a macro transformer.
	// expanderCtx is set on the VM context for auxiliary syntax
	// hygiene (R7RS Section 4.3.2); nil is valid when no hygiene context
	// is needed (e.g. ExpandOnce). args are passed to Apply — one arg for
	// syntax-rules/lambda transformers, three for ER macros (form, rename,
	// compare). On success, the caller receives the MachineContext with the
	// result in the value register and must call ReleaseSubContext when done.
	InvokeTransformer(ctx context.Context, cls Closure, expanderCtx ExpanderCtx, args ...values.Value) (*MachineContext, error)
}

MacroEvaluator abstracts VM execution for the compiler and expander so that compile-time evaluation and transformer invocation can be tested and wired without depending on the concrete MachineContext construction path.

func NewVMMacroEvaluator

func NewVMMacroEvaluator() MacroEvaluator

NewVMMacroEvaluator returns a MacroEvaluator backed by the real VM.

type MultipleValues

type MultipleValues []values.Value

MultipleValues represents multiple return values from a function.

func NewMultipleValues

func NewMultipleValues(values ...values.Value) MultipleValues

NewMultipleValues creates a new MultipleValues from the given values.

func (MultipleValues) Copy

func (p MultipleValues) Copy() MultipleValues

Copy creates a copy of the MultipleValues.

func (MultipleValues) EqualTo

func (p MultipleValues) EqualTo(o values.Value) bool

EqualTo checks if the MultipleValues is equal to another value.

func (MultipleValues) IsVoid

func (p MultipleValues) IsVoid() bool

IsVoid returns true if the MultipleValues represents 'void' - either

func (MultipleValues) Len

func (p MultipleValues) Len() int

Len returns the number of values in the MultipleValues.

func (MultipleValues) SchemeString

func (p MultipleValues) SchemeString() string

SchemeString returns the Scheme representation of the MultipleValues.

type NamedCallable

type NamedCallable interface {
	Name() string
	Doc() string
}

NamedCallable is implemented by callable values that carry a name and documentation string. MachineClosure, ForeignClosure, and CaseLambdaClosure all satisfy this interface.

type NativeTemplate

type NativeTemplate struct {
	// contains filtered or unexported fields
}

func NewEmptyNativeTemplate

func NewEmptyNativeTemplate() *NativeTemplate

NewEmptyNativeTemplate creates a new NativeTemplate with default empty parameters. This is used when a template is initialized without any known parameters or operations yet.

func NewNativeTemplate

func NewNativeTemplate(pcnt int, vcnt int, vd bool, operations ...Operation) *NativeTemplate

func (*NativeTemplate) AppendCachedBinding

func (p *NativeTemplate) AppendCachedBinding(bd *environment.Binding) int32

AppendCachedBinding adds a *Binding to the cached bindings array, deduplicating by pointer identity. Returns the index for use as an OpLoadCachedBinding/OpPushCachedBinding operand.

func (*NativeTemplate) AppendInstruction

func (p *NativeTemplate) AppendInstruction(instr Instruction)

AppendInstruction appends a single instruction with no source attribution.

func (*NativeTemplate) AppendInstructionWithSource

func (p *NativeTemplate) AppendInstructionWithSource(src *syntax.SourceContext, instr Instruction)

AppendInstructionWithSource appends a single instruction to the integer-dispatch bytecode and tags it with the given source context.

func (*NativeTemplate) AppendOperations

func (p *NativeTemplate) AppendOperations(ops ...Operation)

AppendOperations appends operations with no source attribution (index 0 = nil). Converts operations to instructions using AppendOperationsWithSource.

func (*NativeTemplate) AppendOperationsWithSource

func (p *NativeTemplate) AppendOperationsWithSource(src *syntax.SourceContext, ops ...Operation)

AppendOperationsWithSource converts operations to instructions and tags each with the given source. Wave 1-3 operations become direct switch cases; complex operations go through the sideTable and are dispatched via OpComplex. This is a public method for test use.

func (*NativeTemplate) AppendSideTableOp

func (p *NativeTemplate) AppendSideTableOp(op InlinedOperation) Instruction

AppendSideTableOp adds a complex operation to the side table and returns an OpComplex instruction that references it.

func (*NativeTemplate) CachedBindings

func (p *NativeTemplate) CachedBindings() []*environment.Binding

CachedBindings returns the compile-time resolved bindings array. Used by the disassembler to annotate binding references.

func (*NativeTemplate) Code

func (p *NativeTemplate) Code() []Instruction

Code returns the integer-dispatch bytecode slice.

func (*NativeTemplate) CodeLen

func (p *NativeTemplate) CodeLen() int

CodeLen returns the current code[] length (number of instructions emitted).

func (*NativeTemplate) Copy

func (p *NativeTemplate) Copy() *NativeTemplate

func (*NativeTemplate) DeduplicateLiteral

func (p *NativeTemplate) DeduplicateLiteral(v values.Value) values.Value

DeduplicateLiteral deduplicates the given value using the template's literal pool. For composite values (pairs and vectors), all elements are deduplicated recursively. Returns the deduplicated value.

func (*NativeTemplate) Doc

func (p *NativeTemplate) Doc() string

func (*NativeTemplate) EnableCoverage

func (p *NativeTemplate) EnableCoverage()

EnableCoverage allocates the per-PC executed array (if not already allocated) so the VM dispatch loop will record executions. Length is kept parallel to code via AppendInstruction. Idempotent: safe to call multiple times; an existing array is preserved.

func (*NativeTemplate) EqualTo

func (p *NativeTemplate) EqualTo(o values.Value) bool

func (*NativeTemplate) Executed

func (p *NativeTemplate) Executed() []bool

Executed returns the per-PC executed array, or nil if coverage is disabled. Returned slice aliases internal state; callers must not resize it.

func (*NativeTemplate) IncrementParameterCount

func (p *NativeTemplate) IncrementParameterCount()

IncrementParameterCount adds one to the parameter count.

func (*NativeTemplate) IsCoverageEnabled

func (p *NativeTemplate) IsCoverageEnabled() bool

IsCoverageEnabled reports whether coverage tracking is active on this template.

func (*NativeTemplate) IsVariadic

func (p *NativeTemplate) IsVariadic() bool

func (*NativeTemplate) IsVoid

func (p *NativeTemplate) IsVoid() bool

func (*NativeTemplate) Literals

func (p *NativeTemplate) Literals() MultipleValues

Literals returns the literals pool.

func (*NativeTemplate) MaybeAppendLiteral

func (p *NativeTemplate) MaybeAppendLiteral(v values.Value) LiteralIndex

func (*NativeTemplate) Name

func (p *NativeTemplate) Name() string

func (*NativeTemplate) Operations

func (p *NativeTemplate) Operations() Operations

Operations reconstructs the operation sequence from the bytecode. Converts Instructions back to Operation values for compatibility with existing code that expects Operations (e.g., tests, EqualTo).

func (*NativeTemplate) Optimize

func (p *NativeTemplate) Optimize()

Optimize performs a peephole optimization pass on the template's bytecode. It removes dead instructions identified by pattern-matching rules, fixes branch offsets to account for removed instructions, and compacts the code and source reference arrays in parallel.

Superinstruction formation (Ertl & Gregg 2003). Fusing adjacent instructions reduces dispatch overhead in the Run() switch loop.

Fusions:
  Load* + Push  → Push*       (eliminates 1 dispatch)
  Pull + Apply  → PullApply   (eliminates 1 dispatch)
  SaveCont + PushCachedBinding ... PullApply
              → CallForeignCached  (eliminates ~5 dispatches)

Cost model: each fusion saves one (fetch opcode + switch branch).
  In switch-dispatch interpreters, dispatch dominates execution time.

Invariant: fusions must not change observable semantics. Branch
  offsets are recomputed after compaction.
Constrains: Run() must implement fused opcodes with identical
  semantics to the original sequence.
Constrained by: must preserve semantic equivalence of fused
  instruction sequences.

See BIBLIOGRAPHY.md "Superinstruction Formation".

After compacting its own code, Optimize recurses into any *NativeTemplate values in the literals pool (lambda closures compiled as sub-templates).

Idempotent: a second call finds nothing to remove.

func (*NativeTemplate) ParameterCount

func (p *NativeTemplate) ParameterCount() int

func (*NativeTemplate) PatchInstructionArg

func (p *NativeTemplate) PatchInstructionArg(codeIdx int, arg int32)

PatchInstructionArg updates the Arg field of the instruction at code[codeIdx]. Used for patching branch offsets and continuation save offsets after the target PC is known.

func (*NativeTemplate) SchemeString

func (p *NativeTemplate) SchemeString() string

func (*NativeTemplate) SetDoc

func (p *NativeTemplate) SetDoc(doc string)

func (*NativeTemplate) SetName

func (p *NativeTemplate) SetName(name string)

func (*NativeTemplate) SetVariadic

func (p *NativeTemplate) SetVariadic()

SetVariadic marks this template as accepting a variadic rest argument.

func (*NativeTemplate) SideTable

func (p *NativeTemplate) SideTable() []InlinedOperation

SideTable returns the complex operations referenced by OpComplex instructions.

func (*NativeTemplate) SourceAt

func (p *NativeTemplate) SourceAt(pc int) *syntax.SourceContext

SourceAt returns the source location for the operation at pc. Returns nil if pc is out of bounds or no source was recorded. O(1) lookup via the parallel sourceRefs array.

func (*NativeTemplate) ValueCount

func (p *NativeTemplate) ValueCount() int

type OpCode

type OpCode uint16

OpCode is an integer opcode for the switch-dispatch VM loop. Operations migrated from interface dispatch to integer dispatch get a dedicated OpCode. Complex operations that remain as interface values use OpComplex with a side table index.

Adding a new opcode requires changes in:

  1. opcode.go — add OpXxx constant and entry in opcodeTable (name + metadata flags; operandKind must match step 3's extraction logic)
  2. machine_context.go Run() — add dispatch case in the main switch
  3. native_template.go — add a case in instructionToOperation() (always required) and in operationToInstruction() (required for operand-bearing ops; zero-operand ops fall through the default branch, which cross-checks opcodeTable[kind].operandKind == OperandNone)
  4. operation_xxx.go — create new operation type (or add to existing file)
  5. op_kind.go — add OpKind() returning the new OpCode (or compilation/op_kind.go for compilation/ types); for OpComplex types, also add a var _ InlinedOperation assertion
  6. compile_*.go — add compiler method to emit the new opcode
  7. Relevant _test.go files
  8. peephole.go — if the new op participates in fusion/chaining (e.g. loadToFusedPush)

For promoted primitive ops specifically, see the guide comment at the top of call_promoted.go — promoted ops have a different (smaller) set of edit sites.

const (
	OpInvalid OpCode = iota

	OpPush
	OpPop
	OpPull
	OpLoadVoid
	OpDrop
	OpPopEnv
	OpReleaseEnvFrame // Release the current (dead, pool-owned) env frame before a reclaimable tail call
	OpApply
	OpUnpackListToStack
	OpRestoreContinuation

	OpBranchOnFalseValue
	OpBranch
	OpSaveContinuation
	OpLoadLiteral
	OpLoadGlobal
	OpStoreGlobal
	OpPeekK
	OpPushEnv      // Push new env frame with Arg local slots
	OpSelfTailCall // Self-recursive tail call: rebind Arg param slots in place, pc=0

	OpLoadLocal
	OpStoreLocal

	OpPushLiteral // LoadLiteral + Push
	OpPushGlobal  // LoadGlobal + Push
	OpPushLocal   // LoadLocal + Push

	OpPullApply // Pull + Apply

	OpMakeClosure // MakeClosure (was OpComplex)

	OpLoadCachedBinding // Load from compile-time resolved *Binding
	OpPushCachedBinding // LoadCachedBinding + Push (fused)

	OpCallForeignCached     // Non-tail: call ForeignClosure, then mc.pc++
	OpCallForeignCachedTail // Tail: call ForeignClosure, then returnImmediate()

	OpCallLocal         // Resolve local binding, drain args, ApplyCallable
	OpCallCachedBinding // Resolve cached binding, drain args, ApplyCallable

	OpEqQ           // Non-tail inlined eq?
	OpEqQTail       // Tail inlined eq?
	OpVectorQ       // Non-tail inlined vector?
	OpVectorQTail   // Tail inlined vector?
	OpVectorRef     // Non-tail inlined vector-ref
	OpVectorRefTail // Tail inlined vector-ref
	OpNullQ         // Non-tail inlined null?
	OpNullQTail     // Tail inlined null?
	OpPairQ         // Non-tail inlined pair?
	OpPairQTail     // Tail inlined pair?
	OpCar           // Non-tail inlined car
	OpCarTail       // Tail inlined car
	OpCdr           // Non-tail inlined cdr
	OpCdrTail       // Tail inlined cdr
	OpAdd           // Non-tail inlined 2-arg +
	OpAddTail       // Tail inlined 2-arg +
	OpSub           // Non-tail inlined 2-arg -
	OpSubTail       // Tail inlined 2-arg -
	OpNumLt         // Non-tail inlined 2-arg <
	OpNumLtTail     // Tail inlined 2-arg <
	OpNumLe         // Non-tail inlined 2-arg <=
	OpNumLeTail     // Tail inlined 2-arg <=
	OpNumGt         // Non-tail inlined 2-arg >
	OpNumGtTail     // Tail inlined 2-arg >
	OpNumGe         // Non-tail inlined 2-arg >=
	OpNumGeTail     // Tail inlined 2-arg >=
	OpNumEq         // Non-tail inlined 2-arg =
	OpNumEqTail     // Tail inlined 2-arg =
	OpCons          // Non-tail inlined cons
	OpConsTail      // Tail inlined cons
	OpMul           // Non-tail inlined 2-arg *
	OpMulTail       // Tail inlined 2-arg *
	OpDiv           // Non-tail inlined 2-arg /
	OpDivTail       // Tail inlined 2-arg /

	OpComplex
)

func (OpCode) String

func (op OpCode) String() string

String returns the human-readable name of the opcode.

type OperandKind

type OperandKind uint8

OperandKind classifies what an opcode's Arg field means. Used by cold-path consumers (Disassemble, instructionToOperation) to avoid re-deriving operand semantics in per-opcode switch branches.

const (
	// OperandNone means Arg is unused (zero-operand ops).
	OperandNone OperandKind = iota
	// OperandRaw means Arg is a meaningful integer but needs no resolution
	// (e.g., PushEnv slot count, PeekK depth).
	OperandRaw
	// OperandLiteralIdx means Arg indexes into the literals pool.
	OperandLiteralIdx
	// OperandLocalIdx means Arg is a bit-packed (slot, depth) pair.
	OperandLocalIdx
	// OperandBranchOffset means Arg is a relative PC offset.
	OperandBranchOffset
	// OperandCachedBinding means Arg indexes into cachedBindings.
	OperandCachedBinding
	// OperandSideTable means Arg indexes into the side table.
	OperandSideTable
)

type Operation

type Operation interface {
	values.Value
	OpKind() OpCode
}

Operation is the base interface for all bytecode operations. Every operation is also a values.Value so it can appear in the literals pool and be printed. Operations that are inlined into the Run() switch loop only need this base interface. Operations dispatched through the side table (OpComplex) must additionally implement InlinedOperation.

OpKind reports the OpCode the operation encodes to. For operations that have a dedicated opcode in the main Run() switch, OpKind returns that opcode. For operations dispatched via the side table, OpKind returns OpComplex. This is the discriminator the compiler consults in operationToInstruction; placing it on the interface lets each type carry its dispatch identity rather than re-deriving it via a central type switch.

type OperationApply

type OperationApply struct {
	OperationBase
}

OperationApply is the bytecode operation that dispatches procedure calls. The compiler emits it after pushing arguments onto the eval stack and placing the callee in the value register. Apply pops all arguments and delegates to MachineContext.ApplyCallable, which handles the five callable types (MachineClosure, ForeignClosure, CaseLambdaClosure, Parameter, ComposableContinuation).

func NewOperationApply

func NewOperationApply() *OperationApply

NewOperationApply returns a new apply operation.

func (*OperationApply) EqualTo

func (p *OperationApply) EqualTo(o values.Value) bool

EqualTo returns true if o is also an OperationApply (identity by type).

func (*OperationApply) OpKind

func (*OperationApply) OpKind() OpCode

type OperationBase

type OperationBase struct {
	// contains filtered or unexported fields
}

OperationBase provides default SchemeString, IsVoid, and String methods for VM operations. Embed as the first field in operation structs. EqualTo is intentionally not provided: Go requires per-type assertions.

func NewOperationBase

func NewOperationBase(opName string) OperationBase

NewOperationBase creates an OperationBase with the given Scheme name. The name is used as: "#<" + opName + ">".

func NewOperationBaseWithGoName

func NewOperationBaseWithGoName(opName, goName string) OperationBase

NewOperationBaseWithGoName creates an OperationBase with both a Scheme name and a separate Go fmt.Stringer name.

func (OperationBase) IsVoid

func (p OperationBase) IsVoid() bool

IsVoid returns false; operations are never void. Unlike other values.Value implementations, this does not handle nil receivers — operations are bytecode instructions constructed by the compiler and stored in NativeTemplate slices; they are never nil.

func (OperationBase) SchemeString

func (p OperationBase) SchemeString() string

SchemeString returns the Scheme representation of the operation.

func (OperationBase) String

func (p OperationBase) String() string

String returns the Go string representation of the operation.

type OperationBoxValues

type OperationBoxValues struct {
	OperationBase
}

OperationBoxValues collapses the value register (0, 1, or N values) into a single boxedValuesType carrier left in the value register. A following OpPush then saves it as exactly one eval-stack slot, so callers that must preserve a multiple-value result across an intervening call (dynamic-wind's after-thunk) keep a fixed one-slot footprint regardless of value count. Paired with OperationUnboxValues.

Pre: value register = v1 … vN Post: value register = a boxed-values carrier holding v1 … vN, pc++

(the carrier prints as #<boxed-values>; it never escapes to Scheme)

func NewOperationBoxValues

func NewOperationBoxValues() *OperationBoxValues

func (*OperationBoxValues) Apply

func (*OperationBoxValues) EqualTo

func (p *OperationBoxValues) EqualTo(o values.Value) bool

func (*OperationBoxValues) OpKind

func (*OperationBoxValues) OpKind() OpCode

type OperationBranchOffsetImmediate

type OperationBranchOffsetImmediate struct {
	OperationBase
	Offset int
}

func NewOperationBranchOffsetImmediate

func NewOperationBranchOffsetImmediate(offset int) *OperationBranchOffsetImmediate

func (*OperationBranchOffsetImmediate) EqualTo

func (*OperationBranchOffsetImmediate) OpKind

func (*OperationBranchOffsetImmediate) SchemeString

func (p *OperationBranchOffsetImmediate) SchemeString() string

SchemeString overrides OperationBase to include offset value.

type OperationBranchOnFalseValueOffsetImmediate

type OperationBranchOnFalseValueOffsetImmediate struct {
	OperationBase
	Offset int
}

OperationBranchOnFalseValueOffsetImmediate branches if the value register is #f. This reads directly from the value register instead of popping from the eval stack, eliminating the Push instruction that would otherwise be needed.

Peephole optimization (Aho et al., Compilers §8.9): examines a small window of generated instructions and replaces inefficient patterns. Here, the Push+BranchOnFalse+Pop sequence is replaced with a single BranchOnFalseValue that reads the value register directly. See BIBLIOGRAPHY.md "Peephole Optimization".

func NewOperationBranchOnFalseValueOffsetImmediate

func NewOperationBranchOnFalseValueOffsetImmediate(offset int) *OperationBranchOnFalseValueOffsetImmediate

func (*OperationBranchOnFalseValueOffsetImmediate) EqualTo

func (*OperationBranchOnFalseValueOffsetImmediate) OpKind

func (*OperationBranchOnFalseValueOffsetImmediate) SchemeString

SchemeString overrides OperationBase to include offset value.

type OperationDrop

type OperationDrop struct {
	OperationBase
}

OperationDrop removes the top value from the eval stack without affecting the value register. This is used when we need to clean up the stack but preserve the current result.

func NewOperationDrop

func NewOperationDrop() *OperationDrop

func (*OperationDrop) EqualTo

func (p *OperationDrop) EqualTo(o values.Value) bool

func (*OperationDrop) OpKind

func (*OperationDrop) OpKind() OpCode

type OperationForeignFunctionCall

type OperationForeignFunctionCall struct {
	OperationBase
	Function ForeignFunction
}

OperationForeignFunctionCall executes a Go function within the VM loop. Used for foreign closures that do nested VM execution (sub-context + Run), where the iterative VM loop prevents Go stack growth. Leaf primitives use ForeignClosure + applyForeign instead.

func NewOperationForeignFunctionCall

func NewOperationForeignFunctionCall(ffn ForeignFunction) *OperationForeignFunctionCall

func (*OperationForeignFunctionCall) Apply

func (*OperationForeignFunctionCall) EqualTo

func (*OperationForeignFunctionCall) OpKind

type OperationLoadCachedBinding

type OperationLoadCachedBinding struct {
	OperationBase
	BindingIndex int32
}

OperationLoadCachedBinding loads a global variable from a compile-time resolved *Binding pointer, bypassing the runtime environment lookup path used by OpLoadGlobal.

func NewOperationLoadCachedBinding

func NewOperationLoadCachedBinding(idx int32) *OperationLoadCachedBinding

NewOperationLoadCachedBinding creates a new cached binding load operation.

func (*OperationLoadCachedBinding) EqualTo

EqualTo returns true if both operations have the same binding index.

func (*OperationLoadCachedBinding) OpKind

func (*OperationLoadCachedBinding) SchemeString

func (p *OperationLoadCachedBinding) SchemeString() string

SchemeString returns the Scheme representation of the operation.

type OperationLoadGlobalByGlobalIndexLiteralIndexImmediate

type OperationLoadGlobalByGlobalIndexLiteralIndexImmediate struct {
	OperationBase
	LiteralIndex LiteralIndex
}

OperationLoadGlobalByGlobalIndexLiteralIndexImmediate loads a global variable using an index from the literals pool.

func NewOperationLoadGlobalByGlobalIndexLiteralIndexImmediate

func NewOperationLoadGlobalByGlobalIndexLiteralIndexImmediate(li LiteralIndex) *OperationLoadGlobalByGlobalIndexLiteralIndexImmediate

NewOperationLoadGlobalByGlobalIndexLiteralIndexImmediate creates a new global load operation.

func (*OperationLoadGlobalByGlobalIndexLiteralIndexImmediate) EqualTo

EqualTo returns true if both operations have the same literal index.

func (*OperationLoadGlobalByGlobalIndexLiteralIndexImmediate) OpKind

func (*OperationLoadGlobalByGlobalIndexLiteralIndexImmediate) SchemeString

SchemeString returns the Scheme representation of the operation.

type OperationLoadLiteralByLiteralIndexImmediate

type OperationLoadLiteralByLiteralIndexImmediate struct {
	OperationBase
	LiteralIndex LiteralIndex
}

OperationLoadLiteralByLiteralIndexImmediate loads a literal value from the literals pool.

func NewOperationLoadLiteralByLiteralIndexImmediate

func NewOperationLoadLiteralByLiteralIndexImmediate(li LiteralIndex) *OperationLoadLiteralByLiteralIndexImmediate

NewOperationLoadLiteralByLiteralIndexImmediate creates a new literal load operation.

func (*OperationLoadLiteralByLiteralIndexImmediate) EqualTo

EqualTo returns true if both operations have the same literal index.

func (*OperationLoadLiteralByLiteralIndexImmediate) OpKind

func (*OperationLoadLiteralByLiteralIndexImmediate) SchemeString

SchemeString returns the Scheme representation of the operation.

type OperationLoadLocalByLocalIndexImmediate

type OperationLoadLocalByLocalIndexImmediate struct {
	OperationBase
	LocalIndex *environment.LocalIndex
}

func (*OperationLoadLocalByLocalIndexImmediate) EqualTo

func (*OperationLoadLocalByLocalIndexImmediate) OpKind

func (*OperationLoadLocalByLocalIndexImmediate) SchemeString

type OperationLoadVoid

type OperationLoadVoid struct {
	OperationBase
}

func NewOperationLoadVoid

func NewOperationLoadVoid() *OperationLoadVoid

func (*OperationLoadVoid) EqualTo

func (p *OperationLoadVoid) EqualTo(o values.Value) bool

func (*OperationLoadVoid) OpKind

func (*OperationLoadVoid) OpKind() OpCode

type OperationMakeCaseLambdaClosure

type OperationMakeCaseLambdaClosure struct {
	OperationBase
	// contains filtered or unexported fields
}

OperationMakeCaseLambdaClosure creates a case-lambda closure from multiple closures. Stack layout (top to bottom): closure_n, closure_n-1, ..., closure_1 The closureCount immediate specifies how many closures to pop.

func NewOperationMakeCaseLambdaClosure

func NewOperationMakeCaseLambdaClosure(closureCount int) *OperationMakeCaseLambdaClosure

func (*OperationMakeCaseLambdaClosure) Apply

func (*OperationMakeCaseLambdaClosure) EqualTo

func (*OperationMakeCaseLambdaClosure) OpKind

type OperationMakeClosure

type OperationMakeClosure struct {
	OperationBase
}

func NewOperationMakeClosure

func NewOperationMakeClosure() *OperationMakeClosure

func (*OperationMakeClosure) Apply

func (*OperationMakeClosure) EqualTo

func (p *OperationMakeClosure) EqualTo(o values.Value) bool

func (*OperationMakeClosure) OpKind

func (*OperationMakeClosure) OpKind() OpCode

OpKind returns OpMakeClosure.

OperationMakeClosure is the only Op type that both has a dedicated opcode (OpMakeClosure) and implements Apply. The Apply method is vestigial in production -- the compiler emits OpMakeClosure directly, routing through the Run() switch case rather than the side table.

Apply is preserved so OperationMakeClosure satisfies InlinedOperation, allowing TestEditPlan_SideTableGC (edit_plan_test.go:320) to use it as a no-arg placeholder when populating tpl.sideTable. That test asserts only GC remapping of indices and never invokes Apply itself, so the production and test code paths are decoupled. If Apply's body is ever changed, the matching OpMakeClosure inline case in machine_context.go's Run() must be updated to keep production and test behavior consistent (or Apply should be removed and the test migrated to use testInlinedOp from machine_context_test.go:1374).

type OperationPeekK

type OperationPeekK struct {
	OperationBase
	Depth int
}

func NewOperationPeekK

func NewOperationPeekK(depth int) *OperationPeekK

func (*OperationPeekK) EqualTo

func (p *OperationPeekK) EqualTo(o values.Value) bool

func (*OperationPeekK) OpKind

func (*OperationPeekK) OpKind() OpCode

func (*OperationPeekK) SchemeString

func (p *OperationPeekK) SchemeString() string

SchemeString overrides OperationBase to include depth value.

type OperationPop

type OperationPop struct {
	OperationBase
}

func NewOperationPop

func NewOperationPop() *OperationPop

func (*OperationPop) EqualTo

func (p *OperationPop) EqualTo(o values.Value) bool

func (*OperationPop) OpKind

func (*OperationPop) OpKind() OpCode

type OperationPopEnv

type OperationPopEnv struct {
	OperationBase
}

OperationPopEnv unconditionally restores the parent environment. It pops one level from the environment chain (restoring the parent environment).

This is used in syntax-case fender evaluation to restore the environment when the fender returns false, before branching to the next clause.

func NewOperationPopEnv

func NewOperationPopEnv() *OperationPopEnv

func (*OperationPopEnv) EqualTo

func (p *OperationPopEnv) EqualTo(other values.Value) bool

func (*OperationPopEnv) OpKind

func (*OperationPopEnv) OpKind() OpCode

type OperationPopWind

type OperationPopWind struct {
	OperationBase
}

OperationPopWind pops the innermost dynamic-wind frame from the winding stack. This operation does NOT call the after thunk - that is done explicitly in the bytecode stream to ensure proper continuation semantics.

The frame is simply removed from the winding stack. If a continuation captured inside the dynamic extent is later restored, the RestoreWithWinding mechanism will handle running the appropriate before/after thunks.

R7RS §6.10: dynamic-wind establishes a dynamic extent during which the before and after thunks are called whenever control enters or exits.

func NewOperationPopWind

func NewOperationPopWind() *OperationPopWind

func (*OperationPopWind) Apply

func (*OperationPopWind) EqualTo

func (p *OperationPopWind) EqualTo(o values.Value) bool

func (*OperationPopWind) OpKind

func (*OperationPopWind) OpKind() OpCode

type OperationPull

type OperationPull struct {
	OperationBase
}

func NewOperationPull

func NewOperationPull() *OperationPull

func (*OperationPull) EqualTo

func (p *OperationPull) EqualTo(o values.Value) bool

func (*OperationPull) OpKind

func (*OperationPull) OpKind() OpCode

type OperationPush

type OperationPush struct {
	OperationBase
}

func NewOperationPush

func NewOperationPush() *OperationPush

func (*OperationPush) EqualTo

func (p *OperationPush) EqualTo(o values.Value) bool

func (*OperationPush) OpKind

func (*OperationPush) OpKind() OpCode

type OperationPushEnv

type OperationPushEnv struct {
	OperationBase
	SlotCount int
}

OperationPushEnv allocates a new environment frame with the specified number of local binding slots and chains it to the current environment. Paired with OpPopEnv which restores the parent.

func NewOperationPushEnv

func NewOperationPushEnv(slotCount int) *OperationPushEnv

func (*OperationPushEnv) EqualTo

func (p *OperationPushEnv) EqualTo(other values.Value) bool

func (*OperationPushEnv) OpKind

func (*OperationPushEnv) OpKind() OpCode

type OperationPushWind

type OperationPushWind struct {
	OperationBase
}

OperationPushWind creates a dynamic-wind frame and pushes it onto the winding stack. It expects the stack to contain [before, thunk, after] where:

  • before is at PeekK(2) - the before thunk
  • thunk is at PeekK(1) - the main thunk (not used by this operation)
  • after is at PeekK(0) - the after thunk

The frame is created from the before and after closures and pushed onto the winding stack. The stack is not modified.

R7RS §6.10: dynamic-wind establishes a dynamic extent during which the before and after thunks are called whenever control enters or exits.

func NewOperationPushWind

func NewOperationPushWind() *OperationPushWind

func (*OperationPushWind) Apply

func (*OperationPushWind) EqualTo

func (p *OperationPushWind) EqualTo(o values.Value) bool

func (*OperationPushWind) OpKind

func (*OperationPushWind) OpKind() OpCode

type OperationReleaseEnvFrame

type OperationReleaseEnvFrame struct {
	OperationBase
}

OperationReleaseEnvFrame releases the current pool-owned env frame back to the FreeList immediately before a tail call in a frame-releasable body (no capture, no escaping closure, only capture-safe callees). The frame is dead at this point — the tail call's args are already on the eval stack — so the next acquire reuses it, giving O(1) steady-state frame allocation for fib-shaped recursion. A no-op when the frame is not pool-owned (parentless thunk, continuation-shared).

func NewOperationReleaseEnvFrame

func NewOperationReleaseEnvFrame() *OperationReleaseEnvFrame

NewOperationReleaseEnvFrame returns a release-env-frame op.

func (*OperationReleaseEnvFrame) EqualTo

func (p *OperationReleaseEnvFrame) EqualTo(o values.Value) bool

EqualTo returns true if o is also an OperationReleaseEnvFrame (identity by type).

func (*OperationReleaseEnvFrame) OpKind

func (*OperationReleaseEnvFrame) OpKind() OpCode

type OperationRestoreContMark

type OperationRestoreContMark struct {
	OperationBase
}

OperationRestoreContMark restores the previous mark value after body evaluation. Paired with OperationSaveContMark.

Pre: eval stack = [..., key, old_val_or_sentinel] Post: eval stack = [...], marks[key] restored or deleted, pc++

func NewOperationRestoreContMark

func NewOperationRestoreContMark() *OperationRestoreContMark

func (*OperationRestoreContMark) Apply

func (*OperationRestoreContMark) EqualTo

func (p *OperationRestoreContMark) EqualTo(o values.Value) bool

func (*OperationRestoreContMark) OpKind

func (*OperationRestoreContMark) OpKind() OpCode

type OperationRestoreContinuation

type OperationRestoreContinuation struct {
	OperationBase
}

func NewOperationRestoreContinuation

func NewOperationRestoreContinuation() *OperationRestoreContinuation

func (*OperationRestoreContinuation) EqualTo

func (*OperationRestoreContinuation) OpKind

type OperationSaveContMark

type OperationSaveContMark struct {
	OperationBase
}

OperationSaveContMark saves the previous mark value and sets a new one. Used in non-tail position, paired with OperationRestoreContMark.

Pre: eval stack = [..., key], value register = val Post: eval stack = [..., key, old_val_or_sentinel], marks[key] = val, pc++

func NewOperationSaveContMark

func NewOperationSaveContMark() *OperationSaveContMark

func (*OperationSaveContMark) Apply

func (*OperationSaveContMark) EqualTo

func (p *OperationSaveContMark) EqualTo(o values.Value) bool

func (*OperationSaveContMark) OpKind

func (*OperationSaveContMark) OpKind() OpCode

type OperationSaveContinuationOffsetImmediate

type OperationSaveContinuationOffsetImmediate struct {
	OperationBase
	Offset int
}

func NewOperationSaveContinuationOffsetImmediate

func NewOperationSaveContinuationOffsetImmediate(off int) *OperationSaveContinuationOffsetImmediate

func (*OperationSaveContinuationOffsetImmediate) EqualTo

func (*OperationSaveContinuationOffsetImmediate) OpKind

func (*OperationSaveContinuationOffsetImmediate) SchemeString

SchemeString overrides OperationBase to include offset value.

type OperationSelfTailCall

type OperationSelfTailCall struct {
	OperationBase
	ArgCount int
}

OperationSelfTailCall is the in-place self-recursive tail call: it drains the ArgCount already-evaluated argument values off the eval stack, writes them into the current frame's parameter slots 0..ArgCount-1 (parallel assignment — the args are on the stack, so old slot values stay intact during evaluation), and resets pc=0. No frame acquire, no SaveContinuation, no continuation growth.

Emitted only behind validate.bodyIsSelfTailReusable + a depth-0 self-tail call site; that proof (no capture, no escaping closure, non-variadic) is what makes reusing the live frame sound (escape-gated plan Phase 4).

func NewOperationSelfTailCall

func NewOperationSelfTailCall(argCount int) *OperationSelfTailCall

NewOperationSelfTailCall returns a self-tail-call op rebinding argCount slots.

func (*OperationSelfTailCall) EqualTo

func (p *OperationSelfTailCall) EqualTo(o values.Value) bool

EqualTo returns true if o is also an OperationSelfTailCall with the same arity.

func (*OperationSelfTailCall) OpKind

func (*OperationSelfTailCall) OpKind() OpCode

type OperationSetContMark

type OperationSetContMark struct {
	OperationBase
}

OperationSetContMark sets a continuation mark on the current frame. Used in tail position where no restore is needed.

Pre: eval stack = [..., key], value register = val Post: eval stack = [...], marks[key] = val, pc++

func NewOperationSetContMark

func NewOperationSetContMark() *OperationSetContMark

func (*OperationSetContMark) Apply

func (*OperationSetContMark) EqualTo

func (p *OperationSetContMark) EqualTo(o values.Value) bool

func (*OperationSetContMark) OpKind

func (*OperationSetContMark) OpKind() OpCode

type OperationStoreGlobalByGlobalIndexLiteralIndexImmediate

type OperationStoreGlobalByGlobalIndexLiteralIndexImmediate struct {
	OperationBase
	LiteralIndex LiteralIndex
}

OperationStoreGlobalByGlobalIndexLiteralIndexImmediate stores a value to a global variable using an index from the literals pool.

func NewOperationStoreGlobalByGlobalIndexLiteralIndexImmediate

func NewOperationStoreGlobalByGlobalIndexLiteralIndexImmediate(liti LiteralIndex) *OperationStoreGlobalByGlobalIndexLiteralIndexImmediate

NewOperationStoreGlobalByGlobalIndexLiteralIndexImmediate creates a new global store operation.

func (*OperationStoreGlobalByGlobalIndexLiteralIndexImmediate) EqualTo

func (*OperationStoreGlobalByGlobalIndexLiteralIndexImmediate) OpKind

func (*OperationStoreGlobalByGlobalIndexLiteralIndexImmediate) SchemeString

SchemeString returns the Scheme representation of the operation.

type OperationStoreLocalByLocalIndexImmediate

type OperationStoreLocalByLocalIndexImmediate struct {
	OperationBase
	LocalIndex *environment.LocalIndex
}

func (*OperationStoreLocalByLocalIndexImmediate) EqualTo

func (*OperationStoreLocalByLocalIndexImmediate) OpKind

func (*OperationStoreLocalByLocalIndexImmediate) SchemeString

type OperationUnboxValues

type OperationUnboxValues struct {
	OperationBase
}

OperationUnboxValues expands a boxedValuesType carrier in the value register back into the value register's 0/1/N values (the inverse of OperationBoxValues). A preceding OpPeekK loads the carrier into the value register; this op replaces it with the boxed values.

Pre: value register = a boxed-values carrier holding v1 … vN Post: value register = v1 … vN, pc++

func NewOperationUnboxValues

func NewOperationUnboxValues() *OperationUnboxValues

func (*OperationUnboxValues) Apply

func (*OperationUnboxValues) EqualTo

func (p *OperationUnboxValues) EqualTo(o values.Value) bool

func (*OperationUnboxValues) OpKind

func (*OperationUnboxValues) OpKind() OpCode

type OperationUnpackListToStack

type OperationUnpackListToStack struct {
	OperationBase
}

OperationUnpackListToStack reads a proper list from the value register and pushes each element to the eval stack in order. Used by compiled (apply proc arg1 ... args) to flatten the final arg list onto the stack before Pull + OpApply.

Errors if the value is not a proper list (improper list or non-list).

func NewOperationUnpackListToStack

func NewOperationUnpackListToStack() *OperationUnpackListToStack

NewOperationUnpackListToStack returns a new unpack-list-to-stack operation.

func (*OperationUnpackListToStack) EqualTo

EqualTo returns true if o is also an OperationUnpackListToStack (identity by type).

func (*OperationUnpackListToStack) OpKind

type Operations

type Operations []Operation

func NewOperations

func NewOperations(ops ...Operation) Operations

func (Operations) AsList

func (p Operations) AsList() values.Tuple

func (Operations) Copy

func (p Operations) Copy() Operations

func (Operations) EqualTo

func (p Operations) EqualTo(o values.Value) bool

func (Operations) IsVoid

func (p Operations) IsVoid() bool

func (Operations) Len

func (p Operations) Len() int

func (Operations) SchemeString

func (p Operations) SchemeString() string

type Parameter

type Parameter struct {
	// contains filtered or unexported fields
}

Parameter represents an R7RS parameter object. Parameters are dynamically-scoped variables that can be temporarily rebound using parameterize. They act as procedures:

  • (param) returns the current value
  • (param val) sets the current value (after applying converter if present)

func NewParameter

func NewParameter(init values.Value, converter Closure) *Parameter

NewParameter creates a new parameter with the given initial value and optional converter. The converter should be a procedure that takes one argument and returns the converted value. Pass nil for converter if no conversion is needed.

func (*Parameter) AcceptsArity

func (p *Parameter) AcceptsArity(n int) bool

AcceptsArity reports whether this parameter can be called with n arguments. Parameters accept 0 args (get current value) or 1 arg (set value).

func (*Parameter) Converter

func (p *Parameter) Converter() Closure

Converter returns the converter procedure, or nil if none.

func (*Parameter) EqualTo

func (p *Parameter) EqualTo(v values.Value) bool

EqualTo uses identity comparison for parameters. Two parameters are equal only if they are the same object.

func (*Parameter) HasConverter

func (p *Parameter) HasConverter() bool

HasConverter returns true if the parameter has a converter procedure.

func (*Parameter) IsVoid

func (p *Parameter) IsVoid() bool

IsVoid returns true if the parameter is nil.

func (*Parameter) SchemeString

func (p *Parameter) SchemeString() string

SchemeString returns the Scheme representation of the parameter.

func (*Parameter) SetValue

func (p *Parameter) SetValue(v values.Value)

SetValue sets the current value of the parameter. Note: This does NOT apply the converter. The caller is responsible for converting the value before calling SetValue.

func (*Parameter) Value

func (p *Parameter) Value() values.Value

Value returns the current value of the parameter.

type Pool

type Pool[T any] struct {
	// contains filtered or unexported fields
}

Pool is a type-safe, observable object pool backed by sync.Pool. It wraps sync.Pool with atomic counters (acquires, releases, misses) and an enable/disable toggle for debugging or benchmarking.

func NewPool

func NewPool[T any](name string, newFn func() *T, resetFn func(*T)) *Pool[T]

NewPool creates a Pool[T] with the given name, constructor, and reset function. The pool starts enabled.

func (*Pool[T]) Acquire

func (p *Pool[T]) Acquire() *T

Acquire returns an object from the pool. If the pool is disabled, it calls newFn directly (bypassing sync.Pool).

func (*Pool[T]) Drain

func (p *Pool[T]) Drain()

Drain is a no-op on individual pools. Use PoolManager.DrainAll to trigger a GC-assisted drain across all pools.

func (*Pool[T]) Name

func (p *Pool[T]) Name() string

Name returns the pool's name.

func (*Pool[T]) Release

func (p *Pool[T]) Release(v *T)

Release resets the object and returns it to the pool. If the pool is disabled, the object is discarded after reset.

func (*Pool[T]) SetEnabled

func (p *Pool[T]) SetEnabled(on bool)

SetEnabled toggles the pool on or off. When disabled, Acquire calls newFn directly and Release discards after reset, useful for benchmarking or debugging.

func (*Pool[T]) Stats

func (p *Pool[T]) Stats() PoolSnapshot

Stats returns a point-in-time snapshot of the pool's counters.

type PoolHandle

type PoolHandle interface {
	Name() string
	Stats() PoolSnapshot
	Drain()
	SetEnabled(bool)
}

PoolHandle is the type-erased interface that PoolManager uses to observe and control heterogeneous pools.

type PoolManager

type PoolManager struct {
	// contains filtered or unexported fields
}

PoolManager tracks a collection of PoolHandle instances for unified observation and control.

func NewPoolManager

func NewPoolManager() *PoolManager

NewPoolManager creates an empty PoolManager.

func (*PoolManager) AllStats

func (p *PoolManager) AllStats() []PoolSnapshot

AllStats returns a snapshot of every registered pool's counters.

func (*PoolManager) DrainAll

func (p *PoolManager) DrainAll()

DrainAll triggers a garbage collection, which clears all sync.Pool instances, then calls Drain on each registered pool.

func (*PoolManager) Register

func (p *PoolManager) Register(h PoolHandle)

Register adds a pool to the manager.

func (*PoolManager) SetAllEnabled

func (p *PoolManager) SetAllEnabled(on bool)

SetAllEnabled sets the enabled flag on every registered pool.

func (*PoolManager) String

func (p *PoolManager) String() string

String returns a tabular summary of all registered pools.

type PoolSnapshot

type PoolSnapshot struct {
	Name     string
	Acquires uint64
	Releases uint64
	Misses   uint64
	InFlight uint64
}

PoolSnapshot is a point-in-time view of a pool's counters.

type PromptTag

type PromptTag struct {
	// contains filtered or unexported fields
}

PromptTag is an opaque identity value for delimited continuation prompts. Equality is pointer identity (each tag is unique). Follows the Racket model of continuation prompt tags.

See: Flatt, Yu, Findler, Felleisen "Adding Delimited and Composable Control to a Production Programming Environment" (ICFP 2007).

func NewPromptTag

func NewPromptTag(name string) *PromptTag

NewPromptTag creates a new prompt tag with an optional name for debugging.

func (*PromptTag) EqualTo

func (p *PromptTag) EqualTo(o values.Value) bool

func (*PromptTag) IsVoid

func (p *PromptTag) IsVoid() bool

func (*PromptTag) SchemeString

func (p *PromptTag) SchemeString() string

type SchemeError

type SchemeError struct {
	Message    string
	Source     *syntax.SourceContext // Where error occurred
	StackTrace string                // Formatted stack trace
	Cause      error                 // Underlying error (if any)
}

SchemeError is a runtime error with Scheme-level stack trace.

func NewSchemeError

func NewSchemeError(msg string, source *syntax.SourceContext, stackTrace string) *SchemeError

func NewSchemeErrorWithCause

func NewSchemeErrorWithCause(msg string, source *syntax.SourceContext, stackTrace string, cause error) *SchemeError

func (*SchemeError) EqualTo

func (p *SchemeError) EqualTo(o values.Value) bool

EqualTo compares for equality.

func (*SchemeError) Error

func (p *SchemeError) Error() string

func (*SchemeError) IsVoid

func (p *SchemeError) IsVoid() bool

IsVoid returns false (errors are not void).

func (*SchemeError) SchemeString

func (p *SchemeError) SchemeString() string

SchemeString returns the Scheme representation.

func (*SchemeError) Unwrap

func (p *SchemeError) Unwrap() error

type Stack

type Stack values.Vector

func NewStack

func NewStack(vs ...values.Value) *Stack

NewStack creates a new stack with the given initial values.

func (Stack) AsList

func (p Stack) AsList() values.Tuple

AsList converts the stack to a Scheme list (values.Tuple). The list is in stack order (first pushed = first element).

func (*Stack) Clear

func (p *Stack) Clear()

Clear removes all elements from the stack.

func (Stack) Copy

func (p Stack) Copy() *Stack

Copy creates a shallow copy of the stack.

func (*Stack) Drain

func (p *Stack) Drain() []values.Value

Drain returns a view of all stack elements and resets the stack to empty. The returned slice shares the stack's backing array — it is valid only until the next mutation (Push, PushAll, or any append). Callers must finish reading before any stack mutation.

Unlike PopAll (which copies into a new slice), Drain is zero-allocation. Use Drain when the caller consumes values immediately (e.g., binding arguments in Apply); use PopAll when the caller needs to own the slice.

func (*Stack) DrainN

func (p *Stack) DrainN(n int) []values.Value

DrainN returns the top n values (in stack order: first-pushed first) and removes them, leaving any values beneath them on the stack. Like Drain it returns a non-allocating view, not a copy — the caller must consume it before pushing. A request larger than the stack panics with a wrapped sentinel rather than letting a downstream index run out of range. Used by OpSelfTailCall, which must consume exactly the call's argument count and never silently discard anything beneath it.

func (Stack) IsVoid

func (p Stack) IsVoid() bool

IsVoid returns true if the stack is nil.

func (Stack) Len

func (p Stack) Len() int

Len returns the number of elements in the stack.

func (Stack) PeekK

func (p Stack) PeekK(i int) values.Value

PeekK returns the kth value from the top of the stack without removing it. `K` is zero-based, so PeekK(0) returns the top value. `K` is used for methods that need a numeric index.

func (*Stack) Pop

func (p *Stack) Pop() values.Value

Pop removes and returns the top value from the stack.

func (*Stack) Pop2

func (p *Stack) Pop2() (q0, q1 values.Value)

Pop2 removes and returns the top two values from the stack. q0 is the top-most value (popped first), q1 is the value beneath it. It checks the length once and is equivalent to two successive Pop() calls.

func (*Stack) PopAll

func (p *Stack) PopAll() []values.Value

PopAll removes and returns all values from the stack. The caller gets exclusive ownership of the returned slice. The stack retains its backing array for reuse (avoids re-allocation on subsequent pushes). References in the retained portion are cleared so the GC can collect the values.

func (*Stack) PopN

func (p *Stack) PopN(n int) []values.Value

PopN removes and returns the top n values from the stack. Values are returned in stack order (top-most element last). This is more efficient than calling Pop() n times.

func (*Stack) Pull

func (p *Stack) Pull() values.Value

Pull removes and returns the bottom value from the stack. In the SECD model (Landin 1964), the procedure is evaluated first but needed last. Pull retrieves it from the bottom after all arguments have been pushed on top. See BIBLIOGRAPHY.md "Stack-Based Virtual Machines".

func (*Stack) PullDrain

func (p *Stack) PullDrain() (values.Value, []values.Value)

PullDrain removes and returns the bottom value (position 0) as the first return, and all remaining values as the second return. The stack is cleared. This is O(1) — no element shifting, just slice header arithmetic.

The returned args slice shares the stack's backing array (same contract as Drain). Valid only until the next stack mutation.

func (*Stack) Push

func (p *Stack) Push(v values.Value)

Push adds a value to the top of the stack.

func (*Stack) PushAll

func (p *Stack) PushAll(vs []values.Value)

PushAll pushes all values from the slice onto the stack.

func (Stack) SchemeString

func (p Stack) SchemeString() string

SchemeString returns a Scheme-like string representation of the stack.

func (Stack) String

func (p Stack) String() string

String returns a string representation of the stack.

type StackFrame

type StackFrame struct {
	FunctionName string                // Function name (or "<anonymous>")
	CallSite     *syntax.SourceContext // Where the call was made
	CurrentLoc   *syntax.SourceContext // Current execution point
}

StackFrame represents one frame in a Scheme stack trace.

func (*StackFrame) String

func (p *StackFrame) String() string

String formats the frame for display.

type StackTrace

type StackTrace []StackFrame

StackTrace is a list of stack frames.

func (StackTrace) String

func (p StackTrace) String() string

String formats the entire stack trace.

type StepMode

type StepMode int

StepMode represents the stepping mode for the debugger.

const (
	StepNone StepMode = iota
	StepInto          // Step to next source location
	StepOver          // Step to next source location in same or parent frame
	StepOut           // Step until current frame returns
)

type SubContextParams

type SubContextParams struct {
	Ctx          context.Context
	Env          *environment.EnvironmentFrame
	EscapeCont   *MachineContinuation
	MaxCallDepth int
	MaxStackSize uint64
	WindingStack WindingStack
}

SubContextParams holds the parent state copied into a thread's sub-context across the goroutine boundary. It deliberately carries NO pointer to the parent MachineContext: a thread runs CONCURRENTLY with its parent, so a live parentMC link would let the thread's parentMC walks (CaptureStackTrace, findParameterInMarks, the subContextPool release counter) read the parent's still-mutating VM fields — an unsynchronized data race (see TODO.md Tier 1; reproduced by TestMutexAbandonedOnTermination under -race). Only values safe to snapshot once at spawn time are captured here.

type VMCounters

type VMCounters struct {
	OpsExecuted uint64

	ClosuresApplied        uint64
	EnvsCopied             uint64
	BindingsCopied         uint64
	ContinuationsSaved     uint64
	ContinuationsRestored  uint64
	StackDrains            uint64
	StackElementsDrained   uint64
	ForeignCalls           uint64
	SubContextsCreated     uint64
	StackPoolReleases      uint64
	SubContextPoolReleases uint64
	// Pool effectiveness under call/cc:
	//   ratio = SharedFrameRestores / (SharedFrameRestores + ContinuationPoolReleases)
	//   0.0 = no call/cc impact (all frames recycled via pool)
	//   1.0 = all frames shared (no recycling, pure GC pressure)
	//   > 0.5 = pool losing more than it saves; consider profiling GC pauses
	ContinuationPoolReleases uint64
	EnvFramePoolReleases     uint64
	SharedFrameRestores      uint64
	KeysShared               uint64
	InlineEvalsSaved         uint64 // SaveContinuation used inline slots instead of stack pool

	// Stack depth instrumentation (ongoing monitoring; prior cap-tuning investigation
	// showed cap-8 is sufficient for observed workloads)
	StackMaxDepth   uint64
	StackDepth0to2  uint64 // depth 0-2: fits trivially
	StackDepth3to4  uint64 // depth 3-4: typical calls
	StackDepth5to8  uint64 // depth 5-8: fits in pool cap 8
	StackDepth9to16 uint64 // depth 9-16: requires 1 growth from cap 8
	StackDepth17p   uint64 // depth 17+: requires 2+ growths
	// contains filtered or unexported fields
}

VMCounters holds performance counters for a single MachineContext execution. All counters are plain uint64 — no atomics needed because each MachineContext is single-goroutine. Sub-contexts have their own counters (not aggregated into the parent).

func (VMCounters) CallCounts

func (p VMCounters) CallCounts() map[string]uint64

CallCounts returns the per-callee call-count map for this context, or nil when call counting was disabled. Keys are foreign primitive names and named Scheme procedures (NativeTemplate.Name); values are invocation counts. The map is the live counter map, not a copy — read it after the run completes.

func (VMCounters) CallHistogram

func (p VMCounters) CallHistogram() string

CallHistogram returns a formatted histogram of per-callee call counts (both foreign primitives and named Scheme procedures), sorted by frequency (descending). Returns empty string when profiling is disabled.

func (VMCounters) OpcodeHistogram

func (p VMCounters) OpcodeHistogram() string

OpcodeHistogram returns a formatted histogram of opcode hit counts, sorted by frequency (descending). Only opcodes with non-zero hits are included.

func (*VMCounters) RecordCall

func (p *VMCounters) RecordCall(name string)

RecordCall increments the call count for the named callee (foreign primitive or Scheme-defined procedure). No-op when profiling is disabled (nil map).

func (*VMCounters) RecordStackDepth

func (p *VMCounters) RecordStackDepth(n int)

RecordStackDepth updates the depth histogram and max tracker.

func (VMCounters) String

func (p VMCounters) String() string

String returns a tabular summary of all counters.

type WindingStack

type WindingStack []*DynamicWindFrame

WindingStack tracks the current dynamic-wind context. It's a slice of frames from outermost to innermost.

func (WindingStack) Copy

func (p WindingStack) Copy() WindingStack

Copy creates a shallow copy of the winding stack.

func (WindingStack) Depth

func (p WindingStack) Depth() int

Depth returns the number of active dynamic-wind frames.

func (*WindingStack) Pop

func (p *WindingStack) Pop() *DynamicWindFrame

Pop removes the innermost frame from the winding stack.

func (*WindingStack) Push

func (p *WindingStack) Push(frame *DynamicWindFrame)

Push adds a frame to the winding stack.

Directories

Path Synopsis
resolver
Package resolver provides file resolution infrastructure for the Scheme compiler.
Package resolver provides file resolution infrastructure for the Scheme compiler.
sourceload
Package sourceload provides file-finding and load-stack tracking for locating source files across virtual filesystems.
Package sourceload provides file-finding and load-stack tracking for locating source files across virtual filesystems.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL