about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-01-26 00:42:08 +0000
committerbors <bors@rust-lang.org>2016-01-26 00:42:08 +0000
commitfaf6d1e87391b25196b35909c3c95e5d873cacf0 (patch)
tree2bc19619fba5216c21015aee7cee4bec5b263b06 /src/libsyntax/parse
parenteceb96b40dedd903ddfca6df97bb1e5749b87787 (diff)
parent43b3681588ef40c78c794548d67a8f50101bc8ad (diff)
downloadrust-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.rs20
-rw-r--r--src/libsyntax/parse/parser.rs107
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;
             }