Documentation
¶
Overview ¶
Package syntax implements Scheme syntax representation with hygiene support.
The package wraps Scheme values with source location and scope information:
Syntax Types ¶
- SyntaxSymbol: symbols with scope tracking for hygiene
- SyntaxPair: cons cells with recursive scope propagation
- SyntaxVector: vectors with source context
- SyntaxObject: wrapper for self-evaluating values
All syntax types implement SyntaxValue, which provides:
- [SyntaxValue.SourceContext]: source location, scopes, and origin
- [SyntaxValue.Unwrap]: shallow unwrap to underlying value
- [SyntaxValue.UnwrapAll]: deep recursive unwrap
Hygiene ¶
The package implements Flatt's "sets of scopes" model for macro hygiene:
- Scope: unique identifier with optional rebinding flag
- [SourceContext.Scopes]: scope set attached to syntax objects
- ScopesMatch: binding/reference scope subset check
Source Tracking ¶
- SourceContext: file, line, column, text, scopes, and origin
- SourceIndexes: position within source (line, column, byte offset)
- OriginInfo: macro expansion chain for debugging
Index ¶
- func EqualTo(a, b SyntaxValue) bool
- func FormatOriginChain(origin *OriginInfo, maxDepth int) string
- func IsSyntaxEmptyList(v SyntaxValue) bool
- func IsSyntaxList(v SyntaxValue) bool
- func IsSyntaxVoid(v SyntaxValue) bool
- func ScopeFingerprint(scopes []*Scope) string
- func ScopesCompatible(bindingScopes, useScopes []*Scope) bool
- func ScopesMatch(useScopes, bindingScopes []*Scope) bool
- func Spine(p *SyntaxPair) iter.Seq2[*SyntaxPair, SpineEnd]
- func SyntaxWalk(ctx context.Context, o SyntaxValue, fn func(SyntaxValue) error) error
- func UnwrapAllShared(sv SyntaxValue, cache map[SyntaxValue]values.Value) values.Value
- type FormArityError
- type OriginInfo
- type ResolvedRef
- type Scope
- type ScopeSet
- type SourceContext
- type SourceIndexes
- type SourceTableRefs
- type SpineEnd
- type SyntaxBox
- type SyntaxComment
- type SyntaxDatumComment
- func (p *SyntaxDatumComment) AddScope(_ *Scope) SyntaxValue
- func (p *SyntaxDatumComment) EqualTo(v values.Value) bool
- func (p *SyntaxDatumComment) IsVoid() bool
- func (p *SyntaxDatumComment) SchemeString() string
- func (p *SyntaxDatumComment) Unwrap() values.Value
- func (p *SyntaxDatumComment) UnwrapAll() values.Value
- type SyntaxDatumLabelAssignment
- func (p *SyntaxDatumLabelAssignment) AddScope(_ *Scope) SyntaxValue
- func (p *SyntaxDatumLabelAssignment) EqualTo(v values.Value) bool
- func (p *SyntaxDatumLabelAssignment) IsVoid() bool
- func (p *SyntaxDatumLabelAssignment) SchemeString() string
- func (p *SyntaxDatumLabelAssignment) Unwrap() values.Value
- func (p *SyntaxDatumLabelAssignment) UnwrapAll() values.Value
- type SyntaxDirective
- type SyntaxForEachFunc
- type SyntaxObject
- type SyntaxPair
- func (p *SyntaxPair) AddScope(scope *Scope) SyntaxValue
- func (p *SyntaxPair) Append(vs values.Value) values.Value
- func (p *SyntaxPair) AsSyntaxVector() *SyntaxVector
- func (p *SyntaxPair) AsVector() *values.Vector
- func (p *SyntaxPair) Car() values.Value
- func (p *SyntaxPair) Cdr() values.Value
- func (p *SyntaxPair) EqualTo(o values.Value) bool
- func (p *SyntaxPair) ForEach(ctx context.Context, fn values.ForEachFunc) (values.Value, error)
- func (*SyntaxPair) IsEmptyList() bool
- func (p *SyntaxPair) IsList() bool
- func (p *SyntaxPair) IsPair() bool
- func (p *SyntaxPair) IsVoid() bool
- func (p *SyntaxPair) Length() int
- func (p *SyntaxPair) SchemeString() string
- func (p *SyntaxPair) SetCar(v values.Value)
- func (p *SyntaxPair) SetCdr(v values.Value)
- func (p *SyntaxPair) SyntaxAppend(vs SyntaxValue) SyntaxValue
- func (p *SyntaxPair) SyntaxCar() SyntaxValue
- func (p *SyntaxPair) SyntaxCdr() SyntaxValue
- func (p *SyntaxPair) SyntaxForEach(ctx context.Context, fn SyntaxForEachFunc) (SyntaxValue, error)
- func (p *SyntaxPair) Unwrap() values.Value
- func (p *SyntaxPair) UnwrapAll() values.Value
- type SyntaxSymbol
- func (p *SyntaxSymbol) AddScope(scope *Scope) SyntaxValue
- func (p *SyntaxSymbol) Datum() *values.Symbol
- func (p *SyntaxSymbol) EqualTo(o values.Value) bool
- func (p *SyntaxSymbol) IsVoid() bool
- func (p *SyntaxSymbol) Key() string
- func (p *SyntaxSymbol) RemoveScope(scope *Scope) *SyntaxSymbol
- func (p *SyntaxSymbol) SchemeString() string
- func (p *SyntaxSymbol) Scopes() []*Scope
- func (p *SyntaxSymbol) Unwrap() values.Value
- func (p *SyntaxSymbol) UnwrapAll() values.Value
- func (p *SyntaxSymbol) WithResolvedBinding(binding ResolvedRef) *SyntaxSymbol
- type SyntaxTuple
- type SyntaxValue
- func AddScopeToSyntax(stx SyntaxValue, scope *Scope) SyntaxValue
- func FlipScope(stx SyntaxValue, scope *Scope) SyntaxValue
- func FormParts(form SyntaxValue, name string, minLen, maxLen int) ([]SyntaxValue, error)
- func SyntaxForEach(ctx context.Context, o SyntaxValue, ...) (SyntaxValue, error)
- func SyntaxList(sc *SourceContext, os ...SyntaxValue) SyntaxValue
- type SyntaxVector
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EqualTo ¶
func EqualTo(a, b SyntaxValue) bool
EqualTo compares two syntax values for equality, handling nil and pointer identity.
func FormatOriginChain ¶
func FormatOriginChain(origin *OriginInfo, maxDepth int) string
FormatOriginChain renders a macro expansion chain as a string. maxDepth limits how many expansions to show (0 = unlimited).
func IsSyntaxEmptyList ¶
func IsSyntaxEmptyList(v SyntaxValue) bool
IsSyntaxEmptyList returns true if the value is the syntax empty list.
Delegates to values.IsEmptyList — after the empty-list duality merge, the syntax empty list is the same singleton as values.EmptyList, and values.IsEmptyList works on any Tuple. This restores symmetric equality (previously the strict pointer-type assertion produced #f for `(equal? (syntax ()) '())`, contrary to Chez).
func IsSyntaxList ¶
func IsSyntaxList(v SyntaxValue) bool
IsSyntaxList returns true if the value is a proper syntax list.
func IsSyntaxVoid ¶
func IsSyntaxVoid(v SyntaxValue) bool
IsSyntaxVoid returns true if the value is nil or void.
func ScopeFingerprint ¶ added in v1.19.0
ScopeFingerprint builds a deterministic map-key string from a scope set. See values.ScopeFingerprint for the full documentation.
func ScopesCompatible ¶
ScopesCompatible checks whether a binding's scopes can match a reference's. A binding with no scopes matches any reference.
func ScopesMatch ¶
ScopesMatch checks if two sets of scopes are compatible for binding resolution. See values.ScopesMatch for the full hygiene-model documentation.
func Spine ¶ added in v1.20.0
func Spine(p *SyntaxPair) iter.Seq2[*SyntaxPair, SpineEnd]
Spine yields each *SyntaxPair along p's cdr chain — the syntax-phase twin of values.Spine, with the same contract: every cell carries a zero SpineEnd except the last, which carries the terminating cdr. Like values.Spine it does NOT detect cycles, and like values.Spine an abandoned walk observes only zero ends, which is the truthful report that no terminator was reached.
It yields CELLS where ForEach and SyntaxForEach yield cars, and that is the whole reason it exists. Two shapes in the quasiquote reader are properties of a cell rather than of an element, and neither can be stated over cars:
- Dotted unquote. `(a . ,x) parses as (a unquote x) — a bare unquote symbol in the SPINE followed by exactly one element (R7RS §4.2.8). Deciding it needs the cell's cdr while standing on the unquote, which a car-yielding callback cannot reach; restating it over cars turns a local pattern test into a stateful post-condition.
- Early exit. A predicate stops at its first true. A ForEach consumer can only stop by returning an error, so it has to signal a FOUND through the error channel; a range-over-func just breaks.
Not a replacement for SyntaxForEach, which stays open-coded for the reason its own comment gives: each yield here goes through two function pointers, and the equivalent rewrite of values.Pair.ForEach cost 40-56% on BenchmarkPairForEach. Prefer this where the consumer needs the cell or the break, and that one where it needs neither.
func SyntaxWalk ¶
func SyntaxWalk(ctx context.Context, o SyntaxValue, fn func(SyntaxValue) error) error
SyntaxWalk iterates over a syntax tuple, calling fn for each element. It is a convenience wrapper around SyntaxForEach for callers that only need the element value (ignoring the index and hasNext arguments).
func UnwrapAllShared ¶
func UnwrapAllShared(sv SyntaxValue, cache map[SyntaxValue]values.Value) values.Value
UnwrapAllShared recursively unwraps a syntax value while preserving object identity. This is essential for datum labels (R7RS §2.4) where #n# must refer to the exact same object as #n=. The cache parameter tracks already-unwrapped syntax values to ensure the same SyntaxValue always unwraps to the same values.Value. This also handles circular structures by pre-registering placeholders before recursing.
Types ¶
type FormArityError ¶
type FormArityError struct {
Name string
// Min and Max are the element-count bounds (keyword included); Max < 0
// means unbounded. Got is the actual element count.
Min, Max, Got int
}
FormArityError reports that a form is a proper list of the wrong length. It is the one FormParts failure that carries structured data — the bounds and the actual count — because callers re-render it in their own vocabulary: compilation reports keyword-inclusive "element" counts (FormParts counts the form keyword at index 0), while the validator restates them as keyword- exclusive "argument" counts. Structural failures (not a list, improper list) carry no such data and are returned as plain ErrInvalidSyntax wraps, not as this type. FormArityError Unwraps to werr.ErrInvalidSyntax so callers keep matching with errors.Is regardless of the failure mode.
func (*FormArityError) Error ¶
func (e *FormArityError) Error() string
func (*FormArityError) Unwrap ¶
func (*FormArityError) Unwrap() error
Unwrap reports ErrInvalidSyntax so an arity failure matches with errors.Is(err, werr.ErrInvalidSyntax), like the structural failures.
type OriginInfo ¶
type OriginInfo = values.OriginInfo
OriginInfo tracks macro expansion chains. Defined in package values alongside SourceContext.
type ResolvedRef ¶
ResolvedRef is the type for a pre-resolved binding stored on a SyntaxSymbol. The concrete type is always *environment.GlobalIndex; this interface exists solely to break the circular import between pkg/syntax and environment.
type Scope ¶
Scope is the macro-hygiene identity marker. Defined in package values alongside SourceContext (the empty-list duality merge).
func FlipScopeInSet ¶
FlipScopeInSet toggles the presence of a scope in a set. It is the set-level half of FlipScope, whose only intended consumer (syntax-local-introduce) is not wired; see FlipScope.
func NewRebindingScope ¶
func NewRebindingScope() *Scope
NewRebindingScope creates a new scope that can potentially rebind auxiliary syntax.
func NewRebindingScopeWithLabel ¶
NewRebindingScopeWithLabel creates a new rebinding scope with a label.
func NewScope ¶
func NewScope() *Scope
NewScope creates a new scope with unique identity for hygiene tracking.
func NewScopeWithLabel ¶
NewScopeWithLabel creates a new scope with a human-readable label for debugging.
type ScopeSet ¶ added in v1.19.0
ScopeSet is a hygiene query constraint (all / empty / specific). Defined in package values alongside the Scope type; re-exported here so environment and compiler code can spell it syntax.ScopeSet beside syntax.ScopesCompatible.
func AllScopes ¶ added in v1.19.0
func AllScopes() ScopeSet
AllScopes returns the wildcard scope-set query. See values.AllScopes.
func EmptyScopes ¶ added in v1.19.0
func EmptyScopes() ScopeSet
EmptyScopes returns the ambient (empty) scope-set query. See values.EmptyScopes.
type SourceContext ¶
type SourceContext = values.SourceContext
SourceContext is the source-location-and-hygiene metadata type. It is defined in package values so that values.emptyListType can implement values.SyntaxValue directly (the empty-list duality merge — see values/syntax_value.go and the comment in values/source_context.go).
func NewSourceContext ¶
func NewSourceContext(text, file string, start, end SourceIndexes) *SourceContext
NewSourceContext constructs a SourceContext.
func NewZeroValueSourceContext ¶
func NewZeroValueSourceContext() *SourceContext
NewZeroValueSourceContext constructs an empty SourceContext.
type SourceIndexes ¶
type SourceIndexes = values.SourceIndexes
SourceIndexes is the source-position type. It is defined in package values so that values.emptyListType can implement values.SyntaxValue directly (the empty-list duality merge — see values/syntax_value.go).
func NewSourceIndexes ¶
func NewSourceIndexes(index, column, line int) SourceIndexes
NewSourceIndexes constructs a SourceIndexes at the given position.
type SourceTableRefs ¶ added in v1.20.0
type SourceTableRefs = values.SourceTableRefs
type SpineEnd ¶ added in v1.20.0
type SpineEnd struct {
// Tail is the terminating cdr: SyntaxEmptyList for a proper list, the
// trailing syntax value for an improper one. nil while walking.
Tail SyntaxValue
}
SpineEnd is the syntax-phase twin of values.SpineEnd: it travels with the last cell a Spine walk yields, and its zero value means "not the last cell", which is also what a consumer that breaks out observes.
There is no Cyclic field because there is no syntax-phase cycle-detecting walker: syntax is a compile-time tree built by the reader and the expander, neither of which can close a cycle (datum labels are resolved into shared, acyclic structure during parsing). Add the field with the walker, not before.
type SyntaxBox ¶ added in v1.20.0
type SyntaxBox struct {
Value SyntaxValue
// contains filtered or unexported fields
}
SyntaxBox wraps a box (#&datum) with source context, keeping the boxed datum as syntax.
The alternative — unwrapping the content at read time and storing a plain *values.Box in a SyntaxObject — is about ten lines instead of this file, and costs the content its source location and its participation in hygiene. A box is a container like a vector, so it gets the container treatment: the content keeps its wrappers, an error inside #&(1 . 2) still has somewhere to point, and a box in a macro template propagates scopes to what it holds.
func NewSyntaxBox ¶ added in v1.20.0
func NewSyntaxBox(value SyntaxValue, sctx *SourceContext) *SyntaxBox
NewSyntaxBox creates a new syntax box wrapping the given datum.
func (*SyntaxBox) AddScope ¶ added in v1.20.0
func (p *SyntaxBox) AddScope(scope *Scope) SyntaxValue
AddScope propagates the scope into the boxed datum, as SyntaxVector does for its elements. Only symbols accumulate scopes; everything else is threaded through unchanged.
func (*SyntaxBox) EqualTo ¶ added in v1.20.0
EqualTo performs pointer comparison, as the other syntax types do.
func (*SyntaxBox) SchemeString ¶ added in v1.20.0
SchemeString renders the box in its read syntax, so it round trips.
type SyntaxComment ¶
type SyntaxComment struct {
Text string
// contains filtered or unexported fields
}
SyntaxComment represents a source comment (line or block) with source location.
func NewSyntaxComment ¶
func NewSyntaxComment(text string, sctx *SourceContext) *SyntaxComment
NewSyntaxComment creates a new syntax comment with the given text and source context.
func (*SyntaxComment) AddScope ¶
func (p *SyntaxComment) AddScope(scope *Scope) SyntaxValue
AddScope returns the comment unchanged (comments don't participate in hygiene).
func (*SyntaxComment) EqualTo ¶
func (p *SyntaxComment) EqualTo(v values.Value) bool
EqualTo returns true if the comments have the same text.
func (*SyntaxComment) IsVoid ¶
func (p *SyntaxComment) IsVoid() bool
IsVoid returns true if the comment is nil.
func (*SyntaxComment) SchemeString ¶
func (p *SyntaxComment) SchemeString() string
SchemeString returns the comment text.
func (*SyntaxComment) Unwrap ¶
func (p *SyntaxComment) Unwrap() values.Value
func (*SyntaxComment) UnwrapAll ¶
func (p *SyntaxComment) UnwrapAll() values.Value
UnwrapAll returns the comment text as a string value.
type SyntaxDatumComment ¶
type SyntaxDatumComment struct {
Label string
Value SyntaxValue
// contains filtered or unexported fields
}
SyntaxDatumComment represents a datum comment (#;datum).
func NewSyntaxDatumComment ¶
func NewSyntaxDatumComment(label string, value SyntaxValue, sctx *SourceContext) *SyntaxDatumComment
NewSyntaxDatumComment creates a new datum comment.
func (*SyntaxDatumComment) AddScope ¶
func (p *SyntaxDatumComment) AddScope(_ *Scope) SyntaxValue
AddScope returns the comment unchanged (comments don't participate in hygiene).
func (*SyntaxDatumComment) EqualTo ¶
func (p *SyntaxDatumComment) EqualTo(v values.Value) bool
EqualTo compares datum comments by label and value.
func (*SyntaxDatumComment) IsVoid ¶
func (p *SyntaxDatumComment) IsVoid() bool
IsVoid returns true if the comment is nil.
func (*SyntaxDatumComment) SchemeString ¶
func (p *SyntaxDatumComment) SchemeString() string
SchemeString returns a string representation of the datum comment.
func (*SyntaxDatumComment) Unwrap ¶
func (p *SyntaxDatumComment) Unwrap() values.Value
func (*SyntaxDatumComment) UnwrapAll ¶
func (p *SyntaxDatumComment) UnwrapAll() values.Value
UnwrapAll recursively unwraps the commented value.
type SyntaxDatumLabelAssignment ¶
type SyntaxDatumLabelAssignment struct {
Label int
Value values.Value
// contains filtered or unexported fields
}
SyntaxDatumLabelAssignment represents a datum label assignment (#n=datum).
func NewSyntaxDatumLabelAssignment ¶
func NewSyntaxDatumLabelAssignment(label int, value values.Value, sctx *SourceContext) *SyntaxDatumLabelAssignment
NewSyntaxDatumLabelAssignment creates a new datum label assignment.
func (*SyntaxDatumLabelAssignment) AddScope ¶
func (p *SyntaxDatumLabelAssignment) AddScope(_ *Scope) SyntaxValue
AddScope returns the assignment unchanged (labels don't participate in hygiene).
func (*SyntaxDatumLabelAssignment) EqualTo ¶
func (p *SyntaxDatumLabelAssignment) EqualTo(v values.Value) bool
EqualTo returns true if both assignments are the same object.
func (*SyntaxDatumLabelAssignment) IsVoid ¶
func (p *SyntaxDatumLabelAssignment) IsVoid() bool
IsVoid returns true if the assignment is nil.
func (*SyntaxDatumLabelAssignment) SchemeString ¶
func (p *SyntaxDatumLabelAssignment) SchemeString() string
SchemeString returns the Scheme representation of the label.
func (*SyntaxDatumLabelAssignment) Unwrap ¶
func (p *SyntaxDatumLabelAssignment) Unwrap() values.Value
func (*SyntaxDatumLabelAssignment) UnwrapAll ¶
func (p *SyntaxDatumLabelAssignment) UnwrapAll() values.Value
UnwrapAll recursively unwraps the assigned value.
type SyntaxDirective ¶
type SyntaxDirective struct {
Name string
// contains filtered or unexported fields
}
SyntaxDirective represents a reader directive (#!fold-case, etc.).
func NewSyntaxDirective ¶
func NewSyntaxDirective(name string, sctx *SourceContext) *SyntaxDirective
NewSyntaxDirective creates a new reader directive with the given name.
func (*SyntaxDirective) AddScope ¶
func (p *SyntaxDirective) AddScope(_ *Scope) SyntaxValue
AddScope returns the directive unchanged (directives don't participate in hygiene).
func (*SyntaxDirective) EqualTo ¶
func (p *SyntaxDirective) EqualTo(v values.Value) bool
EqualTo returns true if both directives have the same name.
func (*SyntaxDirective) IsVoid ¶
func (p *SyntaxDirective) IsVoid() bool
IsVoid returns true if the directive is nil.
func (*SyntaxDirective) SchemeString ¶
func (p *SyntaxDirective) SchemeString() string
SchemeString returns the directive name.
func (*SyntaxDirective) Unwrap ¶
func (p *SyntaxDirective) Unwrap() values.Value
func (*SyntaxDirective) UnwrapAll ¶
func (p *SyntaxDirective) UnwrapAll() values.Value
UnwrapAll returns the directive name as a string value.
type SyntaxForEachFunc ¶
type SyntaxForEachFunc = values.SyntaxForEachFunc
SyntaxForEachFunc is the callback type for iterating over syntax tuples.
type SyntaxObject ¶
type SyntaxObject struct {
// contains filtered or unexported fields
}
SyntaxObject wraps a non-compound Scheme value with source context.
func NewSyntaxObject ¶
func NewSyntaxObject(v values.Value, sctx *SourceContext) *SyntaxObject
NewSyntaxObject creates a new SyntaxObject wrapping the given value and source context. It panics if the value is already a syntax value to prevent double-wrapping.
func (*SyntaxObject) Datum ¶
func (p *SyntaxObject) Datum() values.Value
Datum returns the underlying datum of the syntax object.
func (*SyntaxObject) EqualTo ¶
func (p *SyntaxObject) EqualTo(v values.Value) bool
EqualTo performs pointer comparison only, matching Chez Scheme/Racket behavior. Two syntax objects are equal? only if they are the same object. For value comparison of syntax objects, use bound-identifier=? or free-identifier=?.
func (*SyntaxObject) IsVoid ¶
func (p *SyntaxObject) IsVoid() bool
IsVoid returns true if the syntax object is nil.
func (*SyntaxObject) SchemeString ¶
func (p *SyntaxObject) SchemeString() string
SchemeString returns the Scheme representation of the syntax object.
func (*SyntaxObject) Unwrap ¶
func (p *SyntaxObject) Unwrap() values.Value
func (*SyntaxObject) UnwrapAll ¶
func (p *SyntaxObject) UnwrapAll() values.Value
UnwrapAll recursively unwraps all syntax wrappers and returns the underlying value.
type SyntaxPair ¶
type SyntaxPair struct {
Values [2]SyntaxValue
// contains filtered or unexported fields
}
SyntaxPair wraps a Scheme pair (cons cell) with source context.
func NewSyntaxCons ¶
func NewSyntaxCons(v0, v1 SyntaxValue, sctx *SourceContext) *SyntaxPair
NewSyntaxCons creates a new syntax pair (cons cell).
func (*SyntaxPair) AddScope ¶
func (p *SyntaxPair) AddScope(scope *Scope) SyntaxValue
AddScope recursively propagates a scope to all nested symbols.
This implements scope propagation for Flatt's "sets of scopes" hygiene. When a macro expands, the intro scope must be added to all identifiers (symbols) in the expansion. This method walks the pair structure and calls AddScope on each element, ultimately reaching the symbols.
Only symbols store scopes for hygiene resolution. Pairs just propagate.
func (*SyntaxPair) Append ¶
func (p *SyntaxPair) Append(vs values.Value) values.Value
Append appends a value to the end of the list.
func (*SyntaxPair) AsSyntaxVector ¶
func (p *SyntaxPair) AsSyntaxVector() *SyntaxVector
AsSyntaxVector converts the list to a syntax vector.
func (*SyntaxPair) AsVector ¶
func (p *SyntaxPair) AsVector() *values.Vector
AsVector converts the SyntaxPair (assumed to be a proper list) into a Vector of unwrapped values.
func (*SyntaxPair) EqualTo ¶
func (p *SyntaxPair) EqualTo(o values.Value) bool
EqualTo performs pointer comparison only, matching Chez Scheme/Racket behavior. Two syntax objects are equal? only if they are the same object. For value comparison of syntax objects, use bound-identifier=? or free-identifier=?.
func (*SyntaxPair) ForEach ¶
func (p *SyntaxPair) ForEach(ctx context.Context, fn values.ForEachFunc) (values.Value, error)
ForEach iterates over the elements of the list.
func (*SyntaxPair) IsEmptyList ¶
func (*SyntaxPair) IsEmptyList() bool
IsEmptyList returns false. A *SyntaxPair is never the empty list; SyntaxEmptyList (an alias for the values.EmptyList singleton) is the only representation of the empty list at the syntax phase.
func (*SyntaxPair) IsList ¶
func (p *SyntaxPair) IsList() bool
IsList returns true if the pair forms a proper list.
func (*SyntaxPair) IsPair ¶
func (p *SyntaxPair) IsPair() bool
IsPair returns true; SyntaxPair is always a pair.
func (*SyntaxPair) IsVoid ¶
func (p *SyntaxPair) IsVoid() bool
IsVoid returns true if the pair is nil.
func (*SyntaxPair) Length ¶
func (p *SyntaxPair) Length() int
Length returns the length of the list. Unlike the values.Tuple contract, it panics with werr.ErrNotAList on an improper list rather than counting the proper prefix.
func (*SyntaxPair) SchemeString ¶
func (p *SyntaxPair) SchemeString() string
SchemeString returns a string representation of the syntax pair.
func (*SyntaxPair) SetCar ¶
func (p *SyntaxPair) SetCar(v values.Value)
SetCar sets the car of the pair. It panics if v is not a SyntaxValue: at the syntax phase every car is invariantly a SyntaxValue.
func (*SyntaxPair) SetCdr ¶
func (p *SyntaxPair) SetCdr(v values.Value)
SetCdr sets the cdr of the pair. It panics if v is not a SyntaxValue: at the syntax phase every cdr is invariantly a SyntaxValue.
func (*SyntaxPair) SyntaxAppend ¶
func (p *SyntaxPair) SyntaxAppend(vs SyntaxValue) SyntaxValue
SyntaxAppend appends a syntax value to the end of the list.
func (*SyntaxPair) SyntaxCar ¶
func (p *SyntaxPair) SyntaxCar() SyntaxValue
SyntaxCar returns the car as a syntax value.
func (*SyntaxPair) SyntaxCdr ¶
func (p *SyntaxPair) SyntaxCdr() SyntaxValue
SyntaxCdr returns the cdr as a syntax value.
func (*SyntaxPair) SyntaxForEach ¶
func (p *SyntaxPair) SyntaxForEach(ctx context.Context, fn SyntaxForEachFunc) (SyntaxValue, error)
SyntaxForEach iterates over the syntax elements of the list.
func (*SyntaxPair) Unwrap ¶
func (p *SyntaxPair) Unwrap() values.Value
Unwrap returns a regular Scheme pair without recursively unwrapping.
func (*SyntaxPair) UnwrapAll ¶
func (p *SyntaxPair) UnwrapAll() values.Value
UnwrapAll recursively unwraps the pair and returns a regular Scheme pair.
type SyntaxSymbol ¶
type SyntaxSymbol struct {
Sym *values.Symbol
// ResolvedBinding holds a pre-resolved binding for free identifiers in macro templates.
// This is set during macro expansion for identifiers that should resolve to bindings
// in the macro's definition environment rather than the use-site environment.
// Type: *environment.GlobalIndex (satisfies ResolvedRef via values.Value).
// nil for normal symbols; only set for free identifiers from macros.
ResolvedBinding ResolvedRef
// contains filtered or unexported fields
}
SyntaxSymbol wraps a Scheme symbol with source context and hygiene scopes.
func NewSyntaxSymbol ¶
func NewSyntaxSymbol(key string, sctx *SourceContext) *SyntaxSymbol
NewSyntaxSymbol creates a new syntax symbol from a key string.
func NewSyntaxSymbolForSymbol ¶
func NewSyntaxSymbolForSymbol(sym *values.Symbol, sctx *SourceContext) *SyntaxSymbol
NewSyntaxSymbolForSymbol creates a new syntax symbol from an existing symbol.
func NewSyntaxSymbolForSyntaxSymbol ¶
func NewSyntaxSymbolForSyntaxSymbol(sym *SyntaxSymbol, sctx *SourceContext) *SyntaxSymbol
NewSyntaxSymbolForSyntaxSymbol creates a new syntax symbol with a different source context. The source symbol's ResolvedBinding is NOT carried over; re-apply it with WithResolvedBinding if the caller needs it.
func (*SyntaxSymbol) AddScope ¶
func (p *SyntaxSymbol) AddScope(scope *Scope) SyntaxValue
AddScope returns a new SyntaxSymbol with an additional scope. This is the core operation for implementing hygiene in Flatt's "sets of scopes" model. When a macro expands, an "intro scope" is added to all identifiers in the expansion. This scope distinguishes macro-introduced identifiers from user-provided ones.
The method returns a NEW SyntaxSymbol (syntax objects are immutable) with the scope added to its SourceContext. The SyntaxValue return type supports recursive scope propagation through nested syntax structures.
Example: When swap! macro introduces "tmp", that "tmp" gets the macro's intro scope. A user's "tmp" at the call site doesn't have this scope, so they're distinguished during variable resolution (see ScopesMatch in scope_utils.go).
func (*SyntaxSymbol) Datum ¶
func (p *SyntaxSymbol) Datum() *values.Symbol
Datum returns the underlying symbol.
func (*SyntaxSymbol) EqualTo ¶
func (p *SyntaxSymbol) EqualTo(o values.Value) bool
EqualTo performs pointer comparison only, matching Chez Scheme/Racket behavior. Two syntax objects are equal? only if they are the same object. For value comparison of syntax objects, use bound-identifier=? or free-identifier=?.
func (*SyntaxSymbol) IsVoid ¶
func (p *SyntaxSymbol) IsVoid() bool
IsVoid returns true if the syntax symbol is nil.
func (*SyntaxSymbol) Key ¶
func (p *SyntaxSymbol) Key() string
Key returns the underlying symbol's name. For void symbols it returns "".
func (*SyntaxSymbol) RemoveScope ¶ added in v1.20.0
func (p *SyntaxSymbol) RemoveScope(scope *Scope) *SyntaxSymbol
RemoveScope returns this symbol with scope removed from its SourceContext, or the receiver unchanged when the scope is absent. The inverse of AddScope, and the primitive use-site-scope pruning is built from.
It returns *SyntaxSymbol where AddScope returns SyntaxValue: AddScope exists to be applied generically down a syntax tree, while removal is applied to one identifier in a known binder position, and its caller wants the symbol back. ResolvedBinding survives, as it must — a macro-introduced define name can carry a definition-site pin, and dropping it here would silently re-open the binding to use-site resolution.
func (*SyntaxSymbol) SchemeString ¶
func (p *SyntaxSymbol) SchemeString() string
SchemeString returns a string representation of the syntax symbol.
func (*SyntaxSymbol) Scopes ¶
func (p *SyntaxSymbol) Scopes() []*Scope
Scopes returns the scopes of this syntax symbol. Always returns a non-nil slice (empty when the symbol has no scopes). Callers wrap the result in ScopesOf to form the ScopeSet query taken by environment.GetBinding / GetLocalIndex; ScopesOf(nil) is the empty set, never the wildcard (that is AllScopes).
func (*SyntaxSymbol) Unwrap ¶
func (p *SyntaxSymbol) Unwrap() values.Value
func (*SyntaxSymbol) UnwrapAll ¶
func (p *SyntaxSymbol) UnwrapAll() values.Value
UnwrapAll returns the underlying symbol value.
func (*SyntaxSymbol) WithResolvedBinding ¶
func (p *SyntaxSymbol) WithResolvedBinding(binding ResolvedRef) *SyntaxSymbol
WithResolvedBinding returns a new SyntaxSymbol with the given pre-resolved binding. This is used during macro expansion to tag free identifiers with their definition-site bindings, enabling proper resolution across library boundaries.
type SyntaxTuple ¶
type SyntaxTuple = values.SyntaxTuple
SyntaxTuple is the interface for syntax lists (pairs and vectors). Defined in package values so that values.emptyListType can satisfy it.
var ( // SyntaxEmptyList is the empty list singleton at the syntax phase. // It is the same singleton as values.EmptyList — the empty list has no // symbols, scopes, or source-attachable hygiene content, so the // value-level singleton serves both phases (matching Chez's // `(equal? (syntax ()) '()) → #t`). SyntaxEmptyList SyntaxTuple = values.SyntaxEmptyList )
type SyntaxValue ¶
type SyntaxValue = values.SyntaxValue
SyntaxValue is the interface for all syntax objects. Defined in package values so that values.emptyListType can satisfy it directly (the empty-list duality merge — see values/syntax_value.go).
var SyntaxVoid SyntaxValue = syntaxVoidType{}
SyntaxVoid is the singleton syntax void value.
func AddScopeToSyntax ¶
func AddScopeToSyntax(stx SyntaxValue, scope *Scope) SyntaxValue
AddScopeToSyntax adds a scope to a syntax object. Returns a new syntax object with the scope added. Symbols, pairs, and vectors receive the scope; self-evaluating literals (SyntaxObject) and other types are returned unchanged. Used by the binding-form expanders (let, letrec, lambda, let-syntax, include).
func FlipScope ¶
func FlipScope(stx SyntaxValue, scope *Scope) SyntaxValue
FlipScope toggles the presence of a scope on a syntax object. Returns a new syntax object with the scope flipped. Intended for syntax-local-introduce, which is currently NOT wired: the expander context never carries an introduction scope, so that primitive raises werr.ErrNotImplemented and this function has no live production caller.
func FormParts ¶
func FormParts(form SyntaxValue, name string, minLen, maxLen int) ([]SyntaxValue, error)
FormParts destructures a fixed-shape syntax form into its positional elements, validating that the form is a proper list of acceptable length.
It replaces the recurring hand-rolled "assert *SyntaxPair, take car, assert cdr, ..." chains used by special-form compilers and expanders. name is the form name used in error messages. minLen and maxLen bound the number of elements (set maxLen to -1 for an unbounded upper limit; set minLen == maxLen for an exact count). All elements are counted — callers that keep the form keyword at element 0 should include it in the bounds.
On success it returns the elements in source order. On a structural failure (not a list, improper list) it returns a nil slice and an ErrInvalidSyntax wrap naming the form. On an arity mismatch it returns a nil slice and a *FormArityError carrying the bounds and actual count; callers add source context. Both error forms match errors.Is(err, werr.ErrInvalidSyntax).
Call sites cluster into three consumption paths (grep FormParts / formSingleArg / formPrologue for the authoritative list):
- Directly, from fixed-arity special-form compilers and expanders in machine/compilation: define-syntax (both the top-level CompileDefineSyntax and the body-path compileDefineSyntaxFromSyntax), er-macro-transformer, and the (rename internal external) export specs (compile path and library-summary index).
- Via formSingleArg, the arity-1 convenience wrapper, for single-argument forms: syntax, quasisyntax, and the (description <string>) forms.
- Via internal/validate.formPrologue, which shifts these keyword-inclusive element bounds to keyword-exclusive "argument" bounds and restates a *FormArityError in "argument" vocabulary; it backs the core-form validators (if, lambda, set!, quote, begin, dynamic-wind, apply, ...).
func SyntaxForEach ¶
func SyntaxForEach(ctx context.Context, o SyntaxValue, fn func(ctx context.Context, i int, hasNext bool, v SyntaxValue) error) (SyntaxValue, error)
SyntaxForEach iterates over a syntax tuple, calling fn for each element.
func SyntaxList ¶
func SyntaxList(sc *SourceContext, os ...SyntaxValue) SyntaxValue
SyntaxList constructs a syntax list from the given elements. The sc parameter provides a fallback source context for the list container. Each intermediate pair uses the source context of its car element when available, preserving per-element source location information for better error reporting.
type SyntaxVector ¶
type SyntaxVector = values.SyntaxVector
SyntaxVector wraps a Scheme vector with source context. Defined in package values (the empty-list duality merge — see values/syntax_vector.go). Methods that need to traverse concrete syntax types defined in this package (AddScope, UnwrapAll) dispatch via hooks registered at init time below.
func NewSyntaxVector ¶
func NewSyntaxVector(sc *SourceContext, vs ...SyntaxValue) *SyntaxVector
NewSyntaxVector creates a new syntax vector with the given source context and elements.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package syntaxtest provides test helpers for the syntax package.
|
Package syntaxtest provides test helpers for the syntax package. |