analysis

package
v1.39.0 Latest Latest
Warning

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

Go to latest
Published: Mar 17, 2026 License: BSD-3-Clause Imports: 11 Imported by: 0

Documentation

Overview

Package analysis provides scope-aware semantic analysis for ELPS lisp source.

The analyzer builds a scope tree from parsed expressions, resolves symbol references, and identifies unresolved symbols. It is designed to be used by lint analyzers for semantic checks like undefined-symbol and unused-variable.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractPackageExports

func ExtractPackageExports(reg *lisp.PackageRegistry) map[string][]ExternalSymbol

ExtractPackageExports creates a map of package name to exported symbols from a loaded runtime's package registry. This is used to resolve use-package imports for packages defined in Go (stdlib) that cannot be found by workspace scanning.

func ScanWorkspaceAll added in v1.39.0

func ScanWorkspaceAll(root string) (globals []ExternalSymbol, pkgs map[string][]ExternalSymbol, allDefs []ExternalSymbol, err error)

ScanWorkspaceAll combines ScanWorkspaceFull and ScanWorkspaceDefinitions into a single pass: each file is parsed once and all three results are extracted from the same AST.

func ScanWorkspacePackages

func ScanWorkspacePackages(root string) (map[string][]ExternalSymbol, error)

ScanWorkspacePackages is like ScanWorkspace but returns a map of package name to exported symbols, suitable for use as Config.PackageExports.

func ScanWorkspaceRefs added in v1.31.0

func ScanWorkspaceRefs(root string, cfg *Config) map[string][]FileReference

ScanWorkspaceRefs walks the workspace directory tree, performs full analysis on each .lisp file, and extracts cross-file references. The cfg should have ExtraGlobals and PackageExports populated from a prior ScanWorkspaceFull call. Parsing is done concurrently.

Returns a map from SymbolKey.String() to FileReference slices.

func ShouldSkipDir added in v1.32.0

func ShouldSkipDir(name string) bool

ShouldSkipDir returns true for directories that should not be walked. It skips hidden directories (e.g. .git, .vscode) and node_modules, but not "." or ".." which represent the current/parent directory.

Types

type Config

type Config struct {
	// ExtraGlobals are symbols from other files (e.g. workspace scanning).
	ExtraGlobals []ExternalSymbol

	// PackageExports maps package names to their exported symbols.
	// Used to resolve use-package imports from stdlib and workspace packages.
	PackageExports map[string][]ExternalSymbol

	// DefForms declares additional definition-form heads for embedding programs.
	// Head is matched exactly against the form head symbol. FormalsIndex must
	// point at the parameter list cell. If BindsName is true, NameIndex points
	// at the defined symbol cell and the analyzer registers it using NameKind.
	DefForms []DefFormSpec

	// Filename is the source file being analyzed.
	Filename string
}

Config controls the behavior of the analyzer.

type DefFormSpec added in v1.38.0

type DefFormSpec struct {
	Head         string
	FormalsIndex int
	BindsName    bool
	NameIndex    int
	NameKind     SymbolKind
}

DefFormSpec describes a custom definition-like form.

type ExternalSymbol

type ExternalSymbol struct {
	Name      string
	Kind      SymbolKind
	Package   string
	Signature *Signature
	Source    *token.Location
	DocString string
}

ExternalSymbol represents a symbol defined in another file.

func ScanWorkspace

func ScanWorkspace(root string) ([]ExternalSymbol, error)

ScanWorkspace walks a directory tree, parsing all .lisp files and extracting exported top-level definitions. The result can be used as Config.ExtraGlobals for cross-file symbol resolution.

Files that fail to parse are silently skipped (fault tolerant).

func ScanWorkspaceDefinitions added in v1.39.0

func ScanWorkspaceDefinitions(root string) ([]ExternalSymbol, error)

ScanWorkspaceDefinitions walks a directory tree and returns all top-level definitions, including non-exported symbols. The result is intended for workspace symbol search, not cross-file resolution.

func ScanWorkspaceFull added in v1.27.0

func ScanWorkspaceFull(root string) ([]ExternalSymbol, map[string][]ExternalSymbol, error)

