Documentation
¶
Index ¶
- Constants
- Variables
- func AllFeatures() []string
- func BuildInlineHOFTemplates(ctx context.Context, env *environment.EnvironmentFrame) error
- func CompileSyntaxRules(ctx context.Context, env *environment.EnvironmentFrame, ...) (*machine.MachineClosure, error)
- func CompileValidatedApply(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedBegin(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedCaseLambda(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedDefine(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedDynamicWind(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedIf(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedLambda(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedLet(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedQuasiquote(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedQuote(p *CompileTimeContinuation, _ CompileTimeCallContext, expr forms.ValidatedExpr) error
- func CompileValidatedSetBang(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CompileValidatedWithContinuationMark(p *CompileTimeContinuation, ctctx CompileTimeCallContext, ...) error
- func CopyLibraryBindingsToEnv(lib *CompiledLibrary, bindings map[string]string, ...) error
- func CopyLibraryBindingsToEnvAtPhase(lib *CompiledLibrary, bindings map[string]string, ...) error
- func ExpandAndCompile(ctx context.Context, env *environment.EnvironmentFrame, stx syntax.SyntaxValue, ...) (*machine.NativeTemplate, error)
- func ImportSpecInto(ctx context.Context, specVal values.Value, ...) error
- func IsFeatureSupported(feature string) bool
- func LoadBootstrapSources(ctx context.Context, env *environment.EnvironmentFrame, sources []string, ...) error
- func LookupPhaseBinding[T any](phaseEnv *environment.EnvironmentFrame, sym *values.Symbol, ...) T
- func NewERCompareClosure(useEnv *environment.EnvironmentFrame) *machine.ForeignClosure
- func NewERRenameClosure(defExpandEnv *environment.EnvironmentFrame, introScope *syntax.Scope) *machine.ForeignClosure
- func RegisterAllPhaseHandlers(env *environment.EnvironmentFrame) error
- func RegisterPhaseBindings[F any](env *environment.EnvironmentFrame, ...) error
- func RegisterPrimitiveExpanders(env *environment.EnvironmentFrame) error
- func RegisterSyntaxCompilers(env *environment.EnvironmentFrame) error
- func ResolveAndInstallImportSet(ctx context.Context, datum values.Value, env *environment.EnvironmentFrame, ...) error
- func ResolveLibraryFile(ctx context.Context, res FileResolver, name LibraryName) (fs.File, string, error)
- func StampInlineHOFs(frame *environment.EnvironmentFrame)
- func TemplateLocalEmits() uint64
- func VerifyAllPhaseHandlers() error
- func VerifyCompilers() error
- func VerifyExpanders() error
- type ChainFileResolver
- type ClausesWrapper
- type CompileTimeCallContext
- func (p CompileTimeCallContext) Context() context.Context
- func (p CompileTimeCallContext) NotInTail() CompileTimeCallContext
- func (p CompileTimeCallContext) UnderLetFrame(pushesFrame bool) CompileTimeCallContext
- func (p CompileTimeCallContext) WithEnclosingDefines(body []validate.ValidatedExpr) CompileTimeCallContext
- func (p CompileTimeCallContext) WithFrameReuse(fr frameReuse) CompileTimeCallContext
- type CompileTimeContinuation
- func (p *CompileTimeContinuation) AppendOperations(ops ...machine.Operation)
- func (p *CompileTimeContinuation) CompileBeginForSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileCondExpand(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileDefineForSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileDefineLibrary(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileDefineSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileEvalWhen(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileExport(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileExpression(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileImport(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileInclude(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileIncludeCi(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileMeta(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileQuasisyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileSelfEvaluating(_ CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileSymbol(ctctx CompileTimeCallContext, expr *syntax.SyntaxSymbol) error
- func (p *CompileTimeContinuation) CompileSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileSyntaxCase(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileUnquote(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileUnquoteSplicing(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileUnsyntax(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileUnsyntaxSplicing(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) CompileValidatedDefineFn(ctctx CompileTimeCallContext, v *validate.ValidatedDefine) error
- func (p *CompileTimeContinuation) CompileWithSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
- func (p *CompileTimeContinuation) SetFileResolver(r FileResolver)
- func (p *CompileTimeContinuation) SetInlineThreshold(n int)
- func (p *CompileTimeContinuation) SetLibraryCallback(cb func(*CompiledLibrary))
- type CompiledLibrary
- type CompilerFunc
- type ERMacroTransformer
- type EmbedFileResolver
- type ExpanderContext
- func (p *ExpanderContext) Env() *environment.EnvironmentFrame
- func (p *ExpanderContext) Expand(stx syntax.SyntaxValue) (syntax.SyntaxValue, error)
- func (p *ExpanderContext) ExpandOnce(stx syntax.SyntaxValue) (syntax.SyntaxValue, bool, error)
- func (p *ExpanderContext) IntroductionScope() *syntax.Scope
- func (p *ExpanderContext) SetIntroductionScope(scope *syntax.Scope)
- func (p *ExpanderContext) SetUseSiteScope(scope *syntax.Scope)
- func (p *ExpanderContext) UseSiteScope() *syntax.Scope
- type ExpanderTimeContinuation
- func (p *ExpanderTimeContinuation) ExpandBodyWithDefineSyntax(forms []syntax.SyntaxValue) ([]syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandExpression(expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandOnce(expr syntax.SyntaxValue) (syntax.SyntaxValue, bool, error)
- func (p *ExpanderTimeContinuation) ExpandPrimitiveForm(primName string, sym *syntax.SyntaxSymbol, expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandSelfEvaluating(expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandSymbol(expr *syntax.SyntaxSymbol) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandSyntaxArgumentList(args syntax.SyntaxValue) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandSyntaxExpression(sym *syntax.SyntaxSymbol, expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandSyntaxOrProcedureCall(car syntax.SyntaxValue, cdr syntax.SyntaxValue, ...) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) ExpandTopLevelExpression(expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
- func (p *ExpanderTimeContinuation) SetMaxDepth(n int)
- type FSFileResolver
- type FeatureRequirement
- func NewAndRequirement(reqs ...FeatureRequirement) FeatureRequirement
- func NewElseRequirement() FeatureRequirement
- func NewFeatureIdentifier(name string) FeatureRequirement
- func NewLibraryRequirement(name LibraryName) FeatureRequirement
- func NewNotRequirement(req FeatureRequirement) FeatureRequirement
- func NewOrRequirement(reqs ...FeatureRequirement) FeatureRequirement
- type FileResolver
- type FreeIdResolution
- type ImportSet
- type LibraryExportIndex
- type LibraryImportEvent
- type LibraryImportObserver
- type LibraryLoadProbe
- type LibraryName
- func DiscoverAvailableLibraries(res FileResolver, reg *LibraryRegistry) ([]LibraryName, error)
- func FilePathToLibraryName(path string) (LibraryName, error)
- func NewLibraryName(parts ...string) LibraryName
- func ParseLibraryNameFromDatum(ctx context.Context, expr values.Tuple) (LibraryName, error)
- func ParseLibraryNameFromSyntax(ctx context.Context, expr syntax.SyntaxValue) (LibraryName, error)
- type LibraryRegistry
- func (p *LibraryRegistry) All() []*CompiledLibrary
- func (p *LibraryRegistry) AllNames() []LibraryName
- func (p *LibraryRegistry) FinishLoading(name LibraryName)
- func (p *LibraryRegistry) GetSearchPaths() []string
- func (p *LibraryRegistry) ImportObserver() LibraryImportObserver
- func (p *LibraryRegistry) IsLoading(name LibraryName) bool
- func (p *LibraryRegistry) Lookup(name LibraryName) *CompiledLibrary
- func (p *LibraryRegistry) LookupClaimOrWait(name LibraryName) (cached *CompiledLibrary, wait <-chan struct{})
- func (p *LibraryRegistry) PrependSearchPath(path string)
- func (p *LibraryRegistry) Register(lib *CompiledLibrary) error
- func (p *LibraryRegistry) SetImportObserver(obs LibraryImportObserver)
- func (p *LibraryRegistry) SetSearchPaths(paths []string)
- type LibrarySummary
- type OSFileResolver
- type OperationBindPatternVars
- type OperationBuildSyntaxList
- type OperationClearSyntaxCaseInput
- type OperationStoreSyntaxCaseInput
- type OperationSyntaxCaseMatch
- type OperationSyntaxCaseNoMatch
- type OperationSyntaxRulesTransform
- type OperationSyntaxTemplateExpand
- type PhaseEntry
- type PrimitiveExpander
- func (p *PrimitiveExpander) EqualTo(other values.Value) bool
- func (p *PrimitiveExpander) Expand(etc *ExpanderTimeContinuation, sym *syntax.SyntaxSymbol, ...) (syntax.SyntaxValue, error)
- func (p *PrimitiveExpander) IsVoid() bool
- func (p *PrimitiveExpander) Name() string
- func (p *PrimitiveExpander) SchemeString() string
- type PrimitiveExpanderFunc
- type ResolvedImportSet
- type SourcedError
- type SyntaxCaseClause
- type SyntaxCompiler
- type SyntaxCompilerFunc
- type SyntaxRulesClause
Constants ¶
const ( // TransformerSyntaxRules is the leading symbol for (syntax-rules ...) transformers. TransformerSyntaxRules = "syntax-rules" // TransformerERMacro is the leading symbol for (er-macro-transformer ...) transformers. TransformerERMacro = "er-macro-transformer" // FormDefineSyntax is the form name for (define-syntax ...) definitions. FormDefineSyntax = "define-syntax" )
const DefaultInlineThreshold = 5
DefaultInlineThreshold is the default maximum body length for procedure inlining. A lambda body with more expressions than this is not inlined.
const DefaultMaxExpandDepth int = 50000
DefaultMaxExpandDepth bounds structural recursion depth during macro expansion. Without a bound, deeply nested syntax — reachable not from text (the parser caps that, see parser.DefaultMaxParseDepth) but from programmatically-constructed syntax such as macro output, datum->syntax, and quasiquote — triggers a fatal, unrecoverable Go stack overflow that kills the host process. 0 means unlimited. Mirrors the VM's DefaultMaxCallDepth and the parser's DefaultMaxParseDepth.
Chosen empirically: the expander overflows the Go stack between ~400k (heavy macro-re-expansion paths) and ~800k (light procedure-call nesting) levels; 50000 leaves an order-of-magnitude margin below the crash while sitting far above any practical program. A flat recursive macro (and/or/cond with N clauses) accumulates expansion depth linearly in N, but such forms are O(N^2) to expand and unusable well before 50000 clauses, so the bound does not regress any program anyone actually runs. Callers with genuinely deeper machine-generated syntax opt out via SetMaxDepth(0) / WithMaxExpandDepth(0).
const SchemeIncludePathEnv = resolver.SchemeIncludePathEnv
SchemeIncludePathEnv is the environment variable name for the Scheme include path.
Variables ¶
var DefaultLibraryPaths = []string{
".",
}
DefaultLibraryPaths are the default directories to search for libraries.
Only the current directory is searched by default. The embedded standard library is the real source of the stdlib (resolved via the FileResolver chain over stdlib.FS); the former "./pkg/stdlib/lib" entry was a development-tree convenience that resolves nothing in a deployed binary.
Functions ¶
func AllFeatures ¶
func AllFeatures() []string
AllFeatures returns all supported feature identifiers.
func BuildInlineHOFTemplates ¶
func BuildInlineHOFTemplates(ctx context.Context, env *environment.EnvironmentFrame) error
BuildInlineHOFTemplates parses, expands, and validates each curated HOF loop template against env (the sealed base) and stores the registry on env's Namespace. Idempotent: a no-op when a store is already installed (the root bootstrap builds it; flat library envs sharing the Namespace skip). A failure aborts engine init — the templates are fixed source, so it is a build bug.
func CompileSyntaxRules ¶
func CompileSyntaxRules(ctx context.Context, env *environment.EnvironmentFrame, syntaxRulesForm syntax.SyntaxValue, libraryScope *syntax.Scope) (*machine.MachineClosure, error)
CompileSyntaxRules compiles a syntax-rules form into a transformer procedure.
R7RS Forms:
(syntax-rules (literal ...) (pattern template) ...) (syntax-rules <ellipsis> (literal ...) (pattern template) ...) ; custom ellipsis
The compilation process:
- Parse optional custom ellipsis identifier
- Parse the literals list - these symbols are matched literally, not as variables
- For each clause, identify pattern variables (symbols not in literals list)
- Compile each pattern to bytecode (see match/syntax_compiler.go)
- Create a machine.MachineClosure that, when invoked: - Tries each pattern in order against the input form - On first match, expands the template with captured bindings - Adds an "intro scope" to the expansion for hygiene
The returned closure is stored in the environment with BindingTypeSyntax, allowing the expander to recognize it as a macro transformer.
func CompileValidatedApply ¶
func CompileValidatedApply(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedApply compiles a validated (apply proc arg1 ... args) form.
R7RS §6.10: apply calls proc with the arguments arg1 ... concatenated with the elements of args (the final argument, which must be a list).
Bytecode (non-tail):
SaveContinuation →after <compile proc> PUSH <compile arg1> PUSH ... <compile argN> PUSH <compile finalList> ; value = finalList OpUnpackListToStack ; stack: [proc, arg1, ..., argN, x1, x2, ...] Pull ; value = proc Apply ; calls proc(arg1, ..., argN, x1, x2, ...) after:
Tail position: same without SaveContinuation/patch.
func CompileValidatedBegin ¶
func CompileValidatedBegin(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedBegin compiles a validated (begin expr...) form.
begin (R7RS 4.2.3) sequences expressions for side effects. All expressions are evaluated left-to-right; the value of the last expression becomes the value of the entire begin form.
R7RS §5.3.2: Internal definitions use letrec* semantics - all defined names are visible throughout the body, enabling forward references between defines.
Example: (begin (display "hello") (newline) 42) => 42 (after printing)
func CompileValidatedCaseLambda ¶
func CompileValidatedCaseLambda(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedCaseLambda compiles a validated (case-lambda [clause] ...) form.
case-lambda (R7RS 4.2.9) creates a procedure that dispatches to different implementations based on the number of arguments. For example:
(case-lambda ((x) (* x x)) ; 1 arg: square ((x y) (* x y)) ; 2 args: multiply ((x y . rest) (apply + x y rest))) ; 2+ args: sum all
At runtime, the VM selects the first clause whose arity matches the call.
func CompileValidatedDefine ¶
func CompileValidatedDefine(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedDefine compiles a validated define form.
func CompileValidatedDynamicWind ¶
func CompileValidatedDynamicWind(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedDynamicWind compiles a validated (dynamic-wind before thunk after) form.
R7RS §6.10: dynamic-wind calls thunk without arguments, returning the result(s). Before is called whenever execution enters the dynamic extent of the call to thunk, and after is called whenever it exits.
The key insight is that by compiling to bytecode, the cleanup code (calling after) is in the bytecode stream. When a continuation is captured inside the thunk and later restored, the cleanup code will run on normal completion.
Bytecode structure:
<compile before> PUSH <compile thunk> PUSH <compile after> PUSH ; Stack: [before, thunk, after] PEEK_K 2 ; value = before SAVE_CONTINUATION →after_before APPLY ; call before() after_before: ; Stack: [before, thunk, after] OP_PUSH_WIND ; create winding frame PEEK_K 1 ; value = thunk SAVE_CONTINUATION →after_thunk APPLY ; call thunk() after_thunk: ; Stack: [before, thunk, after] BOX_VALUES ; collapse thunk's 0/1/N result values to one carrier PUSH ; save boxed result, Stack: [before, thunk, after, boxed] OP_POP_WIND ; pop winding frame PEEK_K 1 ; value = after SAVE_CONTINUATION →after_after APPLY ; call after() after_after: ; Stack: [before, thunk, after, boxed] PEEK_K 0 ; value = boxed result UNBOX_VALUES ; expand carrier back to thunk's 0/1/N values DROP DROP DROP DROP ; clean up stack
BOX_VALUES/UNBOX_VALUES keep the saved result at exactly one eval-stack slot: OpPush pushes every value in the register (PushAll for multiple, nothing for zero), so without boxing a thunk returning (values …) would mis-align the PeekK/Drop offsets (R7RS §6.10 requires dynamic-wind to return the thunk's values, including zero or several).
func CompileValidatedIf ¶
func CompileValidatedIf(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedIf compiles a validated (if test conseq [alt]) form. The structure is guaranteed to be valid by the validator.
Constant folding (Aho et al., Compilers §8.5): when the test is a compile-time literal, the entire if-form reduces to one branch. This is the simplest form of constant folding — evaluating known expressions at compile time rather than runtime. See BIBLIOGRAPHY.md "Constant Folding".
func CompileValidatedLambda ¶
func CompileValidatedLambda(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedLambda compiles a validated (lambda params body...) form.
func CompileValidatedLet ¶
func CompileValidatedLet(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedLet compiles all binding forms based on Kind.
let: <inits> Push... | OpPushEnv | StoreLocal(reverse) | body | OpPopEnv let*: OpPushEnv | (init Push StoreLocal)... | body | OpPopEnv letrec: OpPushEnv | <inits> Push... | StoreLocal(reverse) | body | OpPopEnv letrec*: OpPushEnv | (init Push StoreLocal)... | body | OpPopEnv
The trailing OpPopEnv is emitted only in non-tail position; a tail let leaves the frame for the enclosing return to unwind.
A MERGED let (canMergeLet, merged_slots.go) emits NEITHER bracket: its slots come out of the enclosing lambda's parameter frame, so the stores and loads above are the whole shape. That is the ordinary case — every let inside a procedure body — and the pushing form survives only where there is no frame to merge into (the top level, a syntax-case clause body).
func CompileValidatedQuasiquote ¶
func CompileValidatedQuasiquote(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedQuasiquote compiles a validated (quasiquote template) form. Quasiquote has complex runtime semantics, so we delegate to the existing compiler.
func CompileValidatedQuote ¶
func CompileValidatedQuote(p *CompileTimeContinuation, _ CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedQuote compiles a validated (quote datum) form.
func CompileValidatedSetBang ¶
func CompileValidatedSetBang(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedSetBang compiles a validated (set! name expr) form.
func CompileValidatedWithContinuationMark ¶
func CompileValidatedWithContinuationMark(p *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompileValidatedWithContinuationMark compiles (with-continuation-mark key val body).
Tail position:
<compile key> PUSH <compile val> SetContMark ; pops key, sets marks[key] = val <compile body in tail>
Non-tail position:
<compile key> PUSH <compile val> SaveContMark ; pops key, saves (key, old) on stack, sets mark <compile body in non-tail> RestoreContMark ; pops (old, key), restores mark
func CopyLibraryBindingsToEnv ¶
func CopyLibraryBindingsToEnv(lib *CompiledLibrary, bindings map[string]string, targetEnv *environment.EnvironmentFrame) error
CopyLibraryBindingsToEnv copies exported bindings from a library to an environment. bindings is the map from localName -> externalName produced by ApplyToExports. Both runtime and syntax bindings are copied. This is a convenience wrapper that imports to phase 0 (runtime).
func CopyLibraryBindingsToEnvAtPhase ¶
func CopyLibraryBindingsToEnvAtPhase(lib *CompiledLibrary, bindings map[string]string, targetEnv *environment.EnvironmentFrame, targetPhase environment.Phase) error
CopyLibraryBindingsToEnvAtPhase copies exported bindings from a library to a specific phase. bindings is the map from localName -> externalName produced by ApplyToExports.
Phase semantics:
- targetPhase == 0: Runtime import (default). Runtime bindings go to phase 0. A syntax binding that came from the library's expand phase skips the phase-0 install (skipBase below) and lands only at phase 1, so it cannot shadow the importer's own define-syntax.
- targetPhase > 0: For-syntax import. Bindings are shifted to the target phase. Runtime bindings become available during macro expansion at targetPhase. Syntax bindings follow the same skipBase rule: targetPhase+1 only.
- targetPhase < 0: For-template import. Bindings shifted to negative phase (used for generating code that will run at a lower phase).
func ExpandAndCompile ¶
func ExpandAndCompile(ctx context.Context, env *environment.EnvironmentFrame, stx syntax.SyntaxValue, resolver FileResolver, inlineThreshold int, maxExpandDepth int) (*machine.NativeTemplate, error)
ExpandAndCompile runs the expand+compile pipeline on a single syntax value, returning a ready-to-execute template.
A single MacroEvaluator is shared across both phases. If resolver is non-nil, it is set on the compiler for include/load file resolution. inlineThreshold controls procedure inlining (0 disables). maxExpandDepth bounds expander recursion to prevent a fatal Go stack overflow on deeply nested syntax (0 disables the bound; pass DefaultMaxExpandDepth for the standard limit). Errors are wrapped with phase context ("expansion" or "compilation"); callers may add site-specific context on top. Callers may call tpl.Optimize() on the returned template if desired.
func ImportSpecInto ¶
func ImportSpecInto(ctx context.Context, specVal values.Value, callerEnv, targetEnv *environment.EnvironmentFrame, evaluator machine.MacroEvaluator, op string) error
ImportSpecInto parses a single import-spec datum, loads the named library, applies the import set's modifiers (only/except/prefix/rename), and copies the resulting bindings into targetEnv at the spec's phase shift. It is the shared core of the (environment ...), (make-namespace ...), and (namespace-require ...) primitives; op names the calling primitive for error context. callerEnv supplies the library registry for resolution.
func IsFeatureSupported ¶
IsFeatureSupported checks if a feature identifier is supported.
func LoadBootstrapSources ¶
func LoadBootstrapSources(ctx context.Context, env *environment.EnvironmentFrame, sources []string, resolver FileResolver, kind string) error
LoadBootstrapSources runs the canonical bootstrap pipeline — parse → expand → compile → optimize → execute — for each source string against env, using the default inline and expand-depth thresholds. Templates ARE optimized and executed on a pooled top-level context, matching production engine initialization. The kind argument ("macro" / "procedure") names the source category in error context.
This is the single implementation shared by the engine-root (pkg/wile) and internal (internal/bootstrap) bootstrap paths. Each previously kept its own copy of this loop, and the copies had drifted: the internal one ran on a raw, unpooled context and did NOT optimize, so bootstrap procedures loaded via the internal API (test helpers, embedders on the internal API) ran unoptimized while the public NewEngine path optimized them. Consolidating here removes that divergence.
func LookupPhaseBinding ¶
func LookupPhaseBinding[T any]( phaseEnv *environment.EnvironmentFrame, sym *values.Symbol, scopes []*syntax.Scope, ) T
LookupPhaseBinding looks up a binding by symbol in the target phase environment. Returns the value cast to type T if found, or the zero value if not found or if the value is not of type T.
This function handles hygiene by using scoped lookup - it will only match bindings whose scopes are a subset of the symbol's scopes.
func NewERCompareClosure ¶
func NewERCompareClosure(useEnv *environment.EnvironmentFrame) *machine.ForeignClosure
NewERCompareClosure creates the `compare` closure for an ER macro invocation. useEnv is the use-site environment for resolving identifiers. The closure accepts two identifier arguments and returns #t if both resolve to the same binding (the same binding object, or two bindings sharing one import-provenance root, see erBindingsEqual) or both are unbound with the same name.
func NewERRenameClosure ¶
func NewERRenameClosure( defExpandEnv *environment.EnvironmentFrame, introScope *syntax.Scope, ) *machine.ForeignClosure
NewERRenameClosure creates the `rename` closure for an ER macro invocation. defExpandEnv is the definition-site expand environment. introScope is a fresh scope unique to this macro invocation, used to ensure that renamed symbols not found in the definition-site env (e.g., temporary names like 'tmp') get a unique identity that prevents variable capture. The returned closure accepts a single symbol argument and returns a SyntaxSymbol that resolves to the definition-site binding. Results are cached per symbol name so that (eq? (rename 'x) (rename 'x)) is #t.
func RegisterAllPhaseHandlers ¶
func RegisterAllPhaseHandlers(env *environment.EnvironmentFrame) error
RegisterAllPhaseHandlers registers both syntax compilers (compile phase) and primitive expanders (expand phase) in the correct order. Use this instead of calling RegisterSyntaxCompilers and RegisterPrimitiveExpanders separately at engine/bootstrap/test init sites.
func RegisterPhaseBindings ¶
func RegisterPhaseBindings[F any]( env *environment.EnvironmentFrame, phaseEnv func() *environment.EnvironmentFrame, entries []PhaseEntry[F], wrapper func(name string, fn F) values.Value, ) error
RegisterPhaseBindings binds all entries in the target phase environment. This is a generic helper for registering primitives in expand or compile phases.
Parameters:
- phaseEnv: Accessor for the target phase (e.g., env.Expand or env.Compile). This alone determines the target; env is not consulted.
- entries: Slice of (name, function) pairs to register
- wrapper: Creates the values.Value wrapper from name and function
func RegisterPrimitiveExpanders ¶
func RegisterPrimitiveExpanders(env *environment.EnvironmentFrame) error
RegisterPrimitiveExpanders binds all primitive expanders at (PhaseExpand, handler) — the sealed expand base, or a flat library frame's own expand child. These are looked up by ExpandPrimitiveForm() when the expander encounters a special form.
Each primitive has different expansion behavior:
- quote, define-syntax, define-library, quasiquote: return unchanged (no expansion)
- if: expand test, consequent, alternative separately
- begin: expand all subexpressions
- set!: expand only the value expression
- define: expand value if simple define
- lambda, case-lambda: expand body expressions
- syntax-case, cond-expand: return unchanged (compile-time forms)
func RegisterSyntaxCompilers ¶
func RegisterSyntaxCompilers(env *environment.EnvironmentFrame) error
RegisterSyntaxCompilers binds all syntax compilers through the level-0 SEALED-WRITE view, which every owner of a sealed axis has: the main namespace's, or a NewChildRuntime library env's own. Unlike the primitive expanders, these WANT the level-0 seal, because that is the one write whose coordinate is the ambient (AnyPhase, sealed) one — every other write, mutable at any level or sealed above 0, lands at an exact level (EnvironmentFrame.writeCoordinates). A binding placed here is therefore reachable from a frame at any level as the ranked probe's T3 tier, instead of being pinned to the PhaseCompile view.
This is a write COORDINATE, not a topology: phase views have no lexical parent, and hermeticity is key disjointness in the one store. Comments here once said "every phase frame parents to that taproot"; createPhaseEnv stopped reparenting when the store was flattened.
These bindings serve two purposes:
- Library export/import: findLibraryBinding in library_bindings.go searches the levels the library's own registry has instantiated (PresentPhases) to locate syntax compilers when exporting or importing forms like syntax-case, define-syntax, etc. A NewChildRuntime library env is an island — it owns its own store, so the engine root's ambient tier is not reachable from it at any level — and special forms stay ambient-only, unchanged by this relocation.
- Scope-aware lookup via LookupSyntaxCompiler for hygiene resolution.
Compilation dispatch itself goes through the forms registry (register.go), not through these bindings. Both paths are populated from syntaxCompilerEntries to stay in sync.
The syntax compilers are bound with BindingTypePrimitive to distinguish them from syntax transformers (BindingTypeSyntax) and regular variables.
func ResolveAndInstallImportSet ¶
func ResolveAndInstallImportSet(ctx context.Context, datum values.Value, env *environment.EnvironmentFrame, phase environment.Phase, evaluator machine.MacroEvaluator) error
ResolveAndInstallImportSet resolves an import set and installs bindings into env. Used for top-level imports (both expander and compiler). Library-internal imports share the resolution step (resolveImportSet) but use copyLibraryBindingsDirect for installation.
The phase argument is import-observer metadata only; it does NOT select the install phase. That comes from composePhaseShift below, which combines the environment's own phase level with the import set's for-syntax/for-meta shift.
func ResolveLibraryFile ¶
func ResolveLibraryFile(ctx context.Context, res FileResolver, name LibraryName) (fs.File, string, error)
ResolveLibraryFile resolves a library name to an open file handle, trying each extension in libraryExtensions order. Non-file-not-found errors (security denial, I/O) propagate immediately: only the ABSENCE of the .sld licenses trying the .scm, or an unreadable .sld would silently be replaced by a readable file of the same name.
func StampInlineHOFs ¶
func StampInlineHOFs(frame *environment.EnvironmentFrame)
StampInlineHOFs sweeps frame's own bindings, stamping every curated SEALED-BASE tail HOF bound there. Called post-bootstrap on the sealed base. Import-gated entries (fold, fold-right) are skipped here and stamped on their import path instead.
func TemplateLocalEmits ¶ added in v1.20.0
func TemplateLocalEmits() uint64
TemplateLocalEmits reports how many syntax-template occurrences have been emitted as local loads in this process. Ratchet on a DIFFERENCE across a known unit of work, never on the absolute value.
func VerifyAllPhaseHandlers ¶
func VerifyAllPhaseHandlers() error
VerifyAllPhaseHandlers cross-checks all three phase registries: form validators (internal/forms), compilers (Tier 1 + Tier 2), and primitive expanders. Returns the first inconsistency found, or nil.
Call from tests only — not on the production init path.
func VerifyCompilers ¶
func VerifyCompilers() error
VerifyCompilers checks that every registered form either carries a valid CompilerFunc on its FormSpec or is classified expand-only in formDispatch. The type-checked assertion catches a mis-typed Compile (any → non-CompilerFunc), which compilerFor would otherwise swallow to a nil "no compiler" diagnostic.
func VerifyExpanders ¶
func VerifyExpanders() error
VerifyExpanders checks that every Tier 2 syntax compiler entry has a corresponding primitive expander entry. A Tier 2 form without an expander is silently treated as a procedure call during expansion — the most dangerous form of registration drift.
Types ¶
type ChainFileResolver ¶
type ChainFileResolver = resolver.ChainFileResolver
func NewChainFileResolver ¶
func NewChainFileResolver(resolvers []environment.FileResolver) *ChainFileResolver
NewChainFileResolver creates a resolver that searches multiple resolvers.
type ClausesWrapper ¶
type ClausesWrapper struct {
Clauses []*SyntaxRulesClause
}
ClausesWrapper wraps a slice of SyntaxRulesClause as a values.Value for storage in NativeTemplate literals.
func (*ClausesWrapper) IsVoid ¶
func (p *ClausesWrapper) IsVoid() bool
func (*ClausesWrapper) SchemeString ¶
func (p *ClausesWrapper) SchemeString() string
type CompileTimeCallContext ¶
type CompileTimeCallContext struct {
// contains filtered or unexported fields
}
CompileTimeCallContext carries contextual information through the compilation process. It tracks whether an expression is in tail position, which controls whether the compiler emits SaveContinuation (non-tail) or reuses the current frame (tail).
This structure is passed by value (not pointer) through the compiler, allowing each compilation step to create modified copies without affecting the caller's context.
Tail Call Optimization ¶
Tail call optimization (Steele 1977, R7RS §3.5): tail calls reuse the caller's continuation frame instead of allocating a new one, making recursive procedures in tail position run in constant stack space. See BIBLIOGRAPHY.md "Tail Call Optimization".
The inTail flag tracks whether an expression is in tail position. An expression is in tail position if its value will be the final result of the enclosing procedure. When inTail is true, the compiler can generate a tail call that reuses the current stack frame instead of creating a new one, preventing stack overflow in recursive procedures.
Per R7RS Section 3.5, these positions are tail positions:
- The body of a lambda expression
- The last expression in a begin sequence (if the begin is in tail position)
- The consequent and alternative of an if expression (if the if is in tail position)
- The body of a let/let*/letrec (if the let is in tail position)
These are NOT tail positions (use NotInTail()):
- Function arguments: (f (g x)) - the call to g is not in tail position
- Condition of if: (if (pred x) ...) - pred is not in tail position
- Definitions: (define x (expr)) - expr is not in tail position
- Non-final expressions in begin: (begin (a) (b) (c)) - only c is in tail position
func NewCompileTimeCallContext ¶
func NewCompileTimeCallContext(ctx context.Context, inTail bool) CompileTimeCallContext
NewCompileTimeCallContext creates a new compile-time context. Parameters:
- inTail: true if compiling an expression in tail position
func (CompileTimeCallContext) Context ¶
func (p CompileTimeCallContext) Context() context.Context
Context returns the context associated with this compile-time call context.
func (CompileTimeCallContext) NotInTail ¶
func (p CompileTimeCallContext) NotInTail() CompileTimeCallContext
NotInTail returns a copy of the context with inTail set to false. Use this when compiling sub-expressions that are not in tail position:
- Function arguments
- Condition expressions in if
- Initial values in define/let bindings
- Non-final expressions in begin
Example:
// Compiling (f (g x)) - the call to g is not in tail position err := p.CompileExpression(ctctx.NotInTail(), argExpr)
func (CompileTimeCallContext) UnderLetFrame ¶ added in v1.20.0
func (p CompileTimeCallContext) UnderLetFrame(pushesFrame bool) CompileTimeCallContext
UnderLetFrame returns a copy describing the body of a let. It is the ONLY site that may say so, because it is paired 1:1 with compileValidatedLet's single descent into a body.
pushesFrame says whether that let emitted an OpPushEnv. A merged let does not (compilation/merged_slots.go): its slots live in the enclosing lambda's frame, so the body runs in the SAME runtime frame the head did.
The two dispositions answer differently, and the asymmetry is the phase:
SELF-TAIL survives, with letDepth incremented ONLY for a pushing let. OpSelfTailCall pops that many frames before rebinding, so a self call under a let is rewritable after all (frame-reclaim Phase C). Before Phase C this cleared, and the call leaked one parameter frame per iteration. A merged let contributes no frame, so incrementing would unwind the parameter frame's PARENT — the count has to equal the runtime frame count by construction, which is the whole reason it is counted here rather than by a second walk.
RELEASE survives a MERGED let and is still cleared by a pushing one. For a pushing let the reason is that OpReleaseEnvFrame releases mc.env, which inside the body is the LET frame — not pool-owned, so the release would be a no-op at best. A merged let removes that reason exactly: mc.env inside its body IS the enclosing pooled parameter frame, and the merged slots the body reads are slots OF that frame, so the enclosing body's releasability proof covers them unchanged.
Merging on its own recovers only the RETURN-path release (no OpPushEnv means no envPooled clear, so RestoreAndRelease recycles). A frame abandoned at a general TAIL call still needs the explicit OpReleaseEnvFrame, and 92% of let frames are in tail position, so this clause is what reaches them. Measured on the Gabriel corpus at the default immutable top level: nqueens 2,264 -> 868,868 releases, pool hit 78.6% -> 88.8%, wall −3.5%. It does NOT explain schelog zebra's 66.9% — that harness needs a mutable top level, under which no global callee is Stable and frame reclaim arms nowhere at all. See memory/flat-closure-baseline.local.md §6.
The peephole hazard this used to name is real but belongs to the peephole: a fusion that hoisted a PushLocal callee across the release would resolve it out of the frame just handed to the pool. The interior scans refuse that by callee kind (peephole.go, releaseSafeCallee) rather than by refusing to emit the release.
func (CompileTimeCallContext) WithEnclosingDefines ¶ added in v1.19.1
func (p CompileTimeCallContext) WithEnclosingDefines(body []validate.ValidatedExpr) CompileTimeCallContext
WithEnclosingDefines returns a copy carrying the body sequence whose internal defines form the letrec* group currently being compiled — the group InternalDefineFrameReleasable needs to prove one member releasable, since a define alone cannot name its own siblings.
It must be set wherever internal defines are PREDECLARED (the three predeclareDefineFromValidatedRecursive / predeclareBodyDefines sites), and reset rather than inherited on the way into a nested body: a lambda body starts a fresh context, and a let body overrides with its own. Inheriting a stale body would be a correctness bug, not just imprecision, which is why the predicate independently verifies the define is a member of what it is handed.
func (CompileTimeCallContext) WithFrameReuse ¶
func (p CompileTimeCallContext) WithFrameReuse(fr frameReuse) CompileTimeCallContext
WithFrameReuse returns a copy armed with the given frame-reuse disposition. Preserves inTail and ctx.
type CompileTimeContinuation ¶
type CompileTimeContinuation struct {
// contains filtered or unexported fields
}
CompileTimeContinuation is a continuation used during the compilation phase
func NewCompileTimeContinuation ¶
func NewCompileTimeContinuation(tpl *machine.NativeTemplate, env *environment.EnvironmentFrame, evaluator machine.MacroEvaluator) *CompileTimeContinuation
NewCompileTimeContinuation creates a new CompileTimeContinuation. The file resolver defaults to the one stored on the Namespace. If none is set, falls back to a fresh OSFileResolver.
func (*CompileTimeContinuation) AppendOperations ¶
func (p *CompileTimeContinuation) AppendOperations(ops ...machine.Operation)
AppendOperations appends operations tagged with the current source from the source stack. Routes through the integer-dispatch code[] path: Wave 1-3 operations become direct instructions, everything else goes via machine.OpComplex to the sideTable.
func (*CompileTimeContinuation) CompileBeginForSyntax ¶
func (p *CompileTimeContinuation) CompileBeginForSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileBeginForSyntax handles (begin-for-syntax expr ...).
Evaluates a sequence of expressions at compile time in the expand phase environment. Used for setting up compile-time state (hash tables, registries) that macros can access. No runtime effect — used for side effects only.
func (*CompileTimeContinuation) CompileCondExpand ¶
func (p *CompileTimeContinuation) CompileCondExpand(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileCondExpand compiles a cond-expand expression. cond-expand is evaluated at compile-time and expands to the body of the first clause whose feature requirement is satisfied.
Syntax: (cond-expand <clause> ...) where <clause> is (<feature-requirement> <expression> ...)
Example:
(cond-expand (r7rs (display "R7RS")) (else (display "other")))
func (*CompileTimeContinuation) CompileDefineForSyntax ¶
func (p *CompileTimeContinuation) CompileDefineForSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileDefineForSyntax handles (define-for-syntax name expr) or (define-for-syntax (name args...) body...).
This form defines a binding in the expand phase environment that is available during macro expansion. The expression is compiled and evaluated at compile time, and the result is stored one phase up from the defining frame (env.NextPhase(); equals env.Expand() at phase 0).
Unlike define-syntax (which stores macro transformers), define-for-syntax stores regular values with BindingTypeVariable.
func (*CompileTimeContinuation) CompileDefineLibrary ¶
func (p *CompileTimeContinuation) CompileDefineLibrary(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileDefineLibrary handles (define-library (lib-name) <library-declaration> ...).
R7RS library syntax:
(define-library <library-name> <library-declaration> ...) <library-declaration> = | (export <export-spec> ...) | (import <import-set> ...) | (begin <command-or-definition> ...) | (include <filename> ...) | (include-ci <filename> ...) | (include-library-declarations <filename> ...) | (cond-expand <ce-clause> ...) | (description <string>)
This creates an isolated environment for the library, processes declarations in order, and hands the finished CompiledLibrary to the library callback (LoadLibrary is what installs it in the registry).
func (*CompileTimeContinuation) CompileDefineSyntax ¶
func (p *CompileTimeContinuation) CompileDefineSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileDefineSyntax handles (define-syntax keyword transformer-expr).
This is the compile-time handler for R7RS define-syntax. Unlike most definitions, define-syntax is processed entirely at compile time:
- Parse the form: (define-syntax keyword (syntax-rules ...))
- Compile the syntax-rules transformer to a machine.MachineClosure
- Store the closure in the environment with BindingTypeSyntax
- Emit NO runtime operations (the binding is already established)
The BindingTypeSyntax marker is crucial: when the expander encounters a symbol, it checks if that symbol is bound to a syntax transformer. If so, it invokes the transformer closure to expand the macro.
This is how derived expressions like 'let' work: they're defined as macros using define-syntax, and expand to lambda expressions:
(define-syntax let
(syntax-rules ()
((let ((name val) ...) body)
((lambda (name ...) body) val ...))))
Reference: R7RS Section 5.4 (Syntax definitions)
func (*CompileTimeContinuation) CompileEvalWhen ¶
func (p *CompileTimeContinuation) CompileEvalWhen(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileEvalWhen handles (eval-when (phase ...) body ...).
This form controls when code is evaluated based on phase specifiers. Phase names follow Chez Scheme's eval-when (Dybvig, TSPL §12.10):
- expand: evaluate during macro expansion (at compile time)
- compile: evaluate during compilation (currently same as expand)
- run: evaluate at runtime (generate code for normal execution)
Multiple phases can be specified. If both expand and run are specified, the body is evaluated at compile time AND code is generated for runtime.
eval-when is not part of R7RS-small; it is a Wile extension.
Examples:
(eval-when (expand) (display "at expansion time")) (eval-when (run) (display "at runtime")) (eval-when (expand run) (display "both times"))
func (*CompileTimeContinuation) CompileExport ¶
func (p *CompileTimeContinuation) CompileExport(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
CompileExport handles top-level (export <export-spec> ...).
This is only valid within a library definition. At top-level, it's an error.
func (*CompileTimeContinuation) CompileExpression ¶
func (p *CompileTimeContinuation) CompileExpression(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileExpression compiles a general expression. Pushes the expression's source context onto the source stack so that all operations emitted during compilation (including infrastructure ops like Branch and Push) are tagged with the source location.
func (*CompileTimeContinuation) CompileImport ¶
func (p *CompileTimeContinuation) CompileImport(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileImport handles top-level (import <import-set> ...).
This is for top-level imports outside of a library definition. It loads the specified libraries and binds their exports in the current environment.
Supports Racket-style phased imports:
- (import (scheme base)) ; Phase 0 (runtime)
- (import (for-syntax (scheme base))) ; Phase 1 (expand)
- (import (for-template (scheme base))) ; Phase -1
- (import (for-meta 2 (scheme base))) ; Phase 2
func (*CompileTimeContinuation) CompileInclude ¶
func (p *CompileTimeContinuation) CompileInclude(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileInclude compiles an include expression. It reads and compiles all forms from the specified files in order. Each form is expanded and compiled in the current environment.
func (*CompileTimeContinuation) CompileIncludeCi ¶
func (p *CompileTimeContinuation) CompileIncludeCi(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileIncludeCi compiles an include-ci expression (R7RS §4.1.7 / §5.6). It is identical to include except that each included file is read with case folding enabled, as if the file began with a #!fold-case directive.
func (*CompileTimeContinuation) CompileMeta ¶
func (p *CompileTimeContinuation) CompileMeta(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileMeta compiles a meta expression.
func (*CompileTimeContinuation) CompileQuasisyntax ¶
func (p *CompileTimeContinuation) CompileQuasisyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileQuasisyntax compiles the (quasisyntax template) form.
quasisyntax is like quasiquote but for syntax objects. It supports:
- (unsyntax expr) - evaluate expr and insert the result at depth 1
- (unsyntax-splicing expr) - evaluate and splice list at depth 1
- nested quasisyntax increases depth
Like quasiquote, unsyntax only evaluates when depth reaches 0. The result is a syntax object, not a raw datum.
func (*CompileTimeContinuation) CompileSelfEvaluating ¶
func (p *CompileTimeContinuation) CompileSelfEvaluating(_ CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileSelfEvaluating compiles a self-evaluating expression (literal).
func (*CompileTimeContinuation) CompileSymbol ¶
func (p *CompileTimeContinuation) CompileSymbol(ctctx CompileTimeCallContext, expr *syntax.SyntaxSymbol) error
CompileSymbol compiles a syntax symbol expression.
Resolution order (Flatt 2016 "sets of scopes"): a scope-set local match wins over everything, including a ResolvedBinding pin carried from macro expansion. This lets a binding co-introduced by a template — which carries the same intro scope as the reference — shadow a same-named global. The ResolvedBinding and library-scope fallbacks fire only when no lexical binding shadows. See plans/2026-06-15-macro-hygiene-global-shadow-fix.local.md (Change 2).
func (*CompileTimeContinuation) CompileSyntax ¶
func (p *CompileTimeContinuation) CompileSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileSyntax compiles the (syntax template) form.
Unlike quote which unwraps syntax to raw values, syntax preserves the syntax structure. When used inside syntax-case, pattern variables in the template are substituted with their matched values.
For templates containing ellipsis (...), runtime expansion is used because ellipsis patterns capture variable-length lists that must be expanded dynamically.
(syntax template) -> syntax-object
func (*CompileTimeContinuation) CompileSyntaxCase ¶
func (p *CompileTimeContinuation) CompileSyntaxCase(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileSyntaxCase compiles the (syntax-case expr (literal ...) clause ...) form.
R6RS syntax-case is a pattern matching form that provides procedural macro facilities. Unlike syntax-rules which expands to templates, syntax-case evaluates arbitrary Scheme code in the body, with pattern variables bound as local variables.
Syntax:
(syntax-case expr (literal ...) (pattern body) (pattern fender body) ...)
Compilation strategy:
- Compile expr to get the input syntax object
- For each clause, generate pattern matching and body code
- Pattern variables are bound as local variables in the body's scope
- If fender exists, it's evaluated as a guard condition
func (*CompileTimeContinuation) CompileUnquote ¶
func (p *CompileTimeContinuation) CompileUnquote(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
CompileUnquote errors - unquote outside of quasiquote
func (*CompileTimeContinuation) CompileUnquoteSplicing ¶
func (p *CompileTimeContinuation) CompileUnquoteSplicing(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
CompileUnquoteSplicing errors - unquote-splicing outside of quasiquote
func (*CompileTimeContinuation) CompileUnsyntax ¶
func (p *CompileTimeContinuation) CompileUnsyntax(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
CompileUnsyntax errors - unsyntax outside of quasisyntax
func (*CompileTimeContinuation) CompileUnsyntaxSplicing ¶
func (p *CompileTimeContinuation) CompileUnsyntaxSplicing(_ CompileTimeCallContext, _ syntax.SyntaxValue) error
CompileUnsyntaxSplicing errors - unsyntax-splicing outside of quasisyntax
func (*CompileTimeContinuation) CompileValidatedDefineFn ¶
func (p *CompileTimeContinuation) CompileValidatedDefineFn(ctctx CompileTimeCallContext, v *validate.ValidatedDefine) error
CompileValidatedDefineFn compiles the function shorthand form of define.
Usage: (define (name param ...) body ...)
(define (name param ... . rest) body ...)
This is syntactic sugar equivalent to:
(define name (lambda (param ...) body ...))
Examples:
(define (square x) (* x x)) ; fixed arity (define (sum . args) (apply + args)) ; variadic (all args) (define (sum x . rest) (apply + x rest)) ; variadic (1+ args)
The function name is bound before compiling the body to enable self-recursion:
(define (fact n) (if (<= n 1) 1 (* n (fact (- n 1)))))
func (*CompileTimeContinuation) CompileWithSyntax ¶
func (p *CompileTimeContinuation) CompileWithSyntax(ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
CompileWithSyntax compiles the (with-syntax ((pattern expr) ...) body ...) form.
with-syntax is a convenience form for binding pattern variables from expressions. It's equivalent to:
(syntax-case (list expr ...) () ((pattern ...) (begin body ...)))
For now, this implements a simple transformation approach.
func (*CompileTimeContinuation) SetFileResolver ¶
func (p *CompileTimeContinuation) SetFileResolver(r FileResolver)
SetFileResolver overrides the file resolver used by include/load. Nil resets to the environment's resolver (or OSFileResolver as fallback).
func (*CompileTimeContinuation) SetInlineThreshold ¶
func (p *CompileTimeContinuation) SetInlineThreshold(n int)
SetInlineThreshold sets the maximum body length for procedure inlining. 0 disables inlining entirely.
func (*CompileTimeContinuation) SetLibraryCallback ¶
func (p *CompileTimeContinuation) SetLibraryCallback(cb func(*CompiledLibrary))
SetLibraryCallback sets a callback function that will be called when a library is compiled via CompileDefineLibrary. This is used by LoadLibrary to capture the compiled library.
type CompiledLibrary ¶
type CompiledLibrary struct {
Name LibraryName // Library name
Description string // from (description ...) clause; "" if absent
Env *environment.EnvironmentFrame // Library's private environment
Exports map[string]string // external-name -> internal-name
SourceFile string // Path to .sld file (for error messages)
Template *machine.NativeTemplate // Compiled bytecode (for execution)
// Scope is the library's own hygiene scope, the one every binder written in
// the library body carries. It is the KEY the export lookup resolves under
// (findLibraryBinding), which is what lets a library define a name it also
// imports: the define lands at {Scope}, the import at {}, and maximal
// resolution prefers the define while {} ⊆ {Scope} still reaches a name the
// library only re-exports. Nil for a library built without a body scope, in
// which case the export lookup degrades to the empty set.
Scope *syntax.Scope
}
CompiledLibrary holds a loaded and compiled library.
func LoadLibrary ¶
func LoadLibrary(ctx context.Context, name LibraryName, env *environment.EnvironmentFrame, evaluator machine.MacroEvaluator) (*CompiledLibrary, error)
LoadLibrary loads a library by name, compiling and executing it if not already loaded. Returns the CompiledLibrary which can be used to import bindings.
The function: 1. Checks for circular dependencies 2. Checks if already loaded (returns cached library) 3. Resolves and opens the library file via FileResolver 4. Parses and compiles the define-library form 5. Executes the library to create runtime bindings 6. Registers the library in the registry
func NewCompiledLibrary ¶
func NewCompiledLibrary(name LibraryName, env *environment.EnvironmentFrame) *CompiledLibrary
NewCompiledLibrary creates a new compiled library.
func (*CompiledLibrary) AddExport ¶
func (p *CompiledLibrary) AddExport(externalName, internalName string)
AddExport adds an export to the library. If internalName is empty, it defaults to externalName (no rename).
func (*CompiledLibrary) ExportedBinding ¶ added in v1.19.0
func (p *CompiledLibrary) ExportedBinding(internalName string) (*environment.Binding, bool)
ExportedBinding resolves one of the library's exportable bindings by its internal name, using the same hygienic rule the import path uses. Callers outside this package (the doc-registration observer) must go through this rather than reaching into lib.Env with a bare-name lookup, or they will disagree with what an import actually installs.
func (*CompiledLibrary) GetInternalName ¶
func (p *CompiledLibrary) GetInternalName(externalName string) string
GetInternalName returns the internal name for an exported external name. Returns empty string if not exported.
func (*CompiledLibrary) IsExported ¶
func (p *CompiledLibrary) IsExported(externalName string) bool
IsExported returns true if the given external name is exported.
type CompilerFunc ¶
type CompilerFunc func(ctc *CompileTimeContinuation, ctctx CompileTimeCallContext, expr forms.ValidatedExpr) error
CompilerFunc is the uniform codegen signature for both Tier-1 and Tier-2 forms, dispatched by FormName through the per-engine forms registry. Its parameter is the ValidatedExpr interface (not a concrete type) so one type covers every form; each handler asserts its concrete type at its head.
type ERMacroTransformer ¶
type ERMacroTransformer struct {
// contains filtered or unexported fields
}
ERMacroTransformer wraps a 3-arg machine.MachineClosure to identify it as an explicit-renaming transformer in expandMacroInvocation. The defEnv captures the expand-time environment at the macro definition site, used by the rename closure to resolve definition-site bindings.
func NewERMacroTransformer ¶
func NewERMacroTransformer(closure *machine.MachineClosure, defEnv *environment.EnvironmentFrame) *ERMacroTransformer
func (*ERMacroTransformer) Closure ¶
func (p *ERMacroTransformer) Closure() *machine.MachineClosure
func (*ERMacroTransformer) DefEnv ¶
func (p *ERMacroTransformer) DefEnv() *environment.EnvironmentFrame
func (*ERMacroTransformer) IsVoid ¶
func (p *ERMacroTransformer) IsVoid() bool
func (*ERMacroTransformer) SchemeString ¶
func (p *ERMacroTransformer) SchemeString() string
type EmbedFileResolver ¶
type EmbedFileResolver = resolver.EmbedFileResolver
func NewEmbedFileResolver ¶
func NewEmbedFileResolver(fsys fs.FS) *EmbedFileResolver
NewEmbedFileResolver creates a resolver backed by an embedded filesystem.
type ExpanderContext ¶
type ExpanderContext struct {
// contains filtered or unexported fields
}
ExpanderContext provides access to the macro expander from within Scheme code during macro expansion. It is set on machine.MachineContext when invoking macro transformers, enabling syntax-local-* primitives.
func NewExpanderContext ¶
func NewExpanderContext( env *environment.EnvironmentFrame, expander *ExpanderTimeContinuation, ) *ExpanderContext
NewExpanderContext creates a new ExpanderContext.
func (*ExpanderContext) Env ¶
func (p *ExpanderContext) Env() *environment.EnvironmentFrame
Env returns the environment frame associated with this context.
func (*ExpanderContext) Expand ¶
func (p *ExpanderContext) Expand(stx syntax.SyntaxValue) (syntax.SyntaxValue, error)
Expand fully expands a syntax object.
func (*ExpanderContext) ExpandOnce ¶
func (p *ExpanderContext) ExpandOnce(stx syntax.SyntaxValue) (syntax.SyntaxValue, bool, error)
ExpandOnce performs a single step of macro expansion. Returns (expanded-syntax, did-expand, error). If the input is a macro call, it expands it once and returns (result, true, nil). If the input is not a macro call, it returns (input, false, nil).
func (*ExpanderContext) IntroductionScope ¶
func (p *ExpanderContext) IntroductionScope() *syntax.Scope
IntroductionScope returns the introduction scope for the current macro expansion. This scope is added to identifiers introduced by a macro and can be flipped using syntax-local-introduce.
func (*ExpanderContext) SetIntroductionScope ¶
func (p *ExpanderContext) SetIntroductionScope(scope *syntax.Scope)
SetIntroductionScope sets the introduction scope for the current macro expansion.
func (*ExpanderContext) SetUseSiteScope ¶
func (p *ExpanderContext) SetUseSiteScope(scope *syntax.Scope)
SetUseSiteScope sets the use-site scope for binding forms.
func (*ExpanderContext) UseSiteScope ¶
func (p *ExpanderContext) UseSiteScope() *syntax.Scope
UseSiteScope returns the use-site scope for binding forms. This scope is used by syntax-local-identifier-as-binding to mark identifiers as binding sites.
type ExpanderTimeContinuation ¶
type ExpanderTimeContinuation struct {
// contains filtered or unexported fields
}
ExpanderTimeContinuation is a continuation used during the expansion phase.
It walks the syntax tree, detecting and expanding macro invocations. The env field provides access to macro definitions (BindingTypeSyntax bindings).
func NewExpanderTimeContinuation ¶
func NewExpanderTimeContinuation(ctx context.Context, env *environment.EnvironmentFrame, evaluator machine.MacroEvaluator) *ExpanderTimeContinuation
NewExpanderTimeContinuation creates a new ExpanderTimeContinuation. The returned expander begins a fresh expansion run with its own depth guard. The bound is read from the env's namespace (WithMaxExpandDepth, forwarded onto the shared EngineServices at engine build) so every expander site — the top-level pass and the ~8 compile-time re-expansion sites reached during library and body compilation — honors it uniformly. A namespace not built by an Engine (e.g., a direct unit-test compiler) reports unset and defaults to DefaultMaxExpandDepth. SetMaxDepth still overrides per-run afterward.
func (*ExpanderTimeContinuation) ExpandBodyWithDefineSyntax ¶
func (p *ExpanderTimeContinuation) ExpandBodyWithDefineSyntax( forms []syntax.SyntaxValue, ) ([]syntax.SyntaxValue, error)
ExpandBodyWithDefineSyntax expands a sequence of body forms, compiling define-syntax forms as encountered so subsequent forms can use the macros.
This unifies the expansion pattern used by: - Lambda bodies (internal define-syntax) - Library bodies (top-level define-syntax) - Include files (top-level define-syntax)
R7RS §5.3: Internal define-syntax forms must be processed before expanding subsequent body expressions so that locally-defined macros are visible.
R7RS §5.3.2: Bodies use letrec* semantics where all defined names are visible to all initializers. This enables forward references within macros - a macro can reference a definition that appears later in the same body.
func (*ExpanderTimeContinuation) ExpandExpression ¶
func (p *ExpanderTimeContinuation) ExpandExpression(expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
ExpandExpression expands a syntax expression.
This is the single recursion chokepoint of the expander: every descent into a sub-expression — nested cars, argument lists, primitive-form bodies (via child expanders), and macro re-expansion — funnels through here. The depth guard therefore bounds total Go-stack recursion for the whole expansion run, returning a catchable ErrExpandDepthExceeded instead of letting deeply nested (programmatically-constructed) syntax crash the host with a fatal Go stack overflow. See expandDepthGuard and DefaultMaxExpandDepth.
func (*ExpanderTimeContinuation) ExpandOnce ¶
func (p *ExpanderTimeContinuation) ExpandOnce(expr syntax.SyntaxValue) (syntax.SyntaxValue, bool, error)
ExpandOnce performs a single step of macro expansion. Returns (expanded-syntax, did-expand, error). If the input is a macro call, it expands it once and returns (result, true, nil). If the input is not a macro call, it returns (input, false, nil). Unlike ExpandExpression, this does NOT recursively expand the result.
func (*ExpanderTimeContinuation) ExpandPrimitiveForm ¶
func (p *ExpanderTimeContinuation) ExpandPrimitiveForm(primName string, sym *syntax.SyntaxSymbol, expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
ExpandPrimitiveForm handles expansion within primitive forms like if, begin, lambda, define, etc. Some primitives need their subexpressions expanded (like if, begin) while others should be left unchanged (like quote, define-syntax).
This function looks up the primitive expander in the expanded environment registry. If found, it invokes the expander; otherwise returns the form unchanged.
func (*ExpanderTimeContinuation) ExpandSelfEvaluating ¶
func (p *ExpanderTimeContinuation) ExpandSelfEvaluating(expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
ExpandSelfEvaluating handles self-evaluating expressions.
func (*ExpanderTimeContinuation) ExpandSymbol ¶
func (p *ExpanderTimeContinuation) ExpandSymbol(expr *syntax.SyntaxSymbol) (syntax.SyntaxValue, error)
ExpandSymbol handles a symbol expression.
func (*ExpanderTimeContinuation) ExpandSyntaxArgumentList ¶
func (p *ExpanderTimeContinuation) ExpandSyntaxArgumentList(args syntax.SyntaxValue) (syntax.SyntaxValue, error)
ExpandSyntaxArgumentList expands each argument in the argument list. It returns a new syntax list with the expanded arguments.
func (*ExpanderTimeContinuation) ExpandSyntaxExpression ¶
func (p *ExpanderTimeContinuation) ExpandSyntaxExpression(sym *syntax.SyntaxSymbol, expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
ExpandSyntaxExpression checks if sym is a macro and expands it, or returns the expression as a procedure call if not.
This is where macro invocation happens:
- Look up the symbol in the expand environment
- If bound with BindingTypeSyntax, it's a macro - invoke the transformer
- If it's a primitive (like quote, if, define-syntax), don't expand args
- Otherwise, treat as procedure call and expand arguments
The transformer closure (machine.MachineClosure from CompileSyntaxRules) is invoked by creating a machine.MachineContext and running it. The transformer:
- Receives the full macro invocation form on the eval stack
- Pattern matches against its clauses (OperationSyntaxRulesTransform)
- Expands the matching template with captured bindings
- Adds an intro scope to the expansion for hygiene
- Returns the expanded syntax in the value register
The expanded result may itself contain macro invocations, so the caller should recursively expand it.
func (*ExpanderTimeContinuation) ExpandSyntaxOrProcedureCall ¶
func (p *ExpanderTimeContinuation) ExpandSyntaxOrProcedureCall(car syntax.SyntaxValue, cdr syntax.SyntaxValue, parentCtx *syntax.SourceContext) (syntax.SyntaxValue, error)
ExpandSyntaxOrProcedureCall handles a list expression. The car may be a symbol (possibly a macro), a nested pair (computed procedure), or a self-evaluating value (like in quoted data or malformed expressions).
func (*ExpanderTimeContinuation) ExpandTopLevelExpression ¶ added in v1.19.0
func (p *ExpanderTimeContinuation) ExpandTopLevelExpression(expr syntax.SyntaxValue) (syntax.SyntaxValue, error)
ExpandTopLevelExpression expands a whole TOP-LEVEL form.
Use this at every top-level entry point (the Engine's ExpandAndCompile, the test-harness pipelines); use ExpandExpression for sub-forms.
Hygiene for a macro-introduced top-level binder is a property of the GLOBAL FRAME, not of this expansion step: the binder carries the expansion's intro scope and the frame keys its slots by scope set, so two expansions land in two slots and a bare (empty-scope) reference cannot reach either (R7RS §4.3.2). This used to be restored syntactically here, by renaming every macro-introduced binder and its references to a fresh unique name; see pkg/environment/global_environment_frame.go for the storage that replaced it, and pkg/wile/toplevel_binder_scope_test.go for the pinned behavior.
func (*ExpanderTimeContinuation) SetMaxDepth ¶
func (p *ExpanderTimeContinuation) SetMaxDepth(n int)
SetMaxDepth sets the maximum structural recursion depth allowed during expansion for this run. A value of 0 (or negative, clamped to 0) disables the limit. Mirrors the parser's SetMaxDepth and MachineContext.SetMaxCallDepth.
type FSFileResolver ¶
type FSFileResolver = resolver.FSFileResolver
func NewFSFileResolver ¶
func NewFSFileResolver(fsys fs.FS, env *environment.EnvironmentFrame) *FSFileResolver
NewFSFileResolver creates a resolver backed by a virtual filesystem.
type FeatureRequirement ¶
type FeatureRequirement interface {
// IsSatisfied returns true if this requirement is satisfied.
// The registry parameter is used to check if a library is already loaded.
// The resolver parameter is used to check if a library file exists
// (via the FileResolver chain, supporting both OS and virtual fs.FS).
// The load parameter, when non-nil, lets a (library X) requirement attempt
// a real load (so a .sld that resolves on disk but fails to import counts
// as unsatisfied); when nil, library availability falls back to a
// file-existence check via the resolver.
IsSatisfied(ctx context.Context, registry *LibraryRegistry, resolver FileResolver, load LibraryLoadProbe) bool
}
FeatureRequirement represents a parsed cond-expand feature requirement. Feature requirements can be:
- A symbol (feature identifier)
- (library <library-name>) - check if library is available
- (and <req> ...) - all requirements must be satisfied
- (or <req> ...) - at least one requirement must be satisfied
- (not <req>) - requirement must NOT be satisfied
func NewAndRequirement ¶
func NewAndRequirement(reqs ...FeatureRequirement) FeatureRequirement
NewAndRequirement creates an and requirement.
func NewElseRequirement ¶
func NewElseRequirement() FeatureRequirement
NewElseRequirement creates an else requirement (always satisfied).
func NewFeatureIdentifier ¶
func NewFeatureIdentifier(name string) FeatureRequirement
NewFeatureIdentifier creates a feature identifier requirement.
func NewLibraryRequirement ¶
func NewLibraryRequirement(name LibraryName) FeatureRequirement
NewLibraryRequirement creates a library requirement.
func NewNotRequirement ¶
func NewNotRequirement(req FeatureRequirement) FeatureRequirement
NewNotRequirement creates a not requirement.
func NewOrRequirement ¶
func NewOrRequirement(reqs ...FeatureRequirement) FeatureRequirement
NewOrRequirement creates an or requirement.
type FileResolver ¶
type FileResolver = environment.FileResolver
FileResolver resolves and opens files for include/load operations. The interface is defined in the environment package; this alias keeps the name available in compilation without re-declaration.
Concrete resolver types (OSFileResolver, EmbedFileResolver, FSFileResolver, ChainFileResolver) and their constructors live in the resolver sub-package. Backward-compatible aliases are provided in resolver_compat.go.
type FreeIdResolution ¶
type FreeIdResolution struct {
Global *environment.GlobalIndex
LocalScopes []*syntax.Scope
HasLocalBinding bool
LibScope *syntax.Scope
}
FreeIdResolution records how a free identifier in a syntax-rules template was bound at macro definition time. The match package uses this during template expansion to preserve hygiene.
Implements localScopesProvider, globalBindingProvider, hasLocalBindingProvider, and libraryScopeProvider from the match package.
func (*FreeIdResolution) GetGlobal ¶
func (p *FreeIdResolution) GetGlobal() *environment.GlobalIndex
GetGlobal implements the globalBindingProvider interface.
func (*FreeIdResolution) GetHasLocalBinding ¶
func (p *FreeIdResolution) GetHasLocalBinding() bool
GetHasLocalBinding implements the hasLocalBindingProvider interface.
func (*FreeIdResolution) GetLibraryScope ¶
func (p *FreeIdResolution) GetLibraryScope() *syntax.Scope
GetLibraryScope implements the libraryScopeProvider interface.
func (*FreeIdResolution) GetLocalScopes ¶
func (p *FreeIdResolution) GetLocalScopes() []*syntax.Scope
GetLocalScopes implements the localScopesProvider interface.
type ImportSet ¶
type ImportSet struct {
LibraryName LibraryName // Base library to import from
Modifiers []importModifier // only/except/prefix/rename, innermost first
PhaseShift environment.Phase // Phase offset: 0=runtime, 1=for-syntax, -1=for-template
}
ImportSet represents a parsed import specification. It can be a simple library reference or include modifiers.
PhaseShift supports Racket-style phased imports:
- (import (scheme base)) ; Phase 0 (runtime) - default
- (import (for-syntax (scheme base))) ; Phase +1 (expand)
- (import (for-template (scheme base))) ; Phase -1
- (import (for-meta 2 (scheme base))) ; Phase +2
- (import (for-meta -1 (scheme base))) ; Phase -1 (same as for-template)
Phase shifts compose additively: (for-syntax (for-syntax lib)) = phase +2
Modifiers preserves the written nesting order of only/except/prefix/rename so ApplyToExports can fold them INSIDE-OUT, as R7RS §5.6 requires. The innermost (textually deepest) modifier is Modifiers[0]; each later modifier operates on the output of the one before it. A flat representation (separate Only/Except/Prefix/ Renames fields) cannot express this — it both loses the ordering between different modifier kinds and silently overwrites a repeated kind, so e.g. (prefix (prefix LIB a-) b-) would bind b-car instead of b-a-car.
func NewImportSet ¶
func NewImportSet(name LibraryName) *ImportSet
NewImportSet creates a new import set for a library, with no modifiers.
func ParseImportSetFromDatum ¶
ParseImportSetFromDatum parses an import set from datum values. Used at both runtime (by the 'environment' procedure) and compile time (via UnwrapAll on syntax objects).
Import sets can be:
- (<library-name>) : import all exports
- (only <import-set> <id> ...) : import only specified identifiers
- (except <import-set> <id> ...): import all except specified
- (prefix <import-set> <prefix>): add prefix to all imported names
- (rename <import-set> (<old> <new>) ...): rename specific imports
- (for-syntax <import-set>) : import at phase +1 (macro expansion)
- (for-template <import-set>) : import at phase -1
- (for-meta <n> <import-set>) : import at phase +n
func (*ImportSet) AddExcept ¶
AddExcept appends an `except` modifier removing ids from the import. Empty/nil is a no-op.
func (*ImportSet) AddOnly ¶
AddOnly appends an `only` modifier restricting the import to ids. An empty/nil ids set installs a modifier that imports NOTHING: R7RS §5.6 grammar is (only <import-set> <identifier> …) with zero-or-more identifiers, so (only LIB) with no identifiers denotes the empty subset. AddOnly is called exactly once per syntactic `only` form, so the empty case is a real "import nothing", not "no filter".
func (*ImportSet) AddPrefix ¶
AddPrefix appends a `prefix` modifier prepending prefix to every imported name. An empty prefix is a no-op.
func (*ImportSet) AddRename ¶
AddRename appends a `rename` modifier mapping old names to new names. Empty/nil is a no-op.
func (*ImportSet) ApplyToExports ¶
func (p *ImportSet) ApplyToExports(lib *CompiledLibrary) (map[string]string, error)
ApplyToExports applies the import modifiers inside-out and returns the final bindings as a map of local-name -> external-name (the name in the library).
type LibraryExportIndex ¶
type LibraryExportIndex struct {
// contains filtered or unexported fields
}
LibraryExportIndex maps library keys to their summaries. Immutable after construction.
func BuildExportIndex ¶
func BuildExportIndex(ctx context.Context, res FileResolver, reg *LibraryRegistry) (*LibraryExportIndex, error)
BuildExportIndex scans all discoverable library files via the resolver's FileEnumerator, parses their exports, and returns a LibraryExportIndex. Libraries already loaded in reg are skipped (their metadata is already available via the registry). If the resolver does not implement FileEnumerator, an empty index is returned (not an error).
Best-effort: per-file name and parse errors are joined and returned alongside a valid (partial) index; only an EnumerateFiles failure or a cancelled context returns a nil index.
func NewLibraryExportIndexFromEntries ¶
func NewLibraryExportIndexFromEntries(entries map[string]*LibrarySummary) *LibraryExportIndex
NewLibraryExportIndexFromEntries creates an index from pre-built entries.
func (*LibraryExportIndex) Entries ¶
func (p *LibraryExportIndex) Entries() []*LibrarySummary
Entries returns all indexed summaries sorted by library key.
func (*LibraryExportIndex) Lookup ¶
func (p *LibraryExportIndex) Lookup(name LibraryName) *LibrarySummary
Lookup returns the summary for a library, or nil if not indexed.
type LibraryImportEvent ¶
type LibraryImportEvent struct {
Library LibraryName // imported library name, e.g., (scheme base)
SourceFile string // path to .sld file (empty for synthetic libraries)
Exports []string // all names exported by the library
Imported []string // names that actually landed in the importer (after only/except/prefix/rename)
Importer LibraryName // importing library name (zero value for top-level import)
Phase environment.Phase // pipeline phase: environment.PhaseExpand or environment.PhaseCompile
}
LibraryImportEvent records what happened when a library was imported.
type LibraryImportObserver ¶
type LibraryImportObserver func(LibraryImportEvent)
LibraryImportObserver is called when a library is imported. Observers are read-only — they cannot influence the import.
type LibraryLoadProbe ¶
type LibraryLoadProbe func(name LibraryName) bool
LibraryLoadProbe attempts to actually load a library by name, returning true iff the load (parse + compile + execute + register) succeeds. A successful probe caches the library in the registry, so the subsequent real import is free. cond-expand's (library X) requirement uses this so importability — not mere file presence — decides the clause (R7RS §4.2.1, plan item 5F/P6).
type LibraryName ¶
type LibraryName struct {
Parts []string // e.g., ["scheme", "base"]
}
LibraryName represents an R7RS library name like (scheme base) or (my lib). Library names are lists of identifiers used to uniquely identify a library.
func DiscoverAvailableLibraries ¶
func DiscoverAvailableLibraries(res FileResolver, reg *LibraryRegistry) ([]LibraryName, error)
DiscoverAvailableLibraries returns all importable library names by combining filesystem discovery (via the resolver's FileEnumerator) with registry-known libraries (synthetic extension libraries). Returns a sorted, deduplicated list.
If the resolver does not implement FileEnumerator, only registry libraries are returned. If reg is nil, only filesystem libraries are returned.
Two error shapes: an EnumerateFiles failure aborts with (nil, err), discarding any partial result; per-path FilePathToLibraryName failures are joined and returned alongside a complete list.
func FilePathToLibraryName ¶
func FilePathToLibraryName(path string) (LibraryName, error)
FilePathToLibraryName converts a forward-slash-separated file path with .sld or .scm extension to a LibraryName. This is the inverse of ToFSPath(). Returns an error if the path has no recognized extension or is empty.
func NewLibraryName ¶
func NewLibraryName(parts ...string) LibraryName
NewLibraryName creates a LibraryName from a list of string parts.
func ParseLibraryNameFromDatum ¶
ParseLibraryNameFromDatum extracts a LibraryName from a datum list like (scheme base). Used at both runtime (by the library-reflection primitives) and compile time (via ParseLibraryNameFromSyntax).
The parameter is values.Tuple, not values.Value: "a library name is a list" is a precondition, not a parse failure, so it is settled before the call. The two entry points that face untyped input carry that check — ParseLibraryNameFromSyntax for the three compile-time sites, and the primitive itself for user-supplied arguments.
func ParseLibraryNameFromSyntax ¶ added in v1.20.0
func ParseLibraryNameFromSyntax(ctx context.Context, expr syntax.SyntaxValue) (LibraryName, error)
ParseLibraryNameFromSyntax unwraps a syntax datum to a library name. It is the compile-time entry point, and the one place the "a library name is a list" precondition is checked for it — the three sites that need a name out of source (define-library's own name, cond-expand's (library ...) feature requirement, and the export-index prescan) all previously repeated UnwrapAll at the call and let the parser sort out non-lists.
A non-list here is a malformed program, not an internal error, so it reports ErrNotAList and leaves the source-context wrapping to the caller, which is the only one that knows which form is at fault.
func (LibraryName) Key ¶
func (p LibraryName) Key() string
Key returns a unique string key for map lookups.
func (LibraryName) SchemeString ¶
func (p LibraryName) SchemeString() string
SchemeString returns the Scheme representation like "(scheme base)".
func (LibraryName) String ¶
func (p LibraryName) String() string
String returns a human-readable representation like "scheme/base".
func (LibraryName) ToFSPath ¶
func (p LibraryName) ToFSPath() string
ToFSPath returns the library name as a forward-slash-separated path with .sld extension, suitable for fs.FS and FileResolver operations.
func (LibraryName) ToSchemeValue ¶
func (p LibraryName) ToSchemeValue() values.Value
ToSchemeValue converts a LibraryName to a Scheme list. Parts that parse as nonnegative integers become exact integers; all others become symbols. Matches R7RS library name syntax.
type LibraryRegistry ¶
type LibraryRegistry struct {
// contains filtered or unexported fields
}
LibraryRegistry manages loaded libraries and handles library loading.
All fields are guarded by mu so the registry is safe for concurrent use by SRFI-18 threads that load libraries via (environment …) / (eval '(import …)). Read methods take RLock; methods that mutate a map, the search paths, or the observer take Lock. mu is not reentrant — public methods must not call other locking methods while holding the lock (AllNames uses the unlocked all() helper for this reason).
func NewLibraryRegistry ¶
func NewLibraryRegistry() *LibraryRegistry
NewLibraryRegistry creates a new library registry with default search paths.
func (*LibraryRegistry) All ¶
func (p *LibraryRegistry) All() []*CompiledLibrary
All returns all loaded libraries, sorted by name key for determinism.
func (*LibraryRegistry) AllNames ¶
func (p *LibraryRegistry) AllNames() []LibraryName
AllNames returns the names of all registered libraries, sorted by key.
func (*LibraryRegistry) FinishLoading ¶
func (p *LibraryRegistry) FinishLoading(name LibraryName)
FinishLoading marks a library as finished loading and wakes every goroutine waiting on its latch (whether the load succeeded and Registered or failed). Waiters re-consult the registry: a successful load is now cached; a failed one is neither cached nor loading, so a waiter re-claims and retries.
func (*LibraryRegistry) GetSearchPaths ¶
func (p *LibraryRegistry) GetSearchPaths() []string
GetSearchPaths returns a copy of the current library search paths. Returning a copy keeps the registry's internal slice immutable from outside, so a caller cannot mutate the backing array and race a concurrent reader.
func (*LibraryRegistry) ImportObserver ¶
func (p *LibraryRegistry) ImportObserver() LibraryImportObserver
ImportObserver returns the current import observer, or nil.
func (*LibraryRegistry) IsLoading ¶
func (p *LibraryRegistry) IsLoading(name LibraryName) bool
IsLoading reports whether the library is currently being loaded by some goroutine. Diagnostic only: it does not distinguish which goroutine, and it is not part of the claim protocol (that is LookupClaimOrWait → FinishLoading). Cycle detection — re-entry on the caller's own load chain — is handled in LoadLibrary via the ctx-borne load chain, not here.
func (*LibraryRegistry) Lookup ¶
func (p *LibraryRegistry) Lookup(name LibraryName) *CompiledLibrary
Lookup returns a library by name, or nil if not found.
func (*LibraryRegistry) LookupClaimOrWait ¶
func (p *LibraryRegistry) LookupClaimOrWait(name LibraryName) (cached *CompiledLibrary, wait <-chan struct{})
LookupClaimOrWait atomically resolves a library, claims its loading slot, or returns a latch to wait on. It is the single check-and-mark decision point so the lookup → claim sequence cannot interleave across threads. The two return values encode three outcomes; "claimed" is the both-nil case, not a separate flag, so the contradictory states a third flag would admit are unrepresentable:
- cached != nil ⇒ already loaded; use it.
- cached == nil, wait != nil ⇒ another goroutine is loading this exact library; block on wait, then re-call to read the now-cached result (or re-claim if that load failed).
- cached == nil, wait == nil ⇒ the caller now owns the loading slot and MUST load, Register, and FinishLoading (which closes the latch installed here).
Unlike the former LookupOrClaim, a concurrent same-library load is NOT a circular-dependency error: that false positive is what blocked concurrent shared-dependency loads. A genuine import cycle (A→B→A) is re-entry on one goroutine's own synchronous load chain and is caught earlier, in LoadLibrary, via the ctx-borne load chain — before reaching this method — so a goroutine never waits on a latch it installed itself.
func (*LibraryRegistry) PrependSearchPath ¶
func (p *LibraryRegistry) PrependSearchPath(path string)
PrependSearchPath adds a path to the beginning of the search path list.
func (*LibraryRegistry) Register ¶
func (p *LibraryRegistry) Register(lib *CompiledLibrary) error
Register adds a compiled library to the registry.
func (*LibraryRegistry) SetImportObserver ¶
func (p *LibraryRegistry) SetImportObserver(obs LibraryImportObserver)
SetImportObserver sets an optional observer that is called each time a library is imported. The observer is read-only and cannot influence the import. Pass nil to remove the observer.
func (*LibraryRegistry) SetSearchPaths ¶
func (p *LibraryRegistry) SetSearchPaths(paths []string)
SetSearchPaths sets the library search paths. The slice is copied so the registry owns its searchPaths memory: a caller mutating the slice it passed in must not be able to race a concurrent reader of the registry's state.
type LibrarySummary ¶
type LibrarySummary struct {
Name LibraryName
Description string
Exports []string
SourceFile string
}
LibrarySummary holds the statically-extracted metadata for a single library definition file (.sld). It captures exports and description without compiling or executing any library code.
func ParseLibrarySummary ¶
func ParseLibrarySummary(ctx context.Context, r io.Reader, filePath string, name LibraryName) (*LibrarySummary, error)
ParseLibrarySummary reads a library definition from r and extracts its export list and description without compiling the library. This is a best-effort parser: malformed export specs are silently skipped.
type OSFileResolver ¶
type OSFileResolver = resolver.OSFileResolver
func NewOSFileResolver ¶
func NewOSFileResolver(env *environment.EnvironmentFrame) *OSFileResolver
NewOSFileResolver creates a resolver backed by the OS filesystem.
type OperationBindPatternVars ¶
type OperationBindPatternVars struct {
machine.OperationBase
PatternVars []string // Ordered list for consistent indexing
// MergedSlots is how many anonymous slots a `let` in the clause body took
// out of this frame instead of pushing one of its own.
//
// WRITTEN AFTER THE OPERATION IS EMITTED, by compileSyntaxCaseClause, once
// the body it brackets has been compiled — the count is not knowable before
// then, and this operation is reached through the side table by pointer, so
// the emitted instruction sees the final value. Compare
// CompileValidatedLet's OpPushEnv operand patch, which solves the same
// problem for an operand that is packed into the instruction word.
MergedSlots int
}
OperationBindPatternVars binds pattern variables from the last match into a new local environment frame that is pushed onto the current environment.
This operation creates a new environment frame with local slots for each pattern variable, binds the matched values, and makes this the current environment.
func NewOperationBindPatternVars ¶
func NewOperationBindPatternVars(patternVars values.StringSet) *OperationBindPatternVars
func (*OperationBindPatternVars) Apply ¶
func (p *OperationBindPatternVars) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
func (*OperationBindPatternVars) EqualTo ¶
func (p *OperationBindPatternVars) EqualTo(other values.Value) bool
EqualTo compares the frame this operation builds: which pattern variables it binds AND how wide the frame ends up. Two clauses over the same pattern whose bodies merge different numbers of `let` slots build different frames, so MergedSlots is part of the identity rather than metadata.
func (*OperationBindPatternVars) OpKind ¶
func (*OperationBindPatternVars) OpKind() machine.OpCode
type OperationBuildSyntaxList ¶
type OperationBuildSyntaxList struct {
machine.OperationBase
Count int
Dotted bool
}
OperationBuildSyntaxList builds a syntax list from elements on the eval stack. Count elements are popped (in reverse order) and consed into a list.
Dotted makes the LAST of those elements the list's tail rather than its final element, which is what `(a b . c)` needs. Without it every template was built onto SyntaxEmptyList, so an improper template came back proper — (syntax->datum (syntax (a b . c))) answered (a b c) where Chez answers (a b . c). The tail rides on the stack like any other element rather than getting its own operand, so the push protocol is unchanged and Count still says exactly how many values this pops.
func NewOperationBuildDottedSyntaxList ¶ added in v1.20.0
func NewOperationBuildDottedSyntaxList(count int) *OperationBuildSyntaxList
NewOperationBuildDottedSyntaxList creates an OperationBuildSyntaxList whose last popped element is the improper tail. count includes that tail, so a template with k elements before the dot has count == k+1.
func NewOperationBuildSyntaxList ¶
func NewOperationBuildSyntaxList(count int) *OperationBuildSyntaxList
NewOperationBuildSyntaxList creates a new OperationBuildSyntaxList.
func (*OperationBuildSyntaxList) Apply ¶
func (p *OperationBuildSyntaxList) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
Apply implements the Operation interface.
func (*OperationBuildSyntaxList) EqualTo ¶
func (p *OperationBuildSyntaxList) EqualTo(other values.Value) bool
func (*OperationBuildSyntaxList) OpKind ¶
func (*OperationBuildSyntaxList) OpKind() machine.OpCode
type OperationClearSyntaxCaseInput ¶
type OperationClearSyntaxCaseInput struct {
machine.OperationBase
}
OperationClearSyntaxCaseInput drops the PENDING syntax-case state at the end of a syntax-case form, releasing the input syntax object and the matcher.
It is no longer load-bearing for correctness, and that is the point. It used to be the only thing that stopped a later (syntax ...) from expanding against a finished form's matcher, which made it a bug that a clause body ending in a tail CALL never reaches it — the epilogue sits after the body's tail position. Template expansion now resolves through the pattern-variable frame, so skipping this instruction costs a retention, not an answer: the state a tail call leaves installed is read by nothing.
func NewOperationClearSyntaxCaseInput ¶
func NewOperationClearSyntaxCaseInput() *OperationClearSyntaxCaseInput
func (*OperationClearSyntaxCaseInput) Apply ¶
func (p *OperationClearSyntaxCaseInput) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
func (*OperationClearSyntaxCaseInput) EqualTo ¶
func (p *OperationClearSyntaxCaseInput) EqualTo(other values.Value) bool
func (*OperationClearSyntaxCaseInput) OpKind ¶
func (*OperationClearSyntaxCaseInput) OpKind() machine.OpCode
type OperationStoreSyntaxCaseInput ¶
type OperationStoreSyntaxCaseInput struct {
machine.OperationBase
}
OperationStoreSyntaxCaseInput opens a syntax-case form by installing a FRESH pending syntaxCaseState holding the value register as the input, for OperationSyntaxCaseMatch to match against.
Minting a fresh state rather than reusing whatever is installed is what keeps a nested syntax-case from mutating the enclosing form's snapshot: the enclosing frame holds its own object, not this one.
func NewOperationStoreSyntaxCaseInput ¶
func NewOperationStoreSyntaxCaseInput() *OperationStoreSyntaxCaseInput
func (*OperationStoreSyntaxCaseInput) Apply ¶
func (p *OperationStoreSyntaxCaseInput) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
func (*OperationStoreSyntaxCaseInput) EqualTo ¶
func (p *OperationStoreSyntaxCaseInput) EqualTo(other values.Value) bool
func (*OperationStoreSyntaxCaseInput) OpKind ¶
func (*OperationStoreSyntaxCaseInput) OpKind() machine.OpCode
type OperationSyntaxCaseMatch ¶
type OperationSyntaxCaseMatch struct {
machine.OperationBase
}
OperationSyntaxCaseMatch performs pattern matching for syntax-case.
Expects:
- Value register: *SyntaxCaseClause with compiled pattern
- Per-context syntaxCaseState.input: input syntax object (set by OperationStoreSyntaxCaseInput)
Results:
- If match succeeds: value register = #t, pattern bindings stored in context
- If match fails: value register = #f
func NewOperationSyntaxCaseMatch ¶
func NewOperationSyntaxCaseMatch() *OperationSyntaxCaseMatch
func (*OperationSyntaxCaseMatch) Apply ¶
func (p *OperationSyntaxCaseMatch) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
func (*OperationSyntaxCaseMatch) EqualTo ¶
func (p *OperationSyntaxCaseMatch) EqualTo(other values.Value) bool
func (*OperationSyntaxCaseMatch) OpKind ¶
func (*OperationSyntaxCaseMatch) OpKind() machine.OpCode
type OperationSyntaxCaseNoMatch ¶
type OperationSyntaxCaseNoMatch struct {
machine.OperationBase
}
OperationSyntaxCaseNoMatch is emitted at the end of syntax-case when no clause matches.
func NewOperationSyntaxCaseNoMatch ¶
func NewOperationSyntaxCaseNoMatch() *OperationSyntaxCaseNoMatch
func (*OperationSyntaxCaseNoMatch) Apply ¶
func (p *OperationSyntaxCaseNoMatch) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
func (*OperationSyntaxCaseNoMatch) EqualTo ¶
func (p *OperationSyntaxCaseNoMatch) EqualTo(other values.Value) bool
func (*OperationSyntaxCaseNoMatch) OpKind ¶
func (*OperationSyntaxCaseNoMatch) OpKind() machine.OpCode
type OperationSyntaxRulesTransform ¶
type OperationSyntaxRulesTransform struct {
machine.OperationBase
}
OperationSyntaxRulesTransform is a VM operation that performs macro expansion.
Execution context:
- Value register: contains clausesWrapper with compiled pattern/template pairs
- Local parameter 0: contains the input form (the macro invocation)
The operation is part of the transformer closure created by CompileSyntaxRules.
func NewOperationSyntaxRulesTransform ¶
func NewOperationSyntaxRulesTransform() *OperationSyntaxRulesTransform
func (*OperationSyntaxRulesTransform) Apply ¶
func (p *OperationSyntaxRulesTransform) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
func (*OperationSyntaxRulesTransform) EqualTo ¶
func (p *OperationSyntaxRulesTransform) EqualTo(other values.Value) bool
func (*OperationSyntaxRulesTransform) OpKind ¶
func (*OperationSyntaxRulesTransform) OpKind() machine.OpCode
type OperationSyntaxTemplateExpand ¶
type OperationSyntaxTemplateExpand struct {
machine.OperationBase
// FreeIds and PatternVarSyntax carry the enclosing syntax-case clause's
// hygiene data, computed once at compile time by CompileSyntax. They mirror
// the SyntaxRulesClause fields the syntax-rules transformer uses, so the
// ellipsis template-expansion path is hygienic (R7RS §4.3): free template
// identifiers resolve at the macro definition site and template-introduced
// binders carry a fresh intro scope rather than capturing use-site identifiers.
FreeIds map[string]*FreeIdResolution
PatternVarSyntax map[string]*syntax.SyntaxSymbol
}
OperationSyntaxTemplateExpand expands a syntax template using the current pattern variable bindings. This is used for templates containing ellipsis, which require runtime expansion rather than compile-time code generation.
The template is stored in the value register (loaded from literals). The result is the expanded syntax object, left in the value register.
func NewOperationSyntaxTemplateExpand ¶
func NewOperationSyntaxTemplateExpand(freeIds map[string]*FreeIdResolution, patternVarSyntax map[string]*syntax.SyntaxSymbol) *OperationSyntaxTemplateExpand
func (*OperationSyntaxTemplateExpand) Apply ¶
func (p *OperationSyntaxTemplateExpand) Apply(mc *machine.MachineContext) (*machine.MachineContext, error)
func (*OperationSyntaxTemplateExpand) EqualTo ¶
func (p *OperationSyntaxTemplateExpand) EqualTo(other values.Value) bool
func (*OperationSyntaxTemplateExpand) OpKind ¶
func (*OperationSyntaxTemplateExpand) OpKind() machine.OpCode
type PhaseEntry ¶
PhaseEntry represents a named item to register in a phase environment.
type PrimitiveExpander ¶
type PrimitiveExpander struct {
// contains filtered or unexported fields
}
PrimitiveExpander wraps a PrimitiveExpanderFunc as a values.Value so it can be stored in the environment.
func LookupPrimitiveExpander ¶
func LookupPrimitiveExpander(env *environment.EnvironmentFrame, sym *values.Symbol, scopes []*syntax.Scope) *PrimitiveExpander
LookupPrimitiveExpander looks up a primitive expander by symbol in the expand environment. Returns the PrimitiveExpander if found, or nil if the symbol does not name a primitive expander.
This function handles hygiene by using scoped lookup - it will only match bindings whose scopes are a subset of the symbol's scopes.
func NewPrimitiveExpander ¶
func NewPrimitiveExpander(name string, fn PrimitiveExpanderFunc) *PrimitiveExpander
NewPrimitiveExpander creates a new primitive expander.
func (*PrimitiveExpander) EqualTo ¶
func (p *PrimitiveExpander) EqualTo(other values.Value) bool
EqualTo implements values.Value interface.
func (*PrimitiveExpander) Expand ¶
func (p *PrimitiveExpander) Expand( etc *ExpanderTimeContinuation, sym *syntax.SyntaxSymbol, expr syntax.SyntaxValue, ) (syntax.SyntaxValue, error)
Expand invokes the primitive expander function.
func (*PrimitiveExpander) IsVoid ¶
func (p *PrimitiveExpander) IsVoid() bool
IsVoid returns false — named handlers are never void.
func (*PrimitiveExpander) Name ¶
func (p *PrimitiveExpander) Name() string
Name returns the handler's name.
func (*PrimitiveExpander) SchemeString ¶
func (p *PrimitiveExpander) SchemeString() string
SchemeString returns the Scheme representation: #<prefix:name>.
type PrimitiveExpanderFunc ¶
type PrimitiveExpanderFunc func( etc *ExpanderTimeContinuation, sym *syntax.SyntaxSymbol, expr syntax.SyntaxValue, ) (syntax.SyntaxValue, error)
PrimitiveExpanderFunc is the type for expand-time special form handlers. These functions handle macro expansion of primitive forms like `if`, `lambda`, `define`, `quote`, etc.
Parameters:
- etc: The expander-time continuation (expander state, carries context)
- sym: The keyword symbol (e.g., 'if', 'lambda')
- expr: The expression arguments (everything after the keyword)
Returns the expanded syntax value.
type ResolvedImportSet ¶
type ResolvedImportSet struct {
ImportSet *ImportSet
Library *CompiledLibrary
Bindings map[string]string // localName -> externalName
}
ResolvedImportSet holds the result of parsing and loading an import set. This is the shared prefix of all import processing: parse the import set datum, load the named library, and apply modifiers (only, except, prefix, rename) to produce the final binding map.
type SourcedError ¶
type SourcedError struct {
Source *syntax.SourceContext
Cause error
}
SourcedError wraps a compilation error with the source location where it occurred. The compiler tracks source context via pushSource/popSource; wrapCompilationError attaches the current source to errors so that callers (especially the public Engine API) can report file:line:col.
Use errors.As to extract the source from an error chain:
var se *compilation.SourcedError
if errors.As(err, &se) && se.Source != nil { ... }
func (*SourcedError) Error ¶
func (p *SourcedError) Error() string
func (*SourcedError) SourceContext ¶ added in v1.20.0
func (p *SourcedError) SourceContext() *syntax.SourceContext
SourceContext returns the context this error was stamped with. It exists so that pkg/machine can recognise the type structurally: this package imports pkg/machine, so the concrete type cannot be named from that side of the edge, and an errors.As target there has to be an interface. Source is the same field and stays exported for the callers that already read it.
func (*SourcedError) Unwrap ¶
func (p *SourcedError) Unwrap() error
type SyntaxCaseClause ¶
type SyntaxCaseClause struct {
Bytecode []match.SyntaxCommand
PatternVars values.StringSet
// LiteralSyntax carries each pattern literal with the scopes it had at the
// macro definition site, the same data SyntaxRulesClause.LiteralSyntax
// carries. Without it match.go's hygiene block is gated off on this path
// (it needs a non-nil literal map AND a non-nil matcher), so a syntax-case
// pattern literal matched a use-site identifier that shadows it — R7RS
// §4.3.2 requires the two to share a binding.
LiteralSyntax map[string]*syntax.SyntaxSymbol
// LiteralDefs pins each pattern literal to the binding it had in the macro
// DEFINITION environment. It has to ride on the clause because this path
// builds its matcher at RUNTIME, in the use site's environment — the one
// place that cannot recompute a definition-site resolution. (The syntax-rules
// path needs no such field: its matcher is built at definition time and
// carries the pins directly.)
LiteralDefs map[string]match.LiteralPin
EllipsisVars map[int]values.StringSet
EllipsisDepths map[int]int
}
SyntaxCaseClause wraps compiled pattern info for a syntax-case clause. Created by the compiler, consumed by OperationSyntaxCaseMatch at runtime.
func (*SyntaxCaseClause) IsVoid ¶
func (p *SyntaxCaseClause) IsVoid() bool
func (*SyntaxCaseClause) SchemeString ¶
func (p *SyntaxCaseClause) SchemeString() string
type SyntaxCompiler ¶
type SyntaxCompiler struct {
// contains filtered or unexported fields
}
SyntaxCompiler wraps a SyntaxCompilerFunc as a values.Value so it can be stored in the environment.
func LookupSyntaxCompiler ¶
func LookupSyntaxCompiler(env *environment.EnvironmentFrame, sym *values.Symbol, scopes []*syntax.Scope) *SyntaxCompiler
LookupSyntaxCompiler looks up a syntax compiler by symbol, entering through the PhaseCompile view. Returns the SyntaxCompiler if found, or nil if the symbol does not name a syntax compiler. The compilers live in the ambient tier (see RegisterSyntaxCompilers), which that view's ranked probe reaches as T3, so a PhaseCompile shadow at T1 or T2 still takes precedence.
Naming PhaseCompile by constant is correct here, unlike a climb: it is a fixed registry coordinate rather than a rung of the macro tower, so it does not vary with the level of the frame asking. See environment.Phase.
This function handles hygiene by using scoped lookup - it will only match bindings whose scopes are a subset of the symbol's scopes.
func NewSyntaxCompiler ¶
func NewSyntaxCompiler(name string, fn SyntaxCompilerFunc) *SyntaxCompiler
NewSyntaxCompiler creates a new syntax compiler.
func (*SyntaxCompiler) EqualTo ¶
func (p *SyntaxCompiler) EqualTo(other values.Value) bool
EqualTo implements values.Value interface.
func (*SyntaxCompiler) IsVoid ¶
func (p *SyntaxCompiler) IsVoid() bool
IsVoid returns false — named handlers are never void.
func (*SyntaxCompiler) Name ¶
func (p *SyntaxCompiler) Name() string
Name returns the handler's name.
func (*SyntaxCompiler) SchemeString ¶
func (p *SyntaxCompiler) SchemeString() string
SchemeString returns the Scheme representation: #<prefix:name>.
type SyntaxCompilerFunc ¶
type SyntaxCompilerFunc func(ctc *CompileTimeContinuation, ctctx CompileTimeCallContext, expr syntax.SyntaxValue) error
SyntaxCompilerFunc is the type for compile-time special form handlers. These functions handle syntax-directed compilation of extension forms like `syntax-case`, `import`, `define-syntax`, `include`, etc.
Parameters:
- ctc: The compile-time continuation (compiler state)
- ctctx: The compile-time call context (tail position info, etc.)
- expr: The expression arguments (everything after the keyword)
The function should emit operations via ctc.AppendOperations and return nil on success.
type SyntaxRulesClause ¶
type SyntaxRulesClause struct {
Template syntax.SyntaxValue
Bytecode []match.SyntaxCommand
Matcher *match.SyntaxMatcher
PatternVars values.StringSet
PatternVarSyntax map[string]*syntax.SyntaxSymbol
EllipsisVars map[int]values.StringSet
FreeIds map[string]*FreeIdResolution
Ellipsis string
LiteralSyntax map[string]*syntax.SyntaxSymbol
}
SyntaxRulesClause represents a single compiled pattern-template pair in a syntax-rules form. Created by the compiler, consumed by OperationSyntaxRulesTransform at runtime.
func ClausesFromClosure ¶ added in v1.19.0
func ClausesFromClosure(closure values.Value) []*SyntaxRulesClause
ClausesFromClosure recovers the syntax-rules clause set from a compiled transformer closure — the *ClausesWrapper stored as the closure's template literal by createTransformerClosure. Returns nil for a non-syntax-rules transformer (an ER-macro or lambda body carries no ClausesWrapper). A syntax-rules closure carries exactly one wrapper, so the first match is the whole set. Shared by pinTemplateSelfReferences and the bootstrap nil-pin census, so both read clauses through one extractor rather than parallel copies.
Source Files
¶
- boxing.go
- compile_begin_for_syntax.go
- compile_call.go
- compile_call_arity.go
- compile_closure.go
- compile_cond_expand.go
- compile_define.go
- compile_define_for_syntax.go
- compile_define_syntax.go
- compile_er_macro.go
- compile_eval_when.go
- compile_helpers.go
- compile_import.go
- compile_let.go
- compile_library_forms.go
- compile_literal_immutability.go
- compile_quasisyntax.go
- compile_syntax_case.go
- compile_syntax_form.go
- compile_syntax_rules.go
- compile_time_call_context.go
- compile_time_continuation.go
- compile_time_continuation_include.go
- compile_time_continuation_library.go
- compile_time_continuation_quasiquote.go
- compile_transformer.go
- compile_validated.go
- compile_with_syntax.go
- compiler_registry.go
- counters.go
- er_macro_compare.go
- er_macro_rename.go
- er_macro_transformer.go
- expand_and_compile.go
- expander_body.go
- expander_context.go
- expander_lambda.go
- expander_let.go
- expander_let_syntax.go
- expander_primitive_forms.go
- expander_time_continuation.go
- expander_use_site.go
- features.go
- file_resolver.go
- free_vars.go
- import_set_datum.go
- inline_hof.go
- inline_hof_template.go
- letrec_semantics.go
- library_bindings.go
- library_discovery.go
- library_export_index.go
- library_load_chain.go
- library_loader.go
- library_registry.go
- load_bootstrap.go
- merged_slots.go
- named_handler_base.go
- op_kind.go
- operation_build_syntax.go
- operation_syntax_case.go
- operation_syntax_rules_transform.go
- phase_registry.go
- primitive_expander.go
- primitive_expanders_registry.go
- quasi_expand.go
- ref_index.go
- register.go
- resolver_compat.go
- sourced_error.go
- syntax_bridge_types.go
- syntax_compiler.go
- syntax_compilers_registry.go
- syntax_error.go
- tier1_compilers_registry.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package resolver provides file resolution infrastructure for the Scheme compiler.
|
Package resolver provides file resolution infrastructure for the Scheme compiler. |
|
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. |