use std::slice;
bitflags! {
- pub flags Restrictions: u8 {
- const RESTRICTION_STMT_EXPR = 1 << 0,
- const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
+ pub struct Restrictions: u8 {
+ const STMT_EXPR = 1 << 0;
+ const NO_STRUCT_LITERAL = 1 << 1;
}
}
Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum TokenExpectType {
+ Expect,
+ NoExpect,
+}
+
impl<'a> Parser<'a> {
pub fn new(sess: &'a ParseSess,
tokens: TokenStream,
}
}
+ /// Expect and consume an `|`. If `||` is seen, replace it with a single
+ /// `|` and continue. If an `|` is not seen, signal an error.
+ fn expect_or(&mut self) -> PResult<'a, ()> {
+ self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or)));
+ match self.token {
+ token::BinOp(token::Or) => {
+ self.bump();
+ Ok(())
+ }
+ token::OrOr => {
+ let span = self.span.with_lo(self.span.lo() + BytePos(1));
+ Ok(self.bump_with(token::BinOp(token::Or), span))
+ }
+ _ => self.unexpected()
+ }
+ }
+
pub fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
match suffix {
None => {/* everything ok */}
self.parse_seq_to_before_tokens(kets,
SeqSep::none(),
+ TokenExpectType::Expect,
|p| Ok(p.parse_token_tree()),
|mut e| handler.cancel(&mut e));
}
-> Vec<T>
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
- self.parse_seq_to_before_tokens(&[ket], sep, f, |mut e| e.emit())
+ self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f, |mut e| e.emit())
}
// `fe` is an error handler.
fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
kets: &[&token::Token],
sep: SeqSep,
+ expect: TokenExpectType,
mut f: F,
mut fe: Fe)
-> Vec<T>
}
}
}
- if sep.trailing_sep_allowed && kets.iter().any(|k| self.check(k)) {
+ if sep.trailing_sep_allowed && kets.iter().any(|k| {
+ match expect {
+ TokenExpectType::Expect => self.check(k),
+ TokenExpectType::NoExpect => self.token == **k,
+ }
+ }) {
break;
}
let e = if self.token.can_begin_expr()
&& !(self.token == token::OpenDelim(token::Brace)
&& self.restrictions.contains(
- RESTRICTION_NO_STRUCT_LITERAL)) {
+ Restrictions::NO_STRUCT_LITERAL)) {
Some(self.parse_expr()?)
} else {
None
// This is a struct literal, unless we're prohibited
// from parsing struct literals here.
let prohibited = self.restrictions.contains(
- RESTRICTION_NO_STRUCT_LITERAL
+ Restrictions::NO_STRUCT_LITERAL
);
if !prohibited {
return self.parse_struct_expr(lo, pth, attrs);
self.bump();
let e = self.parse_prefix_expr(None);
let (span, e) = self.interpolated_or_expr_span(e)?;
- (span, self.mk_unary(UnOp::Not, e))
+ (lo.to(span), self.mk_unary(UnOp::Not, e))
}
// Suggest `!` for bitwise negation when encountering a `~`
token::Tilde => {
err.span_label(span_of_tilde, "did you mean `!`?");
err.help("use `!` instead of `~` if you meant to perform bitwise negation");
err.emit();
- (span, self.mk_unary(UnOp::Not, e))
+ (lo.to(span), self.mk_unary(UnOp::Not, e))
}
token::BinOp(token::Minus) => {
self.bump();
let e = self.parse_prefix_expr(None);
let (span, e) = self.interpolated_or_expr_span(e)?;
- (span, self.mk_unary(UnOp::Neg, e))
+ (lo.to(span), self.mk_unary(UnOp::Neg, e))
}
token::BinOp(token::Star) => {
self.bump();
let e = self.parse_prefix_expr(None);
let (span, e) = self.interpolated_or_expr_span(e)?;
- (span, self.mk_unary(UnOp::Deref, e))
+ (lo.to(span), self.mk_unary(UnOp::Deref, e))
}
token::BinOp(token::And) | token::AndAnd => {
self.expect_and()?;
let m = self.parse_mutability();
let e = self.parse_prefix_expr(None);
let (span, e) = self.interpolated_or_expr_span(e)?;
- (span, ExprKind::AddrOf(m, e))
+ (lo.to(span), ExprKind::AddrOf(m, e))
}
token::Ident(..) if self.token.is_keyword(keywords::In) => {
self.bump();
let place = self.parse_expr_res(
- RESTRICTION_NO_STRUCT_LITERAL,
+ Restrictions::NO_STRUCT_LITERAL,
None,
)?;
let blk = self.parse_block()?;
let span = blk.span;
let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new());
- (span, ExprKind::InPlace(place, blk_expr))
+ (lo.to(span), ExprKind::InPlace(place, blk_expr))
}
token::Ident(..) if self.token.is_keyword(keywords::Box) => {
self.bump();
let e = self.parse_prefix_expr(None);
let (span, e) = self.interpolated_or_expr_span(e)?;
- (span, ExprKind::Box(e))
+ (lo.to(span), ExprKind::Box(e))
}
_ => return self.parse_dot_or_call_expr(Some(attrs))
};
let cur_op_span = self.span;
let restrictions = if op.is_assign_like() {
- self.restrictions & RESTRICTION_NO_STRUCT_LITERAL
+ self.restrictions & Restrictions::NO_STRUCT_LITERAL
} else {
self.restrictions
};
let rhs = match op.fixity() {
Fixity::Right => self.with_res(
- restrictions - RESTRICTION_STMT_EXPR,
+ restrictions - Restrictions::STMT_EXPR,
|this| {
this.parse_assoc_expr_with(op.precedence(),
LhsExpr::NotYetParsed)
}),
Fixity::Left => self.with_res(
- restrictions - RESTRICTION_STMT_EXPR,
+ restrictions - Restrictions::STMT_EXPR,
|this| {
this.parse_assoc_expr_with(op.precedence() + 1,
LhsExpr::NotYetParsed)
// We currently have no non-associative operators that are not handled above by
// the special cases. The code is here only for future convenience.
Fixity::None => self.with_res(
- restrictions - RESTRICTION_STMT_EXPR,
+ restrictions - Restrictions::STMT_EXPR,
|this| {
this.parse_assoc_expr_with(op.precedence() + 1,
LhsExpr::NotYetParsed)
if self.token.can_begin_expr() {
// parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
if self.token == token::OpenDelim(token::Brace) {
- return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL);
+ return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
}
true
} else {
return self.parse_if_let_expr(attrs);
}
let lo = self.prev_span;
- let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+ let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
// verify that the last statement is either an implicit return (no `;`) or an explicit
self.expect_keyword(keywords::Let)?;
let pat = self.parse_pat()?;
self.expect(&token::Eq)?;
- let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+ let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let thn = self.parse_block()?;
let (hi, els) = if self.eat_keyword(keywords::Else) {
let expr = self.parse_else_expr()?;
let decl_hi = self.prev_span;
let body = match decl.output {
FunctionRetTy::Default(_) => {
- let restrictions = self.restrictions - RESTRICTION_STMT_EXPR;
+ let restrictions = self.restrictions - Restrictions::STMT_EXPR;
self.parse_expr_res(restrictions, None)?
},
_ => {
let pat = self.parse_pat()?;
self.expect_keyword(keywords::In)?;
- let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+ let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
if self.token.is_keyword(keywords::Let) {
return self.parse_while_let_expr(opt_ident, span_lo, attrs);
}
- let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+ let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let span = span_lo.to(body.span);
self.expect_keyword(keywords::Let)?;
let pat = self.parse_pat()?;
self.expect(&token::Eq)?;
- let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+ let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let span = span_lo.to(body.span);
fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let match_span = self.prev_span;
let lo = self.prev_span;
- let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL,
+ let discriminant = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL,
None)?;
if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
if self.token == token::Token::Semi {
None
};
self.expect(&token::FatArrow)?;
- let expr = self.parse_expr_res(RESTRICTION_STMT_EXPR, None)?;
+ let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)?;
let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
&& self.token != token::CloseDelim(token::Brace);
self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) &&
// prevent `while catch {} {}`, `if catch {} {} else {}`, etc.
- !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL)
+ !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
}
fn is_union_item(&self) -> bool {
self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new())
};
- let expr = self.with_res(RESTRICTION_STMT_EXPR, |this| {
+ let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
})?;
// Remainder are line-expr stmts.
let e = self.parse_expr_res(
- RESTRICTION_STMT_EXPR, Some(attrs.into()))?;
+ Restrictions::STMT_EXPR, Some(attrs.into()))?;
Stmt {
id: ast::DUMMY_NODE_ID,
span: lo.to(e.span),
/// Is this expression a successfully-parsed statement?
fn expr_is_complete(&mut self, e: &Expr) -> bool {
- self.restrictions.contains(RESTRICTION_STMT_EXPR) &&
+ self.restrictions.contains(Restrictions::STMT_EXPR) &&
!classify::expr_requires_semi_to_be_stmt(e)
}
Vec::new()
} else {
self.expect(&token::BinOp(token::Or))?;
- let args = self.parse_seq_to_before_end(
- &token::BinOp(token::Or),
+ let args = self.parse_seq_to_before_tokens(
+ &[&token::BinOp(token::Or), &token::OrOr],
SeqSep::trailing_allowed(token::Comma),
- |p| p.parse_fn_block_arg()
+ TokenExpectType::NoExpect,
+ |p| p.parse_fn_block_arg(),
+ |mut e| e.emit()
);
- self.expect(&token::BinOp(token::Or))?;
+ self.expect_or()?;
args
}
};