ScanWorkspaceFull walks a directory tree in a single pass, parsing all .lisp files and extracting both global symbols and package exports. It skips hidden directories (names starting with '.'), node_modules, and vendor directories. Stops collecting after maxWorkspaceFiles. Parsing is done concurrently using a bounded worker pool.

Files that fail to parse are silently skipped (fault tolerant).

type FileReference added in v1.31.0

type FileReference struct {
	SymbolKey       SymbolKey
	Source          *token.Location
	File            string          // absolute path
	Enclosing       string          // name of enclosing function ("" if top-level)
	EnclosingSource *token.Location // definition site of enclosing function
	EnclosingKind   SymbolKind      // kind of enclosing function
}

FileReference represents a cross-file reference to a symbol.

func ExtractFileRefs added in v1.31.0

func ExtractFileRefs(result *Result, filePath string) []FileReference

ExtractFileRefs extracts cross-file-trackable references from an analysis result. Only references to global-scope, non-builtin symbols are included (builtins, special ops, parameters, and locals are skipped).

type Reference

type Reference struct {
	Symbol *Symbol
	Source *token.Location
	Node   *lisp.LVal
}

Reference records a resolved symbol usage.

type Result

type Result struct {
	RootScope  *Scope
	Symbols    []*Symbol
	References []*Reference
	Unresolved []*UnresolvedRef
}

Result holds the output of semantic analysis.

func Analyze

func Analyze(exprs []*lisp.LVal, cfg *Config) *Result

Analyze performs semantic analysis on a set of parsed expressions. It builds a scope tree, resolves references, and collects unresolved symbols.

func AnalyzeFile added in v1.31.0

func AnalyzeFile(source []byte, filename string, cfg *Config) *Result

AnalyzeFile parses and performs full semantic analysis on a single file. Returns nil if the file fails to parse.

type Scope

type Scope struct {
	Kind           ScopeKind
	Parent         *Scope
	Children       []*Scope
	Symbols        map[string]*Symbol
	PackageSymbols map[string]*Symbol
	PackageImports map[string]map[string]*Symbol

	Node *lisp.LVal // the AST node that introduced this scope
	// contains filtered or unexported fields
}

Scope represents a lexical scope in the source.

func NewScope

func NewScope(kind ScopeKind, parent *Scope, node *lisp.LVal) *Scope

NewScope creates a new scope of the given kind with the given parent.

func ScopeAtPosition added in v1.31.0

func ScopeAtPosition(root *Scope, line, col int) *Scope

ScopeAtPosition returns the innermost scope that contains the given 1-based ELPS line and column. It walks the scope tree depth-first.

func (*Scope) Define

func (s *Scope) Define(sym *Symbol)

Define adds a symbol to this scope.

func (*Scope) DefineImported added in v1.39.0

func (s *Scope) DefineImported(sym *Symbol, pkg string)

DefineImported adds a symbol that should be visible both by package-qualified name and as an unqualified import in the current scope.

func (*Scope) DefineQualifiedOnly added in v1.39.0

func (s *Scope) DefineQualifiedOnly(sym *Symbol)

DefineQualifiedOnly adds a package-qualified symbol without adding it to the bare-name Symbols map. The symbol is still reachable through Lookup/LookupLocal via the bareNameIndex for package-agnostic callers (e.g., minifier, lint arity checker).

func (*Scope) Lookup

func (s *Scope) Lookup(name string) *Symbol

Lookup resolves a symbol by walking the parent chain. Returns nil if the symbol is not found.

func (*Scope) LookupAllLocal added in v1.39.0

func (s *Scope) LookupAllLocal(name string) []*Symbol

LookupAllLocal returns all symbols matching a bare name in this scope, across Symbols and all PackageSymbols entries. Used by call hierarchy to find all package variants of a function name.

func (*Scope) LookupInPackage added in v1.39.0

func (s *Scope) LookupInPackage(name, pkg string) *Symbol

LookupInPackage resolves a symbol by preferring a package-qualified match in the current scope chain before falling back to a bare-name lookup. The bare-name fallback into Symbols is intentional: builtins and user-package symbols are registered with Package == "" and must be reachable when no qualified entry matches.

