diff --git a/Cargo.lock b/Cargo.lock index 13b29a6..2d70f5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -582,8 +582,15 @@ dependencies = [ "regex-cursor", "ropey", "thiserror", + "tree-sitter-language", ] +[[package]] +name = "tree-sitter-language" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8" + [[package]] name = "twox-hash" version = "1.6.3" diff --git a/bindings/Cargo.toml b/bindings/Cargo.toml index 70df944..e264e5b 100644 --- a/bindings/Cargo.toml +++ b/bindings/Cargo.toml @@ -11,12 +11,14 @@ rust-version = "1.76.0" [features] ropey = ["dep:ropey"] +tree-sitter-language = ["dep:tree-sitter-language"] [dependencies] ropey = { version = "1.6", default-features = false, optional=true } regex-cursor = "0.1.5" libloading = "0.8" thiserror = "2.0" +tree-sitter-language = { version = "0.1.5", optional = true } [build-dependencies] cc = "1.0" diff --git a/bindings/src/grammar.rs b/bindings/src/grammar.rs index fdcd82a..8227c84 100644 --- a/bindings/src/grammar.rs +++ b/bindings/src/grammar.rs @@ -3,6 +3,8 @@ use std::path::{Path, PathBuf}; use std::ptr::NonNull; use libloading::{Library, Symbol}; +#[cfg(feature = "tree-sitter-language")] +use tree_sitter_language::LanguageFn; /// Lowest supported ABI version of a grammar. // WARNING: update when updating vendored c sources @@ -44,18 +46,21 @@ impl Grammar { })? }; let language_fn_name = format!("tree_sitter_{}", name.replace('-', "_")); - let grammar = unsafe { - let language_fn: Symbol NonNull> = library - .get(language_fn_name.as_bytes()) - .map_err(|err| Error::DlSym { - err, - symbol: name.to_owned(), - })?; - Grammar { ptr: language_fn() } - }; + let language_fn: Symbol NonNull> = library + .get(language_fn_name.as_bytes()) + .map_err(|err| Error::DlSym { + err, + symbol: name.to_owned(), + })?; + let grammar = Grammar::from_grammar_data(language_fn())?; + std::mem::forget(library); + Ok(grammar) + } + + fn from_grammar_data(ptr: NonNull) -> Result { + let grammar = Grammar { ptr }; let version = grammar.abi_version(); if (MIN_COMPATIBLE_ABI_VERSION..=ABI_VERSION).contains(&version) { - std::mem::forget(library); Ok(grammar) } else { Err(Error::IncompatibleVersion { version }) @@ -72,6 +77,16 @@ impl Grammar { } } +#[cfg(feature = "tree-sitter-language")] +impl TryFrom for Grammar { + type Error = Error; + + fn try_from(builder: LanguageFn) -> Result { + let ptr = unsafe { NonNull::new_unchecked(builder.into_raw()().cast_mut().cast()) }; + Self::from_grammar_data(ptr) + } +} + #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Error opening dynamic library {path:?}")]