Documentation
¶
Overview ¶
Package analyze turns notebook source into a graph.Graph.
The Analyzer interface is the seam that lets the source-analysis backend be swapped without touching the graph algorithms or the engine. Today the only implementation is TypesAnalyzer, which loads the package with go/packages and reads the type checker's results. When re-analysis on every keystroke starts to hurt (the largest engineering risk in the design), a gopls-backed implementation can replace it behind the same interface.
Everything go/types-specific lives in this package. The graph package it produces is plain data.
Index ¶
- func LoadForPurity(dir string) (*packages.Package, error)
- func NotebookWASMable(g *graph.Graph) (ok bool, blockers []graph.CellID)
- func RefineGraphPurity(dir string, g *graph.Graph) error
- func RefinePurity(pkg *packages.Package, g *graph.Graph)
- func WASMability(pkg *packages.Package, g *graph.Graph)
- type Analysis
- type Analyzer
- type PackageInfo
- type Session
- type TypesAnalyzer
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LoadForPurity ¶
LoadForPurity loads the notebook package with full dependency source (LoadAllSyntax implies NeedDeps) so its call graph can be built. This is the heavy load; keep it off the interactive path.
func NotebookWASMable ¶
NotebookWASMable reports whether the whole notebook can run in the browser: every runnable cell must be WASM-able. It returns the offending cells (not WASM-able) so the caller can name them. A notebook with a fold or other deferred feature is judged on its runnable cells only.
func RefineGraphPurity ¶ added in v0.5.0
RefineGraphPurity is the cold-path convenience that build/run/check use to light up the cache: it does the heavy NeedDeps load (LoadForPurity) and runs RefinePurity over g in place. It is deliberately NOT on the interactive Session path — that path drops NeedDeps to hit its ~sub-ms budget and leaves every cell at the safe impure default (a cache miss, never a wrong answer). The one-shot commands already pay ~1s for codegen+compile, so they can afford the heavy load, and doing it here is what makes "cacheability is derived" true of a built binary rather than only of a unit test.
Best-effort like RefinePurity: a load failure is returned so a caller can decide, but a cell whose SSA can't be built simply keeps its impure default.
func RefinePurity ¶
RefinePurity computes the Pure flag for every cell in g from the package call graph, mutating the cells in place. It requires a package loaded with NeedDeps (full dependency source) — use LoadForPurity.
It uses a CHA call graph rather than VTA: purity needs only a sound over-approximation of "does this reach time.Now / rand / os / net", and CHA provides that far more cheaply. CHA over-approximates interface dispatch, so it may occasionally mark a pure cell impure — which costs a cache hit and nothing else, the safe direction.
RefinePurity is best-effort: if SSA cannot be built or a cell's function cannot be found, that cell keeps its (safe, impure) default and no error is returned.
func WASMability ¶
WASMability marks every cell in g with whether it can run under GOOS=js GOARCH=wasm, from the call graph — not by hand, and not from the purity pass. A cell is WASM-able iff it transitively reaches none of the non-portable primitives. Results are written to graph.Cell.WASMable.
Best-effort like RefinePurity: a cell whose SSA function can't be found keeps the safe default (false — not provably portable). Requires a package loaded with full dependency source (use LoadForPurity).
Types ¶
type Analysis ¶
type Analysis struct {
Graph *graph.Graph
Package PackageInfo
Diagnostics []graph.Diagnostic
}
Analysis is the full result of analyzing a notebook package for codegen: the dependency graph, the package identity, and any diagnostics.
func LoadPackage ¶
LoadPackage is the codegen entry point: it derives the graph exactly as TypesAnalyzer.Analyze does, and additionally returns the package identity codegen needs. The graph and diagnostics are identical to Analyze; this just surfaces the package metadata that the Analyzer interface intentionally omits (the interface is the gopls seam and stays graph-only).
type Analyzer ¶
Analyzer derives a notebook's dependency graph from source.
Analyze returns the graph together with any diagnostics. A non-nil error is reserved for failures to load or analyze at all (bad directory, package that does not compile at the syntax level); ordinary notebook problems — a missing producer, a cycle, an unnamed result — are returned as diagnostics on a graph that is otherwise as complete as possible, so the caller can report several at once rather than one per run.
type PackageInfo ¶
type PackageInfo struct {
// ImportPath is the notebook package's import path, e.g.
// "github.com/scttfrdmn/go-notebook/examples/capacity".
ImportPath string
// Name is the package clause name, e.g. "capacity".
Name string
// Dir is the absolute directory containing the package's source.
Dir string
// GoFiles are the absolute paths of the package's non-generated Go files.
GoFiles []string
}
PackageInfo is the identity of the notebook package that codegen needs but the graph IR deliberately does not carry: where the package lives and what it is called. The graph is about dataflow; this is about where to write the generated registry so it can see the notebook's unexported cells.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session is the interactive re-analysis path: it loads the notebook package once, caches its dependency types, and thereafter re-derives the graph by re-typechecking only the notebook package's source against that cache.
This is the number the whole milestone exists to produce (KC2: re-analysis after a one-cell edit). A full packages.Load reruns `go list` and reloads the world (~hundreds of ms); a re-typecheck against a cached importer is sub-millisecond, because the dependency graph has not changed on an edit — only the notebook's own file contents have.
A Session is not safe for concurrent use; drive it from a single edit loop.
func NewSession ¶
NewSession primes a Session for the notebook package in dir. It performs one graph-mode load (no NeedDeps) to obtain the dependency types and the file list, then holds them for fast re-analysis. The prime cost is the ~cold-load number; every subsequent Reanalyze is the interactive number.
type TypesAnalyzer ¶
type TypesAnalyzer struct{}
TypesAnalyzer derives a notebook graph using go/packages and go/types. It is the only Analyzer implementation in this milestone.
The zero value is ready to use. Analyze performs a cold, one-shot derivation. For the interactive re-analysis path (a one-cell edit), use a Session, which primes the importer once and then re-typechecks only the notebook package — orders of magnitude faster than reloading.
func (TypesAnalyzer) Analyze ¶
func (TypesAnalyzer) Analyze(dir string) (*graph.Graph, []graph.Diagnostic, error)
Analyze loads the package in dir (graph mode, no NeedDeps), finds the notebook file, and derives the graph. Purity is NOT computed here: cells default to impure, which is the always-safe default (a conservative impure verdict only costs a cache miss). Refine purity separately with RefinePurity when the cache needs it; never on an interactive edit.
Load failures return an error; notebook-level problems are returned as diagnostics on the fullest graph the analyzer could build.