use super::symbols::SemanticElementTrait;
use super::symbols::Symbol;
use super::text::Text;
use super::text::TextContext;
use super::text::TextPosition;
use super::text::TextSpan;
use super::utils::EitherMut;
use super::utils::biglist::BigList;
use super::utils::iterable::Iterable;
#[derive(Copy, Clone)]
struct TokenRepositoryCell {
terminal: usize,
span: TextSpan
}
pub struct TokenRepositoryImpl {
cells: BigList<TokenRepositoryCell>
}
impl TokenRepositoryImpl {
pub fn new() -> TokenRepositoryImpl {
TokenRepositoryImpl {
cells: BigList::new(TokenRepositoryCell {
terminal: 0,
span: TextSpan {
index: 0,
length: 0
}
})
}
}
}
pub struct TokenRepository<'a> {
terminals: &'static [Symbol],
text: &'a Text,
data: EitherMut<'a, TokenRepositoryImpl>
}
pub struct Token<'a> {
repository: &'a TokenRepository<'a>,
pub index: usize
}
impl<'a> Clone for Token<'a> {
fn clone(&self) -> Self {
Token {
repository: self.repository,
index: self.index
}
}
}
impl<'a> Copy for Token<'a> {}
pub struct TokenRepositoryIterator<'a> {
repository: &'a TokenRepository<'a>,
index: usize
}
impl<'a> Iterator for TokenRepositoryIterator<'a> {
type Item = Token<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.repository.data.get().cells.len() {
None
} else {
let result = Token {
repository: self.repository,
index: self.index
};
self.index = self.index + 1;
Some(result)
}
}
}
impl<'a> Iterable<'a> for TokenRepository<'a> {
type Item = Token<'a>;
type IteratorType = TokenRepositoryIterator<'a>;
fn iter(&'a self) -> Self::IteratorType {
TokenRepositoryIterator {
repository: self,
index: 0
}
}
}
impl<'a> TokenRepository<'a> {
pub fn new(
terminals: &'static [Symbol],
text: &'a Text,
tokens: &'a TokenRepositoryImpl
) -> TokenRepository<'a> {
TokenRepository {
terminals,
text,
data: EitherMut::Immutable(tokens)
}
}
pub fn new_mut(
terminals: &'static [Symbol],
text: &'a Text,
tokens: &'a mut TokenRepositoryImpl
) -> TokenRepository<'a> {
TokenRepository {
terminals,
text,
data: EitherMut::Mutable(tokens)
}
}
pub fn add(&mut self, terminal: usize, index: usize, length: usize) -> usize {
let x = self.data.get_mut();
match x {
None => panic!("Got a mutable token repository with an immutable implementation"),
Some(data) => data.cells.push(TokenRepositoryCell {
terminal,
span: TextSpan { index, length }
})
}
}
pub fn get_terminals(&self) -> &'static [Symbol] {
&self.terminals
}
pub fn get_input(&self) -> &Text {
&self.text
}
pub fn get_tokens_count(&self) -> usize {
self.data.get().cells.len()
}
pub fn get_symbol_id_for(&self, index: usize) -> u32 {
self.terminals[self.data.get().cells[index].terminal].id
}
pub fn get_token(&'a self, index: usize) -> Token<'a> {
Token {
repository: &self,
index
}
}
pub fn get_count(&self) -> usize {
self.data.get().cells.len()
}
pub fn find_token_at(&self, index: usize) -> Option<Token> {
let data = self.data.get();
let count = data.cells.len();
if count == 0 {
return None;
}
let mut l: usize = 0;
let mut r = count - 1;
while l <= r {
let m = (l + r) / 2;
let cell = data.cells[m];
if index < cell.span.index {
r = m - 1;
} else if index < cell.span.index + cell.span.length {
return Some(Token {
repository: self,
index: m
});
} else {
l = m + 1;
}
}
None
}
}
impl<'a> SemanticElementTrait for Token<'a> {
fn get_position(&self) -> Option<TextPosition> {
Some(
self.repository
.text
.get_position_at(self.repository.data.get().cells[self.index].span.index)
)
}
fn get_span(&self) -> Option<TextSpan> {
Some(self.repository.data.get().cells[self.index].span)
}
fn get_context(&self) -> Option<TextContext> {
Some(self.repository.text.get_context_for(
self.get_position().unwrap(),
self.repository.data.get().cells[self.index].span.length
))
}
fn get_symbol(&self) -> Symbol {
self.repository.terminals[self.repository.data.get().cells[self.index].terminal]
}
fn get_value(&self) -> Option<String> {
Some(
self.repository
.text
.get_value_for(self.repository.data.get().cells[self.index].span)
)
}
}