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};
pub fn union(pieces: impl IntoIterator<Item=Self>) -> Self {
let mut pieces = pieces.into_iter();
let mut ret = pieces.next().expect("Cannot form the union of no pieces");
while let Some(piece) = pieces.next() {
ret.start = std::cmp::min(ret.start, piece.start);
ret.end = std::cmp::max(ret.end, piece.end);
}
ret
}
}
impl fmt::Debug for Location {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("{}..{}", self.start, self.end))
}
}
impl From<usize> for Location {
fn from(value: usize) -> Self { Self {start: value, end: value + 1} }
}
impl From<(usize, usize)> for Location {
fn from(value: (usize, usize)) -> Self { Self {start: value.0, end: value.1} }
}
impl From<Range<usize>> for Location {
fn from(value: Range<usize>) -> Self { Self {start: value.start, end: value.end} }
}
#[derive(Debug)]
pub struct Token(pub Location, pub Result<Box<dyn Tree>, String>);
impl Token {
pub fn end_of_file() -> Self { Self(Location::EVERYWHERE, Ok(Box::new(EndOfFile))) }
pub fn incomplete() -> Self { Self(Location::EVERYWHERE, Err("".into())) }
pub fn downcast_copy<T: Tree + Copy>(&self) -> Option<T> {
if let Token(_, Ok(t)) = self { t.downcast_ref().copied() } else { None }
}
pub fn is<T: Tree>(&self) -> bool {
if let Token(_, Ok(t)) = self { t.downcast_ref::<T>().is_some() } else { false }
}
pub fn is_incomplete(&self) -> bool {
if let Token(_, Err(e)) = self { e.len() == 0 } else { false }
}
pub fn unwrap<T: Tree>(self) -> T {
*self.1.unwrap().downcast::<T>().unwrap()
}
pub fn unwrap_err(self) -> String {
self.1.unwrap_err()
}
}
impl<T: Tree + PartialEq> std::cmp::PartialEq<T> for Token {
fn eq(&self, other: &T) -> bool {
if let Token(_, Ok(t)) = self { t.downcast_ref::<T>() == Some(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(Location::EVERYWHERE, Ok(Box::new(EndOfFile)))
)
}
}
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(Location {start, end}, Ok(Box::new(c)))
} else if self.is_complete { Token::end_of_file() } else { Token::incomplete() }
}
}