rts

package
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Jul 4, 2026 License: Apache-2.0 Imports: 13 Imported by: 1

README

RTS: RSL Tree Sitter

A Go library wrapping the Go bindings for Rad's tree sitter implementation.

Installation

go get -u github.com/amterp/rad/rts

Git blame ignore revs

This repo has a .git-blame-ignore-revs file. Add it to your git with:

git config blame.ignoreRevsFile .git-blame-ignore-revs

Documentation

Index

Constants

This section is empty.

Variables

View Source
var FnSignaturesByName map[string]FnSignature

Functions

func ConvertCST added in v0.9.0

func ConvertCST(root *ts.Node, src string, file string) *rl.SourceFile

ConvertCST converts a tree-sitter CST into a Go-native AST. The input CST must be valid (no ERROR/MISSING nodes) - if the converter encounters an unexpected node kind, it panics.

func ConvertExpr added in v0.9.0

func ConvertExpr(node *ts.Node, src string, file string) rl.Node

ConvertExpr converts a single CST expression node into an AST expression. Used to pre-convert built-in function defaults in signatures.go init() and by the converter for user-defined function parameter defaults.

func FuncDocNames added in v0.11.0

func FuncDocNames() []string

FuncDocNames returns the sorted list of function names that have a doc entry. Used by completeness tests to compare against the registered builtin set.

func GeneratedBanner added in v0.11.0

func GeneratedBanner(by, from string) string

GeneratedBanner builds the one-line HTML comment prepended to every embedded markdown doc (the core/embedded_docs/ corpus and the rts/embedded_funcs/ mirror). It makes a file's generated nature obvious when opened locally - which .gitattributes (GitHub diffs only) can't do - while StripGeneratedBanner keeps it out of served output. `by` is the generator (e.g. "tools/gen-docs-embed"); `from` is the source of truth it derives from.

func IsValidFuncDocStem added in v0.11.0

func IsValidFuncDocStem(s string) bool

IsValidFuncDocStem matches the README's rule: file stems must be valid Rad identifiers ([a-z_][a-z0-9_]*). Filters out README.md and contributor notes that happen to land in this directory. Exported so the three codegen tools under tools/gen-funcs-* share the same rule without re-implementing it - if the rule ever changes (e.g. allowing uppercase), there's exactly one place to update.

func NodeName

func NodeName[T Node]() string

func NormalizeIndentedText added in v0.6.18

func NormalizeIndentedText(text string) string

NormalizeIndentedText removes common leading whitespace from all lines. Handles trailing newlines from tree-sitter, expands tabs to spaces (4-char width), and uses rune-aware slicing for UTF-8 safety. Preserves relative indentation.

func ParseFloat

func ParseFloat(src string) (float64, error)

func ParseInt

func ParseInt(src string) (int64, error)

func QueryNodes

func QueryNodes[T Node](rt *RadTree) ([]T, error)

func SpanFromNode added in v0.9.0

func SpanFromNode(node *ts.Node, file string) rl.Span

SpanFromNode creates an rl.Span from a tree-sitter node and file path.

func StripGeneratedBanner added in v0.11.0

func StripGeneratedBanner(s string) string

StripGeneratedBanner drops a leading GeneratedBanner line (and its single trailing newline), returning the remainder verbatim. It does not trim further, so an embedded_funcs file round-trips to its source byte-for-byte after stripping. Input without the banner is returned unchanged.

func ToExternalName added in v0.5.59

func ToExternalName(internalName string) string

ToExternalName converts internal argument names to external CLI flag names. This is the single source of truth for name transformations in Rad.

Types

type BaseNode

type BaseNode struct {
	// contains filtered or unexported fields
}

func (*BaseNode) CompleteSrc

func (n *BaseNode) CompleteSrc() string

func (*BaseNode) CstNode added in v0.9.0

func (n *BaseNode) CstNode() *ts.Node

func (*BaseNode) EndByte

func (n *BaseNode) EndByte() int

func (*BaseNode) EndPos

func (n *BaseNode) EndPos() Position

func (*BaseNode) Src

func (n *BaseNode) Src() string

func (*BaseNode) StartByte

func (n *BaseNode) StartByte() int

func (*BaseNode) StartPos

func (n *BaseNode) StartPos() Position

