rollup merge of #21223: P1start/expected-token-improvements

Fixes #21153.
This commit is contained in:
Alex Crichton 2015-02-02 10:56:05 -08:00
commit ddcfb158fd
20 changed files with 100 additions and 77 deletions

View File

@ -13,7 +13,7 @@ use ast;
use codemap::{spanned, Spanned, mk_sp, Span};
use parse::common::*; //resolve bug?
use parse::token;
use parse::parser::Parser;
use parse::parser::{Parser, TokenType};
use ptr::P;
/// A parser that can parse attributes.
@ -69,7 +69,9 @@ impl<'a> ParserAttr for Parser<'a> {
let lo = self.span.lo;
self.bump();
let style = if self.eat(&token::Not) {
if permit_inner { self.expected_tokens.push(TokenType::Token(token::Not)); }
let style = if self.token == token::Not {
self.bump();
if !permit_inner {
let span = self.span;
self.span_err(span,
@ -96,7 +98,8 @@ impl<'a> ParserAttr for Parser<'a> {
}
};
if permit_inner && self.eat(&token::Semi) {
if permit_inner && self.token == token::Semi {
self.bump();
self.span_warn(span, "this inner attribute syntax is deprecated. \
The new syntax is `#![foo]`, with a bang and no semicolon");
style = ast::AttrInner;

View File

@ -290,6 +290,7 @@ pub struct Parser<'a> {
#[derive(PartialEq, Eq, Clone)]
pub enum TokenType {
Token(token::Token),
Keyword(keywords::Keyword),
Operator,
}
@ -298,6 +299,7 @@ impl TokenType {
match *self {
TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)),
TokenType::Operator => "an operator".to_string(),
TokenType::Keyword(kw) => format!("`{}`", token::get_name(kw.to_name())),
}
}
}
@ -365,9 +367,9 @@ impl<'a> Parser<'a> {
token_str)[]);
}
pub fn unexpected(&self) -> ! {
let this_token = self.this_token_to_string();
self.fatal(&format!("unexpected token: `{}`", this_token)[]);
pub fn unexpected(&mut self) -> ! {
self.expect_one_of(&[], &[]);
unreachable!()
}
/// Expect and consume the token t. Signal an error if
@ -425,10 +427,13 @@ impl<'a> Parser<'a> {
let expect = tokens_to_string(&expected[]);
let actual = self.this_token_to_string();
self.fatal(
&(if expected.len() != 1 {
&(if expected.len() > 1 {
(format!("expected one of {}, found `{}`",
expect,
actual))
} else if expected.len() == 0 {
(format!("unexpected token: `{}`",
actual))
} else {
(format!("expected {}, found `{}`",
expect,
@ -515,7 +520,7 @@ impl<'a> Parser<'a> {
pub fn parse_path_list_item(&mut self) -> ast::PathListItem {
let lo = self.span.lo;
let node = if self.eat_keyword(keywords::Mod) {
let node = if self.eat_keyword_noexpect(keywords::Mod) {
let span = self.last_span;
self.span_warn(span, "deprecated syntax; use the `self` keyword now");
ast::PathListMod { id: ast::DUMMY_NODE_ID }
@ -547,9 +552,23 @@ impl<'a> Parser<'a> {
is_present
}
pub fn check_keyword(&mut self, kw: keywords::Keyword) -> bool {
self.expected_tokens.push(TokenType::Keyword(kw));
self.token.is_keyword(kw)
}
/// If the next token is the given keyword, eat it and return
/// true. Otherwise, return false.
pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool {
if self.check_keyword(kw) {
self.bump();
true
} else {
false
}
}
pub fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> bool {
if self.token.is_keyword(kw) {
self.bump();
true
@ -563,10 +582,7 @@ impl<'a> Parser<'a> {
/// Otherwise, eat it.
pub fn expect_keyword(&mut self, kw: keywords::Keyword) {
if !self.eat_keyword(kw) {
let id_interned_str = token::get_name(kw.to_name());
let token_str = self.this_token_to_string();
self.fatal(&format!("expected `{}`, found `{}`",
id_interned_str, token_str)[])
self.expect_one_of(&[], &[]);
}
}
@ -593,6 +609,7 @@ impl<'a> Parser<'a> {
/// Expect and consume an `&`. If `&&` is seen, replace it with a single
/// `&` and continue. If an `&` is not seen, signal an error.
fn expect_and(&mut self) {
self.expected_tokens.push(TokenType::Token(token::BinOp(token::And)));
match self.token {
token::BinOp(token::And) => self.bump(),
token::AndAnd => {
@ -601,12 +618,7 @@ impl<'a> Parser<'a> {
self.replace_token(token::BinOp(token::And), lo, span.hi)
}
_ => {
let token_str = self.this_token_to_string();
let found_token =
Parser::token_to_string(&token::BinOp(token::And));
self.fatal(&format!("expected `{}`, found `{}`",
found_token,
token_str)[])
self.expect_one_of(&[], &[]);
}
}
}
@ -614,6 +626,7 @@ impl<'a> Parser<'a> {
/// Expect and consume a `|`. If `||` is seen, replace it with a single
/// `|` and continue. If a `|` is not seen, signal an error.
fn expect_or(&mut self) {
self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or)));
match self.token {
token::BinOp(token::Or) => self.bump(),
token::OrOr => {
@ -622,12 +635,7 @@ impl<'a> Parser<'a> {
self.replace_token(token::BinOp(token::Or), lo, span.hi)
}
_ => {
let found_token = self.this_token_to_string();
let token_str =
Parser::token_to_string(&token::BinOp(token::Or));
self.fatal(&format!("expected `{}`, found `{}`",
token_str,
found_token)[])
self.expect_one_of(&[], &[]);
}
}
}
@ -652,6 +660,7 @@ impl<'a> Parser<'a> {
/// This is meant to be used when parsing generics on a path to get the
/// starting token.
fn eat_lt(&mut self) -> bool {
self.expected_tokens.push(TokenType::Token(token::Lt));
match self.token {
token::Lt => { self.bump(); true }
token::BinOp(token::Shl) => {
@ -666,11 +675,7 @@ impl<'a> Parser<'a> {
fn expect_lt(&mut self) {
if !self.eat_lt() {
let found_token = self.this_token_to_string();
let token_str = Parser::token_to_string(&token::Lt);
self.fatal(&format!("expected `{}`, found `{}`",
token_str,
found_token)[])
self.expect_one_of(&[], &[]);
}
}
@ -700,6 +705,7 @@ impl<'a> Parser<'a> {
/// with a single > and continue. If a GT is not seen,
/// signal an error.
pub fn expect_gt(&mut self) {
self.expected_tokens.push(TokenType::Token(token::Gt));
match self.token {
token::Gt => self.bump(),
token::BinOp(token::Shr) => {
@ -998,14 +1004,14 @@ impl<'a> Parser<'a> {
/// Is the current token one of the keywords that signals a bare function
/// type?
pub fn token_is_bare_fn_keyword(&mut self) -> bool {
self.token.is_keyword(keywords::Fn) ||
self.token.is_keyword(keywords::Unsafe) ||
self.token.is_keyword(keywords::Extern)
self.check_keyword(keywords::Fn) ||
self.check_keyword(keywords::Unsafe) ||
self.check_keyword(keywords::Extern)
}
/// Is the current token one of the keywords that signals a closure type?
pub fn token_is_closure_keyword(&mut self) -> bool {
self.token.is_keyword(keywords::Unsafe)
self.check_keyword(keywords::Unsafe)
}
pub fn get_lifetime(&mut self) -> ast::Ident {
@ -1035,7 +1041,7 @@ impl<'a> Parser<'a> {
let lifetime_defs = self.parse_late_bound_lifetime_defs();
// examine next token to decide to do
if self.eat_keyword(keywords::Proc) {
if self.eat_keyword_noexpect(keywords::Proc) {
self.parse_proc_type(lifetime_defs)
} else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() {
self.parse_ty_bare_fn_or_ty_closure(lifetime_defs)
@ -1166,11 +1172,11 @@ impl<'a> Parser<'a> {
// Closure: [unsafe] <'lt> |S| [:Bounds] -> T
// Fn: [unsafe] [extern "ABI"] fn <'lt> (S) -> T
if self.token.is_keyword(keywords::Fn) {
if self.check_keyword(keywords::Fn) {
self.parse_ty_bare_fn(lifetime_defs)
} else if self.token.is_keyword(keywords::Extern) {
} else if self.check_keyword(keywords::Extern) {
self.parse_ty_bare_fn(lifetime_defs)
} else if self.token.is_keyword(keywords::Unsafe) {
} else if self.check_keyword(keywords::Unsafe) {
if self.look_ahead(1, |t| t.is_keyword(keywords::Fn) ||
t.is_keyword(keywords::Extern)) {
self.parse_ty_bare_fn(lifetime_defs)
@ -1480,7 +1486,7 @@ impl<'a> Parser<'a> {
// BORROWED POINTER
self.expect_and();
self.parse_borrowed_pointee()
} else if self.token.is_keyword(keywords::For) {
} else if self.check_keyword(keywords::For) {
self.parse_for_in_type()
} else if self.token_is_bare_fn_keyword() ||
self.token_is_closure_keyword() {
@ -1494,14 +1500,14 @@ impl<'a> Parser<'a> {
})) {
// CLOSURE
self.parse_ty_closure(Vec::new())
} else if self.eat_keyword(keywords::Typeof) {
} else if self.eat_keyword_noexpect(keywords::Typeof) {
// TYPEOF
// In order to not be ambiguous, the type must be surrounded by parens.
self.expect(&token::OpenDelim(token::Paren));
let e = self.parse_expr();
self.expect(&token::CloseDelim(token::Paren));
TyTypeof(e)
} else if self.eat_keyword(keywords::Proc) {
} else if self.eat_keyword_noexpect(keywords::Proc) {
self.parse_proc_type(Vec::new())
} else if self.eat_lt() {
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
@ -2092,6 +2098,7 @@ impl<'a> Parser<'a> {
}
fn expect_open_delim(&mut self) -> token::DelimToken {
self.expected_tokens.push(TokenType::Token(token::Gt));
match self.token {
token::OpenDelim(delim) => {
self.bump();
@ -2233,7 +2240,7 @@ impl<'a> Parser<'a> {
if self.eat_keyword(keywords::Move) {
return self.parse_lambda_expr(CaptureByValue);
}
if self.eat_keyword(keywords::Proc) {
if self.eat_keyword_noexpect(keywords::Proc) {
let span = self.last_span;
let _ = self.parse_proc_decl();
let _ = self.parse_expr();
@ -2307,8 +2314,8 @@ impl<'a> Parser<'a> {
hi = self.span.hi;
} else if self.check(&token::ModSep) ||
self.token.is_ident() &&
!self.token.is_keyword(keywords::True) &&
!self.token.is_keyword(keywords::False) {
!self.check_keyword(keywords::True) &&
!self.check_keyword(keywords::False) {
let pth =
self.parse_path(LifetimeAndTypesWithColons);
@ -2792,7 +2799,7 @@ impl<'a> Parser<'a> {
ex = ExprAddrOf(m, e);
}
token::Ident(_, _) => {
if !self.token.is_keyword(keywords::Box) {
if !self.check_keyword(keywords::Box) {
return self.parse_dot_or_call_expr();
}
@ -2879,7 +2886,7 @@ impl<'a> Parser<'a> {
}
}
None => {
if AS_PREC >= min_prec && self.eat_keyword(keywords::As) {
if AS_PREC >= min_prec && self.eat_keyword_noexpect(keywords::As) {
let rhs = self.parse_ty();
let _as = self.mk_expr(lhs.span.lo,
rhs.span.hi,
@ -3002,7 +3009,7 @@ impl<'a> Parser<'a> {
/// Parse an 'if' or 'if let' expression ('if' token already eaten)
pub fn parse_if_expr(&mut self) -> P<Expr> {
if self.token.is_keyword(keywords::Let) {
if self.check_keyword(keywords::Let) {
return self.parse_if_let_expr();
}
let lo = self.last_span.lo;
@ -3655,7 +3662,7 @@ impl<'a> Parser<'a> {
}
let lo = self.span.lo;
if self.token.is_keyword(keywords::Let) {
if self.check_keyword(keywords::Let) {
check_expected_item(self, &item_attrs[]);
self.expect_keyword(keywords::Let);
let decl = self.parse_let();
@ -5302,7 +5309,7 @@ impl<'a> Parser<'a> {
let (maybe_path, ident) = match self.token {
token::Ident(..) => {
let the_ident = self.parse_ident();
let path = if self.eat_keyword(keywords::As) {
let path = if self.eat_keyword_noexpect(keywords::As) {
// skip the ident if there is one
if self.token.is_ident() { self.bump(); }
@ -5595,14 +5602,13 @@ impl<'a> Parser<'a> {
token_str)[]);
}
if self.eat_keyword(keywords::Virtual) {
if self.eat_keyword_noexpect(keywords::Virtual) {
let span = self.span;
self.span_err(span, "`virtual` structs have been removed from the language");
}
if self.token.is_keyword(keywords::Static) {
if self.eat_keyword(keywords::Static) {
// STATIC ITEM
self.bump();
let m = if self.eat_keyword(keywords::Mut) {MutMutable} else {MutImmutable};
let (ident, item_, extra_attrs) = self.parse_item_const(Some(m));
let last_span = self.last_span;
@ -5614,9 +5620,8 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(item);
}
if self.token.is_keyword(keywords::Const) {
if self.eat_keyword(keywords::Const) {
// CONST ITEM
self.bump();
if self.eat_keyword(keywords::Mut) {
let last_span = self.last_span;
self.span_err(last_span, "const globals cannot be mutable");
@ -5632,7 +5637,7 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(item);
}
if self.token.is_keyword(keywords::Unsafe) &&
if self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1us, |t| t.is_keyword(keywords::Trait))
{
// UNSAFE TRAIT ITEM
@ -5649,7 +5654,7 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(item);
}
if self.token.is_keyword(keywords::Unsafe) &&
if self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1us, |t| t.is_keyword(keywords::Impl))
{
// IMPL ITEM
@ -5665,7 +5670,7 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(item);
}
if self.token.is_keyword(keywords::Fn) {
if self.check_keyword(keywords::Fn) {
// FUNCTION ITEM
self.bump();
let (ident, item_, extra_attrs) =
@ -5679,7 +5684,7 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(item);
}
if self.token.is_keyword(keywords::Unsafe)
if self.check_keyword(keywords::Unsafe)
&& self.look_ahead(1us, |t| *t != token::OpenDelim(token::Brace)) {
// UNSAFE FUNCTION ITEM
self.bump();
@ -5784,11 +5789,11 @@ impl<'a> Parser<'a> {
let visibility = self.parse_visibility();
if self.token.is_keyword(keywords::Static) {
if self.check_keyword(keywords::Static) {
// FOREIGN STATIC ITEM
return Ok(self.parse_item_foreign_static(visibility, attrs));
}
if self.token.is_keyword(keywords::Fn) || self.token.is_keyword(keywords::Unsafe) {
if self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) {
// FOREIGN FUNCTION ITEM
return Ok(self.parse_item_foreign_fn(visibility, attrs));
}

View File

@ -456,7 +456,7 @@ macro_rules! declare_special_idents_and_keywords {(
pub use self::Keyword::*;
use ast;
#[derive(Copy)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Keyword {
$( $sk_variant, )*
$( $rk_variant, )*

View File

@ -9,5 +9,5 @@
// except according to those terms.
fn main() {
let x: [isize 3]; //~ ERROR expected one of `(`, `+`, `::`, `;`, or `]`, found `3`
let x: [isize 3]; //~ ERROR expected one of `(`, `+`, `::`, `;`, `<`, or `]`, found `3`
}

View File

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
impl Foo; //~ ERROR expected one of `(`, `+`, `::`, or `{`, found `;`
impl Foo; //~ ERROR expected one of `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;`

View File

@ -8,9 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:unexpected token
extern {
f();
f(); //~ ERROR expected one of `fn`, `pub`, `static`, `unsafe`, or `}`, found `f`
}
fn main() {

View File

@ -14,7 +14,7 @@ impl Foo {
fn foo() {}
#[stable(feature = "rust1", since = "1.0.0")]
} //~ ERROR expected `fn`, found `}`
} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
fn main() {}

View File

@ -12,6 +12,6 @@ struct Foo;
impl Foo {
#[stable(feature = "rust1", since = "1.0.0")]
} //~ ERROR expected `fn`, found `}`
} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
fn main() {}

View File

@ -0,0 +1,13 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait MyTrait<T>: Iterator {
Item = T; //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `Item`
}

View File

@ -12,7 +12,8 @@ struct S {
y: isize
}
impl Cmp, ToString for S { //~ ERROR: expected one of `(`, `+`, `::`, or `{`, found `,`
impl Cmp, ToString for S {
//~^ ERROR: expected one of `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `,`
fn eq(&&other: S) { false }
fn to_string(&self) -> String { "hi".to_string() }
}

View File

@ -10,7 +10,7 @@
pub fn main() {
match 22 {
0 .. 3 => {} //~ ERROR expected one of `...`, `=>`, or `|`, found `..`
0 .. 3 => {} //~ ERROR expected one of `...`, `=>`, `if`, or `|`, found `..`
_ => {}
}
}

View File

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
type closure = Box<lt/fn()>; //~ ERROR expected one of `(`, `+`, `,`, `::`, or `>`, found `/`
type closure = Box<lt/fn()>; //~ ERROR expected one of `(`, `+`, `,`, `::`, `<`, or `>`, found `/`

View File

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
enum e = isize; //~ ERROR expected one of `<` or `{`, found `=`
enum e = isize; //~ ERROR expected one of `<`, `where`, or `{`, found `=`

View File

@ -9,5 +9,6 @@
// except according to those terms.
extern {
const i: isize; //~ ERROR unexpected token: `const`
const i: isize;
//~^ ERROR expected one of `fn`, `pub`, `static`, `unsafe`, or `}`, found `const`
}

View File

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
type v = [isize * 3]; //~ ERROR expected one of `(`, `+`, `::`, `;`, or `]`, found `*`
type v = [isize * 3]; //~ ERROR expected one of `(`, `+`, `::`, `;`, `<`, or `]`, found `*`

View File

@ -10,4 +10,4 @@
type v = [mut isize];
//~^ ERROR expected identifier, found keyword `mut`
//~^^ ERROR expected one of `(`, `+`, `::`, `;`, or `]`, found `isize`
//~^^ ERROR expected one of `(`, `+`, `::`, `;`, `<`, or `]`, found `isize`

View File

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
type bptr = &lifetime/isize; //~ ERROR expected one of `(`, `+`, `::`, or `;`, found `/`
type bptr = &lifetime/isize; //~ ERROR expected one of `(`, `+`, `::`, `;`, or `<`, found `/`

View File

@ -11,5 +11,6 @@
struct S;
impl S {
static fn f() {} //~ ERROR expected `fn`, found `static`
static fn f() {}
//~^ ERROR expected one of `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
}

View File

@ -10,4 +10,4 @@
type mut_box = Box<mut isize>;
//~^ ERROR expected identifier, found keyword `mut`
//~^^ ERROR expected one of `(`, `+`, `,`, `::`, or `>`, found `isize`
//~^^ ERROR expected one of `(`, `+`, `,`, `::`, `<`, or `>`, found `isize`

View File

@ -14,7 +14,7 @@ struct Foo {
fn main() {
match Foo {
x: 3 //~ ERROR expected one of `!`, `=>`, `@`, or `|`, found `:`
x: 3 //~ ERROR expected one of `!`, `=>`, `@`, `if`, or `|`, found `:`
} {
Foo {
x: x