Documentation
¶
Overview ¶
Package script runs user Go scripts with the yaegi interpreter, exposing the sdb API plus the Go standard library.
Index ¶
Constants ¶
const ( SevError = "error" SevWarning = "warning" )
The two severities. An error means Run would fail (or never start); a warning is legal Go that probably does not do what was meant.
Variables ¶
This section is empty.
Functions ¶
func HasError ¶ added in v0.9.0
HasError reports whether any diag is an error rather than a warning.
Types ¶
type Diag ¶ added in v0.9.0
type Diag struct {
Line int `json:"line"`
Col int `json:"col"`
Severity string `json:"severity"` // SevError or SevWarning
Msg string `json:"msg"`
}
Diag is one problem Check found, at a 1-based line and column (column 0 when only the line is known).
func Check ¶ added in v0.9.0
Check finds what is wrong with a script without running it, so an editor can mark errors on their lines as the user types, and `dbc script --check` can gate a scripts repo in CI. It never executes the script: not Run, not init(), not a package-level initializer.
src ─► 1. parse (go/parser) ── syntax errors? ──► those, and stop
│ (the passes below need a tree)
├► 2. signature: package main, func Run(s *sdb.S) error, from the AST
├► 3. lint: m[k], _ = … (yaegi drops the write)
└► 4. compile (yaegi, newInterp + Compile, no Execute)
Why each pass:
- go/parser first, because its positions are exact and it reports up to ten errors; yaegi stops at its first and words it less helpfully.
- Run's signature from the AST, not the interpreter: asking yaegi for main.Run needs Execute first, which runs init() and the package's var initializers — exactly what a check must never do.
- The lint is the one case that has cost real time: yaegi compiles and runs a two-value assignment into a map element and stores nothing (traefik/yaegi#1655). Without types it cannot tell a map from a slice, so it flags both and says so; a slice there is rare.
- yaegi's compile pass (type analysis and control flow, no code run) catches what the parser cannot: an undefined name, a type mismatch, an import a script cannot have. It is the same interpreter Run builds (newInterp), so the two agree on what a script may import. It reports only its first error, and does not catch everything the Go compiler would (an unused variable passes).
Diags come back sorted by position. A clean script is nil.
type Symbol ¶ added in v0.11.0
type Symbol struct {
Kind string `json:"kind"` // var, const, type, func, method, field, package, label, builtin
Name string `json:"name"`
At Span `json:"at"` // the occurrence under the caret
Def *Span `json:"def"` // nil: declared outside the script
Uses []Span `json:"uses"`
}
Symbol is what the caret is on. Kind "" means nothing that resolves (a keyword, a literal, white space): the editor has nowhere to go. Def is nil when the declaration is not in the script (a builtin such as len or error, or a member of an imported package); Uses then still lists every occurrence. Uses includes the declaration itself, in buffer order.
func Resolve ¶ added in v0.11.0
Resolve finds the symbol at byte offset caret of src. A caret just past a name (where it rests after typing one) counts as on it.
A script with syntax errors still resolves: go/parser hands back the tree it could build, and the checker binds what is in it. A panic deep in the checker over odd input is a symbol with no kind, never a crash of the server that asked.