diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 109 | ||||
| -rw-r--r-- | src/libsyntax/attr/mod.rs | 113 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/mut_visit.rs | 37 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 55 | ||||
| -rw-r--r-- | src/libsyntax/tokenstream.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 10 |
7 files changed, 228 insertions, 105 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 512f43c86ca..8018e005b12 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -27,7 +27,7 @@ pub use syntax_pos::symbol::{Ident, Symbol as Name}; use crate::ptr::P; use crate::source_map::{dummy_spanned, respan, Spanned}; use crate::token::{self, DelimToken}; -use crate::tokenstream::TokenStream; +use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; use syntax_pos::symbol::{kw, sym, Symbol}; use syntax_pos::{Span, DUMMY_SP, ExpnId}; @@ -40,6 +40,7 @@ use rustc_index::vec::Idx; use rustc_serialize::{self, Decoder, Encoder}; use rustc_macros::HashStable_Generic; +use std::iter; use std::fmt; #[cfg(test)] @@ -1372,34 +1373,89 @@ pub enum Movability { Movable, } -/// Represents a macro invocation. The `Path` indicates which macro -/// is being invoked, and the vector of token-trees contains the source -/// of the macro invocation. -/// -/// N.B., the additional ident for a `macro_rules`-style macro is actually -/// stored in the enclosing item. +/// Represents a macro invocation. The `path` indicates which macro +/// is being invoked, and the `args` are arguments passed to it. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Mac { pub path: Path, - pub delim: MacDelimiter, - pub tts: TokenStream, - pub span: Span, + pub args: P<MacArgs>, pub prior_type_ascription: Option<(Span, bool)>, } -#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] +impl Mac { + pub fn span(&self) -> Span { + self.path.span.to(self.args.span().unwrap_or(self.path.span)) + } +} + +/// Arguments passed to an attribute or a function-like macro. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +pub enum MacArgs { + /// No arguments - `#[attr]`. + Empty, + /// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`. + Delimited(DelimSpan, MacDelimiter, TokenStream), + /// Arguments of a key-value attribute - `#[attr = "value"]`. + Eq( + /// Span of the `=` token. + Span, + /// Token stream of the "value". + TokenStream, + ), +} + +impl MacArgs { + pub fn delim(&self) -> DelimToken { + match self { + MacArgs::Delimited(_, delim, _) => delim.to_token(), + MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim, + } + } + + pub fn span(&self) -> Option<Span> { + match *self { + MacArgs::Empty => None, + MacArgs::Delimited(dspan, ..) => Some(dspan.entire()), + MacArgs::Eq(eq_span, ref tokens) => Some(eq_span.to(tokens.span().unwrap_or(eq_span))), + } + } + + /// Tokens inside the delimiters or after `=`. + /// Proc macros see these tokens, for example. + pub fn inner_tokens(&self) -> TokenStream { + match self { + MacArgs::Empty => TokenStream::default(), + MacArgs::Delimited(.., tokens) | + MacArgs::Eq(.., tokens) => tokens.clone(), + } + } + + /// Tokens together with the delimiters or `=`. + /// Use of this method generally means that something suboptimal or hacky is happening. + pub fn outer_tokens(&self) -> TokenStream { + match *self { + MacArgs::Empty => TokenStream::default(), + MacArgs::Delimited(dspan, delim, ref tokens) => + TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into(), + MacArgs::Eq(eq_span, ref tokens) => iter::once(TokenTree::token(token::Eq, eq_span)) + .chain(tokens.trees()).collect(), + } + } + + /// Whether a macro with these arguments needs a semicolon + /// when used as a standalone item or statement. + pub fn need_semicolon(&self) -> bool { + !matches!(self, MacArgs::Delimited(_, MacDelimiter::Brace ,_)) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum MacDelimiter { Parenthesis, Bracket, Brace, } -impl Mac { - pub fn stream(&self) -> TokenStream { - self.tts.clone() - } -} - impl MacDelimiter { crate fn to_token(self) -> DelimToken { match self { @@ -1408,22 +1464,25 @@ impl MacDelimiter { MacDelimiter::Brace => DelimToken::Brace, } } + + pub fn from_token(delim: DelimToken) -> Option<MacDelimiter> { + match delim { + token::Paren => Some(MacDelimiter::Parenthesis), + token::Bracket => Some(MacDelimiter::Bracket), + token::Brace => Some(MacDelimiter::Brace), + token::NoDelim => None, + } + } } /// Represents a macro definition. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct MacroDef { - pub tokens: TokenStream, + pub body: P<MacArgs>, /// `true` if macro was defined with `macro_rules`. pub legacy: bool, } -impl MacroDef { - pub fn stream(&self) -> TokenStream { - self.tokens.clone().into() - } -} - // Clippy uses Hash and PartialEq #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq, HashStable_Generic)] pub enum StrStyle { @@ -2323,7 +2382,7 @@ impl rustc_serialize::Decodable for AttrId { #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct AttrItem { pub path: Path, - pub tokens: TokenStream, + pub args: MacArgs, } /// Metadata associated with an item. diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 29eff5c2981..079a0f6fafa 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -10,7 +10,7 @@ pub use crate::ast::Attribute; use crate::ast; use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment}; -use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; +use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned}; @@ -198,7 +198,7 @@ impl Attribute { pub fn is_word(&self) -> bool { if let AttrKind::Normal(item) = &self.kind { - item.tokens.is_empty() + matches!(item.args, MacArgs::Empty) } else { false } @@ -278,17 +278,9 @@ impl MetaItem { impl AttrItem { pub fn meta(&self, span: Span) -> Option<MetaItem> { - let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { path: self.path.clone(), - kind: if let Some(kind) = MetaItemKind::from_tokens(&mut tokens) { - if tokens.peek().is_some() { - return None; - } - kind - } else { - return None; - }, + kind: MetaItemKind::from_mac_args(&self.args)?, span, }) } @@ -362,8 +354,8 @@ crate fn mk_attr_id() -> AttrId { AttrId(id) } -pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { - mk_attr_from_item(style, AttrItem { path, tokens }, span) +pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { + mk_attr_from_item(style, AttrItem { path, args }, span) } pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { @@ -377,12 +369,12 @@ pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attrib /// Returns an inner attribute with the given value and span. pub fn mk_attr_inner(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Inner, item.path, item.kind.tokens(item.span), item.span) + mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) } /// Returns an outer attribute with the given value and span. pub fn mk_attr_outer(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span) + mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) } pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute { @@ -520,7 +512,26 @@ impl MetaItem { } impl MetaItemKind { - pub fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> { + pub fn mac_args(&self, span: Span) -> MacArgs { + match self { + MetaItemKind::Word => MacArgs::Empty, + MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()), + MetaItemKind::List(list) => { + let mut tts = Vec::new(); + for (i, item) in list.iter().enumerate() { + if i > 0 { + tts.push(TokenTree::token(token::Comma, span).into()); + } + tts.extend(item.token_trees_and_joints()) + } + MacArgs::Delimited( + DelimSpan::from_single(span), MacDelimiter::Parenthesis, TokenStream::new(tts) + ) + } + } + } + + fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> { match *self { MetaItemKind::Word => vec![], MetaItemKind::NameValue(ref lit) => { @@ -548,33 +559,8 @@ impl MetaItemKind { } } - // Premature conversions of `TokenTree`s to `TokenStream`s can hurt - // performance. Do not use this function if `token_trees_and_joints()` can - // be used instead. - pub fn tokens(&self, span: Span) -> TokenStream { - TokenStream::new(self.token_trees_and_joints(span)) - } - - fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemKind> - where I: Iterator<Item = TokenTree>, - { - let delimited = match tokens.peek().cloned() { - Some(TokenTree::Token(token)) if token == token::Eq => { - tokens.next(); - return if let Some(TokenTree::Token(token)) = tokens.next() { - Lit::from_token(&token).ok().map(MetaItemKind::NameValue) - } else { - None - }; - } - Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => { - tokens.next(); - tts.clone() - } - _ => return Some(MetaItemKind::Word), - }; - - let mut tokens = delimited.into_trees().peekable(); + fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> { + let mut tokens = tokens.into_trees().peekable(); let mut result = Vec::new(); while let Some(..) = tokens.peek() { let item = NestedMetaItem::from_tokens(&mut tokens)?; @@ -586,6 +572,47 @@ impl MetaItemKind { } Some(MetaItemKind::List(result)) } + + fn name_value_from_tokens( + tokens: &mut impl Iterator<Item = TokenTree>, + ) -> Option<MetaItemKind> { + match tokens.next() { + Some(TokenTree::Token(token)) => + Lit::from_token(&token).ok().map(MetaItemKind::NameValue), + _ => None, + } + } + + fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> { + match args { + MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => + MetaItemKind::list_from_tokens(tokens.clone()), + MacArgs::Delimited(..) => None, + MacArgs::Eq(_, tokens) => { + assert!(tokens.len() == 1); + MetaItemKind::name_value_from_tokens(&mut tokens.trees()) + } + MacArgs::Empty => Some(MetaItemKind::Word), + } + } + + fn from_tokens( + tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>, + ) -> Option<MetaItemKind> { + match tokens.peek() { + Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => { + let inner_tokens = inner_tokens.clone(); + tokens.next(); + MetaItemKind::list_from_tokens(inner_tokens) + } + Some(TokenTree::Delimited(..)) => None, + Some(TokenTree::Token(Token { kind: token::Eq, .. })) => { + tokens.next(); + MetaItemKind::name_value_from_tokens(tokens) + } + _ => Some(MetaItemKind::Word), + } + } } impl NestedMetaItem { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 3d4a5d624c1..3dcdd4db637 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -12,6 +12,7 @@ #![feature(const_transmute)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] +#![feature(matches_macro)] #![feature(nll)] #![feature(try_trait)] #![feature(slice_patterns)] diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index fbe28215a56..8889e5df26c 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -359,6 +359,26 @@ pub fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl }: &mut FnSig, vis: &mut vis.visit_fn_decl(decl); } +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. +pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) { + match args { + MacArgs::Empty => {} + MacArgs::Delimited(dspan, _delim, tokens) => { + visit_delim_span(dspan, vis); + vis.visit_tts(tokens); + } + MacArgs::Eq(eq_span, tokens) => { + vis.visit_span(eq_span); + vis.visit_tts(tokens); + } + } +} + +pub fn visit_delim_span<T: MutVisitor>(dspan: &mut DelimSpan, vis: &mut T) { + vis.visit_span(&mut dspan.open); + vis.visit_span(&mut dspan.close); +} + pub fn noop_flat_map_field_pattern<T: MutVisitor>( mut fp: FieldPat, vis: &mut T, @@ -550,9 +570,9 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { - AttrKind::Normal(AttrItem { path, tokens }) => { + AttrKind::Normal(AttrItem { path, args }) => { vis.visit_path(path); - vis.visit_tts(tokens); + visit_mac_args(args, vis); } AttrKind::DocComment(_) => {} } @@ -560,15 +580,14 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { } pub fn noop_visit_mac<T: MutVisitor>(mac: &mut Mac, vis: &mut T) { - let Mac { path, delim: _, tts, span, prior_type_ascription: _ } = mac; + let Mac { path, args, prior_type_ascription: _ } = mac; vis.visit_path(path); - vis.visit_tts(tts); - vis.visit_span(span); + visit_mac_args(args, vis); } pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) { - let MacroDef { tokens, legacy: _ } = macro_def; - vis.visit_tts(tokens); + let MacroDef { body, legacy: _ } = macro_def; + visit_mac_args(body, vis); } pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) { @@ -682,9 +701,9 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: token::NtIdent(ident, _is_raw) => vis.visit_ident(ident), token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(AttrItem { path, tokens }) => { + token::NtMeta(AttrItem { path, args }) => { vis.visit_path(path); - vis.visit_tts(tokens); + visit_mac_args(args, vis); } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0d2e8dddce6..4821bbd9ec6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1,6 +1,6 @@ use crate::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use crate::ast::{SelfKind, GenericBound, TraitBoundModifier}; -use crate::ast::{Attribute, MacDelimiter, GenericArg}; +use crate::ast::{Attribute, GenericArg, MacArgs}; use crate::util::parser::{self, AssocOp, Fixity}; use crate::util::comments; use crate::attr; @@ -639,17 +639,22 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { self.ibox(0); - match item.tokens.trees().next() { - Some(TokenTree::Delimited(_, delim, tts)) => { - self.print_mac_common( - Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span - ); - } - tree => { + match &item.args { + MacArgs::Delimited(_, delim, tokens) => self.print_mac_common( + Some(MacHeader::Path(&item.path)), + false, + None, + delim.to_token(), + tokens.clone(), + true, + span, + ), + MacArgs::Empty | MacArgs::Eq(..) => { self.print_path(&item.path, false, 0); - if tree.is_some() { + if let MacArgs::Eq(_, tokens) = &item.args { self.space(); - self.print_tts(item.tokens.clone(), true); + self.word_space("="); + self.print_tts(tokens.clone(), true); } } } @@ -1097,9 +1102,8 @@ impl<'a> State<'a> { } ast::ForeignItemKind::Macro(ref m) => { self.print_mac(m); - match m.delim { - MacDelimiter::Brace => {}, - _ => self.s.word(";") + if m.args.need_semicolon() { + self.s.word(";"); } } } @@ -1361,9 +1365,8 @@ impl<'a> State<'a> { } ast::ItemKind::Mac(ref mac) => { self.print_mac(mac); - match mac.delim { - MacDelimiter::Brace => {} - _ => self.s.word(";"), + if mac.args.need_semicolon() { + self.s.word(";"); } } ast::ItemKind::MacroDef(ref macro_def) => { @@ -1377,8 +1380,8 @@ impl<'a> State<'a> { Some(MacHeader::Keyword(kw)), has_bang, Some(item.ident), - DelimToken::Brace, - macro_def.stream(), + macro_def.body.delim(), + macro_def.body.inner_tokens(), true, item.span, ); @@ -1578,9 +1581,8 @@ impl<'a> State<'a> { } ast::TraitItemKind::Macro(ref mac) => { self.print_mac(mac); - match mac.delim { - MacDelimiter::Brace => {} - _ => self.s.word(";"), + if mac.args.need_semicolon() { + self.s.word(";"); } } } @@ -1608,9 +1610,8 @@ impl<'a> State<'a> { } ast::ImplItemKind::Macro(ref mac) => { self.print_mac(mac); - match mac.delim { - MacDelimiter::Brace => {} - _ => self.s.word(";"), + if mac.args.need_semicolon() { + self.s.word(";"); } } } @@ -1775,10 +1776,10 @@ impl<'a> State<'a> { Some(MacHeader::Path(&m.path)), true, None, - m.delim.to_token(), - m.stream(), + m.args.delim(), + m.args.inner_tokens(), true, - m.span, + m.span(), ); } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 6a0523dd655..491b9a9ade4 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -225,6 +225,14 @@ impl TokenStream { self.0.len() } + pub fn span(&self) -> Option<Span> { + match &**self.0 { + [] => None, + [(tt, _)] => Some(tt.span()), + [(tt_start, _), .., (tt_end, _)] => Some(tt_start.span().to(tt_end.span())), + } + } + pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream { match streams.len() { 0 => TokenStream::default(), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 5ff337fb60e..4ee09b4b87a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -841,11 +841,19 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { match attr.kind { - AttrKind::Normal(ref item) => visitor.visit_tts(item.tokens.clone()), + AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args), AttrKind::DocComment(_) => {} } } +pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) { + match args { + MacArgs::Empty => {} + MacArgs::Delimited(_dspan, _delim, tokens) => visitor.visit_tts(tokens.clone()), + MacArgs::Eq(_eq_span, tokens) => visitor.visit_tts(tokens.clone()), + } +} + pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { match tt { TokenTree::Token(token) => visitor.visit_token(token), |
