]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/parse/lexer/tokentrees.rs
eafc3f77ab05227bbe40a6f20ab9eec74f559371
[rustc.git] / src / libsyntax / parse / lexer / tokentrees.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use print::pprust::token_to_string;
12 use parse::lexer::StringReader;
13 use parse::{token, PResult};
14 use syntax_pos::Span;
15 use tokenstream::{Delimited, TokenTree};
16
17 use std::rc::Rc;
18
19 impl<'a> StringReader<'a> {
20 // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
21 pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> {
22 let mut tts = Vec::new();
23 while self.token != token::Eof {
24 tts.push(self.parse_token_tree()?);
25 }
26 Ok(tts)
27 }
28
29 // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`.
30 fn parse_token_trees_until_close_delim(&mut self) -> Vec<TokenTree> {
31 let mut tts = vec![];
32 loop {
33 if let token::CloseDelim(..) = self.token {
34 return tts;
35 }
36 match self.parse_token_tree() {
37 Ok(tt) => tts.push(tt),
38 Err(mut e) => {
39 e.emit();
40 return tts;
41 }
42 }
43 }
44 }
45
46 fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
47 match self.token {
48 token::Eof => {
49 let msg = "this file contains an un-closed delimiter";
50 let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg);
51 for &(_, sp) in &self.open_braces {
52 err.span_help(sp, "did you mean to close this delimiter?");
53 }
54 Err(err)
55 },
56 token::OpenDelim(delim) => {
57 // The span for beginning of the delimited section
58 let pre_span = self.span;
59
60 // Parse the open delimiter.
61 self.open_braces.push((delim, self.span));
62 self.real_token();
63
64 // Parse the token trees within the delimiters.
65 // We stop at any delimiter so we can try to recover if the user
66 // uses an incorrect delimiter.
67 let tts = self.parse_token_trees_until_close_delim();
68
69 // Expand to cover the entire delimited token tree
70 let span = Span { hi: self.span.hi, ..pre_span };
71
72 match self.token {
73 // Correct delimiter.
74 token::CloseDelim(d) if d == delim => {
75 self.open_braces.pop().unwrap();
76
77 // Parse the close delimiter.
78 self.real_token();
79 }
80 // Incorrect delimiter.
81 token::CloseDelim(other) => {
82 let token_str = token_to_string(&self.token);
83 let msg = format!("incorrect close delimiter: `{}`", token_str);
84 let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
85 // This is a conservative error: only report the last unclosed delimiter.
86 // The previous unclosed delimiters could actually be closed! The parser
87 // just hasn't gotten to them yet.
88 if let Some(&(_, sp)) = self.open_braces.last() {
89 err.span_note(sp, "unclosed delimiter");
90 };
91 err.emit();
92
93 self.open_braces.pop().unwrap();
94
95 // If the incorrect delimiter matches an earlier opening
96 // delimiter, then don't consume it (it can be used to
97 // close the earlier one). Otherwise, consume it.
98 // E.g., we try to recover from:
99 // fn foo() {
100 // bar(baz(
101 // } // Incorrect delimiter but matches the earlier `{`
102 if !self.open_braces.iter().any(|&(b, _)| b == other) {
103 self.real_token();
104 }
105 }
106 token::Eof => {
107 // Silently recover, the EOF token will be seen again
108 // and an error emitted then. Thus we don't pop from
109 // self.open_braces here.
110 },
111 _ => {}
112 }
113
114 Ok(TokenTree::Delimited(span, Rc::new(Delimited {
115 delim: delim,
116 tts: tts,
117 })))
118 },
119 token::CloseDelim(_) => {
120 // An unexpected closing delimiter (i.e., there is no
121 // matching opening delimiter).
122 let token_str = token_to_string(&self.token);
123 let msg = format!("unexpected close delimiter: `{}`", token_str);
124 let err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
125 Err(err)
126 },
127 _ => {
128 let tt = TokenTree::Token(self.span, self.token.clone());
129 self.real_token();
130 Ok(tt)
131 }
132 }
133 }
134 }