Documentation
¶
Overview ¶
Package environment provides variable binding and scoping for the Scheme compiler.
The environment system manages the relationship between variables and values across:
- Lexical scoping via parent chain traversal
- Phase separation (Runtime, Expand, Compile)
- Hygienic macros via Flatt's "sets of scopes" model
- Per-instance symbol interning for eq? identity
- R7RS library import/export mappings
Architecture ¶
Each Wile VM instance owns a TopLevelEnvironment that provides:
- Symbol interning (thread-safe, per-instance)
- Phase registry for accessing phase-specific environments
- The runtime EnvironmentFrame tree
EnvironmentFrame nodes form the lexical scope chain, each containing:
- Local bindings (LocalEnvironmentFrame) for lambda params and let-bound vars
- Global bindings (GlobalEnvironmentFrame) for top-level defines
- Parent pointer for enclosing scopes
Binding Lookup ¶
EnvironmentFrame.GetBinding performs two-phase lookup:
- Local phase: traverse local bindings up the parent chain
- Global phase: search global bindings up the parent chain
EnvironmentFrame.GetBindingWithScopes adds hygiene awareness, using [Scope] sets to match identifiers according to Flatt's algorithm.
Index ¶
- Constants
- type Binding
- func (p *Binding) BindingType() BindingType
- func (p *Binding) Copy() values.Value
- func (p *Binding) EqualTo(o values.Value) bool
- func (p *Binding) IsVoid() bool
- func (p *Binding) SchemeString() string
- func (p *Binding) Scopes() []*syntax.Scope
- func (p *Binding) SetBindingType(value BindingType)
- func (p *Binding) SetScopes(scopes []*syntax.Scope)
- func (p *Binding) SetSource(source *syntax.SourceContext)
- func (p *Binding) SetValue(value values.Value)
- func (p *Binding) Source() *syntax.SourceContext
- func (p *Binding) Value() values.Value
- type BindingType
- type Environment
- type EnvironmentFrame
- func (p *EnvironmentFrame) AtPhase(phase int) *EnvironmentFrame
- func (p *EnvironmentFrame) Compile() *EnvironmentFrame
- func (p *EnvironmentFrame) Copy() *EnvironmentFrame
- func (p *EnvironmentFrame) CreateGlobalBinding(key *values.Symbol, bt BindingType) (*GlobalIndex, bool)
- func (p *EnvironmentFrame) CreateLocalBinding(key *values.Symbol, bt BindingType) (*LocalIndex, bool)
- func (p *EnvironmentFrame) EqualTo(value values.Value) bool
- func (p *EnvironmentFrame) Expand() *EnvironmentFrame
- func (p *EnvironmentFrame) GetBinding(key *values.Symbol) *Binding
- func (p *EnvironmentFrame) GetBindingWithScopes(key *values.Symbol, scopes []*syntax.Scope) *Binding
- func (p *EnvironmentFrame) GetGlobalBinding(key *GlobalIndex) *Binding
- func (p *EnvironmentFrame) GetGlobalIndex(key *values.Symbol) *GlobalIndex
- func (p *EnvironmentFrame) GetIndex(key *values.Symbol) (*LocalIndex, *GlobalIndex, bool)
- func (p *EnvironmentFrame) GetLocalBinding(li *LocalIndex) *Binding
- func (p *EnvironmentFrame) GetLocalBindingByIndex(i int) *Binding
- func (p *EnvironmentFrame) GetLocalIndex(key *values.Symbol) *LocalIndex
- func (p *EnvironmentFrame) GetLocalIndexWithScopes(key *values.Symbol, scopes []*syntax.Scope) *LocalIndex
- func (p *EnvironmentFrame) GlobalEnvironment() *GlobalEnvironmentFrame
- func (p *EnvironmentFrame) InternSymbol(q *values.Symbol) *values.Symbol
- func (p *EnvironmentFrame) InternSyntax(k values.Value, v syntax.SyntaxValue) syntax.SyntaxValue
- func (p *EnvironmentFrame) IsTopLevel() bool
- func (p *EnvironmentFrame) IsVoid() bool
- func (p *EnvironmentFrame) LibraryRegistry() any
- func (p *EnvironmentFrame) LocalEnvironment() *LocalEnvironmentFrame
- func (p *EnvironmentFrame) MaybeCreateLocalBinding(key *values.Symbol, bt BindingType) (*LocalIndex, bool)
- func (p *EnvironmentFrame) MaybeCreateLocalBindingWithScopes(key *values.Symbol, bt BindingType, scopes []*syntax.Scope) (*LocalIndex, bool)
- func (p *EnvironmentFrame) MaybeCreateOwnGlobalBinding(key *values.Symbol, bt BindingType) (*GlobalIndex, bool)
- func (p *EnvironmentFrame) Parent() *EnvironmentFrame
- func (p *EnvironmentFrame) PhaseLevel() int
- func (p *EnvironmentFrame) Runtime() *EnvironmentFrame
- func (p *EnvironmentFrame) SchemeString() string
- func (p *EnvironmentFrame) SetGlobalBindingByIndex(i int, bd *Binding)
- func (p *EnvironmentFrame) SetLibraryRegistry(registry any)
- func (p *EnvironmentFrame) SetLocalValue(li *LocalIndex, v values.Value) error
- func (p *EnvironmentFrame) SetOwnGlobalValue(gi *GlobalIndex, v values.Value) error
- func (p *EnvironmentFrame) TopLevel() *EnvironmentFrame
- func (p *EnvironmentFrame) TopLevelEnv() *TopLevelEnvironment
- type EnvironmentNavigation
- type ExceptImportDirective
- type ExportSet
- type ExportSpec
- type GlobalEnvironmentFrame
- func (p *GlobalEnvironmentFrame) Bindings() []*Binding
- func (p *GlobalEnvironmentFrame) Copy() values.Value
- func (p *GlobalEnvironmentFrame) CreateGlobalBinding(key *values.Symbol, bt BindingType) (*GlobalIndex, bool)
- func (p *GlobalEnvironmentFrame) EqualTo(o values.Value) bool
- func (p *GlobalEnvironmentFrame) GetGlobalIndex(key *values.Symbol) *GlobalIndex
- func (p *GlobalEnvironmentFrame) GetOwnGlobalBinding(gi *GlobalIndex) *Binding
- func (p *GlobalEnvironmentFrame) InternSymbol(q *values.Symbol) *values.Symbol
- func (p *GlobalEnvironmentFrame) InternSyntax(k values.Value, v syntax.SyntaxValue) syntax.SyntaxValue
- func (p *GlobalEnvironmentFrame) IsVoid() bool
- func (p *GlobalEnvironmentFrame) Keys() map[values.Symbol]int
- func (p *GlobalEnvironmentFrame) LibraryRegistry() any
- func (p *GlobalEnvironmentFrame) SchemeString() string
- func (p *GlobalEnvironmentFrame) SetBindings(vs []*Binding)
- func (p *GlobalEnvironmentFrame) SetLibraryRegistry(registry any)
- func (p *GlobalEnvironmentFrame) SetOwnGlobalValue(gi *GlobalIndex, v values.Value) error
- type GlobalIndex
- type ImportSet
- type ImportSpec
- type LibraryImportDirective
- type LocalEnvironmentFrame
- func (p *LocalEnvironmentFrame) Bindings() []*Binding
- func (p *LocalEnvironmentFrame) Copy() values.Value
- func (p *LocalEnvironmentFrame) CreateLocalBinding(key *values.Symbol, bt BindingType) (*LocalIndex, bool)
- func (p *LocalEnvironmentFrame) EqualTo(o values.Value) bool
- func (p *LocalEnvironmentFrame) GetLocalBinding(li *LocalIndex) *Binding
- func (p *LocalEnvironmentFrame) GetLocalIndex(key *values.Symbol) *LocalIndex
- func (p *LocalEnvironmentFrame) IsVoid() bool
- func (p *LocalEnvironmentFrame) Keys() map[values.Symbol]int
- func (p *LocalEnvironmentFrame) SchemeString() string
- func (p *LocalEnvironmentFrame) SetBindings(v []*Binding)
- func (p *LocalEnvironmentFrame) SetLocalValue(li *LocalIndex, v values.Value) error
- type LocalIndex
- type OnlyExportDirective
- type OnlyImportDirective
- type PhaseRegistry
- type PrefixImportDirective
- type RenameExportDirective
- type RenameImportDirective
- type TopLevelEnvironment
- func (p *TopLevelEnvironment) AtPhase(phase int) *EnvironmentFrame
- func (p *TopLevelEnvironment) Compile() *EnvironmentFrame
- func (p *TopLevelEnvironment) EqualTo(v values.Value) bool
- func (p *TopLevelEnvironment) Expand() *EnvironmentFrame
- func (p *TopLevelEnvironment) InternSymbol(s *values.Symbol) *values.Symbol
- func (p *TopLevelEnvironment) InternSyntax(k values.Value, v syntax.SyntaxValue) syntax.SyntaxValue
- func (p *TopLevelEnvironment) IsVoid() bool
- func (p *TopLevelEnvironment) LibraryRegistry() any
- func (p *TopLevelEnvironment) NewChildRuntime() *EnvironmentFrame
- func (p *TopLevelEnvironment) NewChildTopLevelEnvironment() *TopLevelEnvironment
- func (p *TopLevelEnvironment) Phases() *PhaseRegistry
- func (p *TopLevelEnvironment) Runtime() *EnvironmentFrame
- func (p *TopLevelEnvironment) SchemeString() string
- func (p *TopLevelEnvironment) SetLibraryRegistry(registry any)
- func (p *TopLevelEnvironment) SymbolInternCount() int
- func (p *TopLevelEnvironment) SyntaxInternCount() int
Constants ¶
const ( // BindingTypeUnknown indicates a binding with unknown or uninitialized type. BindingTypeUnknown = BindingType(iota) // BindingTypeVariable indicates a regular variable binding (from define, let, lambda parameters). BindingTypeVariable // BindingTypeSyntax indicates a syntax transformer binding (from define-syntax). // These bindings live in the expand phase environment. BindingTypeSyntax // BindingTypePrimitive indicates a built-in primitive procedure. BindingTypePrimitive )
const ( PhaseTemplate = -1 // for-template (template instantiation) PhaseRuntime = 0 // Runtime execution (phase 0) PhaseExpand = 1 // Macro expansion (for-syntax, phase 1) PhaseCompile = 2 // Compile-time (for-meta 2, phase 2) )
Phase level constants for standard Scheme phases. These match Racket's phase numbering convention.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Binding ¶
type Binding struct {
// contains filtered or unexported fields
}
Binding represents a variable binding in the environment. It stores the bound value, the binding type (variable, syntax, or primitive), optional scopes for hygienic macro expansion, and optional source location.
func NewBinding ¶
func NewBinding(value values.Value, bindingType BindingType) *Binding
NewBinding creates a new binding with the given value and type. The binding has no scopes (for backward compatibility with non-hygienic code).
func NewBindingWithScopes ¶
func NewBindingWithScopes(value values.Value, bindingType BindingType, scopes []*syntax.Scope) *Binding
NewBindingWithScopes creates a binding with associated scopes (for hygiene)
func NewBindingWithSource ¶
func NewBindingWithSource(value values.Value, bindingType BindingType, scopes []*syntax.Scope, source *syntax.SourceContext) *Binding
NewBindingWithSource creates a binding with source location information.
func (*Binding) BindingType ¶
func (p *Binding) BindingType() BindingType
BindingType returns the type of this binding (variable, syntax, or primitive).
func (*Binding) EqualTo ¶
EqualTo returns true if this binding is equal to the given value. Two bindings are equal if they have the same value and binding type.
func (*Binding) SchemeString ¶
SchemeString returns a string representation of this binding.
func (*Binding) Scopes ¶
Scopes returns the hygiene scopes associated with this binding. Returns nil for bindings without hygiene information.
func (*Binding) SetBindingType ¶
func (p *Binding) SetBindingType(value BindingType)
SetBindingType updates the type of this binding.
func (*Binding) SetSource ¶
func (p *Binding) SetSource(source *syntax.SourceContext)
SetSource updates the source location for this binding.
func (*Binding) Source ¶
func (p *Binding) Source() *syntax.SourceContext
Source returns the source location where this binding was defined. Returns nil for bindings without source information.
type BindingType ¶
type BindingType int
BindingType represents the type of a binding in the environment.
type Environment ¶
type Environment interface {
Parent() Environment
Values() []*Binding
SetValues(v []*Binding)
Keys() map[string]int
}
Environment is the interface for environment frames that support parent traversal and binding storage.
type EnvironmentFrame ¶
type EnvironmentFrame struct {
// contains filtered or unexported fields
}
EnvironmentFrame represents an environment frame in the hierarchy.
Type Relationships ¶
The environment system has four types with distinct responsibilities:
┌─────────────────────────────────────────────────────────────────────────┐
│ TopLevelEnvironment │
│ (Per-VM instance: owns symbol/syntax interning, phases, libraries) │
│ │
│ symbolInterns ──── map[Symbol]*Symbol (thread-safe, per-instance) │
│ syntaxInterns ──── map[wrt]SyntaxValue (thread-safe) │
│ phases ─────────── *PhaseRegistry │
│ libraryRegistry ── any (*machine.LibraryRegistry) │
│ runtime ────────── *EnvironmentFrame (phase 0) │
└─────────────────────────────────────────────────────────────────────────┘
│
│ owns
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ EnvironmentFrame │
│ (Lexical scope node: links local/global bindings, parent chain) │
│ │
│ parent ─────────── *EnvironmentFrame (lexical parent, nil at top) │
│ local ──────────── *LocalEnvironmentFrame (lambda params, let vars) │
│ global ─────────── *GlobalEnvironmentFrame (define bindings) │
│ phaseLevel ─────── int (0=runtime, 1=expand, 2=compile) │
│ phases ─────────── *PhaseRegistry (shared reference) │
│ topLevel ───────── *TopLevelEnvironment (back-reference) │
└─────────────────────────────────────────────────────────────────────────┘
│ │
│ contains │ contains
▼ ▼
┌───────────────────────────┐ ┌────────────────────────────────────────┐
│ LocalEnvironmentFrame │ │ GlobalEnvironmentFrame │
│ (Single scope bindings) │ │ (Phase-wide global bindings) │
│ │ │ │
│ keys ─── map[Symbol]int │ │ keys ──────── map[Symbol]int │
│ bindings ── []*Binding │ │ bindings ──── []*Binding │
└───────────────────────────┘ │ topLevel ──── *TopLevelEnvironment │
└────────────────────────────────────────┘
Ownership and Sharing ¶
- TopLevelEnvironment: Root owner. One per Wile VM instance.
- EnvironmentFrame: Many per VM. Share topLevel and phases references.
- GlobalEnvironmentFrame: One per phase. Shares topLevel reference.
- LocalEnvironmentFrame: One per lexical scope. No external references.
Lexical Hierarchy (parent chain) ¶
(lambda (x) ; EnvironmentFrame A: local={x}, parent=TopLevel
(let ((y 1)) ; EnvironmentFrame B: local={y}, parent=A
(lambda (z) ; EnvironmentFrame C: local={z}, parent=B
(+ x y z))))
Phase Hierarchy (via PhaseRegistry) ¶
TopLevelEnvironment
└── PhaseRegistry
├── [0] Runtime EnvironmentFrame (normal execution)
├── [1] Expand EnvironmentFrame (macro expansion, for-syntax)
├── [2] Compile EnvironmentFrame (syntax compilers, for-meta 2)
└── [-1] Template EnvironmentFrame (for-template, future)
Each phase has its own GlobalEnvironmentFrame but shares the same TopLevelEnvironment for symbol/syntax interning.
Binding Lookup ¶
Two-phase search: first all locals up parent chain, then globals.
func NewEnvironmentFrame ¶
func NewEnvironmentFrame(local *LocalEnvironmentFrame, global *GlobalEnvironmentFrame) *EnvironmentFrame
NewEnvironmentFrame creates a new environment frame with the given local and global environment frames. The parent field is set to nil. This is typically used for isolated environments.
func NewEnvironmentFrameWithParent ¶
func NewEnvironmentFrameWithParent(local *LocalEnvironmentFrame, parent *EnvironmentFrame) *EnvironmentFrame
NewEnvironmentFrameWithParent creates a new environment frame with the given local environment frame and parent environment frame. The global environment frame is inherited from the parent. This is used for creating child frames within a phase (e.g., lambda bodies, let-syntax). The phase level, registry, and topLevel are inherited from the parent. Panics if parent is nil - use NewTopLevelEnvironmentFrame() instead.
func NewTopLevelEnvironmentFrame
deprecated
func NewTopLevelEnvironmentFrame() *EnvironmentFrame
NewTopLevelEnvironmentFrame creates a new top-level global environment frame. This frame has no parent and contains the shared symbol/syntax interning maps. It also creates the PhaseRegistry for indexed phase access.
Deprecated: Use NewTopLevelEnvironment().Runtime() instead for per-instance symbol interning. This function now internally uses NewTopLevelEnvironment() to provide proper isolation.
func (*EnvironmentFrame) AtPhase ¶
func (p *EnvironmentFrame) AtPhase(phase int) *EnvironmentFrame
AtPhase returns the environment for the given phase level, creating it if needed. Phase 0 is runtime, phase 1 is expansion (for-syntax), phase 2 is compile-time, etc. Negative phases (e.g., -1 for for-template) are also supported.
This is the primary method for cross-phase access with O(1) lookup time. The environment must have been created via NewTopLevelEnvironment().
func (*EnvironmentFrame) Compile ¶
func (p *EnvironmentFrame) Compile() *EnvironmentFrame
Compile returns the compile phase environment (phase 2), creating it if needed. This is where compile-time procedures (syntax compilers) are stored.
func (*EnvironmentFrame) Copy ¶
func (p *EnvironmentFrame) Copy() *EnvironmentFrame
Copy creates a deep copy of the environment frame. The parent, phase registry, and topLevel are shared between the original and the copy.
func (*EnvironmentFrame) CreateGlobalBinding ¶
func (p *EnvironmentFrame) CreateGlobalBinding(key *values.Symbol, bt BindingType) (*GlobalIndex, bool)
CreateGlobalBinding creates a new global binding in the current global environment. It returns the GlobalIndex of the new binding and a boolean indicating whether the binding was created (true) or already existed (false).
func (*EnvironmentFrame) CreateLocalBinding ¶
func (p *EnvironmentFrame) CreateLocalBinding(key *values.Symbol, bt BindingType) (*LocalIndex, bool)
CreateLocalBinding creates a new local binding in the current local environment. It returns the LocalIndex of the new binding and a boolean indicating whether the binding was created (true) or already existed (false).
func (*EnvironmentFrame) EqualTo ¶
func (p *EnvironmentFrame) EqualTo(value values.Value) bool
EqualTo returns true if the environment frame is equal to the given value. Two environment frames are equal if their local and global environments are equal, and their parent environments are either both nil or equal.
func (*EnvironmentFrame) Expand ¶
func (p *EnvironmentFrame) Expand() *EnvironmentFrame
Expand returns the expand phase environment (phase 1), creating it if needed. This is where syntax bindings from define-syntax are stored.
func (*EnvironmentFrame) GetBinding ¶
func (p *EnvironmentFrame) GetBinding(key *values.Symbol) *Binding
GetBinding returns the binding for the given symbol, searching for local bindings first, then global bindings in the current and parent environments. It returns nil if the binding does not exist.
func (*EnvironmentFrame) GetBindingWithScopes ¶
func (p *EnvironmentFrame) GetBindingWithScopes(key *values.Symbol, scopes []*syntax.Scope) *Binding
GetBindingWithScopes returns the binding for the given symbol that matches the provided scopes. This is used for hygienic variable resolution in macros. It searches for local bindings first (walking up the parent chain), then global bindings, checking scope compatibility at each level.
For hygiene to work correctly with nested bindings of the same name:
- Each let-bound variable has scopes from the binding site
- A macro free identifier carries scopes from its definition site
- We search ALL local bindings (not just innermost) to find one with matching scopes
func (*EnvironmentFrame) GetGlobalBinding ¶
func (p *EnvironmentFrame) GetGlobalBinding(key *GlobalIndex) *Binding
GetGlobalBinding returns the binding for the given GlobalIndex, searching global bindings in the current and parent environments. It returns nil if the binding does not exist.
func (*EnvironmentFrame) GetGlobalIndex ¶
func (p *EnvironmentFrame) GetGlobalIndex(key *values.Symbol) *GlobalIndex
GetGlobalIndex returns the GlobalIndex of the binding for the given symbol, searching global bindings in the current and parent environments. It returns nil if the binding does not exist. The returned GlobalIndex records the specific global frame where the binding was found, enabling cross-library macro hygiene (see GlobalIndex.Env).
func (*EnvironmentFrame) GetIndex ¶
func (p *EnvironmentFrame) GetIndex(key *values.Symbol) (*LocalIndex, *GlobalIndex, bool)
GetIndex returns the index of the binding for the given symbol. It returns either a LocalIndex or GlobalIndex depending on where the binding is found. The boolean return value indicates whether the binding was found. Note: This function has known bugs (skips first frame in loops) and may need fixes.
func (*EnvironmentFrame) GetLocalBinding ¶
func (p *EnvironmentFrame) GetLocalBinding(li *LocalIndex) *Binding
GetLocalBinding returns the binding for the given LocalIndex. It returns nil if the binding does not exist.
func (*EnvironmentFrame) GetLocalBindingByIndex ¶
func (p *EnvironmentFrame) GetLocalBindingByIndex(i int) *Binding
GetLocalBindingByIndex returns the local binding at the given index in the current local environment. It does not search parent environments. It returns nil if the binding does not exist.
func (*EnvironmentFrame) GetLocalIndex ¶
func (p *EnvironmentFrame) GetLocalIndex(key *values.Symbol) *LocalIndex
GetLocalIndex returns the LocalIndex of the binding for the given symbol, searching local bindings in the current and parent environments. It returns nil if the binding does not exist.
func (*EnvironmentFrame) GetLocalIndexWithScopes ¶
func (p *EnvironmentFrame) GetLocalIndexWithScopes(key *values.Symbol, scopes []*syntax.Scope) *LocalIndex
GetLocalIndexWithScopes returns the LocalIndex of a local binding that matches the given scopes. This implements Flatt's "maximal" binding resolution: among all bindings whose scopes are a subset of the reference's scopes, we return the one with the LARGEST scope set. This ensures that more specific bindings are preferred over less specific ones. Returns nil if no matching local binding exists.
func (*EnvironmentFrame) GlobalEnvironment ¶
func (p *EnvironmentFrame) GlobalEnvironment() *GlobalEnvironmentFrame
GlobalEnvironment returns the global environment frame.
func (*EnvironmentFrame) InternSymbol ¶
func (p *EnvironmentFrame) InternSymbol(q *values.Symbol) *values.Symbol
InternSymbol interns the given symbol. Delegates to the TopLevelEnvironment for this frame. Per R7RS §6.5: "Two symbols are identical (in the sense of eq?) if and only if their names are spelled the same way." Panics if topLevel is nil (legacy environments no longer supported).
func (*EnvironmentFrame) InternSyntax ¶
func (p *EnvironmentFrame) InternSyntax(k values.Value, v syntax.SyntaxValue) syntax.SyntaxValue
InternSyntax interns the given syntax value. Delegates to the TopLevelEnvironment for this frame. Panics if topLevel is nil (legacy environments no longer supported).
func (*EnvironmentFrame) IsTopLevel ¶
func (p *EnvironmentFrame) IsTopLevel() bool
IsTopLevel returns true if this is the top-level environment frame (no parent).
func (*EnvironmentFrame) IsVoid ¶
func (p *EnvironmentFrame) IsVoid() bool
IsVoid returns true if the environment frame is nil.
func (*EnvironmentFrame) LibraryRegistry ¶
func (p *EnvironmentFrame) LibraryRegistry() any
LibraryRegistry returns the library registry from the top-level environment. The caller must type-assert to *machine.LibraryRegistry. Returns nil if no registry has been set.
func (*EnvironmentFrame) LocalEnvironment ¶
func (p *EnvironmentFrame) LocalEnvironment() *LocalEnvironmentFrame
LocalEnvironment returns the local environment frame.
func (*EnvironmentFrame) MaybeCreateLocalBinding ¶
func (p *EnvironmentFrame) MaybeCreateLocalBinding(key *values.Symbol, bt BindingType) (*LocalIndex, bool)
MaybeCreateLocalBinding creates a new local binding in the current local environment or any parent local environment if it does not already exist. It returns the LocalIndex of the binding and a boolean indicating whether the binding was created (true) or already existed (false).
func (*EnvironmentFrame) MaybeCreateLocalBindingWithScopes ¶
func (p *EnvironmentFrame) MaybeCreateLocalBindingWithScopes(key *values.Symbol, bt BindingType, scopes []*syntax.Scope) (*LocalIndex, bool)
MaybeCreateLocalBindingWithScopes creates a new local binding with associated scopes in the current local environment. It returns the LocalIndex of the new binding and a boolean indicating whether the binding was created (true) or already existed (false).
func (*EnvironmentFrame) MaybeCreateOwnGlobalBinding ¶
func (p *EnvironmentFrame) MaybeCreateOwnGlobalBinding(key *values.Symbol, bt BindingType) (*GlobalIndex, bool)
MaybeCreateOwnGlobalBinding creates a new global binding in the current or parent global environments if it does not already exist. It returns the GlobalIndex of the binding and a boolean indicating whether the binding was created (true) or already existed (false).
func (*EnvironmentFrame) Parent ¶
func (p *EnvironmentFrame) Parent() *EnvironmentFrame
Parent returns the parent environment frame.
func (*EnvironmentFrame) PhaseLevel ¶
func (p *EnvironmentFrame) PhaseLevel() int
PhaseLevel returns the phase level of this environment frame.
func (*EnvironmentFrame) Runtime ¶
func (p *EnvironmentFrame) Runtime() *EnvironmentFrame
Runtime returns the runtime phase environment (phase 0). This is the TopLevel environment where normal bindings live.
func (*EnvironmentFrame) SchemeString ¶
func (p *EnvironmentFrame) SchemeString() string
SchemeString returns a string representation of the environment frame.
func (*EnvironmentFrame) SetGlobalBindingByIndex ¶
func (p *EnvironmentFrame) SetGlobalBindingByIndex(i int, bd *Binding)
SetGlobalBindingByIndex sets the global binding at the given index in the current global environment. It does not search parent environments.
func (*EnvironmentFrame) SetLibraryRegistry ¶
func (p *EnvironmentFrame) SetLibraryRegistry(registry any)
SetLibraryRegistry sets the library registry on the top-level environment. The registry should be a *machine.LibraryRegistry.
func (*EnvironmentFrame) SetLocalValue ¶
func (p *EnvironmentFrame) SetLocalValue(li *LocalIndex, v values.Value) error
SetLocalValue sets the value of the binding for the given LocalIndex. It returns an error if the binding does not exist.
func (*EnvironmentFrame) SetOwnGlobalValue ¶
func (p *EnvironmentFrame) SetOwnGlobalValue(gi *GlobalIndex, v values.Value) error
SetOwnGlobalValue sets the value of the binding for the given GlobalIndex. It returns an error if the binding does not exist.
func (*EnvironmentFrame) TopLevel ¶
func (p *EnvironmentFrame) TopLevel() *EnvironmentFrame
TopLevel returns the top-level environment frame in the hierarchy.
func (*EnvironmentFrame) TopLevelEnv ¶
func (p *EnvironmentFrame) TopLevelEnv() *TopLevelEnvironment
TopLevelEnv returns the TopLevelEnvironment for this frame. Returns nil for legacy environments created without TopLevelEnvironment.
type EnvironmentNavigation ¶
type EnvironmentNavigation interface {
// TODO: remove LocalEnvironment and GlobalEnvironment methods once
// meta environments are fully integrated.
}
EnvironmentNavigation is the interface for navigating between environment frames, including meta phases and local/global scopes.
type ExceptImportDirective ¶
type ExceptImportDirective struct {
// contains filtered or unexported fields
}
ExceptImportDirective indicates that the given identifier should not be imported.
func (*ExceptImportDirective) Next ¶
func (p *ExceptImportDirective) Next() ImportSpec
Next returns the next import spec in the chain.
type ExportSet ¶
type ExportSet struct{}
ExportSet holds the resolved export mappings for a library.
func NewExportSet ¶
func NewExportSet(spec ExportSpec) (*ExportSet, error)
NewExportSet creates an ExportSet from a chain of export specs.
type ExportSpec ¶
type ExportSpec interface {
Next() ExportSpec
}
ExportSpec is the interface for export directives in library definitions.
type GlobalEnvironmentFrame ¶
type GlobalEnvironmentFrame struct {
// contains filtered or unexported fields
}
GlobalEnvironmentFrame represents global bindings for a single phase.
Design: GlobalEnvironmentFrame has no hierarchy of its own. The environment hierarchy is managed by EnvironmentFrame via its parent field. Each phase (runtime, expand, compile) has its own GlobalEnvironmentFrame.
Note: Symbol and syntax interning are delegated to TopLevelEnvironment, ensuring R7RS symbol identity works correctly across all phases.
func NewGlobalEnvironmentFrame ¶
func NewGlobalEnvironmentFrame() *GlobalEnvironmentFrame
NewGlobalEnvironmentFrame creates a new global environment frame.
func (*GlobalEnvironmentFrame) Bindings ¶
func (p *GlobalEnvironmentFrame) Bindings() []*Binding
Bindings returns the slice of bindings in this global environment.
func (*GlobalEnvironmentFrame) Copy ¶
func (p *GlobalEnvironmentFrame) Copy() values.Value
Copy creates a deep copy of the global environment frame. Note that topLevel is shared (not copied) between original and copy.
func (*GlobalEnvironmentFrame) CreateGlobalBinding ¶
func (p *GlobalEnvironmentFrame) CreateGlobalBinding(key *values.Symbol, bt BindingType) (*GlobalIndex, bool)
CreateGlobalBinding creates a new global binding with the given key and type. The key is interned before use. Returns the GlobalIndex and whether a new binding was created (false if the binding already existed).
func (*GlobalEnvironmentFrame) EqualTo ¶
func (p *GlobalEnvironmentFrame) EqualTo(o values.Value) bool
EqualTo returns true if this global environment equals the given value. Two global environments are equal if they have the same bindings.
func (*GlobalEnvironmentFrame) GetGlobalIndex ¶
func (p *GlobalEnvironmentFrame) GetGlobalIndex(key *values.Symbol) *GlobalIndex
GetGlobalIndex returns the GlobalIndex for the given symbol. Returns nil if the symbol is not bound in this global environment.
func (*GlobalEnvironmentFrame) GetOwnGlobalBinding ¶
func (p *GlobalEnvironmentFrame) GetOwnGlobalBinding(gi *GlobalIndex) *Binding
GetOwnGlobalBinding returns the binding for the given GlobalIndex from this frame only. Unlike EnvironmentFrame.GetGlobalBinding, this does NOT traverse the parent chain. Returns nil if the binding does not exist in this frame.
func (*GlobalEnvironmentFrame) InternSymbol ¶
func (p *GlobalEnvironmentFrame) InternSymbol(q *values.Symbol) *values.Symbol
InternSymbol returns the canonical version of the given symbol. Delegates to TopLevelEnvironment. Per R7RS §6.5: "Two symbols are identical (in the sense of eq?) if and only if their names are spelled the same way." Panics if topLevel is nil.
func (*GlobalEnvironmentFrame) InternSyntax ¶
func (p *GlobalEnvironmentFrame) InternSyntax(k values.Value, v syntax.SyntaxValue) syntax.SyntaxValue
InternSyntax returns the canonical version of the given syntax value. If an equivalent syntax value has been seen before, it is returned. Otherwise, the value is added to the intern map and returned. Delegates to TopLevelEnvironment. Panics if topLevel is nil.
func (*GlobalEnvironmentFrame) IsVoid ¶
func (p *GlobalEnvironmentFrame) IsVoid() bool
IsVoid returns true if this global environment frame is nil.
func (*GlobalEnvironmentFrame) Keys ¶
func (p *GlobalEnvironmentFrame) Keys() map[values.Symbol]int
Keys returns the symbol-to-index mapping for this global environment.
func (*GlobalEnvironmentFrame) LibraryRegistry ¶
func (p *GlobalEnvironmentFrame) LibraryRegistry() any
LibraryRegistry returns the library registry for R7RS library loading. The caller must type-assert to *machine.LibraryRegistry. Returns nil if no registry has been set. Delegates to TopLevelEnvironment. Panics if topLevel is nil.
func (*GlobalEnvironmentFrame) SchemeString ¶
func (p *GlobalEnvironmentFrame) SchemeString() string
SchemeString returns a string representation of this global environment.
func (*GlobalEnvironmentFrame) SetBindings ¶
func (p *GlobalEnvironmentFrame) SetBindings(vs []*Binding)
SetBindings replaces the bindings slice in this global environment.
func (*GlobalEnvironmentFrame) SetLibraryRegistry ¶
func (p *GlobalEnvironmentFrame) SetLibraryRegistry(registry any)
SetLibraryRegistry sets the library registry for R7RS library loading. The registry should be a *machine.LibraryRegistry. Delegates to TopLevelEnvironment. Panics if topLevel is nil.
func (*GlobalEnvironmentFrame) SetOwnGlobalValue ¶
func (p *GlobalEnvironmentFrame) SetOwnGlobalValue(gi *GlobalIndex, v values.Value) error
SetOwnGlobalValue sets the value of the binding for the given GlobalIndex. Returns an error if the binding does not exist.
type GlobalIndex ¶
type GlobalIndex struct {
Index *values.Symbol
Env *GlobalEnvironmentFrame
}
GlobalIndex identifies a global binding by its symbol key. Unlike LocalIndex which uses numeric indices, GlobalIndex uses the symbol directly since global bindings are accessed by name at runtime.
Env records the definition-site global frame for cross-library macro hygiene. When a macro references a non-exported helper from its defining library, Env ensures the VM resolves the binding in the library's environment rather than the use-site environment. Nil means "use the current environment" (backward compatible default).
func NewGlobalIndex ¶
func NewGlobalIndex(key *values.Symbol) *GlobalIndex
NewGlobalIndex creates a new GlobalIndex for the given symbol.
func (*GlobalIndex) EqualTo ¶
func (p *GlobalIndex) EqualTo(value values.Value) bool
EqualTo returns true if this global index equals the given value.
func (*GlobalIndex) IsVoid ¶
func (p *GlobalIndex) IsVoid() bool
IsVoid returns true if this global index is nil.
func (*GlobalIndex) SchemeString ¶
func (p *GlobalIndex) SchemeString() string
SchemeString returns a string representation of this global index.
type ImportSet ¶
type ImportSet struct{}
ImportSet holds the resolved import mappings for a library.
func NewImportSet ¶
func NewImportSet(spec ImportSpec) (*ImportSet, error)
NewImportSet creates an ImportSet from a chain of import specs.
type ImportSpec ¶
type ImportSpec interface {
Next() ImportSpec
}
ImportSpec is the interface for import directives in library definitions.
type LibraryImportDirective ¶
type LibraryImportDirective struct {
// contains filtered or unexported fields
}
LibraryImportDirective indicates that all identifiers from the given library should be imported.
func (*LibraryImportDirective) Next ¶
func (p *LibraryImportDirective) Next() ImportSpec
Next returns the next import spec in the chain.
type LocalEnvironmentFrame ¶
type LocalEnvironmentFrame struct {
// contains filtered or unexported fields
}
LocalEnvironmentFrame stores local variable bindings for a single scope. It maps symbols to binding indices for efficient lookup. Local environments are created for lambda parameters and let-bound variables. Note: LocalEnvironmentFrame has no hierarchy of its own; the hierarchy is managed by EnvironmentFrame via its parent field.
func NewLocalEnvironment ¶
func NewLocalEnvironment(pcnt int) *LocalEnvironmentFrame
NewLocalEnvironment creates a new local environment frame with pre-allocated slots for the given parameter count. Each slot is initialized with a void binding of unknown type.
func (*LocalEnvironmentFrame) Bindings ¶
func (p *LocalEnvironmentFrame) Bindings() []*Binding
Bindings returns the slice of bindings in this local environment.
func (*LocalEnvironmentFrame) Copy ¶
func (p *LocalEnvironmentFrame) Copy() values.Value
Copy creates a deep copy of this local environment frame.
func (*LocalEnvironmentFrame) CreateLocalBinding ¶
func (p *LocalEnvironmentFrame) CreateLocalBinding(key *values.Symbol, bt BindingType) (*LocalIndex, bool)
CreateLocalBinding creates a new local binding with the given key and binding type.
func (*LocalEnvironmentFrame) EqualTo ¶
func (p *LocalEnvironmentFrame) EqualTo(o values.Value) bool
EqualTo returns true if this local environment is equal to the given value. Two local environments are equal if they have the same bindings.
func (*LocalEnvironmentFrame) GetLocalBinding ¶
func (p *LocalEnvironmentFrame) GetLocalBinding(li *LocalIndex) *Binding
GetLocalBinding returns the binding at the given LocalIndex.
func (*LocalEnvironmentFrame) GetLocalIndex ¶
func (p *LocalEnvironmentFrame) GetLocalIndex(key *values.Symbol) *LocalIndex
GetLocalIndex returns the LocalIndex for the given symbol in this local environment. Returns nil if the symbol is not bound in this environment.
func (*LocalEnvironmentFrame) IsVoid ¶
func (p *LocalEnvironmentFrame) IsVoid() bool
IsVoid returns true if this local environment frame is nil.
func (*LocalEnvironmentFrame) Keys ¶
func (p *LocalEnvironmentFrame) Keys() map[values.Symbol]int
Keys returns the symbol-to-index mapping for this local environment.
func (*LocalEnvironmentFrame) SchemeString ¶
func (p *LocalEnvironmentFrame) SchemeString() string
SchemeString returns a string representation of this local environment.
func (*LocalEnvironmentFrame) SetBindings ¶
func (p *LocalEnvironmentFrame) SetBindings(v []*Binding)
SetBindings replaces the bindings slice in this local environment.
func (*LocalEnvironmentFrame) SetLocalValue ¶
func (p *LocalEnvironmentFrame) SetLocalValue(li *LocalIndex, v values.Value) error
SetLocalValue sets the value of the binding at the given LocalIndex.
type LocalIndex ¶
type LocalIndex [2]int
LocalIndex represents the location of a local binding as [slot, depth]. The first element (slot/over) is the index within the local environment frame. The second element (depth/up) is how many parent frames to traverse. Example: [2, 1] means "binding at slot 2 in the parent frame".
func NewLocalIndex ¶
func NewLocalIndex(over, up int) *LocalIndex
NewLocalIndex creates a new LocalIndex with the given slot and depth.
func (*LocalIndex) EqualTo ¶
func (p *LocalIndex) EqualTo(i *LocalIndex) bool
EqualTo returns true if this index equals the given index.
func (*LocalIndex) GetBinding ¶
func (p *LocalIndex) GetBinding(env *EnvironmentFrame) *Binding
GetBinding retrieves the binding at this index from the given environment.
func (*LocalIndex) Over ¶
func (p *LocalIndex) Over() int
Over returns the slot index within the local environment frame.
func (*LocalIndex) SchemeString ¶
func (p *LocalIndex) SchemeString() string
SchemeString returns a Scheme-style string representation.
func (*LocalIndex) String ¶
func (p *LocalIndex) String() string
String returns a string representation in "slot:depth" format.
func (*LocalIndex) Up ¶
func (p *LocalIndex) Up() int
Up returns the depth (number of parent frames to traverse).
type OnlyExportDirective ¶
type OnlyExportDirective struct {
// contains filtered or unexported fields
}
OnlyExportDirective indicates that only the given identifier should be exported.
func (*OnlyExportDirective) Next ¶
func (p *OnlyExportDirective) Next() ExportSpec
Next returns the next export spec in the chain.
type OnlyImportDirective ¶
type OnlyImportDirective struct {
// contains filtered or unexported fields
}
OnlyImportDirective indicates that only the given identifier should be imported.
func (*OnlyImportDirective) Next ¶
func (p *OnlyImportDirective) Next() ImportSpec
Next returns the next import spec in the chain.
type PhaseRegistry ¶
type PhaseRegistry struct {
// contains filtered or unexported fields
}
PhaseRegistry manages phase-indexed environment frames. It provides O(1) access to any phase environment and supports lazy creation of phase environments on first access.
The registry is owned by the TopLevel environment and shared across all child environments via pointer. This enables any environment frame to access any phase directly.
Thread-safe: All operations are protected by a read-write mutex to support concurrent macro expansion.
func (*PhaseRegistry) Get ¶
func (p *PhaseRegistry) Get(phase int) *EnvironmentFrame
Get returns the environment for the given phase, or nil if not yet created.
func (*PhaseRegistry) GetOrCreate ¶
func (p *PhaseRegistry) GetOrCreate(phase int) *EnvironmentFrame
GetOrCreate returns the environment for the given phase, creating it if needed. Phase 0 always returns the TopLevel environment. Other phases are lazily created with their own GlobalEnvironmentFrame.
func (*PhaseRegistry) Phases ¶
func (p *PhaseRegistry) Phases() []int
Phases returns all currently instantiated phase levels. Useful for debugging and introspection.
func (*PhaseRegistry) TopLevelEnv ¶
func (p *PhaseRegistry) TopLevelEnv() *TopLevelEnvironment
TopLevelEnv returns the owning TopLevelEnvironment. Returns nil for legacy environments created without TopLevelEnvironment.
func (*PhaseRegistry) TopLevelFrame ¶
func (p *PhaseRegistry) TopLevelFrame() *EnvironmentFrame
TopLevelFrame returns the runtime (phase 0) environment frame.
type PrefixImportDirective ¶
type PrefixImportDirective struct {
// contains filtered or unexported fields
}
PrefixImportDirective indicates that any identifier with the given prefix should be imported.
func (*PrefixImportDirective) Next ¶
func (p *PrefixImportDirective) Next() ImportSpec
Next returns the next import spec in the chain.
type RenameExportDirective ¶
type RenameExportDirective struct {
// contains filtered or unexported fields
}
RenameExportDirective indicates that an identifier should be exported under a different name.
func (*RenameExportDirective) Next ¶
func (p *RenameExportDirective) Next() ExportSpec
Next returns the next export spec in the chain.
type RenameImportDirective ¶
type RenameImportDirective struct {
// contains filtered or unexported fields
}
RenameImportDirective indicates that an identifier should be imported under a different name.
func (*RenameImportDirective) Next ¶
func (p *RenameImportDirective) Next() ImportSpec
Next returns the next import spec in the chain.
type TopLevelEnvironment ¶
type TopLevelEnvironment struct {
// Name is an optional descriptive name (e.g., "interaction-environment").
Name string
// contains filtered or unexported fields
}
TopLevelEnvironment represents a complete Wile VM instance. It owns per-instance symbol interning, syntax interning, phase registry, and library registry. This enables multiple independent Wile VMs in a single Go process.
Design: TopLevelEnvironment is the root of the environment hierarchy. Each EnvironmentFrame holds a reference back to its TopLevelEnvironment to access shared resources (interning, phases, libraries).
Symbol interning is per-TopLevelEnvironment (not global) to support:
- Multiple isolated Wile VMs
- Clean VM teardown without affecting other instances
- R7RS §6.5 symbol identity: "Two symbols are identical (in the sense of eq?) if and only if their names are spelled the same way."
func NewTopLevelEnvironment ¶
func NewTopLevelEnvironment() *TopLevelEnvironment
NewTopLevelEnvironment creates a new TopLevelEnvironment. This is the primary entry point for creating an isolated Wile VM instance.
func (*TopLevelEnvironment) AtPhase ¶
func (p *TopLevelEnvironment) AtPhase(phase int) *EnvironmentFrame
AtPhase returns the environment for the given phase level, creating it if needed. Phase 0 is runtime, phase 1 is expansion (for-syntax), phase 2 is compile-time, etc. Negative phases (e.g., -1 for for-template) are also supported.
func (*TopLevelEnvironment) Compile ¶
func (p *TopLevelEnvironment) Compile() *EnvironmentFrame
Compile returns the compile phase environment (phase 2), creating it if needed. This is where compile-time procedures (syntax compilers) are stored.
func (*TopLevelEnvironment) EqualTo ¶
func (p *TopLevelEnvironment) EqualTo(v values.Value) bool
EqualTo returns true if the environments are the same object.
func (*TopLevelEnvironment) Expand ¶
func (p *TopLevelEnvironment) Expand() *EnvironmentFrame
Expand returns the expand phase environment (phase 1), creating it if needed. This is where syntax bindings from define-syntax are stored.
func (*TopLevelEnvironment) InternSymbol ¶
func (p *TopLevelEnvironment) InternSymbol(s *values.Symbol) *values.Symbol
InternSymbol returns the canonical interned version of the given symbol. If a symbol with the same name has been interned before, that pointer is returned. Otherwise, the symbol is added to the intern table and returned. This ensures symbol identity (eq?) works correctly per R7RS §6.5.
When a parent TopLevelEnvironment exists (child environments created via NewChildTopLevelEnvironment), interning is delegated to the parent to maintain symbol identity across environments.
This function is thread-safe.
func (*TopLevelEnvironment) InternSyntax ¶
func (p *TopLevelEnvironment) InternSyntax(k values.Value, v syntax.SyntaxValue) syntax.SyntaxValue
InternSyntax returns the canonical version of the given syntax value. If an equivalent syntax value has been seen before, it is returned. Otherwise, the value is added to the intern table and returned.
When a parent TopLevelEnvironment exists, interning is delegated to the parent to maintain syntax identity across environments.
This function is thread-safe.
func (*TopLevelEnvironment) IsVoid ¶
func (p *TopLevelEnvironment) IsVoid() bool
IsVoid returns true if the environment is nil.
func (*TopLevelEnvironment) LibraryRegistry ¶
func (p *TopLevelEnvironment) LibraryRegistry() any
LibraryRegistry returns the library registry for R7RS library loading. The caller must type-assert to *machine.LibraryRegistry. Returns nil if no registry has been set.
func (*TopLevelEnvironment) NewChildRuntime ¶
func (p *TopLevelEnvironment) NewChildRuntime() *EnvironmentFrame
NewChildRuntime creates a new runtime environment frame that shares this TopLevelEnvironment for symbol and syntax interning, but has its own GlobalEnvironmentFrame and PhaseRegistry for isolated bindings.
This is used for library environments that need to:
- Share symbol interning (for R7RS §6.5 symbol identity)
- Have isolated bindings (library definitions don't leak)
- Have their own phase hierarchy
func (*TopLevelEnvironment) NewChildTopLevelEnvironment ¶
func (p *TopLevelEnvironment) NewChildTopLevelEnvironment() *TopLevelEnvironment
NewChildTopLevelEnvironment creates a new TopLevelEnvironment whose symbol and syntax interning is delegated to the receiver (the parent). This ensures R7RS §6.5 symbol identity across environment boundaries: symbols interned in the child resolve to the same pointer as identically-named symbols in the parent, so eq? comparisons between them return #t.
Ownership structure ¶
The child is a fully independent TopLevelEnvironment with its own:
- EnvironmentFrame (runtime, phase 0) — the root lexical scope
- GlobalEnvironmentFrame — isolated global bindings (define, set!, etc.)
- PhaseRegistry — isolated phase hierarchy (expand, compile created on demand)
The child's GlobalEnvironmentFrame.topLevel points to the child (not the parent), so new global bindings created in the child are keyed against the child's GlobalEnvironmentFrame. This is what provides binding isolation: definitions in the child do not appear in the parent, and vice versa.
Parent TopLevelEnvironment (root)
+-----------------------------------------------+
| symbolInterns: map[Symbol]*Symbol ◄──────────────── all interning
| syntaxInterns: map[Value]SyntaxValue ◄────────────── goes here
| symbolInternsMu / syntaxInternsMu (mutexes) |
| parent: nil |
| phases: *PhaseRegistry ──► {0: envP} |
| runtime: envP ─────────────────────────────┐ |
| libraryRegistry: *machine.LibraryRegistry | |
+--------------------------------------------│--+
│
▼
EnvironmentFrame (envP, phase 0)
+-------------------------------+
| global: *GlobalEnvFrame ───┐ |
| topLevel: ──► parent TLE | |
+---------------------------│---+
▼
GlobalEnvironmentFrame
+-------------------------+
| keys: {x:0, y:1, ...} |
| bindings: [...] |
| topLevel: ──► parent TLE|
+-------------------------+
Child TopLevelEnvironment (returned by this method)
+-----------------------------------------------+
| symbolInterns: nil (never accessed) |
| syntaxInterns: nil (never accessed) |
| parent: ──► parent TLE (interning delegate) |
| phases: *PhaseRegistry ──► {0: envC} |
| runtime: envC ─────────────────────────────┐ |
| libraryRegistry: ──► same pointer as parent| |
+--------------------------------------------│--+
│
▼
EnvironmentFrame (envC, phase 0)
+-------------------------------+
| global: *GlobalEnvFrame ───┐ |
| topLevel: ──► child TLE | |
+---------------------------│---+
▼
GlobalEnvironmentFrame
+-------------------------+
| keys: {} (empty) |
| bindings: [] |
| topLevel: ──► child TLE |
+-------------------------+
Interning delegation ¶
The child stores a parent pointer and has nil interning maps. InternSymbol and InternSyntax check for a non-nil parent and delegate recursively, ultimately reaching the root TopLevelEnvironment where the maps and mutexes live. This avoids sharing map pointers across structs with independent mutexes (which would be a data race).
child.InternSymbol(s)
│
│ p.parent != nil
▼
parent.InternSymbol(s)
│
│ p.parent == nil (root)
▼
p.symbolInternsMu.RLock() ◄── mutex lives on root only
check p.symbolInterns[*s] ◄── map lives on root only
│
├── found: return canonical *Symbol
│
└── not found:
p.symbolInternsMu.Lock()
double-check, insert, return
Inherited state ¶
The child inherits the parent's libraryRegistry (the *machine.LibraryRegistry) by value copy. This allows the child to load libraries via (import ...) without requiring the caller to set the registry explicitly. The registry itself is a shared pointer; mutations to the registry (e.g., registering a new library) are visible to both parent and child.
Contrast with NewChildRuntime ¶
NewChildRuntime returns an *EnvironmentFrame that shares the parent's TopLevelEnvironment directly (same pointer). It is used for library loading, where the library environment should intern symbols through the same TopLevelEnvironment. However, because it shares the TopLevelEnvironment, it cannot be returned as a standalone environment value — calling Runtime() on the shared TopLevelEnvironment returns the parent's runtime frame, not the child's.
NewChildRuntime: NewChildTopLevelEnvironment:
TopLevelEnvironment (shared) Parent TLE Child TLE
+------------------+ +----------+ +----------+
| runtime: envP | | runtime: | | runtime: |
+------------------+ | envP | | envC |
│ +----------+ +----------+
│ │
┌────┴────┐ ▼
▼ ▼ EnvironmentFrame (envC)
envP envC ◄── new child +---------------------+
(parent (has own Global- | topLevel: child TLE |
frame) EnvFrame, but +---------------------+
topLevel points
to shared TLE)
envC.TopLevelEnv() == parent envC.TopLevelEnv() == child
TLE.Runtime() returns envP child.Runtime() returns envC ✓
NewChildTopLevelEnvironment returns a new *TopLevelEnvironment that can be passed as a first-class Scheme value (e.g., returned from the (environment) primitive and accepted by eval). Its Runtime() returns the child's own runtime frame, and its AtPhase/Expand/Compile methods create phase environments scoped to the child.
Usage ¶
Used by PrimEnvironment and PrimNullEnvironment (R7RS §6.12) to create environments that are identity-compatible with the caller's symbol table while providing isolated bindings. TODO: review whether libraryRegistry should be copied here TODO: review for optimization/refactoring opportunities
func (*TopLevelEnvironment) Phases ¶
func (p *TopLevelEnvironment) Phases() *PhaseRegistry
Phases returns the phase registry.
func (*TopLevelEnvironment) Runtime ¶
func (p *TopLevelEnvironment) Runtime() *EnvironmentFrame
Runtime returns the runtime phase environment (phase 0). This is the main environment where top-level bindings live.
func (*TopLevelEnvironment) SchemeString ¶
func (p *TopLevelEnvironment) SchemeString() string
SchemeString returns the Scheme representation of the environment.
func (*TopLevelEnvironment) SetLibraryRegistry ¶
func (p *TopLevelEnvironment) SetLibraryRegistry(registry any)
SetLibraryRegistry sets the library registry for R7RS library loading. The registry should be a *machine.LibraryRegistry.
func (*TopLevelEnvironment) SymbolInternCount ¶
func (p *TopLevelEnvironment) SymbolInternCount() int
SymbolInternCount returns the number of interned symbols. This is intended for testing and debugging purposes.
func (*TopLevelEnvironment) SyntaxInternCount ¶
func (p *TopLevelEnvironment) SyntaxInternCount() int
SyntaxInternCount returns the number of interned syntax objects. This is intended for testing and debugging purposes.