Documentation
¶
Overview ¶
Package langspec is a data-driven framework for line-oriented language parsers: a language is defined by exactly one Spec value (a set of regex Defs plus a qualification mode), not by a new Go type. Adding a language to spectackle means adding one Spec (see python.go, javascript.go) — the indexing pipeline (internal/index) is never touched (SPX-LSP-001).
SpecParser adapts a Spec to index.LanguageParser so it plugs into index.New's parsers slice exactly like a hand-written parser (see index.CudaParser, index.AsmParser). Parsing is a single-pass line scan: no AST, no cgo, no external grammar — deliberately the cheapest possible backend for languages where an approximate symbol table (function/class definitions, not full semantics) is enough for the cross-language graph. Parsing is deterministic: identical bytes yield identical results (SPX-GRA-001).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func All ¶
func All() []index.LanguageParser
All returns a SpecParser for every registered Spec, ready to append to an index.New parsers slice alongside hand-written parsers such as index.GoParser.
Types ¶
type Def ¶
type Def struct {
Kind graph.NodeKind
Re *regexp.Regexp
Name int // submatch group index (>=1) holding the symbol name
Sig int // submatch group index (>=1) holding Node.Sig; 0 = no signature
}
Def is one regex-driven symbol shape within a Spec: a line matching Re mints a node of Kind, with Re's submatch group Name giving the symbol name and (optionally) submatch group Sig giving a compact signature.
type EndSpanSpec ¶
EndSpanSpec is Spec.EndSpan's shape: the keyword regexes cspan.KeywordSpan depth-counts to find where a def's body ends, standing in for the '{'/'}' pair that cspan.Span counts for brace languages. Open matches increment depth, Close matches decrement it; see cspan.KeywordSpan's doc for the exact counting rules (per-line net sum, def line included).
type QualMode ¶
type QualMode uint8
QualMode selects how a matched symbol name is qualified into the "<lang>:<qualified-name>" NodeID (see internal/ids).
const ( // QualFileStem qualifies with the file's base name minus extension, // e.g. app.py's `def run` -> "py:app.run". Matches Python's one file // == one importable module convention. QualFileStem QualMode = iota // QualDirPkg qualifies with the containing directory's base name, // e.g. mat/ops.s's TEXT ·mulVec -> "asm:mat.mulVec" (see // index.AsmParser, which this mode mirrors for source layouts where // a directory is the unit of namespacing, not the file). QualDirPkg // QualFlat uses the bare matched name with no qualification prefix, // e.g. a CUDA kernel -> "cu:saxpy_kernel" (see index.CudaParser). QualFlat )
type Spec ¶
type Spec struct {
Lang graph.Lang
Exts []string
Qual QualMode
Defs []Def
// CallRe is the optional call-site regex for LSP-001: capture group 1 is
// the callee name. Unset (nil) is the framework default and means zero
// behavior change from before this field existed — Parse emits no edges,
// exactly like every language that doesn't set it (see
// TestSpecParserNoEdgesWithoutCallRe). Set it only for brace languages
// where a def's body is delimited by '{'/'}' (see c.go, cpp.go); a
// language with no braces has nothing for the brace-counted body span to
// bound CallRe to, so it simply leaves CallRe nil.
CallRe *regexp.Regexp
// Stop lists callee names CallRe must never turn into a call edge —
// language keywords/operators whose syntax happens to look like a call
// (`if (`, `sizeof(`, ...). Only consulted when CallRe is set.
Stop []string
// EndSpan is the optional keyword-counting alternative to brace-counted
// body spans, for end-terminated languages (Lua, Ruby, and similar,
// where a def's body is closed by a keyword like "end" rather than by
// '}'). Unset (nil) is the framework default and means zero behavior
// change from before this field existed — Parse bounds a KFunc/KMethod
// def's body with cspan.Span exactly as it always has (see CallRe's doc
// for the same nil-means-unchanged guarantee this mirrors). Set it only
// for languages with no braces at all; a brace language leaves EndSpan
// nil and CallRe (if set) drives cspan.Span as before.
EndSpan *EndSpanSpec
}
Spec is the whole definition of a language for langspec purposes: the language tag, the file extensions it claims, how matched names are qualified into NodeIDs, and the ordered list of regex Defs tried against each source line. One Spec value == one language; see python.go and javascript.go for the reference specs this framework ships with.
type SpecParser ¶
type SpecParser struct {
S Spec
}
SpecParser adapts a Spec to index.LanguageParser.
func (SpecParser) CacheVersion ¶
func (p SpecParser) CacheVersion() string
CacheVersion implements index.CacheVersioner by digesting the Spec itself. A langspec language IS its data, so the data is the version: edit a regex and every cached parse blob for that language — and only that language — stops matching, instead of replaying pre-edit nodes for unchanged files (B-0007). Nothing to bump by hand, which matters because a Spec edit is the single most common change in this package.
Every input is walked in declaration order and never through a map, so the digest is stable across processes; the nil markers keep an unset CallRe or EndSpan from colliding with a set one that happens to stringify empty.
func (SpecParser) Extensions ¶
func (p SpecParser) Extensions() []string
Extensions are the file suffixes this parser claims.
func (SpecParser) Lang ¶
func (p SpecParser) Lang() graph.Lang
Lang identifies the parser's language.
func (SpecParser) Parse ¶
func (p SpecParser) Parse(path string, src []byte) (index.ParseResult, error)
Parse scans one source file line by line, trying each Def in order against every line and minting a node per match. When the Spec sets CallRe, each callable-unit hit — KFunc, KMethod or KKernel, see spanEligibleKinds for why those three and not the rest — also gets its body span scanned for call edges (LSP-001: "WHEN a Spec sets CallRe, the SpecParser SHALL emit ECall edges from each Def's brace-counted body span"): the body span itself is brace-counted via cspan.Span, unless the Spec sets EndSpan, in which case it is keyword-counted via cspan.KeywordSpan instead (for end-terminated languages with no braces at all). With CallRe unset — the default — no edges are emitted and EndLine stays equal to Line, exactly as before this field existed: same-language and cross-language relations are otherwise a resolver's job (see internal/resolve), not a langspec.Spec's.