use parse::SourcePos;
use token::Token;
use token::Token::*;
use std::iter as std_iter;
use std::mem;
#[derive(Debug)]
pub struct UnmatchedError(pub Token, pub SourcePos);
#[derive(Debug)]
enum TokenOrPos {
Tok(Token),
Pos(SourcePos),
}
impl TokenOrPos {
#[inline]
fn is_tok(&self) -> bool {
match *self {
TokenOrPos::Tok(_) => true,
TokenOrPos::Pos(_) => false,
}
}
}
pub trait PositionIterator: Iterator {
fn pos(&self) -> SourcePos;
}
impl<'a, T: PositionIterator> PositionIterator for &'a mut T {
fn pos(&self) -> SourcePos {
(**self).pos()
}
}
pub trait PeekableIterator: Iterator {
fn peek(&mut self) -> Option<&Self::Item>;
}
impl<'a, T: PeekableIterator> PeekableIterator for &'a mut T {
fn peek(&mut self) -> Option<&Self::Item> {
(**self).peek()
}
}
impl<I: Iterator> PeekableIterator for std_iter::Peekable<I> {
fn peek(&mut self) -> Option<&Self::Item> {
std_iter::Peekable::peek(self)
}
}
pub trait PeekablePositionIterator: PeekableIterator + PositionIterator {}
impl<T: PeekableIterator + PositionIterator> PeekablePositionIterator for T {}
pub trait TokenIterator: Sized + PeekablePositionIterator<Item = Token> {
fn balanced(&mut self) -> Balanced<&mut Self> {
Balanced::new(self, None)
}
fn single_quoted(&mut self, pos: SourcePos) -> Balanced<&mut Self> {
Balanced::new(self, Some((SingleQuote, pos)))
}
fn double_quoted(&mut self, pos: SourcePos) -> Balanced<&mut Self> {
Balanced::new(self, Some((DoubleQuote, pos)))
}
fn backticked(&mut self, pos: SourcePos) -> Balanced<&mut Self> {
Balanced::new(self, Some((Backtick, pos)))
}
fn backticked_remove_backslashes(&mut self, pos: SourcePos)
-> BacktickBackslashRemover<&mut Self>
{
BacktickBackslashRemover::new(self.backticked(pos))
}
}
trait RewindableTokenIterator {
fn rewind(&mut self, tokens: Vec<TokenOrPos>);
fn next_token_or_pos(&mut self) -> Option<TokenOrPos>;
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct TokenIter<I> {
iter: std_iter::Fuse<I>,
prev_buffered: Vec<TokenOrPos>,
pos: SourcePos,
}
impl<I: Iterator<Item = Token>> PositionIterator for TokenIter<I> {
fn pos(&self) -> SourcePos {
self.pos
}
}
impl<I: Iterator<Item = Token>> PeekableIterator for TokenIter<I> {
fn peek(&mut self) -> Option<&Self::Item> {
{
let mut peeked = self.multipeek();
if peeked.peek_next().is_none() {
return None;
}
}
if let Some(&TokenOrPos::Tok(ref t)) = self.prev_buffered.last() {
Some(t)
} else {
unreachable!("unexpected state: peeking next token failed. This is a bug!")
}
}
}
impl<I: Iterator<Item = Token>> Iterator for TokenIter<I> {
type Item = Token;
fn next(&mut self) -> Option<Token> {
let mut ret = None;
loop {
match self.next_token_or_pos() {
Some(TokenOrPos::Tok(next)) => {
self.pos.advance(&next);
ret = Some(next);
break;
},
Some(TokenOrPos::Pos(_)) => panic!("unexpected state. This is a bug!"),
None => break,
}
}
self.updated_buffered_pos();
ret
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (low_hint, hi) = self.iter.size_hint();
let low = if self.prev_buffered.is_empty() {
low_hint
} else {
self.prev_buffered.len()
};
(low, hi)
}
}
impl<I: Iterator<Item = Token>> RewindableTokenIterator for TokenIter<I> {
fn rewind(&mut self, tokens: Vec<TokenOrPos>) {
self.buffer_tokens_and_positions_to_yield_first(tokens, None);
}
fn next_token_or_pos(&mut self) -> Option<TokenOrPos> {
self.prev_buffered.pop()
.or_else(|| self.iter.next().map(TokenOrPos::Tok))
}
}
impl<I: Iterator<Item = Token>> TokenIterator for TokenIter<I> {}
impl<I: Iterator<Item = Token>> TokenIter<I> {
pub fn new(iter: I) -> TokenIter<I> {
TokenIter {
iter: iter.fuse(),
prev_buffered: Vec::new(),
pos: SourcePos::new(),
}
}
pub fn with_position(iter: I, pos: SourcePos) -> TokenIter<I> {
let mut iter = TokenIter::new(iter);
iter.pos = pos;
iter
}
pub fn multipeek(&mut self) -> Multipeek {
Multipeek::new(self)
}
fn updated_buffered_pos(&mut self) {
while let Some(&TokenOrPos::Pos(pos)) = self.prev_buffered.last() {
self.prev_buffered.pop();
self.pos = pos;
}
}
fn buffer_tokens_and_positions_to_yield_first(
&mut self,
mut tokens: Vec<TokenOrPos>,
token_start: Option<SourcePos>
) {
self.prev_buffered.reserve(tokens.len() + 1);
if token_start.is_some() {
self.prev_buffered.push(TokenOrPos::Pos(self.pos));
}
tokens.reverse();
self.prev_buffered.extend(tokens);
if let Some(p) = token_start {
self.pos = p;
}
self.updated_buffered_pos();
}
pub fn buffer_tokens_to_yield_first(&mut self, buf: Vec<Token>, buf_start: SourcePos) {
let tokens = buf.into_iter().map(TokenOrPos::Tok).collect();
self.buffer_tokens_and_positions_to_yield_first(tokens, Some(buf_start));
}
pub fn token_iter_from_backticked_with_removed_backslashes(&mut self, pos: SourcePos)
-> Result<TokenIter<std_iter::Empty<Token>>, UnmatchedError>
{
BacktickBackslashRemover::create_token_iter(self.backticked(pos))
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Multipeek<'a> {
iter: &'a mut RewindableTokenIterator,
buf: Vec<TokenOrPos>,
}
impl<'a> Drop for Multipeek<'a> {
fn drop(&mut self) {
let tokens = mem::replace(&mut self.buf, Vec::new());
self.iter.rewind(tokens);
}
}
impl<'a> Multipeek<'a> {
fn new(iter: &'a mut RewindableTokenIterator) -> Self {
Multipeek {
iter: iter,
buf: Vec::new(),
}
}
pub fn peek_next(&mut self) -> Option<&Token> {
loop {
match self.iter.next_token_or_pos() {
Some(t) => {
let is_tok = t.is_tok();
self.buf.push(t);
if is_tok {
break;
}
},
None => return None,
}
}
if let Some(&TokenOrPos::Tok(ref t)) = self.buf.last() {
Some(t)
} else {
None
}
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub enum TokenIterWrapper<I> {
Regular(TokenIter<I>),
Buffered(TokenIter<std_iter::Empty<Token>>),
}
impl<I: Iterator<Item = Token>> PositionIterator for TokenIterWrapper<I> {
fn pos(&self) -> SourcePos {
match *self {
TokenIterWrapper::Regular(ref inner) => inner.pos(),
TokenIterWrapper::Buffered(ref inner) => inner.pos(),
}
}
}
impl<I: Iterator<Item = Token>> PeekableIterator for TokenIterWrapper<I> {
fn peek(&mut self) -> Option<&Self::Item> {
match *self {
TokenIterWrapper::Regular(ref mut inner) => inner.peek(),
TokenIterWrapper::Buffered(ref mut inner) => inner.peek(),
}
}
}
impl<I: Iterator<Item = Token>> Iterator for TokenIterWrapper<I> {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
match *self {
TokenIterWrapper::Regular(ref mut inner) => inner.next(),
TokenIterWrapper::Buffered(ref mut inner) => inner.next(),
}
}
}
impl<I: Iterator<Item = Token>> TokenIterator for TokenIterWrapper<I> {}
impl<I: Iterator<Item = Token>> TokenIterWrapper<I> {
pub fn multipeek(&mut self) -> Multipeek {
match *self {
TokenIterWrapper::Regular(ref mut inner) => inner.multipeek(),
TokenIterWrapper::Buffered(ref mut inner) => inner.multipeek(),
}
}
pub fn buffer_tokens_to_yield_first(&mut self, buf: Vec<Token>, buf_start: SourcePos) {
match *self {
TokenIterWrapper::Regular(ref mut inner) => inner.buffer_tokens_to_yield_first(buf, buf_start),
TokenIterWrapper::Buffered(ref mut inner) => inner.buffer_tokens_to_yield_first(buf, buf_start),
}
}
pub fn token_iter_from_backticked_with_removed_backslashes(&mut self, pos: SourcePos)
-> Result<TokenIter<std_iter::Empty<Token>>, UnmatchedError>
{
match *self {
TokenIterWrapper::Regular(ref mut inner) =>
inner.token_iter_from_backticked_with_removed_backslashes(pos),
TokenIterWrapper::Buffered(ref mut inner) =>
inner.token_iter_from_backticked_with_removed_backslashes(pos),
}
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct Balanced<I> {
iter: I,
escaped: Option<(Token, SourcePos)>,
stack: Vec<(Token, SourcePos)>,
skip_last_delimeter: bool,
done: bool,
pos: SourcePos,
}
impl<I: PositionIterator> Balanced<I> {
pub fn new(iter: I, delim: Option<(Token, SourcePos)>) -> Self {
Balanced {
escaped: None,
skip_last_delimeter: delim.is_some(),
stack: delim.map_or(Vec::new(), |d| vec!(d)),
done: false,
pos: iter.pos(),
iter: iter,
}
}
}
impl<I: PeekablePositionIterator<Item = Token>> PositionIterator for Balanced<I> {
fn pos(&self) -> SourcePos {
self.pos
}
}
impl<I: PeekablePositionIterator<Item = Token>> Iterator for Balanced<I> {
type Item = Result<Token, UnmatchedError>;
fn next(&mut self) -> Option<Self::Item> {
if let Some((tok, pos)) = self.escaped.take() {
self.pos = pos;
return Some(Ok(tok));
} else if self.done {
return None;
}
if self.stack.last().map(|t| &t.0) == self.iter.peek() {
let ret = self.iter.next().map(Ok);
self.stack.pop();
let stack_empty = self.stack.is_empty();
self.done |= stack_empty;
self.pos = self.iter.pos();
if self.skip_last_delimeter && stack_empty {
return None;
} else {
return ret;
};
}
if let Some(&(SingleQuote, pos)) = self.stack.last() {
let ret = match self.iter.next() {
Some(t) => Some(Ok(t)),
None => Some(Err(UnmatchedError(SingleQuote, pos))),
};
self.pos = self.iter.pos();
return ret;
}
let cur_pos = self.iter.pos();
let ret = match self.iter.next() {
Some(Backslash) => {
self.pos = self.iter.pos();
debug_assert_eq!(self.escaped, None);
self.escaped = self.iter.next().map(|t| (t, self.iter.pos()));
self.done |= self.stack.is_empty();
return Some(Ok(Backslash));
},
Some(Backtick) => {
self.stack.push((Backtick, cur_pos));
Some(Ok(Backtick))
},
Some(SingleQuote) => {
if self.stack.last().map(|t| &t.0) != Some(&DoubleQuote) {
self.stack.push((SingleQuote, cur_pos));
}
Some(Ok(SingleQuote))
},
Some(DoubleQuote) => {
self.stack.push((DoubleQuote, cur_pos));
Some(Ok(DoubleQuote))
},
Some(ParenOpen) => {
self.stack.push((ParenClose, cur_pos));
Some(Ok(ParenOpen))
},
Some(Dollar) => {
let cur_pos = self.iter.pos(); match self.iter.peek() {
Some(&CurlyOpen) => self.stack.push((CurlyClose, cur_pos)),
Some(&ParenOpen) => {},
_ => { self.done |= self.stack.is_empty(); },
}
Some(Ok(Dollar))
},
Some(t) => {
self.done |= self.stack.is_empty();
Some(Ok(t))
},
None => match self.stack.pop() {
None => { self.done = true; None },
Some((ParenClose, pos)) => Some(Err(UnmatchedError(ParenOpen, pos))),
Some((CurlyClose, pos)) => Some(Err(UnmatchedError(CurlyOpen, pos))),
Some((delim, pos)) => Some(Err(UnmatchedError(delim, pos))),
},
};
self.pos = self.iter.pos();
ret
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct BacktickBackslashRemover<I> {
iter: Balanced<I>,
peeked: Option<Result<Token, UnmatchedError>>,
done: bool,
}
impl<I> BacktickBackslashRemover<I> {
pub fn new(iter: Balanced<I>) -> Self {
BacktickBackslashRemover {
iter: iter,
peeked: None,
done: false,
}
}
}
impl<I: PeekablePositionIterator<Item = Token>> BacktickBackslashRemover<I> {
fn create_token_iter(mut iter: Balanced<I>)
-> Result<TokenIter<std_iter::Empty<Token>>, UnmatchedError>
{
let mut all_chunks = Vec::new();
let mut chunk_start = iter.pos();
let mut chunk = Vec::new();
loop {
match iter.next() {
Some(Ok(Backslash)) => {
let next_pos = iter.pos();
match iter.next() {
Some(Ok(tok@Dollar)) |
Some(Ok(tok@Backtick)) |
Some(Ok(tok@Backslash)) => {
all_chunks.push((chunk, chunk_start));
chunk_start = next_pos;
chunk = vec!(tok);
},
Some(tok) => {
chunk.push(Backslash);
chunk.push(try!(tok));
},
None => chunk.push(Backslash),
}
},
Some(tok) => chunk.push(try!(tok)),
None => break,
}
}
if !chunk.is_empty() {
all_chunks.push((chunk, chunk_start));
}
let mut tok_iter = TokenIter::with_position(std_iter::empty(), iter.pos());
while let Some((chunk, chunk_end)) = all_chunks.pop() {
tok_iter.buffer_tokens_to_yield_first(chunk, chunk_end);
}
Ok(tok_iter)
}
}
if_nightly! {
impl<I> ::std::iter::FusedIterator for BacktickBackslashRemover<I>
where I: PeekablePositionIterator<Item = Token>
{}
}
impl<I: PeekablePositionIterator<Item = Token>> Iterator for BacktickBackslashRemover<I> {
type Item = Result<Token, UnmatchedError>;
fn next(&mut self) -> Option<Self::Item> {
if self.peeked.is_some() {
return self.peeked.take();
} else if self.done {
return None;
}
match self.iter.next() {
Some(Ok(Backslash)) => {
match self.iter.next() {
ret@Some(Ok(Dollar)) |
ret@Some(Ok(Backtick)) |
ret@Some(Ok(Backslash)) => ret,
Some(t) => {
debug_assert!(self.peeked.is_none());
self.peeked = Some(t);
Some(Ok(Backslash))
},
None => {
self.done = true;
Some(Ok(Backslash))
},
}
},
Some(t) => Some(t),
None => {
self.done = true;
None
},
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[cfg(test)]
mod tests {
use parse::SourcePos;
use super::{PositionIterator, TokenIter, TokenOrPos};
use token::Token;
#[test]
fn test_multipeek() {
let tokens = vec!(Token::ParenOpen, Token::Semi, Token::Dollar, Token::ParenClose);
let mut tok_iter = TokenIter::new(tokens.clone().into_iter());
{
let mut multipeek = tok_iter.multipeek();
let mut expected_peeked = tokens.iter();
while let Some(t) = multipeek.peek_next() {
assert_eq!(expected_peeked.next(), Some(t));
}
assert_eq!(expected_peeked.next(), None);
}
assert_eq!(tokens, tok_iter.collect::<Vec<_>>());
}
#[test]
fn test_buffering_tokens_should_immediately_update_position() {
fn src(byte: usize, line: usize, col: usize) -> SourcePos {
SourcePos {
byte: byte,
line: line,
col: col,
}
}
let mut tok_iter = TokenIter::new(::std::iter::empty());
let pos = src(4, 4, 4);
tok_iter.buffer_tokens_and_positions_to_yield_first(
vec!(
TokenOrPos::Pos(src(2, 2, 2)),
TokenOrPos::Pos(src(3, 3, 3)),
TokenOrPos::Pos(pos),
TokenOrPos::Tok(Token::Newline),
),
Some(src(1, 1, 1)),
);
assert_eq!(tok_iter.pos(), pos);
}
}