use std::collections::hash_map::Entry;
use rustc_hash::FxHashMap;
use tree_sitter::{Parser, Query};
use crate::{ImportSpec, LanguageId, LanguageRegistry};
pub struct ParserPool<'r> {
registry: &'r LanguageRegistry,
parsers: FxHashMap<LanguageId, Option<Parser>>,
tags_queries: FxHashMap<LanguageId, Option<Query>>,
imports_queries: FxHashMap<LanguageId, Option<Query>>,
injections_queries: FxHashMap<LanguageId, Option<Query>>,
}
impl<'r> ParserPool<'r> {
#[must_use]
pub fn new(registry: &'r LanguageRegistry) -> Self {
Self {
registry,
parsers: FxHashMap::default(),
tags_queries: FxHashMap::default(),
imports_queries: FxHashMap::default(),
injections_queries: FxHashMap::default(),
}
}
pub(crate) fn registry(&self) -> &'r LanguageRegistry {
self.registry
}
pub fn parser(&mut self, id: LanguageId) -> Option<&mut Parser> {
if let Entry::Vacant(entry) = self.parsers.entry(id) {
let parser = self.registry.get(id).and_then(|spec| {
let mut parser = Parser::new();
parser.set_language(&spec.language).ok()?;
Some(parser)
});
entry.insert(parser);
}
self.parsers.get_mut(&id).and_then(Option::as_mut)
}
pub fn tags_query(&mut self, id: LanguageId) -> Option<&Query> {
if let Entry::Vacant(entry) = self.tags_queries.entry(id) {
let query = self.registry.get(id).and_then(|spec| {
let source = spec.tags_query.as_deref()?;
Query::new(&spec.language, source).ok()
});
entry.insert(query);
}
self.tags_queries.get(&id).and_then(Option::as_ref)
}
pub fn imports_query(&mut self, id: LanguageId) -> Option<&Query> {
if let Entry::Vacant(entry) = self.imports_queries.entry(id) {
let query = self
.registry
.get(id)
.and_then(|spec| match spec.imports.as_ref()? {
ImportSpec::Query { source, .. } => {
Query::new(&spec.language, source.as_ref()).ok()
}
ImportSpec::Custom(_) => None,
});
entry.insert(query);
}
self.imports_queries.get(&id).and_then(Option::as_ref)
}
pub fn injections_query(&mut self, id: LanguageId) -> Option<&Query> {
if let Entry::Vacant(entry) = self.injections_queries.entry(id) {
let query = self.registry.get(id).and_then(|spec| {
let source = spec.injections_query.as_deref()?;
Query::new(&spec.language, source).ok()
});
entry.insert(query);
}
self.injections_queries.get(&id).and_then(Option::as_ref)
}
}