/// Used to determine the path to externally loaded source files
pub filename: Option<String>,
pub mod_path_stack: Vec<InternedString>,
- /// Stack of spans of open delimiters. Used for error message.
- pub open_braces: Vec<Span>,
+ /// Stack of open delimiters and their spans. Used for error message.
+ pub open_braces: Vec<(token::DelimToken, Span)>,
/// Flag if this parser "owns" the directory that it is currently parsing
/// in. This will affect how nested files are looked up.
pub owns_directory: bool,
sep: SeqSep,
f: F)
-> Vec<T>
- where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+ where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
self.parse_seq_to_before_tokens(&[ket], sep, f, |mut e| e.emit())
}
let mut err: DiagnosticBuilder<'a> =
self.diagnostic().struct_span_err(self.span,
"this file contains an un-closed delimiter");
- for sp in &self.open_braces {
- err.span_help(*sp, "did you mean to close this delimiter?");
+ for &(_, sp) in &self.open_braces {
+ err.span_help(sp, "did you mean to close this delimiter?");
}
Err(err)
let pre_span = self.span;
// Parse the open delimiter.
- self.open_braces.push(self.span);
+ self.open_braces.push((delim, self.span));
let open_span = self.span;
self.bump();
- // Parse the token trees within the delimiters
- let tts = self.parse_seq_to_before_end(&token::CloseDelim(delim),
- SeqSep::none(),
- |p| p.parse_token_tree());
+ // Parse the token trees within the delimiters.
+ // We stop at any delimiter so we can try to recover if the user
+ // uses an incorrect delimiter.
+ let tts = self.parse_seq_to_before_tokens(&[&token::CloseDelim(token::Brace),
+ &token::CloseDelim(token::Paren),
+ &token::CloseDelim(token::Bracket)],
+ SeqSep::none(),
+ |p| p.parse_token_tree(),
+ |mut e| e.emit());
- // Parse the close delimiter.
let close_span = self.span;
- self.bump();
- self.open_braces.pop().unwrap();
-
// Expand to cover the entire delimited token tree
let span = Span { hi: close_span.hi, ..pre_span };
+ match self.token {
+ // Correct delmiter.
+ token::CloseDelim(d) if d == delim => {
+ self.open_braces.pop().unwrap();
+
+ // Parse the close delimiter.
+ self.bump();
+ }
+ // Incorect delimiter.
+ token::CloseDelim(other) => {
+ let token_str = self.this_token_to_string();
+ let mut err = self.diagnostic().struct_span_err(self.span,
+ &format!("incorrect close delimiter: `{}`", token_str));
+ // This is a conservative error: only report the last unclosed delimiter.
+ // The previous unclosed delimiters could actually be closed! The parser
+ // just hasn't gotten to them yet.
+ if let Some(&(_, sp)) = self.open_braces.last() {
+ err.span_note(sp, "unclosed delimiter");
+ };
+ err.emit();
+
+ self.open_braces.pop().unwrap();
+
+ // If the incorrect delimter matches an earlier opening
+ // delimiter, then don't consume it (it can be used to
+ // close the earlier one)Otherwise, consume it.
+ // E.g., we try to recover from:
+ // fn foo() {
+ // bar(baz(
+ // } // Incorrect delimiter but matches the earlier `{`
+ if !self.open_braces.iter().any(|&(b, _)| b == other) {
+ self.bump();
+ }
+ }
+ token::Eof => {
+ // Silently recover, the EOF token will be seen again
+ // and an error emitted then. Thus we don't pop from
+ // self.open_braces here.
+ },
+ _ => unreachable!(),
+ }
+
Ok(TokenTree::Delimited(span, Rc::new(Delimited {
delim: delim,
open_span: open_span,
maybe_whole!(deref self, NtTT);
match self.token {
token::CloseDelim(_) => {
- let token_str = self.this_token_to_string();
- let mut err = self.diagnostic().struct_span_err(self.span,
- &format!("incorrect close delimiter: `{}`", token_str));
- // This is a conservative error: only report the last unclosed delimiter.
- // The previous unclosed delimiters could actually be closed! The parser
- // just hasn't gotten to them yet.
- if let Some(&sp) = self.open_braces.last() {
- err.span_note(sp, "unclosed delimiter");
- };
-
- Err(err)
+ panic!("should have been caught above");
},
/* we ought to allow different depths of unquotation */
token::Dollar | token::SubstNt(..) if self.quote_depth > 0 => {