Make the parser’s ‘expected <foo>, found <bar>’ errors more accurate

As an example of what this changes, the following code:

    let x: [int ..4];

Currently spits out ‘expected `]`, found `..`’. However, a comma would also be
valid there, as would a number of other tokens. This change adjusts the parser
to produce more accurate errors, so that that example now produces ‘expected one
of `(`, `+`, `,`, `::`, or `]`, found `..`’.
This commit is contained in:
P1start 2014-12-03 22:47:53 +13:00
parent 3a325c666d
commit 108bca53f0
29 changed files with 155 additions and 95 deletions

View file

@ -87,6 +87,7 @@ use std::mem;
use std::num::Float; use std::num::Float;
use std::rc::Rc; use std::rc::Rc;
use std::iter; use std::iter;
use std::slice;
bitflags! { bitflags! {
flags Restrictions: u8 { flags Restrictions: u8 {
@ -303,6 +304,22 @@ pub struct Parser<'a> {
/// name is not known. This does not change while the parser is descending /// name is not known. This does not change while the parser is descending
/// into modules, and sub-parsers have new values for this name. /// into modules, and sub-parsers have new values for this name.
pub root_module_name: Option<String>, pub root_module_name: Option<String>,
pub expected_tokens: Vec<TokenType>,
}
#[deriving(PartialEq, Eq, Clone)]
pub enum TokenType {
Token(token::Token),
Operator,
}
impl TokenType {
fn to_string(&self) -> String {
match *self {
TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)),
TokenType::Operator => "an operator".into_string(),
}
}
} }
fn is_plain_ident_or_underscore(t: &token::Token) -> bool { fn is_plain_ident_or_underscore(t: &token::Token) -> bool {
@ -347,6 +364,7 @@ impl<'a> Parser<'a> {
open_braces: Vec::new(), open_braces: Vec::new(),
owns_directory: true, owns_directory: true,
root_module_name: None, root_module_name: None,
expected_tokens: Vec::new(),
} }
} }
@ -375,6 +393,7 @@ impl<'a> Parser<'a> {
/// Expect and consume the token t. Signal an error if /// Expect and consume the token t. Signal an error if
/// the next token is not t. /// the next token is not t.
pub fn expect(&mut self, t: &token::Token) { pub fn expect(&mut self, t: &token::Token) {
if self.expected_tokens.is_empty() {
if self.token == *t { if self.token == *t {
self.bump(); self.bump();
} else { } else {
@ -384,6 +403,9 @@ impl<'a> Parser<'a> {
token_str, token_str,
this_token_str).as_slice()) this_token_str).as_slice())
} }
} else {
self.expect_one_of(slice::ref_slice(t), &[]);
}
} }
/// Expect next token to be edible or inedible token. If edible, /// Expect next token to be edible or inedible token. If edible,
@ -392,15 +414,20 @@ impl<'a> Parser<'a> {
pub fn expect_one_of(&mut self, pub fn expect_one_of(&mut self,
edible: &[token::Token], edible: &[token::Token],
inedible: &[token::Token]) { inedible: &[token::Token]) {
fn tokens_to_string(tokens: &[token::Token]) -> String { fn tokens_to_string(tokens: &[TokenType]) -> String {
let mut i = tokens.iter(); let mut i = tokens.iter();
// This might be a sign we need a connect method on Iterator. // This might be a sign we need a connect method on Iterator.
let b = i.next() let b = i.next()
.map_or("".to_string(), |t| Parser::token_to_string(t)); .map_or("".into_string(), |t| t.to_string());
i.fold(b, |b,a| { i.enumerate().fold(b, |mut b, (i, ref a)| {
let mut b = b; if tokens.len() > 2 && i == tokens.len() - 2 {
b.push_str("`, `"); b.push_str(", or ");
b.push_str(Parser::token_to_string(a).as_slice()); } else if tokens.len() == 2 && i == tokens.len() - 2 {
b.push_str(" or ");
} else {
b.push_str(", ");
}
b.push_str(&*a.to_string());
b b
}) })
} }
@ -409,17 +436,21 @@ impl<'a> Parser<'a> {
} else if inedible.contains(&self.token) { } else if inedible.contains(&self.token) {
// leave it in the input // leave it in the input
} else { } else {
let mut expected = edible.iter().map(|x| x.clone()).collect::<Vec<_>>(); let mut expected = edible.iter().map(|x| TokenType::Token(x.clone()))
expected.push_all(inedible); .collect::<Vec<_>>();
expected.extend(inedible.iter().map(|x| TokenType::Token(x.clone())));
expected.push_all(&*self.expected_tokens);
expected.sort_by(|a, b| a.to_string().cmp(&b.to_string()));
expected.dedup();
let expect = tokens_to_string(expected.as_slice()); let expect = tokens_to_string(expected.as_slice());
let actual = self.this_token_to_string(); let actual = self.this_token_to_string();
self.fatal( self.fatal(
(if expected.len() != 1 { (if expected.len() != 1 {
(format!("expected one of `{}`, found `{}`", (format!("expected one of {}, found `{}`",
expect, expect,
actual)) actual))
} else { } else {
(format!("expected `{}`, found `{}`", (format!("expected {}, found `{}`",
expect, expect,
actual)) actual))
}).as_slice() }).as_slice()
@ -514,10 +545,20 @@ impl<'a> Parser<'a> {
spanned(lo, hi, node) spanned(lo, hi, node)
} }
/// Check if the next token is `tok`, and return `true` if so.
///
/// This method is will automatically add `tok` to `expected_tokens` if `tok` is not
/// encountered.
pub fn check(&mut self, tok: &token::Token) -> bool {
let is_present = self.token == *tok;
if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); }
is_present
}
/// Consume token 'tok' if it exists. Returns true if the given /// Consume token 'tok' if it exists. Returns true if the given
/// token was present, false otherwise. /// token was present, false otherwise.
pub fn eat(&mut self, tok: &token::Token) -> bool { pub fn eat(&mut self, tok: &token::Token) -> bool {
let is_present = self.token == *tok; let is_present = self.check(tok);
if is_present { self.bump() } if is_present { self.bump() }
is_present is_present
} }
@ -739,7 +780,7 @@ impl<'a> Parser<'a> {
// commas in generic parameters, because it can stop either after // commas in generic parameters, because it can stop either after
// parsing a type or after parsing a comma. // parsing a type or after parsing a comma.
for i in iter::count(0u, 1) { for i in iter::count(0u, 1) {
if self.token == token::Gt if self.check(&token::Gt)
|| self.token == token::BinOp(token::Shr) || self.token == token::BinOp(token::Shr)
|| self.token == token::Ge || self.token == token::Ge
|| self.token == token::BinOpEq(token::Shr) { || self.token == token::BinOpEq(token::Shr) {
@ -798,7 +839,7 @@ impl<'a> Parser<'a> {
} }
_ => () _ => ()
} }
if sep.trailing_sep_allowed && self.token == *ket { break; } if sep.trailing_sep_allowed && self.check(ket) { break; }
v.push(f(self)); v.push(f(self));
} }
return v; return v;
@ -881,6 +922,7 @@ impl<'a> Parser<'a> {
self.span = next.sp; self.span = next.sp;
self.token = next.tok; self.token = next.tok;
self.tokens_consumed += 1u; self.tokens_consumed += 1u;
self.expected_tokens.clear();
} }
/// Advance the parser by one token and return the bumped token. /// Advance the parser by one token and return the bumped token.
@ -999,7 +1041,7 @@ impl<'a> Parser<'a> {
self.parse_proc_type(lifetime_defs) self.parse_proc_type(lifetime_defs)
} else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() { } else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() {
self.parse_ty_bare_fn_or_ty_closure(lifetime_defs) self.parse_ty_bare_fn_or_ty_closure(lifetime_defs)
} else if self.token == token::ModSep || } else if self.check(&token::ModSep) ||
self.token.is_ident() || self.token.is_ident() ||
self.token.is_path() self.token.is_path()
{ {
@ -1101,7 +1143,7 @@ impl<'a> Parser<'a> {
/// Parses an optional unboxed closure kind (`&:`, `&mut:`, or `:`). /// Parses an optional unboxed closure kind (`&:`, `&mut:`, or `:`).
pub fn parse_optional_unboxed_closure_kind(&mut self) pub fn parse_optional_unboxed_closure_kind(&mut self)
-> Option<UnboxedClosureKind> { -> Option<UnboxedClosureKind> {
if self.token == token::BinOp(token::And) && if self.check(&token::BinOp(token::And)) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
self.look_ahead(2, |t| *t == token::Colon) { self.look_ahead(2, |t| *t == token::Colon) {
self.bump(); self.bump();
@ -1211,7 +1253,8 @@ impl<'a> Parser<'a> {
lifetime_defs: Vec<ast::LifetimeDef>) lifetime_defs: Vec<ast::LifetimeDef>)
-> Vec<ast::LifetimeDef> -> Vec<ast::LifetimeDef>
{ {
if self.eat(&token::Lt) { if self.token == token::Lt {
self.bump();
if lifetime_defs.is_empty() { if lifetime_defs.is_empty() {
self.warn("deprecated syntax; use the `for` keyword now \ self.warn("deprecated syntax; use the `for` keyword now \
(e.g. change `fn<'a>` to `for<'a> fn`)"); (e.g. change `fn<'a>` to `for<'a> fn`)");
@ -1430,7 +1473,7 @@ impl<'a> Parser<'a> {
let lo = self.span.lo; let lo = self.span.lo;
let t = if self.token == token::OpenDelim(token::Paren) { let t = if self.check(&token::OpenDelim(token::Paren)) {
self.bump(); self.bump();
// (t) is a parenthesized ty // (t) is a parenthesized ty
@ -1440,7 +1483,7 @@ impl<'a> Parser<'a> {
let mut last_comma = false; let mut last_comma = false;
while self.token != token::CloseDelim(token::Paren) { while self.token != token::CloseDelim(token::Paren) {
ts.push(self.parse_ty_sum()); ts.push(self.parse_ty_sum());
if self.token == token::Comma { if self.check(&token::Comma) {
last_comma = true; last_comma = true;
self.bump(); self.bump();
} else { } else {
@ -1464,11 +1507,11 @@ impl<'a> Parser<'a> {
_ => self.obsolete(last_span, ObsoleteOwnedType) _ => self.obsolete(last_span, ObsoleteOwnedType)
} }
TyTup(vec![self.parse_ty()]) TyTup(vec![self.parse_ty()])
} else if self.token == token::BinOp(token::Star) { } else if self.check(&token::BinOp(token::Star)) {
// STAR POINTER (bare pointer?) // STAR POINTER (bare pointer?)
self.bump(); self.bump();
TyPtr(self.parse_ptr()) TyPtr(self.parse_ptr())
} else if self.token == token::OpenDelim(token::Bracket) { } else if self.check(&token::OpenDelim(token::Bracket)) {
// VECTOR // VECTOR
self.expect(&token::OpenDelim(token::Bracket)); self.expect(&token::OpenDelim(token::Bracket));
let t = self.parse_ty_sum(); let t = self.parse_ty_sum();
@ -1481,7 +1524,7 @@ impl<'a> Parser<'a> {
}; };
self.expect(&token::CloseDelim(token::Bracket)); self.expect(&token::CloseDelim(token::Bracket));
t t
} else if self.token == token::BinOp(token::And) || } else if self.check(&token::BinOp(token::And)) ||
self.token == token::AndAnd { self.token == token::AndAnd {
// BORROWED POINTER // BORROWED POINTER
self.expect_and(); self.expect_and();
@ -1492,7 +1535,7 @@ impl<'a> Parser<'a> {
self.token_is_closure_keyword() { self.token_is_closure_keyword() {
// BARE FUNCTION OR CLOSURE // BARE FUNCTION OR CLOSURE
self.parse_ty_bare_fn_or_ty_closure(Vec::new()) self.parse_ty_bare_fn_or_ty_closure(Vec::new())
} else if self.token == token::BinOp(token::Or) || } else if self.check(&token::BinOp(token::Or)) ||
self.token == token::OrOr || self.token == token::OrOr ||
(self.token == token::Lt && (self.token == token::Lt &&
self.look_ahead(1, |t| { self.look_ahead(1, |t| {
@ -1509,7 +1552,7 @@ impl<'a> Parser<'a> {
TyTypeof(e) TyTypeof(e)
} else if self.eat_keyword(keywords::Proc) { } else if self.eat_keyword(keywords::Proc) {
self.parse_proc_type(Vec::new()) self.parse_proc_type(Vec::new())
} else if self.token == token::Lt { } else if self.check(&token::Lt) {
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item` // QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
self.bump(); self.bump();
let self_type = self.parse_ty_sum(); let self_type = self.parse_ty_sum();
@ -1523,7 +1566,7 @@ impl<'a> Parser<'a> {
trait_ref: P(trait_ref), trait_ref: P(trait_ref),
item_name: item_name, item_name: item_name,
})) }))
} else if self.token == token::ModSep || } else if self.check(&token::ModSep) ||
self.token.is_ident() || self.token.is_ident() ||
self.token.is_path() { self.token.is_path() {
// NAMED TYPE // NAMED TYPE
@ -1532,7 +1575,8 @@ impl<'a> Parser<'a> {
// TYPE TO BE INFERRED // TYPE TO BE INFERRED
TyInfer TyInfer
} else { } else {
let msg = format!("expected type, found token {}", self.token); let this_token_str = self.this_token_to_string();
let msg = format!("expected type, found `{}`", this_token_str);
self.fatal(msg.as_slice()); self.fatal(msg.as_slice());
}; };
@ -1635,7 +1679,7 @@ impl<'a> Parser<'a> {
} }
pub fn maybe_parse_fixed_vstore(&mut self) -> Option<P<ast::Expr>> { pub fn maybe_parse_fixed_vstore(&mut self) -> Option<P<ast::Expr>> {
if self.token == token::Comma && if self.check(&token::Comma) &&
self.look_ahead(1, |t| *t == token::DotDot) { self.look_ahead(1, |t| *t == token::DotDot) {
self.bump(); self.bump();
self.bump(); self.bump();
@ -1959,9 +2003,10 @@ impl<'a> Parser<'a> {
token::Gt => { return res; } token::Gt => { return res; }
token::BinOp(token::Shr) => { return res; } token::BinOp(token::Shr) => { return res; }
_ => { _ => {
let this_token_str = self.this_token_to_string();
let msg = format!("expected `,` or `>` after lifetime \ let msg = format!("expected `,` or `>` after lifetime \
name, got: {}", name, found `{}`",
self.token); this_token_str);
self.fatal(msg.as_slice()); self.fatal(msg.as_slice());
} }
} }
@ -2126,7 +2171,7 @@ impl<'a> Parser<'a> {
es.push(self.parse_expr()); es.push(self.parse_expr());
self.commit_expr(&**es.last().unwrap(), &[], self.commit_expr(&**es.last().unwrap(), &[],
&[token::Comma, token::CloseDelim(token::Paren)]); &[token::Comma, token::CloseDelim(token::Paren)]);
if self.token == token::Comma { if self.check(&token::Comma) {
trailing_comma = true; trailing_comma = true;
self.bump(); self.bump();
@ -2167,14 +2212,14 @@ impl<'a> Parser<'a> {
token::OpenDelim(token::Bracket) => { token::OpenDelim(token::Bracket) => {
self.bump(); self.bump();
if self.token == token::CloseDelim(token::Bracket) { if self.check(&token::CloseDelim(token::Bracket)) {
// Empty vector. // Empty vector.
self.bump(); self.bump();
ex = ExprVec(Vec::new()); ex = ExprVec(Vec::new());
} else { } else {
// Nonempty vector. // Nonempty vector.
let first_expr = self.parse_expr(); let first_expr = self.parse_expr();
if self.token == token::Comma && if self.check(&token::Comma) &&
self.look_ahead(1, |t| *t == token::DotDot) { self.look_ahead(1, |t| *t == token::DotDot) {
// Repeating vector syntax: [ 0, ..512 ] // Repeating vector syntax: [ 0, ..512 ]
self.bump(); self.bump();
@ -2182,7 +2227,7 @@ impl<'a> Parser<'a> {
let count = self.parse_expr(); let count = self.parse_expr();
self.expect(&token::CloseDelim(token::Bracket)); self.expect(&token::CloseDelim(token::Bracket));
ex = ExprRepeat(first_expr, count); ex = ExprRepeat(first_expr, count);
} else if self.token == token::Comma { } else if self.check(&token::Comma) {
// Vector with two or more elements. // Vector with two or more elements.
self.bump(); self.bump();
let remaining_exprs = self.parse_seq_to_end( let remaining_exprs = self.parse_seq_to_end(
@ -2284,7 +2329,7 @@ impl<'a> Parser<'a> {
ex = ExprBreak(None); ex = ExprBreak(None);
} }
hi = self.span.hi; hi = self.span.hi;
} else if self.token == token::ModSep || } else if self.check(&token::ModSep) ||
self.token.is_ident() && self.token.is_ident() &&
!self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::True) &&
!self.token.is_keyword(keywords::False) { !self.token.is_keyword(keywords::False) {
@ -2292,7 +2337,7 @@ impl<'a> Parser<'a> {
self.parse_path(LifetimeAndTypesWithColons); self.parse_path(LifetimeAndTypesWithColons);
// `!`, as an operator, is prefix, so we know this isn't that // `!`, as an operator, is prefix, so we know this isn't that
if self.token == token::Not { if self.check(&token::Not) {
// MACRO INVOCATION expression // MACRO INVOCATION expression
self.bump(); self.bump();
@ -2309,7 +2354,7 @@ impl<'a> Parser<'a> {
tts, tts,
EMPTY_CTXT)); EMPTY_CTXT));
} }
if self.token == token::OpenDelim(token::Brace) { if self.check(&token::OpenDelim(token::Brace)) {
// This is a struct literal, unless we're prohibited // This is a struct literal, unless we're prohibited
// from parsing struct literals here. // from parsing struct literals here.
if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) { if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) {
@ -2840,6 +2885,7 @@ impl<'a> Parser<'a> {
self.restrictions.contains(RESTRICTION_NO_BAR_OP) { self.restrictions.contains(RESTRICTION_NO_BAR_OP) {
return lhs; return lhs;
} }
self.expected_tokens.push(TokenType::Operator);
let cur_opt = self.token.to_binop(); let cur_opt = self.token.to_binop();
match cur_opt { match cur_opt {
@ -3079,7 +3125,7 @@ impl<'a> Parser<'a> {
/// Parse the RHS of a local variable declaration (e.g. '= 14;') /// Parse the RHS of a local variable declaration (e.g. '= 14;')
fn parse_initializer(&mut self) -> Option<P<Expr>> { fn parse_initializer(&mut self) -> Option<P<Expr>> {
if self.token == token::Eq { if self.check(&token::Eq) {
self.bump(); self.bump();
Some(self.parse_expr()) Some(self.parse_expr())
} else { } else {
@ -3092,7 +3138,7 @@ impl<'a> Parser<'a> {
let mut pats = Vec::new(); let mut pats = Vec::new();
loop { loop {
pats.push(self.parse_pat()); pats.push(self.parse_pat());
if self.token == token::BinOp(token::Or) { self.bump(); } if self.check(&token::BinOp(token::Or)) { self.bump(); }
else { return pats; } else { return pats; }
}; };
} }
@ -3114,11 +3160,11 @@ impl<'a> Parser<'a> {
} }
if before_slice { if before_slice {
if self.token == token::DotDot { if self.check(&token::DotDot) {
self.bump(); self.bump();
if self.token == token::Comma || if self.check(&token::Comma) ||
self.token == token::CloseDelim(token::Bracket) { self.check(&token::CloseDelim(token::Bracket)) {
slice = Some(P(ast::Pat { slice = Some(P(ast::Pat {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
node: PatWild(PatWildMulti), node: PatWild(PatWildMulti),
@ -3135,7 +3181,7 @@ impl<'a> Parser<'a> {
} }
let subpat = self.parse_pat(); let subpat = self.parse_pat();
if before_slice && self.token == token::DotDot { if before_slice && self.check(&token::DotDot) {
self.bump(); self.bump();
slice = Some(subpat); slice = Some(subpat);
before_slice = false; before_slice = false;
@ -3160,13 +3206,13 @@ impl<'a> Parser<'a> {
} else { } else {
self.expect(&token::Comma); self.expect(&token::Comma);
// accept trailing commas // accept trailing commas
if self.token == token::CloseDelim(token::Brace) { break } if self.check(&token::CloseDelim(token::Brace)) { break }
} }
let lo = self.span.lo; let lo = self.span.lo;
let hi; let hi;
if self.token == token::DotDot { if self.check(&token::DotDot) {
self.bump(); self.bump();
if self.token != token::CloseDelim(token::Brace) { if self.token != token::CloseDelim(token::Brace) {
let token_str = self.this_token_to_string(); let token_str = self.this_token_to_string();
@ -3187,7 +3233,7 @@ impl<'a> Parser<'a> {
let fieldname = self.parse_ident(); let fieldname = self.parse_ident();
let (subpat, is_shorthand) = if self.token == token::Colon { let (subpat, is_shorthand) = if self.check(&token::Colon) {
match bind_type { match bind_type {
BindByRef(..) | BindByValue(MutMutable) => { BindByRef(..) | BindByValue(MutMutable) => {
let token_str = self.this_token_to_string(); let token_str = self.this_token_to_string();
@ -3267,15 +3313,15 @@ impl<'a> Parser<'a> {
token::OpenDelim(token::Paren) => { token::OpenDelim(token::Paren) => {
// parse (pat,pat,pat,...) as tuple // parse (pat,pat,pat,...) as tuple
self.bump(); self.bump();
if self.token == token::CloseDelim(token::Paren) { if self.check(&token::CloseDelim(token::Paren)) {
self.bump(); self.bump();
pat = PatTup(vec![]); pat = PatTup(vec![]);
} else { } else {
let mut fields = vec!(self.parse_pat()); let mut fields = vec!(self.parse_pat());
if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) {
while self.token == token::Comma { while self.check(&token::Comma) {
self.bump(); self.bump();
if self.token == token::CloseDelim(token::Paren) { break; } if self.check(&token::CloseDelim(token::Paren)) { break; }
fields.push(self.parse_pat()); fields.push(self.parse_pat());
} }
} }
@ -3318,7 +3364,7 @@ impl<'a> Parser<'a> {
// These expressions are limited to literals (possibly // These expressions are limited to literals (possibly
// preceded by unary-minus) or identifiers. // preceded by unary-minus) or identifiers.
let val = self.parse_literal_maybe_minus(); let val = self.parse_literal_maybe_minus();
if (self.token == token::DotDotDot) && if (self.check(&token::DotDotDot)) &&
self.look_ahead(1, |t| { self.look_ahead(1, |t| {
*t != token::Comma && *t != token::CloseDelim(token::Bracket) *t != token::Comma && *t != token::CloseDelim(token::Bracket)
}) { }) {
@ -3621,7 +3667,7 @@ impl<'a> Parser<'a> {
let hi = self.span.hi; let hi = self.span.hi;
if id.name == token::special_idents::invalid.name { if id.name == token::special_idents::invalid.name {
if self.token == token::Dot { if self.check(&token::Dot) {
let span = self.span; let span = self.span;
let token_string = self.this_token_to_string(); let token_string = self.this_token_to_string();
self.span_err(span, self.span_err(span,
@ -3934,7 +3980,7 @@ impl<'a> Parser<'a> {
let bounds = self.parse_colon_then_ty_param_bounds(); let bounds = self.parse_colon_then_ty_param_bounds();
let default = if self.token == token::Eq { let default = if self.check(&token::Eq) {
self.bump(); self.bump();
Some(self.parse_ty_sum()) Some(self.parse_ty_sum())
} }
@ -4334,7 +4380,7 @@ impl<'a> Parser<'a> {
(optional_unboxed_closure_kind, args) (optional_unboxed_closure_kind, args)
} }
}; };
let output = if self.token == token::RArrow { let output = if self.check(&token::RArrow) {
self.parse_ret_ty() self.parse_ret_ty()
} else { } else {
Return(P(Ty { Return(P(Ty {
@ -4359,7 +4405,7 @@ impl<'a> Parser<'a> {
seq_sep_trailing_allowed(token::Comma), seq_sep_trailing_allowed(token::Comma),
|p| p.parse_fn_block_arg()); |p| p.parse_fn_block_arg());
let output = if self.token == token::RArrow { let output = if self.check(&token::RArrow) {
self.parse_ret_ty() self.parse_ret_ty()
} else { } else {
Return(P(Ty { Return(P(Ty {
@ -4616,7 +4662,7 @@ impl<'a> Parser<'a> {
token::get_ident(class_name)).as_slice()); token::get_ident(class_name)).as_slice());
} }
self.bump(); self.bump();
} else if self.token == token::OpenDelim(token::Paren) { } else if self.check(&token::OpenDelim(token::Paren)) {
// It's a tuple-like struct. // It's a tuple-like struct.
is_tuple_like = true; is_tuple_like = true;
fields = self.parse_unspanned_seq( fields = self.parse_unspanned_seq(
@ -4801,7 +4847,7 @@ impl<'a> Parser<'a> {
fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> ItemInfo { fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> ItemInfo {
let id_span = self.span; let id_span = self.span;
let id = self.parse_ident(); let id = self.parse_ident();
if self.token == token::Semi { if self.check(&token::Semi) {
self.bump(); self.bump();
// This mod is in an external file. Let's go get it! // This mod is in an external file. Let's go get it!
let (m, attrs) = self.eval_src_mod(id, outer_attrs, id_span); let (m, attrs) = self.eval_src_mod(id, outer_attrs, id_span);
@ -5044,7 +5090,8 @@ impl<'a> Parser<'a> {
let (maybe_path, ident) = match self.token { let (maybe_path, ident) = match self.token {
token::Ident(..) => { token::Ident(..) => {
let the_ident = self.parse_ident(); let the_ident = self.parse_ident();
let path = if self.eat(&token::Eq) { let path = if self.token == token::Eq {
self.bump();
let path = self.parse_str(); let path = self.parse_str();
let span = self.span; let span = self.span;
self.obsolete(span, ObsoleteExternCrateRenaming); self.obsolete(span, ObsoleteExternCrateRenaming);
@ -5184,7 +5231,7 @@ impl<'a> Parser<'a> {
token::get_ident(ident)).as_slice()); token::get_ident(ident)).as_slice());
} }
kind = StructVariantKind(struct_def); kind = StructVariantKind(struct_def);
} else if self.token == token::OpenDelim(token::Paren) { } else if self.check(&token::OpenDelim(token::Paren)) {
all_nullary = false; all_nullary = false;
let arg_tys = self.parse_enum_variant_seq( let arg_tys = self.parse_enum_variant_seq(
&token::OpenDelim(token::Paren), &token::OpenDelim(token::Paren),
@ -5348,7 +5395,7 @@ impl<'a> Parser<'a> {
visibility, visibility,
maybe_append(attrs, extra_attrs)); maybe_append(attrs, extra_attrs));
return IoviItem(item); return IoviItem(item);
} else if self.token == token::OpenDelim(token::Brace) { } else if self.check(&token::OpenDelim(token::Brace)) {
return self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs); return self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs);
} }
@ -5629,7 +5676,7 @@ impl<'a> Parser<'a> {
fn parse_view_path(&mut self) -> P<ViewPath> { fn parse_view_path(&mut self) -> P<ViewPath> {
let lo = self.span.lo; let lo = self.span.lo;
if self.token == token::OpenDelim(token::Brace) { if self.check(&token::OpenDelim(token::Brace)) {
// use {foo,bar} // use {foo,bar}
let idents = self.parse_unspanned_seq( let idents = self.parse_unspanned_seq(
&token::OpenDelim(token::Brace), &token::OpenDelim(token::Brace),
@ -5653,7 +5700,7 @@ impl<'a> Parser<'a> {
self.bump(); self.bump();
let path_lo = self.span.lo; let path_lo = self.span.lo;
path = vec!(self.parse_ident()); path = vec!(self.parse_ident());
while self.token == token::ModSep { while self.check(&token::ModSep) {
self.bump(); self.bump();
let id = self.parse_ident(); let id = self.parse_ident();
path.push(id); path.push(id);
@ -5677,7 +5724,7 @@ impl<'a> Parser<'a> {
token::ModSep => { token::ModSep => {
// foo::bar or foo::{a,b,c} or foo::* // foo::bar or foo::{a,b,c} or foo::*
while self.token == token::ModSep { while self.check(&token::ModSep) {
self.bump(); self.bump();
match self.token { match self.token {
@ -5846,7 +5893,7 @@ impl<'a> Parser<'a> {
loop { loop {
match self.parse_foreign_item(attrs, macros_allowed) { match self.parse_foreign_item(attrs, macros_allowed) {
IoviNone(returned_attrs) => { IoviNone(returned_attrs) => {
if self.token == token::CloseDelim(token::Brace) { if self.check(&token::CloseDelim(token::Brace)) {
attrs = returned_attrs; attrs = returned_attrs;
break break
} }

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.
fn main() {
let x: [int ..3]; //~ ERROR expected one of `(`, `+`, `,`, `::`, or `]`, found `..`
}

View file

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
# //~ ERROR 11:1: 11:2 error: expected `[`, found `<eof>` # //~ ERROR 11:1: 11:2 error: expected one of `!` or `[`, found `<eof>`

View file

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

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// error-pattern:expected `[`, found `vec` // error-pattern:expected one of `!` or `[`, found `vec`
mod blade_runner { mod blade_runner {
#vec[doc( #vec[doc(
brief = "Blade Runner is probably the best movie ever", brief = "Blade Runner is probably the best movie ever",

View file

@ -12,5 +12,5 @@
fn main() { fn main() {
let t = (42i, 42i); let t = (42i, 42i);
t.0::<int>; //~ ERROR expected one of `;`, `}`, found `::` t.0::<int>; //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `::`
} }

View file

@ -13,4 +13,4 @@
fn main() fn main()
{ {
let x = 3 let x = 3
} //~ ERROR: expected `;`, found `}` } //~ ERROR: expected one of `.`, `;`, or an operator, found `}`

View file

@ -11,7 +11,7 @@
fn main() { fn main() {
let a = Vec::new(); let a = Vec::new();
match a { match a {
[1, tail.., tail..] => {}, //~ ERROR: expected `,`, found `..` [1, tail.., tail..] => {}, //~ ERROR: expected one of `!`, `,`, or `@`, found `..`
_ => () _ => ()
} }
} }

View file

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

View file

@ -12,5 +12,5 @@
pub fn main() { pub fn main() {
struct Foo { x: int } struct Foo { x: int }
let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected `;`, found `{` let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{`
} }

View file

@ -8,5 +8,5 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
fn foo(x) { //~ ERROR expected `:`, found `)` fn foo(x) { //~ ERROR expected one of `!`, `:`, or `@`, found `)`
} }

View file

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

View file

@ -10,5 +10,5 @@
static s: &'static str = static s: &'static str =
r#" r#"
"## //~ ERROR expected `;`, found `#` "## //~ ERROR expected one of `.`, `;`, or an operator, found `#`
; ;

View file

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

View file

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

View file

@ -11,5 +11,5 @@
fn removed_moves() { fn removed_moves() {
let mut x = 0; let mut x = 0;
let y <- x; let y <- x;
//~^ ERROR expected `;`, found `<-` //~^ ERROR expected one of `!`, `:`, `;`, `=`, or `@`, found `<-`
} }

View file

@ -12,5 +12,5 @@ fn removed_moves() {
let mut x = 0; let mut x = 0;
let y = 0; let y = 0;
y <- x; y <- x;
//~^ ERROR expected one of `;`, `}`, found `<-` //~^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `<-`
} }

View file

@ -11,5 +11,5 @@
fn f() { fn f() {
let v = [mut 1, 2, 3, 4]; let v = [mut 1, 2, 3, 4];
//~^ ERROR expected identifier, found keyword `mut` //~^ ERROR expected identifier, found keyword `mut`
//~^^ ERROR expected `]`, found `1` //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `]`, `{`, or an operator, found `1`
} }

View file

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

View file

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

View file

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
type t = { f: () }; //~ ERROR expected type, found token OpenDelim(Brace) type t = { f: () }; //~ ERROR expected type, found `{`

View file

@ -11,5 +11,5 @@
fn f() { fn f() {
let a_box = box mut 42; let a_box = box mut 42;
//~^ ERROR expected identifier, found keyword `mut` //~^ ERROR expected identifier, found keyword `mut`
//~^^ ERROR expected `;`, found `42` //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, or an operator, found `42`
} }

View file

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

View file

@ -16,5 +16,5 @@ fn removed_with() {
let a = S { foo: (), bar: () }; let a = S { foo: (), bar: () };
let b = S { foo: () with a }; let b = S { foo: () with a };
//~^ ERROR expected one of `,`, `}`, found `with` //~^ ERROR expected one of `,`, `.`, `}`, or an operator, found `with`
} }

View file

@ -20,7 +20,7 @@ impl Foo {
fn main() { fn main() {
for x in Foo { for x in Foo {
x: 3 //~ ERROR expected one of `;`, `}` x: 3 //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:`
}.hi() { }.hi() {
println!("yo"); println!("yo");
} }

View file

@ -20,7 +20,7 @@ impl Foo {
fn main() { fn main() {
if Foo { if Foo {
x: 3 //~ ERROR expected one of `;`, `}` x: 3 //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:`
}.hi() { }.hi() {
println!("yo"); println!("yo");
} }

View file

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

View file

@ -20,7 +20,7 @@ impl Foo {
fn main() { fn main() {
while Foo { while Foo {
x: 3 //~ ERROR expected one of `;`, `}` x: 3 //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:`
}.hi() { }.hi() {
println!("yo"); println!("yo");
} }