use std::{fmt};
use std::ops::{Range};
use std::str::{Chars};
use super::{Tree, EndOfFile};
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Location {
pub start: usize,
pub end: usize,
}
impl Location {
pub const EVERYWHERE: Location = Location {start: usize::MIN, end: usize::MAX};
}
impl fmt::Debug for Location {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}..{}", self.start, self.end)
}
}
impl From<Range<usize>> for Location {
fn from(value: Range<usize>) -> Self { Self {start: value.start, end: value.end} }
}
#[derive(Copy, Clone)]
pub struct Loc<T>(pub T, pub Location);
impl<T> Loc<T> {
pub fn as_ref(&self) -> Loc<&T> { Loc(&self.0, self.1) }
}
impl<T: fmt::Debug> fmt::Debug for Loc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)?;
write!(f, " ({:?})", self.1)
}
}
impl<U, T: PartialEq<U>> PartialEq<U> for Loc<T> {
fn eq(&self, other: &U) -> bool { self.0 == *other }
}
#[derive(Debug)]
pub struct Token(pub Loc<Result<Box<dyn Tree>, String>>);
impl Token {
pub fn new(tree: Box<dyn Tree>, location: impl Into<Location>) -> Self {
Token(Loc(Ok(tree), location.into()))
}
pub fn new_err(message: impl Into<String>, location: impl Into<Location>) -> Self {
Token(Loc(Err(message.into()), location.into()))
}
pub fn end_of_file() -> Self { Self::new(Box::new(EndOfFile), Location::EVERYWHERE) }
pub fn incomplete() -> Self { Self::new_err("", Location::EVERYWHERE) }
pub fn location(&self) -> Location { self.0.1 }
pub fn result(self) -> Result<Box<dyn Tree>, String> { self.0.0 }
pub fn result_ref(&self) -> &Result<Box<dyn Tree>, String> { &self.0.0 }
pub fn is<T: Tree>(&self) -> bool {
if let Ok(t) = self.result_ref() { t.is::<T>() } else { false }
}
pub fn is_incomplete(&self) -> bool {
if let Err(e) = self.result_ref() { e.len() == 0 } else { false }
}
pub fn unwrap<T: Tree>(self) -> T {
*self.result().unwrap().downcast::<T>().unwrap()
}
pub fn unwrap_err(self) -> String {
self.result().unwrap_err()
}
}
impl<T: Tree + PartialEq> std::cmp::PartialEq<T> for Token {
fn eq(&self, other: &T) -> bool {
if let Ok(t) = self.result_ref() { **t == *other } else { false }
}
}
pub trait Stream {
fn read(&mut self) -> Token;
fn read_all(mut self) -> Vec<Token> where Self: Sized {
let mut ret = Vec::new();
let mut token = self.read();
while token != EndOfFile {
ret.push(token);
token = self.read();
}
ret
}
}
impl<I: Iterator<Item=Token>> Stream for I {
fn read(&mut self) -> Token {
self.next().unwrap_or_else(|| Token::end_of_file())
}
}
pub struct Characters<'a> {
chars: Chars<'a>,
length: usize,
is_complete: bool,
}
impl<'a> Characters<'a> {
pub fn new(source: &'a str, is_complete: bool) -> Self {
Self {chars: source.chars(), length: source.len(), is_complete}
}
pub fn index(&self) -> usize { self.length - self.chars.as_str().len() }
}
impl<'a> Stream for Characters<'a> {
fn read(&mut self) -> Token {
let start = self.index();
if let Some(c) = self.chars.next() {
let end = self.index();
Token::new(Box::new(c), start..end)
} else if self.is_complete { Token::end_of_file() } else { Token::incomplete() }
}
}