diff options
| author | bors <bors@rust-lang.org> | 2016-01-26 00:42:08 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-01-26 00:42:08 +0000 |
| commit | faf6d1e87391b25196b35909c3c95e5d873cacf0 (patch) | |
| tree | 2bc19619fba5216c21015aee7cee4bec5b263b06 /src/libsyntax/parse | |
| parent | eceb96b40dedd903ddfca6df97bb1e5749b87787 (diff) | |
| parent | 43b3681588ef40c78c794548d67a8f50101bc8ad (diff) | |
| download | rust-faf6d1e87391b25196b35909c3c95e5d873cacf0.tar.gz rust-faf6d1e87391b25196b35909c3c95e5d873cacf0.zip | |
Auto merge of #31065 - nrc:ident-correct, r=pnkfelix
This PR adds some minor error correction to the parser - if there is a missing ident, we recover and carry on. It also makes compilation more robust so that non-fatal errors (which is still most of them, unfortunately) in parsing do not cause us to abort compilation. The effect is that a program with a missing or incorrect ident can get all the way to type checking.
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 20 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 107 |
2 files changed, 72 insertions, 55 deletions
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 090b070433f..32372ccc13b 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -98,7 +98,7 @@ pub fn parse_crate_from_source_str(name: String, cfg, name, source); - maybe_aborted(panictry!(p.parse_crate_mod()),p) + panictry!(p.parse_crate_mod()) } pub fn parse_crate_attrs_from_source_str(name: String, @@ -110,7 +110,7 @@ pub fn parse_crate_attrs_from_source_str(name: String, cfg, name, source); - maybe_aborted(panictry!(p.parse_inner_attributes()), p) + panictry!(p.parse_inner_attributes()) } pub fn parse_expr_from_source_str(name: String, @@ -119,7 +119,7 @@ pub fn parse_expr_from_source_str(name: String, sess: &ParseSess) -> P<ast::Expr> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - maybe_aborted(panictry!(p.parse_expr()), p) + panictry!(p.parse_expr()) } pub fn parse_item_from_source_str(name: String, @@ -128,7 +128,7 @@ pub fn parse_item_from_source_str(name: String, sess: &ParseSess) -> Option<P<ast::Item>> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - maybe_aborted(panictry!(p.parse_item()), p) + panictry!(p.parse_item()) } pub fn parse_meta_from_source_str(name: String, @@ -137,7 +137,7 @@ pub fn parse_meta_from_source_str(name: String, sess: &ParseSess) -> P<ast::MetaItem> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - maybe_aborted(panictry!(p.parse_meta_item()), p) + panictry!(p.parse_meta_item()) } pub fn parse_stmt_from_source_str(name: String, @@ -151,7 +151,7 @@ pub fn parse_stmt_from_source_str(name: String, name, source ); - maybe_aborted(panictry!(p.parse_stmt()), p) + panictry!(p.parse_stmt()) } // Warning: This parses with quote_depth > 0, which is not the default. @@ -168,7 +168,7 @@ pub fn parse_tts_from_source_str(name: String, ); p.quote_depth += 1; // right now this is re-creating the token trees from ... token trees. - maybe_aborted(panictry!(p.parse_all_token_trees()),p) + panictry!(p.parse_all_token_trees()) } // Create a new parser from a source string @@ -265,16 +265,10 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess, p } -/// Abort if necessary -pub fn maybe_aborted<T>(result: T, p: Parser) -> T { - p.abort_if_errors(); - result -} fn abort_if_errors<'a, T>(result: PResult<'a, T>, p: &Parser) -> T { match result { Ok(c) => { - p.abort_if_errors(); c } Err(mut e) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bfa42e76129..acce6ed87d0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2355,6 +2355,59 @@ impl<'a> Parser<'a> { ) } + // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue + // parsing into an expression. + fn parse_dot_suffix(&mut self, + ident: Ident, + ident_span: Span, + self_value: P<Expr>) + -> PResult<'a, P<Expr>> { + let (_, tys, bindings) = if self.eat(&token::ModSep) { + try!(self.expect_lt()); + try!(self.parse_generic_values_after_lt()) + } else { + (Vec::new(), Vec::new(), Vec::new()) + }; + + if !bindings.is_empty() { + let last_span = self.last_span; + self.span_err(last_span, "type bindings are only permitted on trait paths"); + } + + let lo = self_value.span.lo; + + Ok(match self.token { + // expr.f() method call. + token::OpenDelim(token::Paren) => { + let mut es = try!(self.parse_unspanned_seq( + &token::OpenDelim(token::Paren), + &token::CloseDelim(token::Paren), + seq_sep_trailing_allowed(token::Comma), + |p| Ok(try!(p.parse_expr())) + )); + let hi = self.last_span.hi; + + es.insert(0, self_value); + let id = spanned(ident_span.lo, ident_span.hi, ident); + let nd = self.mk_method_call(id, tys, es); + self.mk_expr(lo, hi, nd, None) + } + // Field access. + _ => { + if !tys.is_empty() { + let last_span = self.last_span; + self.span_err(last_span, + "field expressions may not \ + have type parameters"); + } + + let id = spanned(ident_span.lo, ident_span.hi, ident); + let field = self.mk_field(self_value, id); + self.mk_expr(lo, ident_span.hi, field, None) + } + }) + } + fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>) -> PResult<'a, P<Expr>> { let mut e = e0; let lo = e.span.lo; @@ -2364,50 +2417,11 @@ impl<'a> Parser<'a> { if self.eat(&token::Dot) { match self.token { token::Ident(i, _) => { - let dot = self.last_span.hi; + let dot_pos = self.last_span.hi; hi = self.span.hi; self.bump(); - let (_, tys, bindings) = if self.eat(&token::ModSep) { - try!(self.expect_lt()); - try!(self.parse_generic_values_after_lt()) - } else { - (Vec::new(), Vec::new(), Vec::new()) - }; - - if !bindings.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, "type bindings are only permitted on trait paths"); - } - // expr.f() method call - match self.token { - token::OpenDelim(token::Paren) => { - let mut es = try!(self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - seq_sep_trailing_allowed(token::Comma), - |p| Ok(try!(p.parse_expr())) - )); - hi = self.last_span.hi; - - es.insert(0, e); - let id = spanned(dot, hi, i); - let nd = self.mk_method_call(id, tys, es); - e = self.mk_expr(lo, hi, nd, None); - } - _ => { - if !tys.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, - "field expressions may not \ - have type parameters"); - } - - let id = spanned(dot, hi, i); - let field = self.mk_field(e, id); - e = self.mk_expr(lo, hi, field, None); - } - } + e = try!(self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e)); } token::Literal(token::Integer(n), suf) => { let sp = self.span; @@ -2452,7 +2466,16 @@ impl<'a> Parser<'a> { self.abort_if_errors(); } - _ => return self.unexpected() + _ => { + // FIXME Could factor this out into non_fatal_unexpected or something. + let actual = self.this_token_to_string(); + self.span_err(self.span, &format!("unexpected token: `{}`", actual)); + + let dot_pos = self.last_span.hi; + e = try!(self.parse_dot_suffix(special_idents::invalid, + mk_sp(dot_pos, dot_pos), + e)); + } } continue; } |
