parent
ca4b9674c2
commit
597b4fa984
20 changed files with 100 additions and 77 deletions
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue