use std::convert::TryFrom;
use fxhash::FxHashMap;
use text_size::TextSize;
use crate::{
green::{interner::TokenInterner, GreenElement, GreenNode, GreenToken, SyntaxKind},
interning::Interner,
NodeOrToken,
};
use super::{node::GreenNodeHead, token::GreenTokenData};
const CHILDREN_CACHE_THRESHOLD: usize = 3;
#[derive(Debug)]
pub struct NodeCache<'i, I = TokenInterner> {
nodes: FxHashMap<GreenNodeHead, GreenNode>,
tokens: FxHashMap<GreenTokenData, GreenToken>,
interner: MaybeOwned<'i, I>,
}
impl NodeCache<'static> {
pub fn new() -> Self {
Self {
nodes: FxHashMap::default(),
tokens: FxHashMap::default(),
interner: MaybeOwned::Owned(TokenInterner::new()),
}
}
}
impl Default for NodeCache<'static> {
fn default() -> Self {
Self::new()
}
}
impl<'i, I> NodeCache<'i, I>
where
I: Interner,
{
pub fn with_interner(interner: &'i mut I) -> Self {
Self {
nodes: FxHashMap::default(),
tokens: FxHashMap::default(),
interner: MaybeOwned::Borrowed(interner),
}
}
fn node<It>(&mut self, kind: SyntaxKind, children: It) -> GreenNode
where
It: IntoIterator<Item = GreenElement>,
It::IntoIter: ExactSizeIterator,
{
let children = children.into_iter();
if children.len() <= CHILDREN_CACHE_THRESHOLD {
self.get_cached_node(kind, children)
} else {
GreenNode::new(kind, children)
}
}
fn get_cached_node<It>(&mut self, kind: SyntaxKind, children: It) -> GreenNode
where
It: IntoIterator<Item = GreenElement>,
It::IntoIter: ExactSizeIterator,
{
#[derive(Clone)]
struct ChildrenIter {
data: [Option<GreenElement>; CHILDREN_CACHE_THRESHOLD],
idx: usize,
len: usize,
}
impl ChildrenIter {
fn new(data: [Option<GreenElement>; CHILDREN_CACHE_THRESHOLD], count: usize) -> Self {
ChildrenIter {
data,
idx: 0,
len: count,
}
}
}
impl Iterator for ChildrenIter {
type Item = GreenElement;
fn next(&mut self) -> Option<Self::Item> {
let item = self.data.get_mut(self.idx)?;
self.idx += 1;
item.take()
}
}
impl ExactSizeIterator for ChildrenIter {
fn len(&self) -> usize {
self.len - self.idx
}
}
let mut data: [Option<GreenElement>; CHILDREN_CACHE_THRESHOLD] = [None, None, None];
let mut count = 0;
for child in children {
data[count] = Some(child);
count += 1;
}
let children = ChildrenIter::new(data, count);
let head = GreenNodeHead::from_child_iter(kind, children.clone());
self.nodes
.entry(head.clone())
.or_insert_with(|| GreenNode::from_head_and_children(head, children))
.clone()
}
fn token(&mut self, kind: SyntaxKind, text: &str) -> GreenToken {
let text_len = TextSize::try_from(text.len()).unwrap();
let text = self.interner.get_or_intern(text);
let data = GreenTokenData { kind, text, text_len };
self.tokens.entry(data).or_insert_with(|| GreenToken::new(data)).clone()
}
}
#[derive(Debug)]
enum MaybeOwned<'a, T> {
Owned(T),
Borrowed(&'a mut T),
}
impl<T> MaybeOwned<'_, T> {
fn into_owned(self) -> Option<T> {
match self {
MaybeOwned::Owned(owned) => Some(owned),
MaybeOwned::Borrowed(_) => None,
}
}
}
impl<T> std::ops::Deref for MaybeOwned<'_, T> {
type Target = T;
fn deref(&self) -> &T {
match self {
MaybeOwned::Owned(it) => it,
MaybeOwned::Borrowed(it) => *it,
}
}
}
impl<T> std::ops::DerefMut for MaybeOwned<'_, T> {
fn deref_mut(&mut self) -> &mut T {
match self {
MaybeOwned::Owned(it) => it,
MaybeOwned::Borrowed(it) => *it,
}
}
}
impl<T: Default> Default for MaybeOwned<'_, T> {
fn default() -> Self {
MaybeOwned::Owned(T::default())
}
}
#[derive(Clone, Copy, Debug)]
pub struct Checkpoint(usize);
#[derive(Debug)]
pub struct GreenNodeBuilder<'cache, 'interner, I = TokenInterner> {
cache: MaybeOwned<'cache, NodeCache<'interner, I>>,
parents: Vec<(SyntaxKind, usize)>,
children: Vec<GreenElement>,
}
impl GreenNodeBuilder<'static, 'static> {
pub fn new() -> Self {
Self {
cache: MaybeOwned::Owned(NodeCache::new()),
parents: Vec::with_capacity(8),
children: Vec::with_capacity(8),
}
}
}
impl Default for GreenNodeBuilder<'static, 'static> {
fn default() -> Self {
Self::new()
}
}
impl<'cache, 'interner, I> GreenNodeBuilder<'cache, 'interner, I>
where
I: Interner,
{
pub fn with_cache(cache: &'cache mut NodeCache<'interner, I>) -> Self {
Self {
cache: MaybeOwned::Borrowed(cache),
parents: Vec::with_capacity(8),
children: Vec::with_capacity(8),
}
}
#[inline]
pub fn token(&mut self, kind: SyntaxKind, text: &str) {
let token = self.cache.token(kind, text);
self.children.push(token.into());
}
#[inline]
pub fn start_node(&mut self, kind: SyntaxKind) {
let len = self.children.len();
self.parents.push((kind, len));
}
#[inline]
pub fn finish_node(&mut self) {
let (kind, first_child) = self.parents.pop().unwrap();
let children = self.children.drain(first_child..);
let node = self.cache.node(kind, children);
self.children.push(node.into());
}
#[inline]
pub fn checkpoint(&self) -> Checkpoint {
Checkpoint(self.children.len())
}
#[inline]
pub fn start_node_at(&mut self, checkpoint: Checkpoint, kind: SyntaxKind) {
let Checkpoint(checkpoint) = checkpoint;
assert!(
checkpoint <= self.children.len(),
"checkpoint no longer valid, was finish_node called early?"
);
if let Some(&(_, first_child)) = self.parents.last() {
assert!(
checkpoint >= first_child,
"checkpoint no longer valid, was an unmatched start_node_at called?"
);
}
self.parents.push((kind, checkpoint));
}
#[inline]
pub fn finish(mut self) -> (GreenNode, Option<I>) {
assert_eq!(self.children.len(), 1);
let resolver = self.cache.into_owned().and_then(|cache| cache.interner.into_owned());
match self.children.pop().unwrap() {
NodeOrToken::Node(node) => (node, resolver),
NodeOrToken::Token(_) => panic!("called `finish` on a `GreenNodeBuilder` which only contained a token"),
}
}
}