Skip to content

Commit e8b04f3

Browse files
feat: Add support for loading tree-sitter-language grammars (#24)
1 parent 029bf64 commit e8b04f3

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ rust-version = "1.76.0"
1111

1212
[features]
1313
ropey = ["dep:ropey"]
14+
tree-sitter-language = ["dep:tree-sitter-language"]
1415

1516
[dependencies]
1617
ropey = { version = "1.6", default-features = false, optional=true }
1718
regex-cursor = "0.1.5"
1819
libloading = "0.8"
1920
thiserror = "2.0"
21+
tree-sitter-language = { version = "0.1.5", optional = true }
2022

2123
[build-dependencies]
2224
cc = "1.0"

bindings/src/grammar.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use std::path::{Path, PathBuf};
33
use std::ptr::NonNull;
44

55
use libloading::{Library, Symbol};
6+
#[cfg(feature = "tree-sitter-language")]
7+
use tree_sitter_language::LanguageFn;
68

79
/// Lowest supported ABI version of a grammar.
810
// WARNING: update when updating vendored c sources
@@ -44,18 +46,21 @@ impl Grammar {
4446
})?
4547
};
4648
let language_fn_name = format!("tree_sitter_{}", name.replace('-', "_"));
47-
let grammar = unsafe {
48-
let language_fn: Symbol<unsafe extern "C" fn() -> NonNull<GrammarData>> = library
49-
.get(language_fn_name.as_bytes())
50-
.map_err(|err| Error::DlSym {
51-
err,
52-
symbol: name.to_owned(),
53-
})?;
54-
Grammar { ptr: language_fn() }
55-
};
49+
let language_fn: Symbol<unsafe extern "C" fn() -> NonNull<GrammarData>> = library
50+
.get(language_fn_name.as_bytes())
51+
.map_err(|err| Error::DlSym {
52+
err,
53+
symbol: name.to_owned(),
54+
})?;
55+
let grammar = Grammar::from_grammar_data(language_fn())?;
56+
std::mem::forget(library);
57+
Ok(grammar)
58+
}
59+
60+
fn from_grammar_data(ptr: NonNull<GrammarData>) -> Result<Grammar, Error> {
61+
let grammar = Grammar { ptr };
5662
let version = grammar.abi_version();
5763
if (MIN_COMPATIBLE_ABI_VERSION..=ABI_VERSION).contains(&version) {
58-
std::mem::forget(library);
5964
Ok(grammar)
6065
} else {
6166
Err(Error::IncompatibleVersion { version })
@@ -72,6 +77,16 @@ impl Grammar {
7277
}
7378
}
7479

80+
#[cfg(feature = "tree-sitter-language")]
81+
impl TryFrom<LanguageFn> for Grammar {
82+
type Error = Error;
83+
84+
fn try_from(builder: LanguageFn) -> Result<Self, Self::Error> {
85+
let ptr = unsafe { NonNull::new_unchecked(builder.into_raw()().cast_mut().cast()) };
86+
Self::from_grammar_data(ptr)
87+
}
88+
}
89+
7590
#[derive(thiserror::Error, Debug)]
7691
pub enum Error {
7792
#[error("Error opening dynamic library {path:?}")]

0 commit comments

Comments
 (0)