Documentation
¶
Index ¶
- Constants
- type Collector
- func (c *Collector) AddFile(root *sitter.Node, source []byte, file, modulePath string)
- func (c *Collector) Collect(root *sitter.Node) (*ast.Program, *symbols.SymbolTable, *symbols.ScopeTable, []error)
- func (c *Collector) CollectBounds(node *sitter.Node) []string
- func (c *Collector) CollectExpr(node *sitter.Node) ast.Expression
- func (c *Collector) CollectGenericParams(node *sitter.Node) []ast.GenericParam
- func (c *Collector) CollectPattern(patternNode *sitter.Node) ast.Pattern
- func (c *Collector) CollectStatement(node *sitter.Node) ast.Statement
- func (c *Collector) DeclareOverload(stmt *ast.VarDeclStmt) (bool, string)
- func (c *Collector) DefinePatternBinding(named ast.Named)
- func (c *Collector) Finish() (*ast.Program, *symbols.SymbolTable, *symbols.ScopeTable, []error)
- func (c *Collector) LookupCurrentScope(name string) (ast.Named, bool)
- func (c *Collector) MergeWhereConstraints(params []ast.GenericParam, whereNode *sitter.Node) []ast.GenericParam
- func (c *Collector) ParseDestructuringPattern(patternNode *sitter.Node) ast.Pattern
- func (c *Collector) ParseLambdaType(node *sitter.Node) *types.LambdaType
- func (c *Collector) ParseType(node *sitter.Node) types.Type
- func (c *Collector) PopScope()
- func (c *Collector) PushBlockScope() *symbols.Scope
- func (c *Collector) PushFunctionScope() *symbols.Scope
- func (c *Collector) PushLoopScope() *symbols.Scope
- func (c *Collector) RecordScope(node ast.AstNode, scope *symbols.Scope)
- func (c *Collector) RecordTypeRef(name string, loc ast.Location)
- func (c *Collector) RedefineVariable(stmt *ast.VarDeclStmt)
- func (c *Collector) RegisterDestructuredName(name string, decl *ast.DestructuringDeclStmt)
- func (c *Collector) RegisterFunction(name string, stmt *ast.LambdaExpr) error
- func (c *Collector) RegisterParameter(p *ast.Parameter) error
- func (c *Collector) RegisterTrait(stmt *ast.TraitDeclStmt) error
- func (c *Collector) RegisterType(stmt *ast.TypeDeclStmt) error
- func (c *Collector) RegisterVariable(stmt *ast.VarDeclStmt) error
- func (c *Collector) SetImports(graph map[string][]string)
- func (c *Collector) SetPreludeModule(path string)
- func (c *Collector) Snapshot() *Snapshot
- type Snapshot
Constants ¶
const ( CollectorErrorSeverityError = diag.SeverityError CollectorErrorSeverityWarning = diag.SeverityWarning CollectorErrorSeverityInfo = diag.SeverityInfo )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Collector ¶
type Collector struct {
// contains filtered or unexported fields
}
Collector walks the CST and builds an AST + symbol table.
func NewCollector ¶
func (*Collector) AddFile ¶
AddFile walks one source file into the accumulating program, and may be called repeatedly — once per module — before Finish.
The split exists because only the *walk* is per-file: every pass in Finish reaches across the whole program. reclassifyStructPatterns has to know every declared struct, resolveCanonicalTypes every declared type, and registerTopLevelFunctions every top-level binding — and with modules those can come from a file that has not been walked yet. Running them per file would make the result depend on collection order.
source is swapped in alongside the tree because every text and location read goes through it (ctx.NodeText / ctx.NodeLocation); a stale source would slice the wrong bytes for the file being walked.
func (*Collector) Collect ¶
func (c *Collector) Collect(root *sitter.Node) (*ast.Program, *symbols.SymbolTable, *symbols.ScopeTable, []error)
Collect walks the entire tree and returns the AST, symbol table, scope table, and any errors. It is AddFile + Finish for the single-file case.
func (*Collector) CollectBounds ¶
CollectBounds reads the trait names in a bound list — a `where` clause's, an inline `<t: Shown>`, a trait's supertraits, an impl's constraints. It is the funnel for all four, which is why recording their spans here covers every one.
A bound is a `[]string` rather than a type, so these names never pass through `parseType` and the span it records; without this, a cursor on `Shown` in `where t: Shown` resolved to nothing while one on `Point` in `(p: Point)` resolved.
func (*Collector) CollectExpr ¶
func (c *Collector) CollectExpr(node *sitter.Node) ast.Expression
func (*Collector) CollectGenericParams ¶
func (c *Collector) CollectGenericParams(node *sitter.Node) []ast.GenericParam
func (*Collector) CollectPattern ¶
func (*Collector) CollectStatement ¶
func (*Collector) DeclareOverload ¶
func (c *Collector) DeclareOverload(stmt *ast.VarDeclStmt) (bool, string)
DeclareOverload offers stmt to the same-named declaration already in scope as a receiver-keyed overload.
**Only at module level.** Overloading is a property of a module's public surface, and a set is resolved by looking one up in a module scope; a `let` inside a function body that happens to reuse a name is sequential rebinding, which is a different feature with a different meaning, and admitting overloads there would change what the second `let` means based on whether the first took a `self` parameter.
func (*Collector) DefinePatternBinding ¶
DefinePatternBinding enters a pattern's binding into the current scope.
Errors are deliberately dropped. `Define` reports a redeclaration, which is the right answer for two `let`s of one name in a block and the wrong one here: a pattern may bind a name that shadows an outer one, which is ordinary and intended, and an arm is its own scope so the only way to collide *within* it is a malformed pattern the pattern collector has already reported.
func (*Collector) Finish ¶
func (c *Collector) Finish() (*ast.Program, *symbols.SymbolTable, *symbols.ScopeTable, []error)
Finish runs the whole-program passes and returns the merged result.
func (*Collector) LookupCurrentScope ¶
LookupCurrentScope returns the symbol registered under name in the current (innermost) scope only, without walking parent scopes.
func (*Collector) MergeWhereConstraints ¶
func (c *Collector) MergeWhereConstraints(params []ast.GenericParam, whereNode *sitter.Node) []ast.GenericParam
func (*Collector) ParseDestructuringPattern ¶
func (*Collector) ParseLambdaType ¶
func (c *Collector) ParseLambdaType(node *sitter.Node) *types.LambdaType
func (*Collector) PushBlockScope ¶
func (*Collector) PushFunctionScope ¶
func (*Collector) PushLoopScope ¶
func (*Collector) RecordScope ¶
func (*Collector) RedefineVariable ¶
func (c *Collector) RedefineVariable(stmt *ast.VarDeclStmt)
RedefineVariable replaces an existing same-scope binding with stmt, used for same-scope sequential rebinding so that later references resolve to the newest declaration.
func (*Collector) RegisterDestructuredName ¶
func (c *Collector) RegisterDestructuredName(name string, decl *ast.DestructuringDeclStmt)
func (*Collector) RegisterFunction ¶
func (c *Collector) RegisterFunction(name string, stmt *ast.LambdaExpr) error
func (*Collector) RegisterTrait ¶
func (c *Collector) RegisterTrait(stmt *ast.TraitDeclStmt) error
func (*Collector) RegisterType ¶
func (c *Collector) RegisterType(stmt *ast.TypeDeclStmt) error
func (*Collector) RegisterVariable ¶
func (c *Collector) RegisterVariable(stmt *ast.VarDeclStmt) error
func (*Collector) SetImports ¶
SetImports hands over the whole import graph before the first file is walked, for the same reason SetPreludeModule is called there: a declaration taking a name an imported module exports is keyed apart from it (symbols.declKeyIn), and a type is registered under that key *during* the walk.
Assembling the graph file by file as each is walked would work for a single-file module and quietly fail for the rest: a module whose `import` sits in its second file would key the first file's types as though nothing were imported, and the key a lookup computes afterwards — with the graph complete — would miss them. The graph is known before collection anyway, since resolving it is what produced the units.
func (*Collector) SetPreludeModule ¶
SetPreludeModule names the implicitly-imported module, so registration can tell a user declaration taking a prelude name (allowed, warned) from two user modules clashing (an error).
type Snapshot ¶
type Snapshot struct {
// contains filtered or unexported fields
}
Snapshot is the collector's state after some prefix of a program's files, held so the rest can be collected onto a copy of it rather than onto a re-collection of everything.
**The prefix is what does not change between keystrokes.** A language server re-analyzes a document's whole import graph on every edit; for a small file with the standard prelude that is 12 units of which 11 cannot have changed, and collection is 75% of the analysis.
A snapshot is **immutable once taken**: Restore hands out a deep copy and the original is never written to again. That is the difference between this and undoing the edited file's contributions — a copy has to be right once, an undo has to be right every time, and the failure mode of getting an undo slightly wrong is analysis that drifts as a session runs.
func (*Snapshot) Restore ¶
Restore builds a collector holding a copy of the snapshot's state, ready for the remaining files to be added to it.
The AST statements are shared rather than copied, which is the point: every side table downstream — ScopeTable, TypeTable, MethodTable — is keyed by AST *pointer*, so copying the nodes would invalidate all of them. What makes that safe is that re-running the analysis passes over one collected AST is idempotent, which pkg/driver's re-analysis test checks directly over the real prelude rather than assuming.
func (*Snapshot) StatementCount ¶
StatementCount is how many top-level statements the snapshot covers — the boundary the typechecker resumes from. Read from the snapshot rather than recomputed from the units, because Finish may append a statement (a synthesized derive) and the count at capture time is the only thing that says where the prefix actually ends.