type CallNode

type CallNode struct {
	BaseNode
	Name     string
	NameSpan rl.Span
}

type FileHeader

type FileHeader struct {
	BaseNode
	Contents        string
	MetadataEntries map[string]string
}

type FnSignature

type FnSignature struct {
	Name      string
	Signature string
	Typing    *rl.TypingFnT
	// IsInternal marks signatures that exist for the runtime's own use
	// (e.g. _rad_docs_* / _rad_explain wiring up the CLI's `rad docs`
	// flow). They
	// remain callable from a script - that's how the runtime invokes
	// them - but completion, hover, and other user-facing surfaces
	// should filter them out so the public API stays focused.
	IsInternal bool
}

func GetSignature

func GetSignature(name string) *FnSignature

type FuncDoc added in v0.11.0

type FuncDoc struct {
	Name        string
	Description string // body of the H1 section, before any "##" subsection
	Signature   string // single line inside the `## Signature` section
	Parameters  []FuncDocParam
	Examples    []string // each rad code block inside `## Examples`
	Category    string
	Notes       string
	SeeAlso     []string // function names listed in `## See also`
}

FuncDoc carries the documentation for a built-in function, parsed from `docs/funcs/<name>.md`. The signature is stored as the raw source line; downstream consumers (rts/signatures.go's parser, the LSP hover renderer) re-parse on demand rather than encoding the parsed form here. The intent is to keep this struct small and serializable; a future commit may grow it (e.g. with a pre-parsed param list) once we have a clearer view of what callers need.

func GetFuncDoc added in v0.11.0

func GetFuncDoc(name string) *FuncDoc

GetFuncDoc returns the parsed FuncDoc for a built-in name, or nil if the function has no doc file. The LSP hover layer uses this to render a function's description alongside its signature.

func ParseFuncDoc added in v0.11.0

func ParseFuncDoc(name, src string) (*FuncDoc, error)

ParseFuncDoc parses a docs/funcs/*.md file into a FuncDoc. The expected shape is documented in docs/funcs/README.md and locked by the codegen test - if you're updating the parser, update both.

Lenient about extra blank lines and trailing whitespace; strict about required sections (returns an error when any of `Signature`, `Examples`, `Category` is missing). Optional sections (`Notes`, `See also`, `Parameters`) just leave the corresponding fields empty when absent.

type FuncDocParam added in v0.11.0

type FuncDocParam struct {
	Name        string
	Type        string
	Description string
}

FuncDocParam is one entry in the `## Parameters` list. The Type column carries whatever the doc author wrote in backticks - it isn't validated against the signature here; that check belongs in the codegen test.

type FunctionSet added in v0.6.15

type FunctionSet struct {
	// contains filtered or unexported fields
}

FunctionSet is the set of *user-facing* built-in function names. It's deliberately narrower than FnSignaturesByName, which also holds internal `_rad_*` entries (six of them today) used by core/runtime machinery that should not be exposed as calls users can write. Keep the two sources in sync only when adding user-callable builtins; internal-only signatures belong in signatures.go alone.

func GetBuiltInFunctions added in v0.6.15

func GetBuiltInFunctions() *FunctionSet

GetBuiltInFunctions returns the singleton instance of built-in functions. This is thread-safe and loads the functions only once.

func (*FunctionSet) Contains added in v0.6.15

func (fs *FunctionSet) Contains(name string) bool

func (*FunctionSet) Names added in v0.11.0

func (fs *FunctionSet) Names() map[string]bool

Names returns a snapshot of the function set as a name -> bool map. Callers (the static checker's did-you-mean suggester) walk every name; returning the map directly would let them mutate the singleton, so we copy. Cheap relative to a Levenshtein pass.

type Node

type Node interface {
	CompleteSrc() string
	Src() string
	// Indexes in the original source code.
	// Zero indexed, so add +1 to get human readable values.
	// todo wrap in own Range object instead?
	StartByte() int
	EndByte() int // inclusive
	StartPos() Position
	EndPos() Position // inclusive
}

type Position

type Position struct {
	Row int
	Col int
}

func NewPosition

func NewPosition(p ts.Point) Position

type RadParser

type RadParser struct {
	// contains filtered or unexported fields
}

func NewRadParser

func NewRadParser() (rts *RadParser, err error)

func (*RadParser) Close

func (rts *RadParser) Close()

func (*RadParser) Language added in v0.11.0

func (rts *RadParser) Language() *ts.Language

Language returns the tree-sitter language for this parser. It is safe to use concurrently with Parse - Language objects are immutable and shared across all parsers built from the same grammar.

func (*RadParser) Parse

func (rts *RadParser) Parse(src string) *RadTree

Parse builds a fresh RadTree. The returned tree retains only the language pointer (immutable), not the parser - so calls into the tree don't race against further Parse calls on this parser.

type RadTree

type RadTree struct {
	// contains filtered or unexported fields
}

RadTree wraps a tree-sitter *ts.Tree, which owns C-heap memory via cgo. The C memory must be released by calling ts.Tree.Close(); the Go garbage collector alone won't free it.

We do NOT register a finalizer on RadTree. The upstream go-tree-sitter README warns against it, and we hit the documented hazard during development: tree-sitter Nodes hold references into the C tree but the Go-side relationship between Node and Tree isn't visible to the GC. A finalizer-driven Close could free the C tree while another goroutine is walking nodes that still point into it (the converter does exactly this).

Cleanup is the caller's responsibility: call Close when no further readers will touch the tree. Higher layers (e.g. radls's snapshot model) coordinate that lifetime via reference counting.

closeOnce makes Close idempotent so callers can defer-Close without worrying about double-free; upstream ts.Tree.Close is NOT idempotent (it always calls ts_tree_delete), so we guard.

We hold only the language (immutable, safe to share across goroutines), not the parser. Any reparse path threads the parser in as a method argument so the same parser can be locked-and- driven by the owning State without RadTree carrying a hazardous back-pointer.

func (*RadTree) Close

func (rt *RadTree) Close()

Close releases the underlying tree-sitter C memory. Idempotent; the underlying ts.Tree.Close is not, so we guard with sync.Once. Safe to call from multiple goroutines.

func (*RadTree) Dump

func (rt *RadTree) Dump() string

func (*RadTree) FindCalls

func (rt *RadTree) FindCalls() []*CallNode

func (*RadTree) FindFileHeader

func (rt *RadTree) FindFileHeader() (*FileHeader, bool)

func (*RadTree) FindInvalidNodeSpans added in v0.9.0

func (rt *RadTree) FindInvalidNodeSpans(file string) []rl.Span

FindInvalidNodeSpans returns spans for all invalid/missing nodes.

func (*RadTree) FindInvalidNodes

func (rt *RadTree) FindInvalidNodes() []*ts.Node

func (*RadTree) FindNodes

func (rt *RadTree) FindNodes(nodeKind string) []*ts.Node

todo should take an ID instead of string for kind

func (*RadTree) FindShebang

func (rt *RadTree) FindShebang() (*Shebang, bool)

func (*RadTree) HasInvalidNodes added in v0.9.0

func (rt *RadTree) HasInvalidNodes() bool

HasInvalidNodes returns true if the tree contains any error/missing nodes.

func (*RadTree) Root

func (rt *RadTree) Root() *ts.Node

func (*RadTree) Sexp

func (rt *RadTree) Sexp() string

func (*RadTree) String

func (rt *RadTree) String() string

func (*RadTree) Update

func (rt *RadTree) Update(parser *RadParser, src string)

Update reparses the tree in place with new source, using the supplied parser. Used by callers that hold a long-lived RadTree (e.g. the check package's standalone driver). The snapshot model in radls doesn't use this - each version gets a fresh tree - so this path is reserved for non-snapshot consumers. Closes the previous tree to avoid leaking C memory.

Taking the parser as an argument (rather than a struct field) means the caller controls parser lifetime and concurrency - a RadTree can't accidentally race a shared parser through its own back-pointer.

type Shebang

type Shebang struct {
	BaseNode
}

type StringNode

type StringNode struct {
	BaseNode
	RawLexeme string // Literal src, excluding delimiters, ws, comments, etc
}

Directories

Path Synopsis
Package radfmt implements `rad fmt`, a gofmt-style canonical re-printer for Rad scripts.
Package radfmt implements `rad fmt`, a gofmt-style canonical re-printer for Rad scripts.

Jump to

Keyboard shortcuts

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