From 2a8f358de7ee71934b8129dff5d908730454d7b1 Mon Sep 17 00:00:00 2001 From: Marvin Löbel Date: Tue, 3 Nov 2015 17:39:51 +0100 Subject: Add syntax support for attributes on expressions and all syntax nodes in statement position. Extended #[cfg] folder to allow removal of statements, and of expressions in optional positions like expression lists and trailing block expressions. Extended lint checker to recognize lint levels on expressions and locals. --- src/libsyntax/parse/parser.rs | 448 ++++++++++++++++++++++++++++-------------- 1 file changed, 302 insertions(+), 146 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 56a06f70ed4..2f67ecad4e7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -56,6 +56,7 @@ use ast::TypeTraitItem; use ast::{UnnamedField, UnsafeBlock}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; +use ast::{ThinAttributes, ThinAttributesExt, AttributesExt}; use ast; use ast_util::{self, ident_to_path}; use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap}; @@ -140,7 +141,7 @@ macro_rules! maybe_whole_expr { _ => 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, @@ -150,7 +151,7 @@ macro_rules! maybe_whole_expr { _ => 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 }; @@ -319,6 +320,27 @@ pub struct ModulePathError { pub help_msg: String, } +pub enum LhsExpr { + NotYetParsed, + AttributesParsed(ThinAttributes), + AlreadyParsed(P), +} + +impl From> for LhsExpr { + fn from(o: Option) -> Self { + if let Some(attrs) = o { + LhsExpr::AttributesParsed(attrs) + } else { + LhsExpr::NotYetParsed + } + } +} + +impl From> for LhsExpr { + fn from(expr: P) -> Self { + LhsExpr::AlreadyParsed(expr) + } +} impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, @@ -1557,19 +1579,18 @@ impl<'a> Parser<'a> { } /// matches '-' lit | lit - pub fn parse_literal_maybe_minus(&mut self) -> PResult> { + pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult> { 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) } @@ -1914,11 +1935,13 @@ impl<'a> Parser<'a> { }) } - pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: Expr_) -> P { + pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, + node: Expr_, attrs: ThinAttributes) -> P { P(Expr { id: ast::DUMMY_NODE_ID, node: node, span: mk_sp(lo, hi), + attrs: attrs, }) } @@ -1966,15 +1989,17 @@ impl<'a> Parser<'a> { ExprAssignOp(binop, lhs, rhs) } - pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, m: Mac_) -> P { + pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, + m: Mac_, attrs: ThinAttributes) -> P { 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 { + pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinAttributes) -> P { let span = &self.span; let lv_lit = P(codemap::Spanned { node: LitInt(i as u64, ast::UnsignedIntLit(TyU32)), @@ -1985,6 +2010,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, node: ExprLit(lv_lit), span: *span, + attrs: attrs, }) } @@ -2002,9 +2028,20 @@ impl<'a> Parser<'a> { /// At the bottom (top?) of the precedence hierarchy, /// parse things like parenthesized exprs, /// macros, return, etc. - pub fn parse_bottom_expr(&mut self) -> PResult> { + /// + /// 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> { 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; @@ -2015,6 +2052,10 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => { try!(self.bump()); + let attrs = try!(self.parse_inner_attributes()) + .into_opt_attrs() + .prepend_outer(attrs); + // (e) is parenthesized e // (e,) is a tuple with only one field, e let mut es = vec![]; @@ -2036,17 +2077,17 @@ impl<'a> Parser<'a> { 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, @@ -2060,6 +2101,10 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Bracket) => { try!(self.bump()); + let inner_attrs = try!(self.parse_inner_attributes()) + .into_opt_attrs(); + attrs.update(|attrs| attrs.append_inner(inner_attrs)); + if self.check(&token::CloseDelim(token::Bracket)) { // Empty vector. try!(self.bump()); @@ -2097,22 +2142,22 @@ impl<'a> Parser<'a> { 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(); @@ -2120,19 +2165,19 @@ impl<'a> Parser<'a> { 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() { @@ -2146,15 +2191,16 @@ impl<'a> Parser<'a> { 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() { @@ -2196,7 +2242,8 @@ impl<'a> Parser<'a> { 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 @@ -2210,6 +2257,10 @@ impl<'a> Parser<'a> { let mut fields = Vec::new(); let mut base = None; + let attrs = attrs.append_inner( + try!(self.parse_inner_attributes()) + .into_opt_attrs()); + while self.token != token::CloseDelim(token::Brace) { if try!(self.eat(&token::DotDot) ){ base = Some(try!(self.parse_expr())); @@ -2225,7 +2276,7 @@ impl<'a> Parser<'a> { 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)); } } @@ -2240,24 +2291,74 @@ impl<'a> Parser<'a> { } } - 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) + -> PResult { + if let Some(attrs) = already_parsed_attrs { + Ok(attrs) + } else { + self.parse_outer_attributes().map(|a| a.into_opt_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> { + + let outer_attrs = attrs; try!(self.expect(&token::OpenDelim(token::Brace))); + + let inner_attrs = try!(self.parse_inner_attributes()).into_opt_attrs(); + let attrs = outer_attrs.append_inner(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> { + pub fn parse_dot_or_call_expr(&mut self, + already_parsed_attrs: Option) + -> PResult> { + 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, + attrs: ThinAttributes) + -> PResult> { + // 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_outer(attrs)); + match expr.node { + ExprIf(..) | ExprIfLet(..) => { + if !expr.attrs.as_attrs().is_empty() { + // Just point to the first attribute in there... + let span = expr.attrs.as_attrs()[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) -> PResult> { + fn parse_dot_or_call_expr_with_(&mut self, e0: P) -> PResult> { let mut e = e0; let lo = e.span.lo; let mut hi; @@ -2295,7 +2396,7 @@ impl<'a> Parser<'a> { 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() { @@ -2307,7 +2408,7 @@ impl<'a> Parser<'a> { 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); } } } @@ -2326,7 +2427,7 @@ impl<'a> Parser<'a> { 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; @@ -2370,7 +2471,7 @@ impl<'a> Parser<'a> { 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[...] @@ -2381,7 +2482,7 @@ impl<'a> Parser<'a> { 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) } @@ -2578,75 +2679,90 @@ impl<'a> Parser<'a> { } /// Parse a prefix-unary-operator expr - pub fn parse_prefix_expr(&mut self) -> PResult> { + pub fn parse_prefix_expr(&mut self, + already_parsed_attrs: Option) + -> PResult> { + 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()); + 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()); + 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()); + 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()); + 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)); + 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)); + 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()); + let subexpression = try!(self.parse_prefix_expr(None)); hi = subexpression.span.hi; ExprBox(subexpression) } - _ => return self.parse_dot_or_call_expr() + _ => return self.parse_dot_or_call_expr(Some(attrs)) }; - return Ok(self.mk_expr(lo, hi, ex)); + return Ok(self.mk_expr(lo, hi, ex, attrs)); } /// 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) -> PResult> { - self.parse_assoc_expr_with(0, None) + pub fn parse_assoc_expr(&mut self, + already_parsed_attrs: Option) + -> PResult> { + self.parse_assoc_expr_with(0, already_parsed_attrs.into()) } /// Parse an associative expression with operators of at least `min_prec` precedence pub fn parse_assoc_expr_with(&mut self, min_prec: usize, - lhs: Option>) + lhs: LhsExpr) -> PResult> { - let mut lhs = if lhs.is_some() { - lhs.unwrap() - } else if self.token == token::DotDot { - return self.parse_prefix_range_expr(); + let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { + expr } else { - try!(self.parse_prefix_expr()) + 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 @@ -2670,7 +2786,8 @@ impl<'a> Parser<'a> { // 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)); + 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 @@ -2679,7 +2796,8 @@ impl<'a> Parser<'a> { // 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, None).ok() + self.parse_assoc_expr_with(op.precedence() + 1, + LhsExpr::NotYetParsed).ok() } else { None }; @@ -2689,22 +2807,22 @@ impl<'a> Parser<'a> { cur_op_span }); let r = self.mk_range(Some(lhs), rhs); - lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r); + lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None); break } let rhs = try!(match op.fixity() { Fixity::Right => self.with_res(restrictions, |this|{ - this.parse_assoc_expr_with(op.precedence(), None) + this.parse_assoc_expr_with(op.precedence(), LhsExpr::NotYetParsed) }), Fixity::Left => self.with_res(restrictions, |this|{ - this.parse_assoc_expr_with(op.precedence() + 1, None) + 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, None) + this.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed) }), }); @@ -2717,12 +2835,12 @@ impl<'a> Parser<'a> { 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) + self.mk_expr(lhs_span.lo, rhs_span.hi, binary, None) } AssocOp::Assign => - self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs)), + 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)), + self.mk_expr(lhs.span.lo, rhs.span.hi, ExprInPlace(lhs, rhs), None), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BiAdd, @@ -2738,7 +2856,7 @@ impl<'a> Parser<'a> { }; 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) + self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None) } AssocOp::As | AssocOp::DotDot => self.bug("As or DotDot branch reached") }; @@ -2769,15 +2887,20 @@ impl<'a> Parser<'a> { } /// Parse prefix-forms of range notation: `..expr` and `..` - fn parse_prefix_range_expr(&mut self) -> PResult> { + fn parse_prefix_range_expr(&mut self, + already_parsed_attrs: Option) + -> PResult> { 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, None).map(|x|{ + Some(try!(self.parse_assoc_expr_with(next_prec, + LhsExpr::NotYetParsed) + .map(|x|{ hi = x.span.hi; x }))) @@ -2785,7 +2908,7 @@ impl<'a> Parser<'a> { None }; let r = self.mk_range(None, opt_end); - Ok(self.mk_expr(lo, hi, r)) + Ok(self.mk_expr(lo, hi, r, attrs)) } fn is_at_start_of_range_notation_rhs(&self) -> bool { @@ -2801,12 +2924,12 @@ impl<'a> Parser<'a> { } /// Parse an 'if' or 'if let' expression ('if' token already eaten) - pub fn parse_if_expr(&mut self) -> PResult> { + pub fn parse_if_expr(&mut self, attrs: ThinAttributes) -> PResult> { 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> = None; let mut hi = thn.span.hi; @@ -2815,16 +2938,17 @@ impl<'a> Parser<'a> { 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> { + pub fn parse_if_let_expr(&mut self, attrs: ThinAttributes) + -> PResult> { let lo = self.last_span.lo; try!(self.expect_keyword(keywords::Let)); 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()); @@ -2832,11 +2956,13 @@ impl<'a> Parser<'a> { } 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> { let decl = try!(self.parse_fn_block_decl()); @@ -2863,80 +2989,98 @@ impl<'a> Parser<'a> { 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> { 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, - span_lo: BytePos) -> PResult> { + span_lo: BytePos, + attrs: ThinAttributes) -> PResult> { // Parse: `for in ` 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_inner(iattrs.into_opt_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, - span_lo: BytePos) -> PResult> { + span_lo: BytePos, + attrs: ThinAttributes) -> PResult> { 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_inner(iattrs.into_opt_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, - span_lo: BytePos) -> PResult> { + span_lo: BytePos, + attrs: ThinAttributes) -> PResult> { try!(self.expect_keyword(keywords::Let)); 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_inner(iattrs.into_opt_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, - span_lo: BytePos) -> PResult> { - let body = try!(self.parse_block()); + span_lo: BytePos, + attrs: ThinAttributes) -> PResult> { + let (iattrs, body) = try!(self.parse_inner_attrs_and_block()); + let attrs = attrs.append_inner(iattrs.into_opt_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> { + // `match` token already eaten + fn parse_match_expr(&mut self, attrs: ThinAttributes) -> PResult> { let match_span = self.last_span; let lo = self.last_span.lo; - let discriminant = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); + 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_inner( + try!(self.parse_inner_attributes()).into_opt_attrs()); let mut arms: Vec = Vec::new(); while self.token != token::CloseDelim(token::Brace) { 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(&mut self) -> PResult { @@ -2949,7 +3093,7 @@ impl<'a> Parser<'a> { 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) @@ -2971,7 +3115,7 @@ impl<'a> Parser<'a> { /// Parse an expression pub fn parse_expr(&mut self) -> PResult> { - self.parse_expr_res(Restrictions::empty()) + self.parse_expr_res(Restrictions::empty(), None) } /// Evaluate the closure with restrictions in place. @@ -2988,8 +3132,10 @@ impl<'a> Parser<'a> { } /// Parse an expression, subject to the given restrictions - pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult> { - self.with_res(r, |this| this.parse_assoc_expr()) + pub fn parse_expr_res(&mut self, r: Restrictions, + already_parsed_attrs: Option) + -> PResult> { + self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) } /// Parse the RHS of a local variable declaration (e.g. '= 14;') @@ -3173,9 +3319,9 @@ impl<'a> Parser<'a> { (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() } } @@ -3274,7 +3420,7 @@ impl<'a> Parser<'a> { 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); @@ -3321,7 +3467,7 @@ impl<'a> Parser<'a> { } } 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); @@ -3378,7 +3524,7 @@ impl<'a> Parser<'a> { } /// Parse a local variable declaration - fn parse_local(&mut self) -> PResult> { + fn parse_local(&mut self, attrs: ThinAttributes) -> PResult> { let lo = self.span.lo; let pat = try!(self.parse_pat()); @@ -3393,13 +3539,14 @@ impl<'a> Parser<'a> { 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> { + fn parse_let(&mut self, attrs: ThinAttributes) -> PResult> { 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)))) } @@ -3444,28 +3591,20 @@ impl<'a> Parser<'a> { fn parse_stmt_(&mut self) -> PResult> { 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 = 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_opt_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)); @@ -3511,11 +3650,12 @@ impl<'a> Parser<'a> { }; 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_opt_attrs()); + spanned(lo, hi, stmt) } else { // if it has a special ident, it's definitely an item // @@ -3535,30 +3675,43 @@ impl<'a> Parser<'a> { 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_opt_attrs()))); + let hi = e.span.hi; + let stmt = StmtExpr(e, ast::DUMMY_NODE_ID); + spanned(lo, hi, stmt) } } })) @@ -3614,22 +3767,23 @@ impl<'a> Parser<'a> { 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_assoc_expr_with(0, Some(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, @@ -3638,12 +3792,12 @@ impl<'a> Parser<'a> { } } } - 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()); @@ -3652,11 +3806,12 @@ impl<'a> Parser<'a> { // 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 })); } @@ -5210,7 +5365,7 @@ impl<'a> Parser<'a> { /// NB: this function no longer parses the items inside an /// extern crate. fn parse_item_(&mut self, attrs: Vec, - macros_allowed: bool) -> PResult>> { + macros_allowed: bool, attributes_allowed: bool) -> PResult>> { let nt_item = match self.token { token::Interpolated(token::NtItem(ref item)) => { Some((**item).clone()) @@ -5468,7 +5623,7 @@ impl<'a> Parser<'a> { 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. @@ -5487,7 +5642,7 @@ impl<'a> Parser<'a> { } // 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")); } @@ -5500,6 +5655,7 @@ impl<'a> Parser<'a> { &mut self, attrs: Vec , macros_allowed: bool, + attributes_allowed: bool, lo: BytePos, visibility: Visibility ) -> PResult>> { @@ -5566,7 +5722,7 @@ impl<'a> Parser<'a> { } } - if !attrs.is_empty() { + if !attributes_allowed && !attrs.is_empty() { self.expected_item_err(&attrs); } Ok(None) @@ -5574,7 +5730,7 @@ impl<'a> Parser<'a> { pub fn parse_item(&mut self) -> PResult>> { let attrs = try!(self.parse_outer_attributes()); - self.parse_item_(attrs, true) + self.parse_item_(attrs, true, false) } -- cgit 1.4.1-3-g733a5 From f0beba0217ad4ac748e93f7ea8d16c3b1fc4db1d Mon Sep 17 00:00:00 2001 From: Marvin Löbel Date: Sun, 15 Nov 2015 17:17:50 +0100 Subject: Moved and refactored ThinAttributes --- src/librustc/lint/context.rs | 7 +-- src/librustc_front/fold.rs | 7 +-- src/librustc_front/hir.rs | 2 +- src/librustc_front/lowering.rs | 4 +- src/libsyntax/ast.rs | 93 +------------------------------------ src/libsyntax/attr.rs | 102 ++++++++++++++++++++++++++++++++++++++--- src/libsyntax/config.rs | 2 +- src/libsyntax/fold.rs | 7 +-- src/libsyntax/parse/parser.rs | 44 +++++++++--------- src/libsyntax/print/pprust.rs | 11 +++-- src/libsyntax/visit.rs | 3 +- 11 files changed, 143 insertions(+), 139 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9a30ec1a2b6..1ed873f0508 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -41,7 +41,8 @@ use syntax::ast_util::{self, IdVisitingOperation}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::Span; use syntax::parse::token::InternedString; -use syntax::ast::{self, ThinAttributesExt}; +use syntax::ast; +use syntax::attr::ThinAttributesExt; use rustc_front::hir; use rustc_front::util; use rustc_front::intravisit as hir_visit; @@ -674,7 +675,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { } fn visit_expr(&mut self, e: &hir::Expr) { - self.with_lint_attrs(e.attrs.as_attrs(), |cx| { + self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| { run_lints!(cx, check_expr, late_passes, e); hir_visit::walk_expr(cx, e); }) @@ -737,7 +738,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { } fn visit_local(&mut self, l: &hir::Local) { - self.with_lint_attrs(l.attrs.as_attrs(), |cx| { + self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| { run_lints!(cx, check_local, late_passes, l); hir_visit::walk_local(cx, l); }) diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs index 028ecbc336e..5073eb62f39 100644 --- a/src/librustc_front/fold.rs +++ b/src/librustc_front/fold.rs @@ -13,7 +13,8 @@ use hir::*; use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem}; -use syntax::ast::{MetaWord, MetaList, MetaNameValue, ThinAttributesExt}; +use syntax::ast::{MetaWord, MetaList, MetaNameValue}; +use syntax::attr::ThinAttributesExt; use hir; use syntax::codemap::{respan, Span, Spanned}; use syntax::owned_slice::OwnedSlice; @@ -508,7 +509,7 @@ pub fn noop_fold_local(l: P, fld: &mut T) -> P { pat: fld.fold_pat(pat), init: init.map(|e| fld.fold_expr(e)), span: fld.new_span(span), - attrs: attrs.map_opt_attrs(|attrs| fold_attrs(attrs, fld)), + attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs, fld)), } }) } @@ -1172,7 +1173,7 @@ pub fn noop_fold_expr(Expr { id, node, span, attrs }: Expr, folder: & } }, span: folder.new_span(span), - attrs: attrs.map_opt_attrs(|attrs| fold_attrs(attrs, folder)), + attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs, folder)), } } diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs index f0f9512cd0f..beb7059d73c 100644 --- a/src/librustc_front/hir.rs +++ b/src/librustc_front/hir.rs @@ -41,7 +41,7 @@ use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId}; use syntax::abi::Abi; use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, CrateConfig}; -use syntax::ast::ThinAttributes; +use syntax::attr::ThinAttributes; use syntax::owned_slice::OwnedSlice; use syntax::parse::token::InternedString; use syntax::ptr::P; diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs index 0f89ddb9987..bbfd9ff520b 100644 --- a/src/librustc_front/lowering.rs +++ b/src/librustc_front/lowering.rs @@ -66,6 +66,7 @@ use hir; use std::collections::BTreeMap; use std::collections::HashMap; use syntax::ast::*; +use syntax::attr::{ThinAttributes, ThinAttributesExt}; use syntax::ptr::P; use syntax::codemap::{respan, Spanned, Span}; use syntax::owned_slice::OwnedSlice; @@ -1219,8 +1220,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // merge attributes into the inner expression. return lower_expr(lctx, ex).map(|mut ex| { ex.attrs.update(|attrs| { - // FIXME: Badly named - attrs.prepend_outer(e.attrs.clone()) + attrs.prepend(e.attrs.clone()) }); ex }); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 48c5be8e07e..f11291fc0f7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -45,6 +45,7 @@ pub use self::ViewPath_::*; pub use self::Visibility::*; pub use self::PathParameters::*; +use attr::ThinAttributes; use codemap::{Span, Spanned, DUMMY_SP, ExpnId}; use abi::Abi; use ast_util; @@ -1952,98 +1953,6 @@ pub struct MacroDef { pub body: Vec, } -/// A list of attributes, behind a optional box as -/// a space optimization. -pub type ThinAttributes = Option>>; - -pub trait ThinAttributesExt { - fn map_opt_attrs(self, f: F) -> Self - where F: FnOnce(Vec) -> Vec; - fn prepend_outer(mut self, attrs: Self) -> Self; - fn append_inner(mut self, attrs: Self) -> Self; - fn update(&mut self, f: F) - where Self: Sized, - F: FnOnce(Self) -> Self; - fn as_attrs(&self) -> &[Attribute]; - fn into_attrs(self) -> Vec; -} - -// FIXME: Rename inner/outer -// FIXME: Rename opt_attrs - -impl ThinAttributesExt for ThinAttributes { - fn map_opt_attrs(self, f: F) -> Self - where F: FnOnce(Vec) -> Vec { - - // This is kinda complicated... Ensure the function is - // always called, and that None inputs or results are - // correctly handled. - if let Some(mut b) = self { - use std::mem::replace; - - let vec = replace(&mut *b, Vec::new()); - let vec = f(vec); - if vec.len() == 0 { - None - } else { - replace(&mut*b, vec); - Some(b) - } - } else { - f(Vec::new()).into_opt_attrs() - } - } - - fn prepend_outer(self, attrs: ThinAttributes) -> Self { - attrs.map_opt_attrs(|mut attrs| { - attrs.extend(self.into_attrs()); - attrs - }) - } - - fn append_inner(self, attrs: ThinAttributes) -> Self { - self.map_opt_attrs(|mut self_| { - self_.extend(attrs.into_attrs()); - self_ - }) - } - - fn update(&mut self, f: F) - where Self: Sized, - F: FnOnce(ThinAttributes) -> ThinAttributes - { - let self_ = f(self.take()); - *self = self_; - } - - fn as_attrs(&self) -> &[Attribute] { - match *self { - Some(ref b) => b, - None => &[], - } - } - - fn into_attrs(self) -> Vec { - match self { - Some(b) => *b, - None => Vec::new(), - } - } -} - -pub trait AttributesExt { - fn into_opt_attrs(self) -> ThinAttributes; -} -impl AttributesExt for Vec { - fn into_opt_attrs(self) -> ThinAttributes { - if self.len() == 0 { - None - } else { - Some(Box::new(self)) - } - } -} - #[cfg(test)] mod tests { use serialize; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 18f7311418f..d020ba8a07b 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -16,8 +16,8 @@ pub use self::IntType::*; use ast; use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList}; -use ast::{Stmt, StmtDecl, StmtExpr, StmtMac, StmtSemi, DeclItem, DeclLocal, ThinAttributes}; -use ast::{Expr, ThinAttributesExt, Item, Local, Decl}; +use ast::{Stmt, StmtDecl, StmtExpr, StmtMac, StmtSemi, DeclItem, DeclLocal}; +use ast::{Expr, Item, Local, Decl}; use codemap::{Span, Spanned, spanned, dummy_spanned}; use codemap::BytePos; use diagnostic::SpanHandler; @@ -723,6 +723,96 @@ impl IntType { } } +/// A list of attributes, behind a optional box as +/// a space optimization. +pub type ThinAttributes = Option>>; + +pub trait ThinAttributesExt { + fn map_thin_attrs(self, f: F) -> Self + where F: FnOnce(Vec) -> Vec; + fn prepend(mut self, attrs: Self) -> Self; + fn append(mut self, attrs: Self) -> Self; + fn update(&mut self, f: F) + where Self: Sized, + F: FnOnce(Self) -> Self; + fn as_attr_slice(&self) -> &[Attribute]; + fn into_attr_vec(self) -> Vec; +} + +impl ThinAttributesExt for ThinAttributes { + fn map_thin_attrs(self, f: F) -> Self + where F: FnOnce(Vec) -> Vec { + + // This is kinda complicated... Ensure the function is + // always called, and that None inputs or results are + // correctly handled. + if let Some(mut b) = self { + use std::mem::replace; + + let vec = replace(&mut *b, Vec::new()); + let vec = f(vec); + if vec.len() == 0 { + None + } else { + replace(&mut*b, vec); + Some(b) + } + } else { + f(Vec::new()).into_thin_attrs() + } + } + + fn prepend(self, attrs: ThinAttributes) -> Self { + attrs.map_thin_attrs(|mut attrs| { + attrs.extend(self.into_attr_vec()); + attrs + }) + } + + fn append(self, attrs: ThinAttributes) -> Self { + self.map_thin_attrs(|mut self_| { + self_.extend(attrs.into_attr_vec()); + self_ + }) + } + + fn update(&mut self, f: F) + where Self: Sized, + F: FnOnce(ThinAttributes) -> ThinAttributes + { + let self_ = f(self.take()); + *self = self_; + } + + fn as_attr_slice(&self) -> &[Attribute] { + match *self { + Some(ref b) => b, + None => &[], + } + } + + fn into_attr_vec(self) -> Vec { + match self { + Some(b) => *b, + None => Vec::new(), + } + } +} + +pub trait AttributesExt { + fn into_thin_attrs(self) -> ThinAttributes; +} + +impl AttributesExt for Vec { + fn into_thin_attrs(self) -> ThinAttributes { + if self.len() == 0 { + None + } else { + Some(Box::new(self)) + } + } +} + /// A cheap way to add Attributes to an AST node. pub trait WithAttrs { // FIXME: Could be extended to anything IntoIter @@ -732,7 +822,7 @@ pub trait WithAttrs { impl WithAttrs for P { fn with_attrs(self, attrs: ThinAttributes) -> Self { self.map(|mut e| { - e.attrs.update(|a| a.append_inner(attrs)); + e.attrs.update(|a| a.append(attrs)); e }) } @@ -741,7 +831,7 @@ impl WithAttrs for P { impl WithAttrs for P { fn with_attrs(self, attrs: ThinAttributes) -> Self { self.map(|Item { ident, attrs: mut ats, id, node, vis, span }| { - ats.extend(attrs.into_attrs()); + ats.extend(attrs.into_attr_vec()); Item { ident: ident, attrs: ats, @@ -757,7 +847,7 @@ impl WithAttrs for P { impl WithAttrs for P { fn with_attrs(self, attrs: ThinAttributes) -> Self { self.map(|Local { pat, ty, init, id, span, attrs: mut ats }| { - ats.update(|a| a.append_inner(attrs)); + ats.update(|a| a.append(attrs)); Local { pat: pat, ty: ty, @@ -794,7 +884,7 @@ impl WithAttrs for P { StmtExpr(expr, id) => StmtExpr(expr.with_attrs(attrs), id), StmtSemi(expr, id) => StmtSemi(expr.with_attrs(attrs), id), StmtMac(mac, style, mut ats) => { - ats.update(|a| a.append_inner(attrs)); + ats.update(|a| a.append(attrs)); StmtMac(mac, style, ats) } }, diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a867b45075f..0d59ff0fbab 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -54,7 +54,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> // Anything else is always required, and thus has to error out // in case of a cfg attr. // - // NB: This intentionally not part of the fold_expr() function + // NB: This is intentionally not part of the fold_expr() function // in order for fold_opt_expr() to be able to avoid this check if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { self.diagnostic.span_err(attr.span, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1d499bce3c6..0cb9f2205be 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -20,6 +20,7 @@ use ast::*; use ast; +use attr::ThinAttributesExt; use ast_util; use codemap::{respan, Span, Spanned}; use owned_slice::OwnedSlice; @@ -522,7 +523,7 @@ pub fn noop_fold_local(l: P, fld: &mut T) -> P { pat: fld.fold_pat(pat), init: init.map(|e| fld.fold_expr(e)), span: fld.new_span(span), - attrs: attrs.map_opt_attrs(|v| fold_attrs(v, fld)), + attrs: attrs.map_thin_attrs(|v| fold_attrs(v, fld)), }) } @@ -1339,7 +1340,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprParen(ex) => ExprParen(folder.fold_expr(ex)) }, span: folder.new_span(span), - attrs: attrs.map_opt_attrs(|v| fold_attrs(v, folder)), + attrs: attrs.map_thin_attrs(|v| fold_attrs(v, folder)), } } @@ -1388,7 +1389,7 @@ pub fn noop_fold_stmt(Spanned {node, span}: Stmt, folder: &mut T) StmtMac(mac, semi, attrs) => SmallVector::one(P(Spanned { node: StmtMac(mac.map(|m| folder.fold_mac(m)), semi, - attrs.map_opt_attrs(|v| fold_attrs(v, folder))), + attrs.map_thin_attrs(|v| fold_attrs(v, folder))), span: span })) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2f67ecad4e7..46bd68428ab 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -56,7 +56,7 @@ use ast::TypeTraitItem; use ast::{UnnamedField, UnsafeBlock}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; -use ast::{ThinAttributes, ThinAttributesExt, AttributesExt}; +use attr::{ThinAttributes, ThinAttributesExt, AttributesExt}; use ast; use ast_util::{self, ident_to_path}; use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap}; @@ -2053,8 +2053,8 @@ impl<'a> Parser<'a> { try!(self.bump()); let attrs = try!(self.parse_inner_attributes()) - .into_opt_attrs() - .prepend_outer(attrs); + .into_thin_attrs() + .prepend(attrs); // (e) is parenthesized e // (e,) is a tuple with only one field, e @@ -2102,8 +2102,8 @@ impl<'a> Parser<'a> { try!(self.bump()); let inner_attrs = try!(self.parse_inner_attributes()) - .into_opt_attrs(); - attrs.update(|attrs| attrs.append_inner(inner_attrs)); + .into_thin_attrs(); + attrs.update(|attrs| attrs.append(inner_attrs)); if self.check(&token::CloseDelim(token::Bracket)) { // Empty vector. @@ -2257,9 +2257,9 @@ impl<'a> Parser<'a> { let mut fields = Vec::new(); let mut base = None; - let attrs = attrs.append_inner( + let attrs = attrs.append( try!(self.parse_inner_attributes()) - .into_opt_attrs()); + .into_thin_attrs()); while self.token != token::CloseDelim(token::Brace) { if try!(self.eat(&token::DotDot) ){ @@ -2300,7 +2300,7 @@ impl<'a> Parser<'a> { if let Some(attrs) = already_parsed_attrs { Ok(attrs) } else { - self.parse_outer_attributes().map(|a| a.into_opt_attrs()) + self.parse_outer_attributes().map(|a| a.into_thin_attrs()) } } @@ -2312,8 +2312,8 @@ impl<'a> Parser<'a> { let outer_attrs = attrs; try!(self.expect(&token::OpenDelim(token::Brace))); - let inner_attrs = try!(self.parse_inner_attributes()).into_opt_attrs(); - let attrs = outer_attrs.append_inner(inner_attrs); + 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), attrs)); @@ -2339,12 +2339,12 @@ impl<'a> Parser<'a> { self.parse_dot_or_call_expr_with_(e0) .map(|expr| expr.map(|mut expr| { - expr.attrs.update(|a| a.prepend_outer(attrs)); + expr.attrs.update(|a| a.prepend(attrs)); match expr.node { ExprIf(..) | ExprIfLet(..) => { - if !expr.attrs.as_attrs().is_empty() { + if !expr.attrs.as_attr_slice().is_empty() { // Just point to the first attribute in there... - let span = expr.attrs.as_attrs()[0].span; + let span = expr.attrs.as_attr_slice()[0].span; self.span_err(span, "attributes are not yet allowed on `if` \ @@ -3012,7 +3012,7 @@ impl<'a> Parser<'a> { try!(self.expect_keyword(keywords::In)); 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_inner(iattrs.into_opt_attrs()); + let attrs = attrs.append(iattrs.into_thin_attrs()); let hi = self.last_span.hi; @@ -3030,7 +3030,7 @@ impl<'a> Parser<'a> { } 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_inner(iattrs.into_opt_attrs()); + 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), attrs)); @@ -3045,7 +3045,7 @@ impl<'a> Parser<'a> { try!(self.expect(&token::Eq)); 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_inner(iattrs.into_opt_attrs()); + 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), attrs)); } @@ -3055,7 +3055,7 @@ impl<'a> Parser<'a> { span_lo: BytePos, attrs: ThinAttributes) -> PResult> { let (iattrs, body) = try!(self.parse_inner_attrs_and_block()); - let attrs = attrs.append_inner(iattrs.into_opt_attrs()); + let attrs = attrs.append(iattrs.into_thin_attrs()); let hi = body.span.hi; Ok(self.mk_expr(span_lo, hi, ExprLoop(body, opt_ident), attrs)) } @@ -3072,8 +3072,8 @@ impl<'a> Parser<'a> { } return Err(e) } - let attrs = attrs.append_inner( - try!(self.parse_inner_attributes()).into_opt_attrs()); + let attrs = attrs.append( + try!(self.parse_inner_attributes()).into_thin_attrs()); let mut arms: Vec = Vec::new(); while self.token != token::CloseDelim(token::Brace) { arms.push(try!(self.parse_arm())); @@ -3596,7 +3596,7 @@ impl<'a> Parser<'a> { Ok(Some(if self.check_keyword(keywords::Let) { try!(self.expect_keyword(keywords::Let)); - let decl = try!(self.parse_let(attrs.into_opt_attrs())); + 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) @@ -3654,7 +3654,7 @@ impl<'a> Parser<'a> { hi, Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })), style, - attrs.into_opt_attrs()); + attrs.into_thin_attrs()); spanned(lo, hi, stmt) } else { // if it has a special ident, it's definitely an item @@ -3708,7 +3708,7 @@ impl<'a> Parser<'a> { // Remainder are line-expr stmts. let e = try!(self.parse_expr_res( - Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into_opt_attrs()))); + 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) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6919bc4efdd..8ea93e5b8da 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -13,7 +13,8 @@ pub use self::AnnNode::*; use abi; use ast::{self, TokenTree}; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; -use ast::{ThinAttributesExt, Attribute}; +use ast::Attribute; +use attr::ThinAttributesExt; use ast_util; use util::parser::AssocOp; use attr; @@ -1638,7 +1639,7 @@ impl<'a> State<'a> { } ast::StmtMac(ref mac, style, ref attrs) => { try!(self.space_if_not_bol()); - try!(self.print_outer_attributes(attrs.as_attrs())); + try!(self.print_outer_attributes(attrs.as_attr_slice())); let delim = match style { ast::MacStmtWithBraces => token::Brace, _ => token::Paren @@ -1983,7 +1984,7 @@ impl<'a> State<'a> { is_inline: bool) -> io::Result<()> { try!(self.maybe_print_comment(expr.span.lo)); - let attrs = expr.attrs.as_attrs(); + let attrs = expr.attrs.as_attr_slice(); if is_inline { try!(self.print_outer_attributes_inline(attrs)); } else { @@ -2124,7 +2125,7 @@ impl<'a> State<'a> { ast::ExprBlock(ref blk) => { try!(self.print_block_unclosed_with_attrs( &**blk, - i_expr.attrs.as_attrs())); + i_expr.attrs.as_attr_slice())); } _ => { // this is a bare expression @@ -2303,7 +2304,7 @@ impl<'a> State<'a> { try!(self.maybe_print_comment(decl.span.lo)); match decl.node { ast::DeclLocal(ref loc) => { - try!(self.print_outer_attributes(loc.attrs.as_attrs())); + try!(self.print_outer_attributes(loc.attrs.as_attr_slice())); try!(self.space_if_not_bol()); try!(self.ibox(INDENT_UNIT)); try!(self.word_nbsp("let")); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 2d97e2680d7..cdc11fb2c1c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -25,6 +25,7 @@ use abi::Abi; use ast::*; +use attr::ThinAttributesExt; use codemap::Span; #[derive(Copy, Clone, PartialEq, Eq)] @@ -630,7 +631,7 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { } StmtMac(ref mac, _, ref attrs) => { visitor.visit_mac(mac); - for attr in attrs.as_attrs() { + for attr in attrs.as_attr_slice() { visitor.visit_attribute(attr); } } -- cgit 1.4.1-3-g733a5