use print::pprust::token_to_string;
use parse::lexer::StringReader;
use parse::{token, PResult};
use tokenstream::{Delimited, TokenStream, TokenTree};
impl<'a> StringReader<'a> {
        crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
        let mut tts = Vec::new();
        while self.token != token::Eof {
            tts.push(self.parse_token_tree()?);
        }
        Ok(TokenStream::concat(tts))
    }
        fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
        let mut tts = vec![];
        loop {
            if let token::CloseDelim(..) = self.token {
                return TokenStream::concat(tts);
            }
            match self.parse_token_tree() {
                Ok(tree) => tts.push(tree),
                Err(mut e) => {
                    e.emit();
                    return TokenStream::concat(tts);
                }
            }
        }
    }
    fn parse_token_tree(&mut self) -> PResult<'a, TokenStream> {
        match self.token {
            token::Eof => {
                let msg = "this file contains an un-closed delimiter";
                let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg);
                for &(_, sp) in &self.open_braces {
                    err.span_help(sp, "did you mean to close this delimiter?");
                }
                Err(err)
            },
            token::OpenDelim(delim) => {
                                let pre_span = self.span;
                                self.open_braces.push((delim, self.span));
                self.real_token();
                                                                let tts = self.parse_token_trees_until_close_delim();
                                let span = pre_span.with_hi(self.span.hi());
                match self.token {
                                        token::CloseDelim(d) if d == delim => {
                        self.open_braces.pop().unwrap();
                                                self.real_token();
                    }
                                        token::CloseDelim(other) => {
                        let token_str = token_to_string(&self.token);
                        let msg = format!("incorrect close delimiter: `{}`", token_str);
                        let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
                                                                                                if let Some(&(_, sp)) = self.open_braces.last() {
                            err.span_note(sp, "unclosed delimiter");
                        };
                        err.emit();
                        self.open_braces.pop().unwrap();
                                                                                                                                                                                                if !self.open_braces.iter().any(|&(b, _)| b == other) {
                            self.real_token();
                        }
                    }
                    token::Eof => {
                                                                                            },
                    _ => {}
                }
                Ok(TokenTree::Delimited(span, Delimited {
                    delim,
                    tts: tts.into(),
                }).into())
            },
            token::CloseDelim(_) => {
                                                let token_str = token_to_string(&self.token);
                let msg = format!("unexpected close delimiter: `{}`", token_str);
                let err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
                Err(err)
            },
            _ => {
                let tt = TokenTree::Token(self.span, self.token.clone());
                                                                let raw = self.span_src_raw;
                self.real_token();
                let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
                Ok(if is_joint { tt.joint() } else { tt.into() })
            }
        }
    }
}