use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use ast::{Public, Unsafety};
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
-use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
+use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, Block};
use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
-use ast::{Constness, ConstImplItem, ConstTraitItem, Crate, CrateConfig};
+use ast::{Constness, ConstTraitItem, Crate, CrateConfig};
use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn};
use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
use ast::{MutImmutable, MutMutable, Mac_};
use ast::{MutTy, BiMul, Mutability};
-use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
+use ast::{NamedField, UnNeg, NoReturn, UnNot};
use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
-use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti};
-use ast::PatWildSingle;
+use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild};
use ast::{PolyTraitRef, QSelf};
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
use ast::{StmtExpr, StmtSemi, StmtMac, VariantData, StructField};
use ast::{BiSub, StrStyle};
use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
-use ast::{TtDelimited, TtSequence, TtToken};
-use ast::{Ty, Ty_, TypeBinding};
-use ast::{TyMac};
+use ast::{Ty, Ty_, TypeBinding, TyMac};
use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr};
use ast::{TyRptr, TyTup, TyU32, TyVec};
-use ast::{TypeImplItem, TypeTraitItem};
+use ast::TypeTraitItem;
use ast::{UnnamedField, UnsafeBlock};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
+use attr::{ThinAttributes, ThinAttributesExt, AttributesExt};
use ast;
-use ast_util::{self, AS_PREC, ident_to_path, operator_prec};
+use ast_util::{self, ident_to_path};
use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap};
use diagnostic;
use ext::tt::macro_parser;
use parse;
-use parse::attr::ParserAttr;
use parse::classify;
use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
use parse::lexer::{Reader, TokenAndSpan};
use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
use parse::token::{keywords, special_idents, SpecialMacroVar};
use parse::{new_sub_parser_from_file, ParseSess};
+use util::parser::{AssocOp, Fixity};
use print::pprust;
use ptr::P;
use owned_slice::OwnedSlice;
Modified,
}
+/// `pub` should be parsed in struct fields and not parsed in variant fields
+#[derive(Clone, Copy, PartialEq)]
+pub enum ParsePub {
+ Yes,
+ No,
+}
+
/// Possibly accept an `token::Interpolated` expression (a pre-parsed expression
/// dropped into the token stream, which happens while parsing the result of
/// macro expansion). Placement of these is not as complex as I feared it would
_ => unreachable!()
};
let span = $p.span;
- Some($p.mk_expr(span.lo, span.hi, ExprPath(None, pt)))
+ Some($p.mk_expr(span.lo, span.hi, ExprPath(None, pt), None))
}
token::Interpolated(token::NtBlock(_)) => {
// FIXME: The following avoids an issue with lexical borrowck scopes,
_ => unreachable!()
};
let span = $p.span;
- Some($p.mk_expr(span.lo, span.hi, ExprBlock(b)))
+ Some($p.mk_expr(span.lo, span.hi, ExprBlock(b), None))
}
_ => None
};
pub help_msg: String,
}
+pub enum LhsExpr {
+ NotYetParsed,
+ AttributesParsed(ThinAttributes),
+ AlreadyParsed(P<Expr>),
+}
+
+impl From<Option<ThinAttributes>> for LhsExpr {
+ fn from(o: Option<ThinAttributes>) -> Self {
+ if let Some(attrs) = o {
+ LhsExpr::AttributesParsed(attrs)
+ } else {
+ LhsExpr::NotYetParsed
+ }
+ }
+}
+
+impl From<P<Expr>> for LhsExpr {
+ fn from(expr: P<Expr>) -> Self {
+ LhsExpr::AlreadyParsed(expr)
+ }
+}
impl<'a> Parser<'a> {
pub fn new(sess: &'a ParseSess,
}
}
- // Panicing fns (for now!)
- // This is so that the quote_*!() syntax extensions
- pub fn parse_expr(&mut self) -> P<Expr> {
- panictry!(self.parse_expr_nopanic())
- }
-
- pub fn parse_item(&mut self) -> Option<P<Item>> {
- panictry!(self.parse_item_nopanic())
- }
-
- pub fn parse_pat(&mut self) -> P<Pat> {
- panictry!(self.parse_pat_nopanic())
- }
-
- pub fn parse_arm(&mut self) -> Arm {
- panictry!(self.parse_arm_nopanic())
- }
-
- pub fn parse_ty(&mut self) -> P<Ty> {
- panictry!(self.parse_ty_nopanic())
- }
-
- pub fn parse_stmt(&mut self) -> Option<P<Stmt>> {
- panictry!(self.parse_stmt_nopanic())
- }
-
/// Convert a token to a string using self's reader
pub fn token_to_string(token: &token::Token) -> String {
pprust::token_to_string(token)
seq_sep_none(),
|p| -> PResult<P<TraitItem>> {
maybe_whole!(no_clone p, NtTraitItem);
- let mut attrs = p.parse_outer_attributes();
+ let mut attrs = try!(p.parse_outer_attributes());
let lo = p.span.lo;
let (name, node) = if try!(p.eat_keyword(keywords::Type)) {
let ty = try!(p.parse_ty_sum());
let default = if p.check(&token::Eq) {
try!(p.bump());
- let expr = try!(p.parse_expr_nopanic());
+ let expr = try!(p.parse_expr());
try!(p.commit_expr_expecting(&expr, token::Semi));
Some(expr)
} else {
/// Parse a possibly mutable type
pub fn parse_mt(&mut self) -> PResult<MutTy> {
let mutbl = try!(self.parse_mutability());
- let t = try!(self.parse_ty_nopanic());
+ let t = try!(self.parse_ty());
Ok(MutTy { ty: t, mutbl: mutbl })
}
if try!(self.eat(&token::Not) ){
Ok(NoReturn(self.last_span))
} else {
- Ok(Return(try!(self.parse_ty_nopanic())))
+ Ok(Return(try!(self.parse_ty())))
}
} else {
let pos = self.span.lo;
/// Parse a type in a context where `T1+T2` is allowed.
pub fn parse_ty_sum(&mut self) -> PResult<P<Ty>> {
let lo = self.span.lo;
- let lhs = try!(self.parse_ty_nopanic());
+ let lhs = try!(self.parse_ty());
if !try!(self.eat(&token::BinOp(token::Plus)) ){
return Ok(lhs);
}
/// Parse a type.
- pub fn parse_ty_nopanic(&mut self) -> PResult<P<Ty>> {
+ pub fn parse_ty(&mut self) -> PResult<P<Ty>> {
maybe_whole!(no_clone self, NtTy);
let lo = self.span.lo;
// TYPEOF
// In order to not be ambiguous, the type must be surrounded by parens.
try!(self.expect(&token::OpenDelim(token::Paren)));
- let e = try!(self.parse_expr_nopanic());
+ let e = try!(self.parse_expr());
try!(self.expect(&token::CloseDelim(token::Paren)));
TyTypeof(e)
} else if try!(self.eat_lt()) {
known as `*const T`");
MutImmutable
};
- let t = try!(self.parse_ty_nopanic());
+ let t = try!(self.parse_ty());
Ok(MutTy { ty: t, mutbl: mutbl })
}
/// This version of parse arg doesn't necessarily require
/// identifier names.
pub fn parse_arg_general(&mut self, require_name: bool) -> PResult<Arg> {
+ maybe_whole!(no_clone self, NtArg);
+
let pat = if require_name || self.is_named_argument() {
debug!("parse_arg_general parse_pat (require_name:{})",
require_name);
- let pat = try!(self.parse_pat_nopanic());
+ let pat = try!(self.parse_pat());
try!(self.expect(&token::Colon));
pat
/// Parse an argument in a lambda header e.g. |arg, arg|
pub fn parse_fn_block_arg(&mut self) -> PResult<Arg> {
- let pat = try!(self.parse_pat_nopanic());
+ let pat = try!(self.parse_pat());
let t = if try!(self.eat(&token::Colon) ){
try!(self.parse_ty_sum())
} else {
pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<Option<P<ast::Expr>>> {
if self.check(&token::Semi) {
try!(self.bump());
- Ok(Some(try!(self.parse_expr_nopanic())))
+ Ok(Some(try!(self.parse_expr())))
} else {
Ok(None)
}
}
/// matches '-' lit | lit
- pub fn parse_literal_maybe_minus(&mut self) -> PResult<P<Expr>> {
+ pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<P<Expr>> {
let minus_lo = self.span.lo;
let minus_present = try!(self.eat(&token::BinOp(token::Minus)));
-
let lo = self.span.lo;
let literal = P(try!(self.parse_lit()));
let hi = self.last_span.hi;
- let expr = self.mk_expr(lo, hi, ExprLit(literal));
+ let expr = self.mk_expr(lo, hi, ExprLit(literal), None);
if minus_present {
let minus_hi = self.last_span.hi;
let unary = self.mk_unary(UnNeg, expr);
- Ok(self.mk_expr(minus_lo, minus_hi, unary))
+ Ok(self.mk_expr(minus_lo, minus_hi, unary, None))
} else {
Ok(expr)
}
|p| p.parse_ty_sum()));
let output_ty = if try!(self.eat(&token::RArrow) ){
- Some(try!(self.parse_ty_nopanic()))
+ Some(try!(self.parse_ty()))
} else {
None
};
});
}
_ => {
- return Err(self.fatal(&format!("expected a lifetime name")));
+ return Err(self.fatal("expected a lifetime name"));
}
}
}
let i = try!(self.parse_ident());
let hi = self.last_span.hi;
try!(self.expect(&token::Colon));
- let e = try!(self.parse_expr_nopanic());
+ let e = try!(self.parse_expr());
Ok(ast::Field {
ident: spanned(lo, hi, i),
span: mk_sp(lo, e.span.hi),
})
}
- pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: Expr_) -> P<Expr> {
+ pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos,
+ node: Expr_, attrs: ThinAttributes) -> P<Expr> {
P(Expr {
id: ast::DUMMY_NODE_ID,
node: node,
span: mk_sp(lo, hi),
+ attrs: attrs,
})
}
ExprAssignOp(binop, lhs, rhs)
}
- pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, m: Mac_) -> P<Expr> {
+ pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos,
+ m: Mac_, attrs: ThinAttributes) -> P<Expr> {
P(Expr {
id: ast::DUMMY_NODE_ID,
node: ExprMac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}),
span: mk_sp(lo, hi),
+ attrs: attrs,
})
}
- pub fn mk_lit_u32(&mut self, i: u32) -> P<Expr> {
+ pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinAttributes) -> P<Expr> {
let span = &self.span;
let lv_lit = P(codemap::Spanned {
node: LitInt(i as u64, ast::UnsignedIntLit(TyU32)),
id: ast::DUMMY_NODE_ID,
node: ExprLit(lv_lit),
span: *span,
+ attrs: attrs,
})
}
/// At the bottom (top?) of the precedence hierarchy,
/// parse things like parenthesized exprs,
/// macros, return, etc.
- pub fn parse_bottom_expr(&mut self) -> PResult<P<Expr>> {
+ ///
+ /// NB: This does not parse outer attributes,
+ /// and is private because it only works
+ /// correctly if called from parse_dot_or_call_expr().
+ fn parse_bottom_expr(&mut self) -> PResult<P<Expr>> {
maybe_whole_expr!(self);
+ // Outer attributes are already parsed and will be
+ // added to the return value after the fact.
+ //
+ // Therefore, prevent sub-parser from parsing
+ // attributes by giving them a empty "already parsed" list.
+ let mut attrs = None;
+
let lo = self.span.lo;
let mut hi = self.span.hi;
token::OpenDelim(token::Paren) => {
try!(self.bump());
+ let attrs = try!(self.parse_inner_attributes())
+ .into_thin_attrs()
+ .prepend(attrs);
+
// (e) is parenthesized e
// (e,) is a tuple with only one field, e
let mut es = vec![];
let mut trailing_comma = false;
while self.token != token::CloseDelim(token::Paren) {
- es.push(try!(self.parse_expr_nopanic()));
+ es.push(try!(self.parse_expr()));
try!(self.commit_expr(&**es.last().unwrap(), &[],
&[token::Comma, token::CloseDelim(token::Paren)]));
if self.check(&token::Comma) {
hi = self.last_span.hi;
return if es.len() == 1 && !trailing_comma {
- Ok(self.mk_expr(lo, hi, ExprParen(es.into_iter().nth(0).unwrap())))
+ Ok(self.mk_expr(lo, hi, ExprParen(es.into_iter().nth(0).unwrap()), attrs))
} else {
- Ok(self.mk_expr(lo, hi, ExprTup(es)))
+ Ok(self.mk_expr(lo, hi, ExprTup(es), attrs))
}
},
token::OpenDelim(token::Brace) => {
- return self.parse_block_expr(lo, DefaultBlock);
+ return self.parse_block_expr(lo, DefaultBlock, attrs);
},
token::BinOp(token::Or) | token::OrOr => {
let lo = self.span.lo;
- return self.parse_lambda_expr(lo, CaptureByRef);
+ return self.parse_lambda_expr(lo, CaptureByRef, attrs);
},
token::Ident(id @ ast::Ident {
name: token::SELF_KEYWORD_NAME,
token::OpenDelim(token::Bracket) => {
try!(self.bump());
+ let inner_attrs = try!(self.parse_inner_attributes())
+ .into_thin_attrs();
+ attrs.update(|attrs| attrs.append(inner_attrs));
+
if self.check(&token::CloseDelim(token::Bracket)) {
// Empty vector.
try!(self.bump());
ex = ExprVec(Vec::new());
} else {
// Nonempty vector.
- let first_expr = try!(self.parse_expr_nopanic());
+ let first_expr = try!(self.parse_expr());
if self.check(&token::Semi) {
// Repeating array syntax: [ 0; 512 ]
try!(self.bump());
- let count = try!(self.parse_expr_nopanic());
+ let count = try!(self.parse_expr());
try!(self.expect(&token::CloseDelim(token::Bracket)));
ex = ExprRepeat(first_expr, count);
} else if self.check(&token::Comma) {
let remaining_exprs = try!(self.parse_seq_to_end(
&token::CloseDelim(token::Bracket),
seq_sep_trailing_allowed(token::Comma),
- |p| Ok(try!(p.parse_expr_nopanic()))
+ |p| Ok(try!(p.parse_expr()))
));
let mut exprs = vec!(first_expr);
exprs.extend(remaining_exprs);
let (qself, path) =
try!(self.parse_qualified_path(LifetimeAndTypesWithColons));
hi = path.span.hi;
- return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
+ return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path), attrs));
}
if try!(self.eat_keyword(keywords::Move) ){
let lo = self.last_span.lo;
- return self.parse_lambda_expr(lo, CaptureByValue);
+ return self.parse_lambda_expr(lo, CaptureByValue, attrs);
}
if try!(self.eat_keyword(keywords::If)) {
- return self.parse_if_expr();
+ return self.parse_if_expr(attrs);
}
if try!(self.eat_keyword(keywords::For) ){
let lo = self.last_span.lo;
- return self.parse_for_expr(None, lo);
+ return self.parse_for_expr(None, lo, attrs);
}
if try!(self.eat_keyword(keywords::While) ){
let lo = self.last_span.lo;
- return self.parse_while_expr(None, lo);
+ return self.parse_while_expr(None, lo, attrs);
}
if self.token.is_lifetime() {
let lifetime = self.get_lifetime();
try!(self.bump());
try!(self.expect(&token::Colon));
if try!(self.eat_keyword(keywords::While) ){
- return self.parse_while_expr(Some(lifetime), lo)
+ return self.parse_while_expr(Some(lifetime), lo, attrs)
}
if try!(self.eat_keyword(keywords::For) ){
- return self.parse_for_expr(Some(lifetime), lo)
+ return self.parse_for_expr(Some(lifetime), lo, attrs)
}
if try!(self.eat_keyword(keywords::Loop) ){
- return self.parse_loop_expr(Some(lifetime), lo)
+ return self.parse_loop_expr(Some(lifetime), lo, attrs)
}
return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
}
if try!(self.eat_keyword(keywords::Loop) ){
let lo = self.last_span.lo;
- return self.parse_loop_expr(None, lo);
+ return self.parse_loop_expr(None, lo, attrs);
}
if try!(self.eat_keyword(keywords::Continue) ){
let ex = if self.token.is_lifetime() {
ExprAgain(None)
};
let hi = self.last_span.hi;
- return Ok(self.mk_expr(lo, hi, ex));
+ return Ok(self.mk_expr(lo, hi, ex, attrs));
}
if try!(self.eat_keyword(keywords::Match) ){
- return self.parse_match_expr();
+ return self.parse_match_expr(attrs);
}
if try!(self.eat_keyword(keywords::Unsafe) ){
return self.parse_block_expr(
lo,
- UnsafeBlock(ast::UserProvided));
+ UnsafeBlock(ast::UserProvided),
+ attrs);
}
if try!(self.eat_keyword(keywords::Return) ){
if self.token.can_begin_expr() {
- let e = try!(self.parse_expr_nopanic());
+ let e = try!(self.parse_expr());
hi = e.span.hi;
ex = ExprRet(Some(e));
} else {
return Ok(self.mk_mac_expr(lo,
hi,
- Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }));
+ Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT },
+ attrs));
}
if self.check(&token::OpenDelim(token::Brace)) {
// This is a struct literal, unless we're prohibited
let mut fields = Vec::new();
let mut base = None;
+ let attrs = attrs.append(
+ try!(self.parse_inner_attributes())
+ .into_thin_attrs());
+
while self.token != token::CloseDelim(token::Brace) {
if try!(self.eat(&token::DotDot) ){
- base = Some(try!(self.parse_expr_nopanic()));
+ base = Some(try!(self.parse_expr()));
break;
}
hi = self.span.hi;
try!(self.expect(&token::CloseDelim(token::Brace)));
ex = ExprStruct(pth, fields, base);
- return Ok(self.mk_expr(lo, hi, ex));
+ return Ok(self.mk_expr(lo, hi, ex, attrs));
}
}
}
}
- return Ok(self.mk_expr(lo, hi, ex));
+ return Ok(self.mk_expr(lo, hi, ex, attrs));
+ }
+
+ fn parse_or_use_outer_attributes(&mut self,
+ already_parsed_attrs: Option<ThinAttributes>)
+ -> PResult<ThinAttributes> {
+ if let Some(attrs) = already_parsed_attrs {
+ Ok(attrs)
+ } else {
+ self.parse_outer_attributes().map(|a| a.into_thin_attrs())
+ }
}
/// Parse a block or unsafe block
- pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode)
+ pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode,
+ attrs: ThinAttributes)
-> PResult<P<Expr>> {
+
+ let outer_attrs = attrs;
try!(self.expect(&token::OpenDelim(token::Brace)));
+
+ let inner_attrs = try!(self.parse_inner_attributes()).into_thin_attrs();
+ let attrs = outer_attrs.append(inner_attrs);
+
let blk = try!(self.parse_block_tail(lo, blk_mode));
- return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)));
+ return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk), attrs));
}
/// parse a.b or a(13) or a[4] or just a
- pub fn parse_dot_or_call_expr(&mut self) -> PResult<P<Expr>> {
+ pub fn parse_dot_or_call_expr(&mut self,
+ already_parsed_attrs: Option<ThinAttributes>)
+ -> PResult<P<Expr>> {
+ let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs));
+
let b = try!(self.parse_bottom_expr());
- self.parse_dot_or_call_expr_with(b)
+ self.parse_dot_or_call_expr_with(b, attrs)
+ }
+
+ pub fn parse_dot_or_call_expr_with(&mut self,
+ e0: P<Expr>,
+ attrs: ThinAttributes)
+ -> PResult<P<Expr>> {
+ // Stitch the list of outer attributes onto the return value.
+ // A little bit ugly, but the best way given the current code
+ // structure
+ self.parse_dot_or_call_expr_with_(e0)
+ .map(|expr|
+ expr.map(|mut expr| {
+ expr.attrs.update(|a| a.prepend(attrs));
+ match expr.node {
+ ExprIf(..) | ExprIfLet(..) => {
+ if !expr.attrs.as_attr_slice().is_empty() {
+ // Just point to the first attribute in there...
+ let span = expr.attrs.as_attr_slice()[0].span;
+
+ self.span_err(span,
+ "attributes are not yet allowed on `if` \
+ expressions");
+ }
+ }
+ _ => {}
+ }
+ expr
+ })
+ )
}
- pub fn parse_dot_or_call_expr_with(&mut self, e0: P<Expr>) -> PResult<P<Expr>> {
+ fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>) -> PResult<P<Expr>> {
let mut e = e0;
let lo = e.span.lo;
let mut hi;
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma),
- |p| Ok(try!(p.parse_expr_nopanic()))
+ |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);
+ e = self.mk_expr(lo, hi, nd, None);
}
_ => {
if !tys.is_empty() {
let id = spanned(dot, hi, i);
let field = self.mk_field(e, id);
- e = self.mk_expr(lo, hi, field);
+ e = self.mk_expr(lo, hi, field, None);
}
}
}
Some(n) => {
let id = spanned(dot, hi, n);
let field = self.mk_tup_field(e, id);
- e = self.mk_expr(lo, hi, field);
+ e = self.mk_expr(lo, hi, field, None);
}
None => {
let last_span = self.last_span;
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma),
- |p| Ok(try!(p.parse_expr_nopanic()))
+ |p| Ok(try!(p.parse_expr()))
));
hi = self.last_span.hi;
let nd = self.mk_call(e, es);
- e = self.mk_expr(lo, hi, nd);
+ e = self.mk_expr(lo, hi, nd, None);
}
// expr[...]
// Could be either an index expression or a slicing expression.
token::OpenDelim(token::Bracket) => {
try!(self.bump());
- let ix = try!(self.parse_expr_nopanic());
+ let ix = try!(self.parse_expr());
hi = self.span.hi;
try!(self.commit_expr_expecting(&*ix, token::CloseDelim(token::Bracket)));
let index = self.mk_index(e, ix);
- e = self.mk_expr(lo, hi, index)
+ e = self.mk_expr(lo, hi, index, None)
}
_ => return Ok(e)
}
));
let (sep, repeat) = try!(self.parse_sep_and_kleene_op());
let name_num = macro_parser::count_names(&seq);
- return Ok(TtSequence(mk_sp(sp.lo, seq_span.hi),
+ return Ok(TokenTree::Sequence(mk_sp(sp.lo, seq_span.hi),
Rc::new(SequenceRepetition {
tts: seq,
separator: sep,
})));
} else if self.token.is_keyword_allow_following_colon(keywords::Crate) {
try!(self.bump());
- return Ok(TtToken(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar)));
+ return Ok(TokenTree::Token(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar)));
} else {
sp = mk_sp(sp.lo, self.span.hi);
let namep = match self.token { token::Ident(_, p) => p, _ => token::Plain };
sp = mk_sp(sp.lo, self.span.hi);
let kindp = match self.token { token::Ident(_, p) => p, _ => token::Plain };
let nt_kind = try!(self.parse_ident());
- Ok(TtToken(sp, MatchNt(name, nt_kind, namep, kindp)))
+ Ok(TokenTree::Token(sp, MatchNt(name, nt_kind, namep, kindp)))
} else {
- Ok(TtToken(sp, SubstNt(name, namep)))
+ Ok(TokenTree::Token(sp, SubstNt(name, namep)))
}
}
/// parse a single token tree from the input.
pub fn parse_token_tree(&mut self) -> PResult<TokenTree> {
// FIXME #6994: currently, this is too eager. It
- // parses token trees but also identifies TtSequence's
+ // parses token trees but also identifies TokenType::Sequence's
// and token::SubstNt's; it's too early to know yet
// whether something will be a nonterminal or a seq
// yet.
p.parse_unquoted()
}
_ => {
- Ok(TtToken(p.span, try!(p.bump_and_get())))
+ Ok(TokenTree::Token(p.span, try!(p.bump_and_get())))
}
}
}
// Expand to cover the entire delimited token tree
let span = Span { hi: close_span.hi, ..pre_span };
- Ok(TtDelimited(span, Rc::new(Delimited {
+ Ok(TokenTree::Delimited(span, Rc::new(Delimited {
delim: delim,
open_span: open_span,
tts: tts,
Ok(tts)
}
- /// Parse a prefix-operator expr
- pub fn parse_prefix_expr(&mut self) -> PResult<P<Expr>> {
+ /// Parse a prefix-unary-operator expr
+ pub fn parse_prefix_expr(&mut self,
+ already_parsed_attrs: Option<ThinAttributes>)
+ -> PResult<P<Expr>> {
+ let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs));
let lo = self.span.lo;
let hi;
-
// Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr()
- let ex;
- match self.token {
- token::Not => {
- try!(self.bump());
- let e = try!(self.parse_prefix_expr());
- hi = e.span.hi;
- ex = self.mk_unary(UnNot, e);
- }
- token::BinOp(token::Minus) => {
- try!(self.bump());
- let e = try!(self.parse_prefix_expr());
- hi = e.span.hi;
- ex = self.mk_unary(UnNeg, e);
- }
- token::BinOp(token::Star) => {
- try!(self.bump());
- let e = try!(self.parse_prefix_expr());
- hi = e.span.hi;
- ex = self.mk_unary(UnDeref, e);
- }
- token::BinOp(token::And) | token::AndAnd => {
- try!(self.expect_and());
- let m = try!(self.parse_mutability());
- let e = try!(self.parse_prefix_expr());
- hi = e.span.hi;
- ex = ExprAddrOf(m, e);
- }
- token::Ident(..) if self.token.is_keyword(keywords::In) => {
- try!(self.bump());
- let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
- let blk = try!(self.parse_block());
- hi = blk.span.hi;
- let blk_expr = self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk));
- ex = ExprInPlace(place, blk_expr);
- }
- token::Ident(..) if self.token.is_keyword(keywords::Box) => {
- try!(self.bump());
- let subexpression = try!(self.parse_prefix_expr());
- hi = subexpression.span.hi;
- ex = ExprBox(subexpression);
- }
- _ => return self.parse_dot_or_call_expr()
- }
- return Ok(self.mk_expr(lo, hi, ex));
+ let ex = match self.token {
+ token::Not => {
+ try!(self.bump());
+ let e = try!(self.parse_prefix_expr(None));
+ hi = e.span.hi;
+ self.mk_unary(UnNot, e)
+ }
+ token::BinOp(token::Minus) => {
+ try!(self.bump());
+ let e = try!(self.parse_prefix_expr(None));
+ hi = e.span.hi;
+ self.mk_unary(UnNeg, e)
+ }
+ token::BinOp(token::Star) => {
+ try!(self.bump());
+ let e = try!(self.parse_prefix_expr(None));
+ hi = e.span.hi;
+ self.mk_unary(UnDeref, e)
+ }
+ token::BinOp(token::And) | token::AndAnd => {
+ try!(self.expect_and());
+ let m = try!(self.parse_mutability());
+ let e = try!(self.parse_prefix_expr(None));
+ hi = e.span.hi;
+ ExprAddrOf(m, e)
+ }
+ token::Ident(..) if self.token.is_keyword(keywords::In) => {
+ try!(self.bump());
+ let place = try!(self.parse_expr_res(
+ Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
+ None,
+ ));
+ let blk = try!(self.parse_block());
+ let span = blk.span;
+ hi = span.hi;
+ let blk_expr = self.mk_expr(span.lo, span.hi, ExprBlock(blk),
+ None);
+ ExprInPlace(place, blk_expr)
+ }
+ token::Ident(..) if self.token.is_keyword(keywords::Box) => {
+ try!(self.bump());
+ let subexpression = try!(self.parse_prefix_expr(None));
+ hi = subexpression.span.hi;
+ ExprBox(subexpression)
+ }
+ _ => return self.parse_dot_or_call_expr(Some(attrs))
+ };
+ return Ok(self.mk_expr(lo, hi, ex, attrs));
}
- /// Parse an expression of binops
- pub fn parse_binops(&mut self) -> PResult<P<Expr>> {
- let prefix_expr = try!(self.parse_prefix_expr());
- self.parse_more_binops(prefix_expr, 0)
+ /// Parse an associative expression
+ ///
+ /// This parses an expression accounting for associativity and precedence of the operators in
+ /// the expression.
+ pub fn parse_assoc_expr(&mut self,
+ already_parsed_attrs: Option<ThinAttributes>)
+ -> PResult<P<Expr>> {
+ self.parse_assoc_expr_with(0, already_parsed_attrs.into())
}
- /// Parse an expression of binops of at least min_prec precedence
- pub fn parse_more_binops(&mut self, lhs: P<Expr>, min_prec: usize) -> PResult<P<Expr>> {
- if self.expr_is_complete(&*lhs) { return Ok(lhs); }
-
+ /// Parse an associative expression with operators of at least `min_prec` precedence
+ pub fn parse_assoc_expr_with(&mut self,
+ min_prec: usize,
+ lhs: LhsExpr)
+ -> PResult<P<Expr>> {
+ let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs {
+ expr
+ } else {
+ let attrs = match lhs {
+ LhsExpr::AttributesParsed(attrs) => Some(attrs),
+ _ => None,
+ };
+ if self.token == token::DotDot {
+ return self.parse_prefix_range_expr(attrs);
+ } else {
+ try!(self.parse_prefix_expr(attrs))
+ }
+ };
+ if self.expr_is_complete(&*lhs) {
+ // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
+ return Ok(lhs);
+ }
self.expected_tokens.push(TokenType::Operator);
+ while let Some(op) = AssocOp::from_token(&self.token) {
+ let cur_op_span = self.span;
+ let restrictions = if op.is_assign_like() {
+ self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL
+ } else {
+ self.restrictions
+ };
+ if op.precedence() < min_prec {
+ break;
+ }
+ try!(self.bump());
+ if op.is_comparison() {
+ self.check_no_chained_comparison(&*lhs, &op);
+ }
+ // Special cases:
+ if op == AssocOp::As {
+ let rhs = try!(self.parse_ty());
+ lhs = self.mk_expr(lhs.span.lo, rhs.span.hi,
+ ExprCast(lhs, rhs), None);
+ continue
+ } else if op == AssocOp::DotDot {
+ // If we didn’t have to handle `x..`, it would be pretty easy to generalise
+ // it to the Fixity::None code.
+ //
+ // We have 2 alternatives here: `x..y` and `x..` The other two variants are
+ // handled with `parse_prefix_range_expr` call above.
+ let rhs = if self.is_at_start_of_range_notation_rhs() {
+ self.parse_assoc_expr_with(op.precedence() + 1,
+ LhsExpr::NotYetParsed).ok()
+ } else {
+ None
+ };
+ let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs {
+ x.span
+ } else {
+ cur_op_span
+ });
+ let r = self.mk_range(Some(lhs), rhs);
+ lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
+ break
+ }
- let cur_op_span = self.span;
- let cur_opt = self.token.to_binop();
- match cur_opt {
- Some(cur_op) => {
- if ast_util::is_comparison_binop(cur_op) {
- self.check_no_chained_comparison(&*lhs, cur_op)
- }
- let cur_prec = operator_prec(cur_op);
- if cur_prec >= min_prec {
- try!(self.bump());
- let expr = try!(self.parse_prefix_expr());
- let rhs = try!(self.parse_more_binops(expr, cur_prec + 1));
- let lhs_span = lhs.span;
- let rhs_span = rhs.span;
- let binary = self.mk_binary(codemap::respan(cur_op_span, cur_op), lhs, rhs);
- let bin = self.mk_expr(lhs_span.lo, rhs_span.hi, binary);
- self.parse_more_binops(bin, min_prec)
- } else {
- Ok(lhs)
+
+ let rhs = try!(match op.fixity() {
+ Fixity::Right => self.with_res(restrictions, |this|{
+ this.parse_assoc_expr_with(op.precedence(), LhsExpr::NotYetParsed)
+ }),
+ Fixity::Left => self.with_res(restrictions, |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, |this|{
+ this.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed)
+ }),
+ });
+
+ lhs = match op {
+ AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide |
+ AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor |
+ AssocOp::BitAnd | AssocOp::BitOr | AssocOp::ShiftLeft | AssocOp::ShiftRight |
+ AssocOp::Equal | AssocOp::Less | AssocOp::LessEqual | AssocOp::NotEqual |
+ AssocOp::Greater | AssocOp::GreaterEqual => {
+ let ast_op = op.to_ast_binop().unwrap();
+ let (lhs_span, rhs_span) = (lhs.span, rhs.span);
+ let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs);
+ self.mk_expr(lhs_span.lo, rhs_span.hi, binary, None)
}
- }
- None => {
- if AS_PREC >= min_prec && try!(self.eat_keyword_noexpect(keywords::As) ){
- let rhs = try!(self.parse_ty_nopanic());
- let _as = self.mk_expr(lhs.span.lo,
- rhs.span.hi,
- ExprCast(lhs, rhs));
- self.parse_more_binops(_as, min_prec)
- } else {
- Ok(lhs)
+ AssocOp::Assign =>
+ self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs), None),
+ AssocOp::Inplace =>
+ self.mk_expr(lhs.span.lo, rhs.span.hi, ExprInPlace(lhs, rhs), None),
+ AssocOp::AssignOp(k) => {
+ let aop = match k {
+ token::Plus => BiAdd,
+ token::Minus => BiSub,
+ token::Star => BiMul,
+ token::Slash => BiDiv,
+ token::Percent => BiRem,
+ token::Caret => BiBitXor,
+ token::And => BiBitAnd,
+ token::Or => BiBitOr,
+ token::Shl => BiShl,
+ token::Shr => BiShr
+ };
+ let (lhs_span, rhs_span) = (lhs.span, rhs.span);
+ let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
+ self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None)
}
- }
+ AssocOp::As | AssocOp::DotDot => self.bug("As or DotDot branch reached")
+ };
+
+ if op.fixity() == Fixity::None { break }
}
+ Ok(lhs)
}
/// Produce an error if comparison operators are chained (RFC #558).
/// We only need to check lhs, not rhs, because all comparison ops
/// have same precedence and are left-associative
- fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: ast::BinOp_) {
- debug_assert!(ast_util::is_comparison_binop(outer_op));
+ fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) {
+ debug_assert!(outer_op.is_comparison());
match lhs.node {
ExprBinary(op, _, _) if ast_util::is_comparison_binop(op.node) => {
// respan to include both operators
let op_span = mk_sp(op.span.lo, self.span.hi);
self.span_err(op_span,
"chained comparison operators require parentheses");
- if op.node == BiLt && outer_op == BiGt {
+ if op.node == BiLt && *outer_op == AssocOp::Greater {
self.fileline_help(op_span,
"use `::<...>` instead of `<...>` if you meant to specify type arguments");
}
}
}
- /// Parse an assignment expression....
- /// actually, this seems to be the main entry point for
- /// parsing an arbitrary expression.
- pub fn parse_assign_expr(&mut self) -> PResult<P<Expr>> {
- match self.token {
- token::DotDot => {
- // prefix-form of range notation '..expr'
- // This has the same precedence as assignment expressions
- // (much lower than other prefix expressions) to be consistent
- // with the postfix-form 'expr..'
- let lo = self.span.lo;
- let mut hi = self.span.hi;
- try!(self.bump());
- let opt_end = if self.is_at_start_of_range_notation_rhs() {
- let end = try!(self.parse_binops());
- hi = end.span.hi;
- Some(end)
- } else {
- None
- };
- let ex = self.mk_range(None, opt_end);
- Ok(self.mk_expr(lo, hi, ex))
- }
- _ => {
- let lhs = try!(self.parse_binops());
- self.parse_assign_expr_with(lhs)
- }
- }
- }
-
- pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> PResult<P<Expr>> {
- let restrictions = self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL;
- let op_span = self.span;
- match self.token {
- token::Eq => {
- try!(self.bump());
- let rhs = try!(self.parse_expr_res(restrictions));
- Ok(self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs)))
- }
- token::BinOpEq(op) => {
- try!(self.bump());
- let rhs = try!(self.parse_expr_res(restrictions));
- let aop = match op {
- token::Plus => BiAdd,
- token::Minus => BiSub,
- token::Star => BiMul,
- token::Slash => BiDiv,
- token::Percent => BiRem,
- token::Caret => BiBitXor,
- token::And => BiBitAnd,
- token::Or => BiBitOr,
- token::Shl => BiShl,
- token::Shr => BiShr
- };
- let rhs_span = rhs.span;
- let span = lhs.span;
- let assign_op = self.mk_assign_op(codemap::respan(op_span, aop), lhs, rhs);
- Ok(self.mk_expr(span.lo, rhs_span.hi, assign_op))
- }
- // A range expression, either `expr..expr` or `expr..`.
- token::DotDot => {
- let lo = lhs.span.lo;
- let mut hi = self.span.hi;
- try!(self.bump());
-
- let opt_end = if self.is_at_start_of_range_notation_rhs() {
- let end = try!(self.parse_binops());
- hi = end.span.hi;
- Some(end)
- } else {
- None
- };
- let range = self.mk_range(Some(lhs), opt_end);
- return Ok(self.mk_expr(lo, hi, range));
- }
-
- _ => {
- Ok(lhs)
- }
- }
+ /// Parse prefix-forms of range notation: `..expr` and `..`
+ fn parse_prefix_range_expr(&mut self,
+ already_parsed_attrs: Option<ThinAttributes>)
+ -> PResult<P<Expr>> {
+ debug_assert!(self.token == token::DotDot);
+ let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs));
+ let lo = self.span.lo;
+ let mut hi = self.span.hi;
+ try!(self.bump());
+ let opt_end = if self.is_at_start_of_range_notation_rhs() {
+ // RHS must be parsed with more associativity than DotDot.
+ let next_prec = AssocOp::from_token(&token::DotDot).unwrap().precedence() + 1;
+ Some(try!(self.parse_assoc_expr_with(next_prec,
+ LhsExpr::NotYetParsed)
+ .map(|x|{
+ hi = x.span.hi;
+ x
+ })))
+ } else {
+ None
+ };
+ let r = self.mk_range(None, opt_end);
+ Ok(self.mk_expr(lo, hi, r, attrs))
}
fn is_at_start_of_range_notation_rhs(&self) -> bool {
}
/// Parse an 'if' or 'if let' expression ('if' token already eaten)
- pub fn parse_if_expr(&mut self) -> PResult<P<Expr>> {
+ pub fn parse_if_expr(&mut self, attrs: ThinAttributes) -> PResult<P<Expr>> {
if self.check_keyword(keywords::Let) {
- return self.parse_if_let_expr();
+ return self.parse_if_let_expr(attrs);
}
let lo = self.last_span.lo;
- let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
+ let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None));
let thn = try!(self.parse_block());
let mut els: Option<P<Expr>> = None;
let mut hi = thn.span.hi;
hi = elexpr.span.hi;
els = Some(elexpr);
}
- Ok(self.mk_expr(lo, hi, ExprIf(cond, thn, els)))
+ Ok(self.mk_expr(lo, hi, ExprIf(cond, thn, els), attrs))
}
/// Parse an 'if let' expression ('if' token already eaten)
- pub fn parse_if_let_expr(&mut self) -> PResult<P<Expr>> {
+ pub fn parse_if_let_expr(&mut self, attrs: ThinAttributes)
+ -> PResult<P<Expr>> {
let lo = self.last_span.lo;
try!(self.expect_keyword(keywords::Let));
- let pat = try!(self.parse_pat_nopanic());
+ let pat = try!(self.parse_pat());
try!(self.expect(&token::Eq));
- let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
+ let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None));
let thn = try!(self.parse_block());
let (hi, els) = if try!(self.eat_keyword(keywords::Else) ){
let expr = try!(self.parse_else_expr());
} else {
(thn.span.hi, None)
};
- Ok(self.mk_expr(lo, hi, ExprIfLet(pat, expr, thn, els)))
+ Ok(self.mk_expr(lo, hi, ExprIfLet(pat, expr, thn, els), attrs))
}
// `|args| expr`
- pub fn parse_lambda_expr(&mut self, lo: BytePos, capture_clause: CaptureClause)
+ pub fn parse_lambda_expr(&mut self, lo: BytePos,
+ capture_clause: CaptureClause,
+ attrs: ThinAttributes)
-> PResult<P<Expr>>
{
let decl = try!(self.parse_fn_block_decl());
DefaultReturn(_) => {
// If no explicit return type is given, parse any
// expr and wrap it up in a dummy block:
- let body_expr = try!(self.parse_expr_nopanic());
+ let body_expr = try!(self.parse_expr());
P(ast::Block {
id: ast::DUMMY_NODE_ID,
stmts: vec![],
Ok(self.mk_expr(
lo,
body.span.hi,
- ExprClosure(capture_clause, decl, body)))
+ ExprClosure(capture_clause, decl, body), attrs))
}
+ // `else` token already eaten
pub fn parse_else_expr(&mut self) -> PResult<P<Expr>> {
if try!(self.eat_keyword(keywords::If) ){
- return self.parse_if_expr();
+ return self.parse_if_expr(None);
} else {
let blk = try!(self.parse_block());
- return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)));
+ return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk), None));
}
}
/// Parse a 'for' .. 'in' expression ('for' token already eaten)
pub fn parse_for_expr(&mut self, opt_ident: Option<ast::Ident>,
- span_lo: BytePos) -> PResult<P<Expr>> {
+ span_lo: BytePos,
+ attrs: ThinAttributes) -> PResult<P<Expr>> {
// Parse: `for <src_pat> in <src_expr> <src_loop_block>`
- let pat = try!(self.parse_pat_nopanic());
+ let pat = try!(self.parse_pat());
try!(self.expect_keyword(keywords::In));
- let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
- let loop_block = try!(self.parse_block());
+ let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None));
+ let (iattrs, loop_block) = try!(self.parse_inner_attrs_and_block());
+ let attrs = attrs.append(iattrs.into_thin_attrs());
+
let hi = self.last_span.hi;
- Ok(self.mk_expr(span_lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident)))
+ Ok(self.mk_expr(span_lo, hi,
+ ExprForLoop(pat, expr, loop_block, opt_ident),
+ attrs))
}
/// Parse a 'while' or 'while let' expression ('while' token already eaten)
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>,
- span_lo: BytePos) -> PResult<P<Expr>> {
+ span_lo: BytePos,
+ attrs: ThinAttributes) -> PResult<P<Expr>> {
if self.token.is_keyword(keywords::Let) {
- return self.parse_while_let_expr(opt_ident, span_lo);
+ return self.parse_while_let_expr(opt_ident, span_lo, attrs);
}
- let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
- let body = try!(self.parse_block());
+ let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None));
+ let (iattrs, body) = try!(self.parse_inner_attrs_and_block());
+ let attrs = attrs.append(iattrs.into_thin_attrs());
let hi = body.span.hi;
- return Ok(self.mk_expr(span_lo, hi, ExprWhile(cond, body, opt_ident)));
+ return Ok(self.mk_expr(span_lo, hi, ExprWhile(cond, body, opt_ident),
+ attrs));
}
/// Parse a 'while let' expression ('while' token already eaten)
pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::Ident>,
- span_lo: BytePos) -> PResult<P<Expr>> {
+ span_lo: BytePos,
+ attrs: ThinAttributes) -> PResult<P<Expr>> {
try!(self.expect_keyword(keywords::Let));
- let pat = try!(self.parse_pat_nopanic());
+ let pat = try!(self.parse_pat());
try!(self.expect(&token::Eq));
- let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
- let body = try!(self.parse_block());
+ let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None));
+ let (iattrs, body) = try!(self.parse_inner_attrs_and_block());
+ let attrs = attrs.append(iattrs.into_thin_attrs());
let hi = body.span.hi;
- return Ok(self.mk_expr(span_lo, hi, ExprWhileLet(pat, expr, body, opt_ident)));
+ return Ok(self.mk_expr(span_lo, hi, ExprWhileLet(pat, expr, body, opt_ident), attrs));
}
+ // parse `loop {...}`, `loop` token already eaten
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>,
- span_lo: BytePos) -> PResult<P<Expr>> {
- let body = try!(self.parse_block());
+ span_lo: BytePos,
+ attrs: ThinAttributes) -> PResult<P<Expr>> {
+ let (iattrs, body) = try!(self.parse_inner_attrs_and_block());
+ let attrs = attrs.append(iattrs.into_thin_attrs());
let hi = body.span.hi;
- Ok(self.mk_expr(span_lo, hi, ExprLoop(body, opt_ident)))
+ Ok(self.mk_expr(span_lo, hi, ExprLoop(body, opt_ident), attrs))
}
- fn parse_match_expr(&mut self) -> PResult<P<Expr>> {
+ // `match` token already eaten
+ fn parse_match_expr(&mut self, attrs: ThinAttributes) -> PResult<P<Expr>> {
+ let match_span = self.last_span;
let lo = self.last_span.lo;
- let discriminant = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
- try!(self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace)));
+ let discriminant = try!(self.parse_expr_res(
+ Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None));
+ if let Err(e) = self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace)) {
+ if self.token == token::Token::Semi {
+ self.span_note(match_span, "did you mean to remove this `match` keyword?");
+ }
+ return Err(e)
+ }
+ let attrs = attrs.append(
+ try!(self.parse_inner_attributes()).into_thin_attrs());
let mut arms: Vec<Arm> = Vec::new();
while self.token != token::CloseDelim(token::Brace) {
- arms.push(try!(self.parse_arm_nopanic()));
+ arms.push(try!(self.parse_arm()));
}
let hi = self.span.hi;
try!(self.bump());
- return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms)));
+ return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms), attrs));
}
- pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
+ pub fn parse_arm(&mut self) -> PResult<Arm> {
maybe_whole!(no_clone self, NtArm);
- let attrs = self.parse_outer_attributes();
+ let attrs = try!(self.parse_outer_attributes());
let pats = try!(self.parse_pats());
let mut guard = None;
if try!(self.eat_keyword(keywords::If) ){
- guard = Some(try!(self.parse_expr_nopanic()));
+ guard = Some(try!(self.parse_expr()));
}
try!(self.expect(&token::FatArrow));
- let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
+ let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR, None));
let require_comma =
!classify::expr_is_simple_block(&*expr)
}
/// Parse an expression
- pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> {
- self.parse_expr_res(Restrictions::empty())
+ pub fn parse_expr(&mut self) -> PResult<P<Expr>> {
+ self.parse_expr_res(Restrictions::empty(), None)
}
- /// Parse an expression, subject to the given restrictions
- pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult<P<Expr>> {
+ /// Evaluate the closure with restrictions in place.
+ ///
+ /// After the closure is evaluated, restrictions are reset.
+ pub fn with_res<F>(&mut self, r: Restrictions, f: F) -> PResult<P<Expr>>
+ where F: FnOnce(&mut Self) -> PResult<P<Expr>> {
let old = self.restrictions;
self.restrictions = r;
- let e = try!(self.parse_assign_expr());
+ let r = f(self);
self.restrictions = old;
- return Ok(e);
+ return r;
+
+ }
+
+ /// Parse an expression, subject to the given restrictions
+ pub fn parse_expr_res(&mut self, r: Restrictions,
+ already_parsed_attrs: Option<ThinAttributes>)
+ -> PResult<P<Expr>> {
+ self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs))
}
/// Parse the RHS of a local variable declaration (e.g. '= 14;')
fn parse_initializer(&mut self) -> PResult<Option<P<Expr>>> {
if self.check(&token::Eq) {
try!(self.bump());
- Ok(Some(try!(self.parse_expr_nopanic())))
+ Ok(Some(try!(self.parse_expr())))
} else {
Ok(None)
}
fn parse_pats(&mut self) -> PResult<Vec<P<Pat>>> {
let mut pats = Vec::new();
loop {
- pats.push(try!(self.parse_pat_nopanic()));
+ pats.push(try!(self.parse_pat()));
if self.check(&token::BinOp(token::Or)) { try!(self.bump());}
else { return Ok(pats); }
};
fn parse_pat_tuple_elements(&mut self) -> PResult<Vec<P<Pat>>> {
let mut fields = vec![];
if !self.check(&token::CloseDelim(token::Paren)) {
- fields.push(try!(self.parse_pat_nopanic()));
+ fields.push(try!(self.parse_pat()));
if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) {
while try!(self.eat(&token::Comma)) &&
!self.check(&token::CloseDelim(token::Paren)) {
- fields.push(try!(self.parse_pat_nopanic()));
+ fields.push(try!(self.parse_pat()));
}
}
if fields.len() == 1 {
self.check(&token::CloseDelim(token::Bracket)) {
slice = Some(P(ast::Pat {
id: ast::DUMMY_NODE_ID,
- node: PatWild(PatWildMulti),
+ node: PatWild,
span: self.span,
}));
before_slice = false;
}
}
- let subpat = try!(self.parse_pat_nopanic());
+ let subpat = try!(self.parse_pat());
if before_slice && self.check(&token::DotDot) {
try!(self.bump());
slice = Some(subpat);
// Parsing a pattern of the form "fieldname: pat"
let fieldname = try!(self.parse_ident());
try!(self.bump());
- let pat = try!(self.parse_pat_nopanic());
+ let pat = try!(self.parse_pat());
hi = pat.span.hi;
(pat, fieldname, false)
} else {
(None, try!(self.parse_path(LifetimeAndTypesWithColons)))
};
let hi = self.last_span.hi;
- Ok(self.mk_expr(lo, hi, ExprPath(qself, path)))
+ Ok(self.mk_expr(lo, hi, ExprPath(qself, path), None))
} else {
- self.parse_literal_maybe_minus()
+ self.parse_pat_literal_maybe_minus()
}
}
}
/// Parse a pattern.
- pub fn parse_pat_nopanic(&mut self) -> PResult<P<Pat>> {
+ pub fn parse_pat(&mut self) -> PResult<P<Pat>> {
maybe_whole!(self, NtPat);
let lo = self.span.lo;
token::Underscore => {
// Parse _
try!(self.bump());
- pat = PatWild(PatWildSingle);
+ pat = PatWild;
}
token::BinOp(token::And) | token::AndAnd => {
// Parse &pat / &mut pat
return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
}
- let subpat = try!(self.parse_pat_nopanic());
+ let subpat = try!(self.parse_pat());
pat = PatRegion(subpat, mutbl);
}
token::OpenDelim(token::Paren) => {
pat = try!(self.parse_pat_ident(BindByRef(mutbl)));
} else if try!(self.eat_keyword(keywords::Box)) {
// Parse box pat
- let subpat = try!(self.parse_pat_nopanic());
+ let subpat = try!(self.parse_pat());
pat = PatBox(subpat);
} else if self.is_path_start() {
// Parse pattern starting with a path
let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim),
seq_sep_none(), |p| p.parse_token_tree()));
let mac = Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT };
- pat = PatMac(codemap::Spanned {node: mac, span: self.span});
+ pat = PatMac(codemap::Spanned {node: mac,
+ span: mk_sp(lo, self.last_span.hi)});
} else {
// Parse ident @ pat
// This can give false positives and parse nullary enums,
token::DotDotDot => {
// Parse range
let hi = self.last_span.hi;
- let begin = self.mk_expr(lo, hi, ExprPath(qself, path));
+ let begin = self.mk_expr(lo, hi, ExprPath(qself, path), None);
try!(self.bump());
let end = try!(self.parse_pat_range_end());
pat = PatRange(begin, end);
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma),
- |p| p.parse_pat_nopanic()));
+ |p| p.parse_pat()));
pat = PatEnum(path, Some(args));
}
}
}
} else {
// Try to parse everything else as literal with optional minus
- let begin = try!(self.parse_literal_maybe_minus());
+ let begin = try!(self.parse_pat_literal_maybe_minus());
if try!(self.eat(&token::DotDotDot)) {
let end = try!(self.parse_pat_range_end());
pat = PatRange(begin, end);
let last_span = self.last_span;
let name = codemap::Spanned{span: last_span, node: ident};
let sub = if try!(self.eat(&token::At) ){
- Some(try!(self.parse_pat_nopanic()))
+ Some(try!(self.parse_pat()))
} else {
None
};
}
/// Parse a local variable declaration
- fn parse_local(&mut self) -> PResult<P<Local>> {
+ fn parse_local(&mut self, attrs: ThinAttributes) -> PResult<P<Local>> {
let lo = self.span.lo;
- let pat = try!(self.parse_pat_nopanic());
+ let pat = try!(self.parse_pat());
let mut ty = None;
if try!(self.eat(&token::Colon) ){
init: init,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, self.last_span.hi),
+ attrs: attrs,
}))
}
/// Parse a "let" stmt
- fn parse_let(&mut self) -> PResult<P<Decl>> {
+ fn parse_let(&mut self, attrs: ThinAttributes) -> PResult<P<Decl>> {
let lo = self.span.lo;
- let local = try!(self.parse_local());
+ let local = try!(self.parse_local(attrs));
Ok(P(spanned(lo, self.last_span.hi, DeclLocal(local))))
}
}
/// Parse a statement. may include decl.
- pub fn parse_stmt_nopanic(&mut self) -> PResult<Option<P<Stmt>>> {
+ pub fn parse_stmt(&mut self) -> PResult<Option<P<Stmt>>> {
Ok(try!(self.parse_stmt_()).map(P))
}
fn parse_stmt_(&mut self) -> PResult<Option<Stmt>> {
maybe_whole!(Some deref self, NtStmt);
- fn check_expected_item(p: &mut Parser, attrs: &[Attribute]) {
- // If we have attributes then we should have an item
- if !attrs.is_empty() {
- p.expected_item_err(attrs);
- }
- }
-
- let attrs = self.parse_outer_attributes();
+ let attrs = try!(self.parse_outer_attributes());
let lo = self.span.lo;
Ok(Some(if self.check_keyword(keywords::Let) {
- check_expected_item(self, &attrs);
try!(self.expect_keyword(keywords::Let));
- let decl = try!(self.parse_let());
- spanned(lo, decl.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID))
+ let decl = try!(self.parse_let(attrs.into_thin_attrs()));
+ let hi = decl.span.hi;
+ let stmt = StmtDecl(decl, ast::DUMMY_NODE_ID);
+ spanned(lo, hi, stmt)
} else if self.token.is_ident()
&& !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not) {
// it's a macro invocation:
- check_expected_item(self, &attrs);
-
// Potential trouble: if we allow macros with paths instead of
// idents, we'd need to look ahead past the whole path here...
let pth = try!(self.parse_path(NoTypesAllowed));
};
if id.name == token::special_idents::invalid.name {
- spanned(lo, hi,
- StmtMac(P(spanned(lo,
- hi,
- Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })),
- style))
+ let stmt = StmtMac(P(spanned(lo,
+ hi,
+ Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })),
+ style,
+ attrs.into_thin_attrs());
+ spanned(lo, hi, stmt)
} else {
// if it has a special ident, it's definitely an item
//
lo, hi, id /*id is good here*/,
ItemMac(spanned(lo, hi,
Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })),
- Inherited, Vec::new(/*no attrs*/))))),
+ Inherited, attrs)))),
ast::DUMMY_NODE_ID))
}
} else {
- match try!(self.parse_item_(attrs, false)) {
+ // FIXME: Bad copy of attrs
+ match try!(self.parse_item_(attrs.clone(), false, true)) {
Some(i) => {
let hi = i.span.hi;
let decl = P(spanned(lo, hi, DeclItem(i)));
spanned(lo, hi, StmtDecl(decl, ast::DUMMY_NODE_ID))
}
None => {
+ let unused_attrs = |attrs: &[_], s: &mut Self| {
+ if attrs.len() > 0 {
+ s.span_err(s.span,
+ "expected statement after outer attribute");
+ }
+ };
+
// Do not attempt to parse an expression if we're done here.
if self.token == token::Semi {
+ unused_attrs(&attrs, self);
try!(self.bump());
return Ok(None);
}
if self.token == token::CloseDelim(token::Brace) {
+ unused_attrs(&attrs, self);
return Ok(None);
}
// Remainder are line-expr stmts.
- let e = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
- spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID))
+ let e = try!(self.parse_expr_res(
+ Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into_thin_attrs())));
+ let hi = e.span.hi;
+ let stmt = StmtExpr(e, ast::DUMMY_NODE_ID);
+ spanned(lo, hi, stmt)
}
}
}))
let lo = self.span.lo;
try!(self.expect(&token::OpenDelim(token::Brace)));
- Ok((self.parse_inner_attributes(),
+ Ok((try!(self.parse_inner_attributes()),
try!(self.parse_block_tail(lo, DefaultBlock))))
}
StmtExpr(e, _) => {
try!(self.handle_expression_like_statement(e, span, &mut stmts, &mut expr));
}
- StmtMac(mac, MacStmtWithoutBraces) => {
+ StmtMac(mac, MacStmtWithoutBraces, attrs) => {
// statement macro without braces; might be an
// expr depending on whether a semicolon follows
match self.token {
token::Semi => {
stmts.push(P(Spanned {
- node: StmtMac(mac, MacStmtWithSemicolon),
+ node: StmtMac(mac, MacStmtWithSemicolon, attrs),
span: mk_sp(span.lo, self.span.hi),
}));
try!(self.bump());
}
_ => {
let e = self.mk_mac_expr(span.lo, span.hi,
- mac.and_then(|m| m.node));
- let e = try!(self.parse_dot_or_call_expr_with(e));
- let e = try!(self.parse_more_binops(e, 0));
- let e = try!(self.parse_assign_expr_with(e));
+ mac.and_then(|m| m.node),
+ None);
+ let e = try!(self.parse_dot_or_call_expr_with(e, attrs));
+ let e = try!(self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e)));
try!(self.handle_expression_like_statement(
e,
span,
}
}
}
- StmtMac(m, style) => {
+ StmtMac(m, style, attrs) => {
// statement macro; might be an expr
match self.token {
token::Semi => {
stmts.push(P(Spanned {
- node: StmtMac(m, MacStmtWithSemicolon),
+ node: StmtMac(m, MacStmtWithSemicolon, attrs),
span: mk_sp(span.lo, self.span.hi),
}));
try!(self.bump());
// if a block ends in `m!(arg)` without
// a `;`, it must be an expr
expr = Some(self.mk_mac_expr(span.lo, span.hi,
- m.and_then(|x| x.node)));
+ m.and_then(|x| x.node),
+ attrs));
}
_ => {
stmts.push(P(Spanned {
- node: StmtMac(m, style),
+ node: StmtMac(m, style, attrs),
span: span
}));
}
self.span_err(self.span, &msg);
let span_hi = self.span.hi;
- let span_hi = if self.parse_ty_nopanic().is_ok() {
+ let span_hi = if self.parse_ty().is_ok() {
self.span.hi
} else {
span_hi
let span = p.span;
p.span_warn(span, "whoops, no =?");
}
- let ty = try!(p.parse_ty_nopanic());
+ let ty = try!(p.parse_ty());
let hi = ty.span.hi;
let span = mk_sp(lo, hi);
return Ok(P(TypeBinding{id: ast::DUMMY_NODE_ID,
/// Parses an optional `where` clause and places it in `generics`.
///
- /// ```
+ /// ```ignore
/// where T : Trait<U, V> + 'b, 'a : 'b
/// ```
pub fn parse_where_clause(&mut self) -> PResult<ast::WhereClause> {
vec![]
};
- let bounded_ty = try!(self.parse_ty_nopanic());
+ let bounded_ty = try!(self.parse_ty());
if try!(self.eat(&token::Colon) ){
let bounds = try!(self.parse_ty_param_bounds(BoundParsingMode::Bare));
parsed_something = true;
} else if try!(self.eat(&token::Eq) ){
- // let ty = try!(self.parse_ty_nopanic());
+ // let ty = try!(self.parse_ty());
let hi = self.last_span.hi;
let span = mk_sp(lo, hi);
// where_clause.predicates.push(
pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
maybe_whole!(no_clone self, NtImplItem);
- let mut attrs = self.parse_outer_attributes();
+ let mut attrs = try!(self.parse_outer_attributes());
let lo = self.span.lo;
let vis = try!(self.parse_visibility());
let (name, node) = if try!(self.eat_keyword(keywords::Type)) {
try!(self.expect(&token::Eq));
let typ = try!(self.parse_ty_sum());
try!(self.expect(&token::Semi));
- (name, TypeImplItem(typ))
+ (name, ast::ImplItemKind::Type(typ))
} else if self.is_const_item() {
try!(self.expect_keyword(keywords::Const));
let name = try!(self.parse_ident());
try!(self.expect(&token::Colon));
let typ = try!(self.parse_ty_sum());
try!(self.expect(&token::Eq));
- let expr = try!(self.parse_expr_nopanic());
+ let expr = try!(self.parse_expr());
try!(self.commit_expr_expecting(&expr, token::Semi));
- (name, ConstImplItem(typ, expr))
+ (name, ast::ImplItemKind::Const(typ, expr))
} else {
let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
attrs.extend(inner_attrs);
/// Parse a method or a macro invocation in a trait impl.
fn parse_impl_method(&mut self, vis: Visibility)
- -> PResult<(Ident, Vec<ast::Attribute>, ast::ImplItem_)> {
+ -> PResult<(Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
// code copied from parse_macro_use_or_failure... abstraction!
if !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not)
let last_span = self.last_span;
self.complain_if_pub_macro(vis, last_span);
+ let lo = self.span.lo;
let pth = try!(self.parse_path(NoTypesAllowed));
try!(self.expect(&token::Not));
|p| p.parse_token_tree()));
let m_ = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
let m: ast::Mac = codemap::Spanned { node: m_,
- span: mk_sp(self.span.lo,
- self.span.hi) };
+ span: mk_sp(lo,
+ self.last_span.hi) };
if delim != token::Brace {
try!(self.expect(&token::Semi))
}
- Ok((token::special_idents::invalid, vec![], ast::MacImplItem(m)))
+ Ok((token::special_idents::invalid, vec![], ast::ImplItemKind::Macro(m)))
} else {
let (constness, unsafety, abi) = try!(self.parse_fn_front_matter());
let ident = try!(self.parse_ident());
}));
generics.where_clause = try!(self.parse_where_clause());
let (inner_attrs, body) = try!(self.parse_inner_attrs_and_block());
- Ok((ident, inner_attrs, MethodImplItem(ast::MethodSig {
+ Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig {
generics: generics,
abi: abi,
explicit_self: explicit_self,
generics.where_clause = try!(self.parse_where_clause());
try!(self.expect(&token::OpenDelim(token::Brace)));
- let attrs = self.parse_inner_attributes();
+ let attrs = try!(self.parse_inner_attributes());
let mut impl_items = vec![];
while !try!(self.eat(&token::CloseDelim(token::Brace))) {
VariantData::Unit(ast::DUMMY_NODE_ID)
} else {
// If we see: `struct Foo<T> where T: Copy { ... }`
- VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
+ VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::Yes)),
+ ast::DUMMY_NODE_ID)
}
// No `where` so: `struct Foo<T>;`
} else if try!(self.eat(&token::Semi) ){
VariantData::Unit(ast::DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(token::Brace) {
- VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
+ VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::Yes)),
+ ast::DUMMY_NODE_ID)
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(token::Paren) {
- VariantData::Tuple(try!(self.parse_tuple_struct_body(&mut generics)),
- ast::DUMMY_NODE_ID)
+ let body = VariantData::Tuple(try!(self.parse_tuple_struct_body(ParsePub::Yes)),
+ ast::DUMMY_NODE_ID);
+ generics.where_clause = try!(self.parse_where_clause());
+ try!(self.expect(&token::Semi));
+ body
} else {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \
Ok((class_name, ItemStruct(vdata, generics), None))
}
- pub fn parse_record_struct_body(&mut self) -> PResult<Vec<StructField>> {
+ pub fn parse_record_struct_body(&mut self, parse_pub: ParsePub) -> PResult<Vec<StructField>> {
let mut fields = Vec::new();
if try!(self.eat(&token::OpenDelim(token::Brace)) ){
while self.token != token::CloseDelim(token::Brace) {
- fields.push(try!(self.parse_struct_decl_field(true)));
+ fields.push(try!(self.parse_struct_decl_field(parse_pub)));
}
try!(self.bump());
Ok(fields)
}
- pub fn parse_tuple_struct_body(&mut self,
- generics: &mut ast::Generics)
- -> PResult<Vec<StructField>> {
+ pub fn parse_tuple_struct_body(&mut self, parse_pub: ParsePub) -> PResult<Vec<StructField>> {
// This is the case where we find `struct Foo<T>(T) where T: Copy;`
// Unit like structs are handled in parse_item_struct function
let fields = try!(self.parse_unspanned_seq(
&token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma),
|p| {
- let attrs = p.parse_outer_attributes();
+ let attrs = try!(p.parse_outer_attributes());
let lo = p.span.lo;
let struct_field_ = ast::StructField_ {
- kind: UnnamedField(try!(p.parse_visibility())),
+ kind: UnnamedField (
+ if parse_pub == ParsePub::Yes {
+ try!(p.parse_visibility())
+ } else {
+ Inherited
+ }
+ ),
id: ast::DUMMY_NODE_ID,
ty: try!(p.parse_ty_sum()),
attrs: attrs,
Ok(spanned(lo, p.span.hi, struct_field_))
}));
- generics.where_clause = try!(self.parse_where_clause());
- try!(self.expect(&token::Semi));
Ok(fields)
}
}
/// Parse an element of a struct definition
- fn parse_struct_decl_field(&mut self, allow_pub: bool) -> PResult<StructField> {
+ fn parse_struct_decl_field(&mut self, parse_pub: ParsePub) -> PResult<StructField> {
- let attrs = self.parse_outer_attributes();
+ let attrs = try!(self.parse_outer_attributes());
if try!(self.eat_keyword(keywords::Pub) ){
- if !allow_pub {
+ if parse_pub == ParsePub::No {
let span = self.last_span;
self.span_err(span, "`pub` is not allowed here");
}
/// Given a termination token, parse all of the items in a module
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<Mod> {
let mut items = vec![];
- while let Some(item) = try!(self.parse_item_nopanic()) {
+ while let Some(item) = try!(self.parse_item()) {
items.push(item);
}
try!(self.expect(&token::Colon));
let ty = try!(self.parse_ty_sum());
try!(self.expect(&token::Eq));
- let e = try!(self.parse_expr_nopanic());
+ let e = try!(self.parse_expr());
try!(self.commit_expr_expecting(&*e, token::Semi));
let item = match m {
Some(m) => ItemStatic(ty, m, e),
let mod_inner_lo = self.span.lo;
let old_owns_directory = self.owns_directory;
self.owns_directory = true;
- let attrs = self.parse_inner_attributes();
+ let attrs = try!(self.parse_inner_attributes());
let m = try!(self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo));
self.owns_directory = old_owns_directory;
self.pop_mod_path();
Some(name),
id_sp);
let mod_inner_lo = p0.span.lo;
- let mod_attrs = p0.parse_inner_attributes();
+ let mod_attrs = try!(p0.parse_inner_attributes());
let m0 = try!(p0.parse_mod_items(&token::Eof, mod_inner_lo));
self.sess.included_mod_stack.borrow_mut().pop();
Ok((ast::ItemMod(m0), mod_attrs))
let abi = opt_abi.unwrap_or(abi::C);
- attrs.extend(self.parse_inner_attributes());
+ attrs.extend(try!(self.parse_inner_attributes()));
let mut foreign_items = vec![];
while let Some(item) = try!(self.parse_foreign_item()) {
Ok((ident, ItemTy(ty, tps), None))
}
- /// Parse a structure-like enum variant definition
- /// this should probably be renamed or refactored...
- fn parse_struct_def(&mut self) -> PResult<VariantData> {
- let mut fields: Vec<StructField> = Vec::new();
- while self.token != token::CloseDelim(token::Brace) {
- fields.push(try!(self.parse_struct_decl_field(false)));
- }
- try!(self.bump());
-
- Ok(VariantData::Struct(fields, ast::DUMMY_NODE_ID))
- }
-
/// Parse the part of an "enum" decl following the '{'
fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<EnumDef> {
let mut variants = Vec::new();
let mut all_nullary = true;
let mut any_disr = None;
while self.token != token::CloseDelim(token::Brace) {
- let variant_attrs = self.parse_outer_attributes();
+ let variant_attrs = try!(self.parse_outer_attributes());
let vlo = self.span.lo;
let struct_def;
let mut disr_expr = None;
let ident = try!(self.parse_ident());
- if try!(self.eat(&token::OpenDelim(token::Brace)) ){
+ if self.check(&token::OpenDelim(token::Brace)) {
// Parse a struct variant.
all_nullary = false;
- struct_def = try!(self.parse_struct_def());
+ struct_def = VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::No)),
+ ast::DUMMY_NODE_ID);
} else if self.check(&token::OpenDelim(token::Paren)) {
all_nullary = false;
- let arg_tys = try!(self.parse_enum_variant_seq(
- &token::OpenDelim(token::Paren),
- &token::CloseDelim(token::Paren),
- seq_sep_trailing_allowed(token::Comma),
- |p| p.parse_ty_sum()
- ));
- let mut fields = Vec::new();
- for ty in arg_tys {
- fields.push(Spanned { span: ty.span, node: ast::StructField_ {
- ty: ty,
- kind: ast::UnnamedField(ast::Inherited),
- attrs: Vec::new(),
- id: ast::DUMMY_NODE_ID,
- }});
- }
- struct_def = ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID);
+ struct_def = VariantData::Tuple(try!(self.parse_tuple_struct_body(ParsePub::No)),
+ ast::DUMMY_NODE_ID);
} else if try!(self.eat(&token::Eq) ){
- disr_expr = Some(try!(self.parse_expr_nopanic()));
+ disr_expr = Some(try!(self.parse_expr()));
any_disr = disr_expr.as_ref().map(|expr| expr.span);
- struct_def = ast::VariantData::Unit(ast::DUMMY_NODE_ID);
+ struct_def = VariantData::Unit(ast::DUMMY_NODE_ID);
} else {
- struct_def = ast::VariantData::Unit(ast::DUMMY_NODE_ID);
+ struct_def = VariantData::Unit(ast::DUMMY_NODE_ID);
}
let vr = ast::Variant_ {
/// NB: this function no longer parses the items inside an
/// extern crate.
fn parse_item_(&mut self, attrs: Vec<Attribute>,
- macros_allowed: bool) -> PResult<Option<P<Item>>> {
+ macros_allowed: bool, attributes_allowed: bool) -> PResult<Option<P<Item>>> {
let nt_item = match self.token {
token::Interpolated(token::NtItem(ref item)) => {
Some((**item).clone())
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
- self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility)
+ self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
}
/// Parse a foreign item.
fn parse_foreign_item(&mut self) -> PResult<Option<P<ForeignItem>>> {
- let attrs = self.parse_outer_attributes();
+ let attrs = try!(self.parse_outer_attributes());
let lo = self.span.lo;
let visibility = try!(self.parse_visibility());
}
// FIXME #5668: this will occur for a macro invocation:
- match try!(self.parse_macro_use_or_failure(attrs, true, lo, visibility)) {
+ match try!(self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)) {
Some(item) => {
return Err(self.span_fatal(item.span, "macros cannot expand to foreign items"));
}
&mut self,
attrs: Vec<Attribute> ,
macros_allowed: bool,
+ attributes_allowed: bool,
lo: BytePos,
visibility: Visibility
) -> PResult<Option<P<Item>>> {
let last_span = self.last_span;
self.complain_if_pub_macro(visibility, last_span);
+ let mac_lo = self.span.lo;
+
// item macro.
let pth = try!(self.parse_path(NoTypesAllowed));
try!(self.expect(&token::Not));
// single-variant-enum... :
let m = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
let m: ast::Mac = codemap::Spanned { node: m,
- span: mk_sp(self.span.lo,
- self.span.hi) };
+ span: mk_sp(mac_lo,
+ self.last_span.hi) };
if delim != token::Brace {
if !try!(self.eat(&token::Semi) ){
}
}
- if !attrs.is_empty() {
+ if !attributes_allowed && !attrs.is_empty() {
self.expected_item_err(&attrs);
}
Ok(None)
}
- pub fn parse_item_nopanic(&mut self) -> PResult<Option<P<Item>>> {
- let attrs = self.parse_outer_attributes();
- self.parse_item_(attrs, true)
+ pub fn parse_item(&mut self) -> PResult<Option<P<Item>>> {
+ let attrs = try!(self.parse_outer_attributes());
+ self.parse_item_(attrs, true, false)
}
pub fn parse_crate_mod(&mut self) -> PResult<Crate> {
let lo = self.span.lo;
Ok(ast::Crate {
- attrs: self.parse_inner_attributes(),
+ attrs: try!(self.parse_inner_attributes()),
module: try!(self.parse_mod_items(&token::Eof, lo)),
config: self.cfg.clone(),
span: mk_sp(lo, self.span.lo),