Unlike Lookup, LookupInPackage does not consult bareNameIndex — a symbol registered only via DefineQualifiedOnly is invisible to LookupInPackage unless the correct package is specified.

func (*Scope) LookupLocal

func (s *Scope) LookupLocal(name string) *Symbol

LookupLocal resolves a symbol only in this scope (not parents).

func (*Scope) LookupLocalInPackage added in v1.39.0

func (s *Scope) LookupLocalInPackage(name, pkg string) *Symbol

LookupLocalInPackage resolves a symbol in the current scope, preferring the package-qualified key when a package is provided.

The bare-name fallback into Symbols is restricted to the default user package. This prevents builtins (Package == "") from blocking package-local definitions like (in-package 'foo) (defun set ...). Unlike LookupInPackage, this method does not consult bareNameIndex.

func (*Scope) LookupLocalVisible added in v1.39.0

func (s *Scope) LookupLocalVisible(name, pkg string) *Symbol

LookupLocalVisible resolves a symbol as it would be seen unqualified in the current scope: first the active package, then imported/bare symbols.

type ScopeKind

type ScopeKind int

ScopeKind classifies the kind of scope.

const (
	ScopeGlobal   ScopeKind = iota // file/module level
	ScopeFunction                  // defun/defmacro body
	ScopeLambda                    // lambda body
	ScopeLet                       // let/let* body
	ScopeFlet                      // flet/labels body
	ScopeDotimes                   // dotimes body
)

func (ScopeKind) String

func (k ScopeKind) String() string

type Signature

type Signature struct {
	Params []lisp.ParamInfo
}

Signature describes the parameter signature of a callable symbol.

func (*Signature) MaxArity

func (sig *Signature) MaxArity() int

MaxArity returns the maximum number of arguments accepted. Returns -1 for variadic functions (those with &rest or &key params).

func (*Signature) MinArity

func (sig *Signature) MinArity() int

MinArity returns the minimum number of arguments required.

type Symbol

type Symbol struct {
	Name       string
	Package    string
	Kind       SymbolKind
	Source     *token.Location // nil for builtins
	Node       *lisp.LVal
	Scope      *Scope
	Signature  *Signature // non-nil for callables
	DocString  string
	References int
	Exported   bool
	External   bool // true for workspace-scanned or package-imported symbols
}

Symbol represents a defined name in a scope.

func FindEnclosingFunction added in v1.31.0

func FindEnclosingFunction(root *Scope, line, col int) *Symbol

FindEnclosingFunction finds the function symbol that contains the given 1-based position by walking the scope tree.

type SymbolKey added in v1.31.0

type SymbolKey struct {
	Package string
	Name    string
	Kind    SymbolKind
}

SymbolKey identifies a symbol across files by name and kind.

func SymbolKeyFromNameKind added in v1.31.0

func SymbolKeyFromNameKind(name string, kind string) SymbolKey

SymbolKeyFromNameKind creates a SymbolKey from raw name and kind strings. The kind string should match SymbolKind.String() output.

func SymbolToKey added in v1.31.0

func SymbolToKey(sym *Symbol) SymbolKey

SymbolToKey derives a SymbolKey from an analysis Symbol.

func (SymbolKey) String added in v1.31.0

func (k SymbolKey) String() string

String returns a lookup key for use in maps.

type SymbolKind

type SymbolKind int

SymbolKind classifies a symbol definition.

const (
	SymVariable  SymbolKind = iota // set, let binding
	SymFunction                    // defun, flet/labels binding
	SymMacro                       // defmacro
	SymParameter                   // function/lambda parameter
	SymSpecialOp                   // special operator (if, cond, etc.)
	SymBuiltin                     // builtin function
	SymType                        // deftype
)

func (SymbolKind) String

func (k SymbolKind) String() string

type UnresolvedRef

type UnresolvedRef struct {
	Name   string
	Source *token.Location
	Node   *lisp.LVal
}

UnresolvedRef records a symbol usage that could not be resolved.

Directories

Path Synopsis
Package perf provides call-graph-based performance analysis for ELPS source files.
Package perf provides call-graph-based performance analysis for ELPS source files.

Jump to

Keyboard shortcuts

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