[feature] Register an in-process tree-sitter grammar without a dynamic library
Problem
The Rust API has no way to register a tree-sitter grammar that is already linked into the process. ast-grep-dynamic only supports grammars loaded from a shared library: Inner holds a libloading::Library alive (crates/dynamic/src/lib.rs, struct Inner { lang, name, meta_var_char, expando_char, _lib: Library }) and Registration takes a lib_path plus a symbol name, loaded through Library::new in load_ts_language. A Rust embedder who already depends on a tree-sitter-* crate cannot hand that grammar to ast-grep; they have to build a .so for every target and ship it beside the binary. The CLI path via sgconfig.yml + customLanguages is fine — this is only about the library API.
The core traits are already public and implementable: ast_grep_core::Language and LanguageExt are not sealed (crates/core/src/language.rs), and LanguageExt::get_ts_language(&self) -> TSLanguage is the only grammar hook. A static wrapper is small:
#[derive(Clone)]
pub struct StaticLang {
name: &'static str,
grammar: TSLanguage,
expando: char,
}
impl ast_grep_core::Language for StaticLang {
fn expando_char(&self) -> char { self.expando }
fn kind_to_id(&self, kind: &str) -> u16 { self.grammar.id_for_node_kind(kind, true) }
fn field_to_id(&self, field: &str) -> Option<u16> {
self.grammar.field_id_for_name(field).map(|id| id.get())
}
fn build_pattern(&self, b: &PatternBuilder) -> Result<Pattern, PatternError> {
b.build(|src| StrDoc::try_new(src, self.clone()))
}
}
impl LanguageExt for StaticLang {
fn get_ts_language(&self) -> TSLanguage { self.grammar.clone() }
}I have this working locally against ast-grep-core 0.45 + tree-sitter 0.27; it parses a linked tree-sitter-sequel grammar and refuses malformed input the same way a built-in does. The wrapper is about 15 lines, so the question is placement and API shape, not feasibility.
Why this is not a request to add a built-in language
I read the add-language guide first, including the <10 MB binary-size budget and the popularity bar, so this deliberately does not ask ast-grep to ship another grammar. Several requested languages have been closed (#1596 clojure, #2130 objective-c, #2675 verilog, #2523 HLSL, #2902 gn), and SQL was added experimentally and removed in #1743 / 35807eda. In-process registration is what lets a downstream embedder keep using any of those grammars through ast-grep-core without ast-grep carrying the binary cost or maintaining the grammar. Related open discussion: #1963 plugin system, #1364 WASM as a custom-language parser.
Ask
Is an in-process / statically linked custom language in scope? If it is, where should it live — ast-grep-core (so any embedder gets it without libloading) or ast-grep-dynamic alongside DynamicLang, for example by letting Inner hold either a Library or a 'static grammar?
I can send a PR with tests in whichever shape you prefer, and I am happy to adapt the code above rather than have you review my naming. If you would rather not add a second registration path, say so and I will keep the wrapper in my own crate and close this.
Source: ast-grep/ast-grep