diff options
author | Haibo Huang <hhb@google.com> | 2020-11-11 03:14:16 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-11-11 03:14:16 +0000 |
commit | bd639ce85e97f1778f06286de0cf7929d202e594 (patch) | |
tree | c29a4ef1cd9f2c53cc8730608ac2a9b7fdce9126 | |
parent | bd8257b72f2d519d1bac208791e4619e6b88ee7e (diff) | |
parent | e6fc3ac9aac02d12bc5d1313a3ebcb0e3ca85b7a (diff) | |
download | paste-bd639ce85e97f1778f06286de0cf7929d202e594.tar.gz |
Upgrade rust/crates/paste to 1.0.3 am: 280ada00d1 am: 7c7272f572 am: e6fc3ac9aa
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/paste/+/1495336
Change-Id: I620e503c65f2ea3e93d0f0b3f2195359259655c9
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | Cargo.toml.orig | 2 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | src/attr.rs | 140 | ||||
-rw-r--r-- | src/doc.rs | 90 | ||||
-rw-r--r-- | src/lib.rs | 23 | ||||
-rw-r--r-- | tests/test_attr.rs | 22 |
8 files changed, 180 insertions, 109 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 8b0f57b..f883456 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "6a5265f7a937412fb1da72fb72fd32bbaffecebc" + "sha1": "a3e4ace7092f5f0b750efe22fe8c4b65e8495d94" } } @@ -13,7 +13,7 @@ [package] edition = "2018" name = "paste" -version = "1.0.2" +version = "1.0.3" authors = ["David Tolnay <dtolnay@gmail.com>"] description = "Macros for all your token pasting needs" readme = "README.md" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 42aee90..e0b2223 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "paste" -version = "1.0.2" +version = "1.0.3" authors = ["David Tolnay <dtolnay@gmail.com>"] edition = "2018" license = "MIT OR Apache-2.0" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/paste/paste-1.0.2.crate" + value: "https://static.crates.io/crates/paste/paste-1.0.3.crate" } - version: "1.0.2" + version: "1.0.3" license_type: NOTICE last_upgrade_date { year: 2020 - month: 10 - day: 26 + month: 11 + day: 10 } } diff --git a/src/attr.rs b/src/attr.rs new file mode 100644 index 0000000..2d23730 --- /dev/null +++ b/src/attr.rs @@ -0,0 +1,140 @@ +use crate::error::Result; +use crate::segment::{self, Segment}; +use proc_macro::{Delimiter, Group, Span, TokenStream, TokenTree}; +use std::iter; +use std::mem; +use std::str::FromStr; + +pub fn expand_attr( + attr: TokenStream, + span: Span, + contains_paste: &mut bool, +) -> Result<TokenStream> { + let mut tokens = attr.clone().into_iter(); + match tokens.next() { + Some(TokenTree::Ident(..)) => {} + _ => return Ok(attr), + } + + let group = match tokens.next() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '=' => { + let mut count = 0; + if tokens.inspect(|_| count += 1).all(|tt| is_stringlike(&tt)) && count > 1 { + *contains_paste = true; + return do_paste_name_value_attr(attr, span); + } + return Ok(attr); + } + Some(TokenTree::Group(group)) => group, + _ => return Ok(attr), + }; + + if group.delimiter() != Delimiter::Parenthesis { + return Ok(attr); + } + + // There can't be anything else after the first group in a valid attribute. + if tokens.next().is_some() { + return Ok(attr); + } + + let mut group_contains_paste = false; + let mut expanded = TokenStream::new(); + let mut nested_attr = TokenStream::new(); + for tt in group.stream().into_iter() { + match &tt { + TokenTree::Punct(punct) if punct.as_char() == ',' => { + expanded.extend(expand_attr( + nested_attr, + group.span(), + &mut group_contains_paste, + )?); + expanded.extend(iter::once(tt)); + nested_attr = TokenStream::new(); + } + _ => nested_attr.extend(iter::once(tt)), + } + } + + if !nested_attr.is_empty() { + expanded.extend(expand_attr( + nested_attr, + group.span(), + &mut group_contains_paste, + )?); + } + + if group_contains_paste { + *contains_paste = true; + let mut group = Group::new(Delimiter::Parenthesis, expanded); + group.set_span(span); + Ok(attr + .into_iter() + // Just keep the initial ident in `#[ident(...)]`. + .take(1) + .chain(iter::once(TokenTree::Group(group))) + .collect()) + } else { + Ok(attr) + } +} + +fn do_paste_name_value_attr(attr: TokenStream, span: Span) -> Result<TokenStream> { + let mut expanded = TokenStream::new(); + let mut tokens = attr.into_iter().peekable(); + expanded.extend(tokens.by_ref().take(2)); // `doc =` + + let mut segments = segment::parse(&mut tokens)?; + + for segment in &mut segments { + if let Segment::String(string) = segment { + if let Some(open_quote) = string.value.find('"') { + if open_quote == 0 { + string.value.truncate(string.value.len() - 1); + string.value.remove(0); + } else { + let begin = open_quote + 1; + let end = string.value.rfind('"').unwrap(); + let raw_string = mem::replace(&mut string.value, String::new()); + for ch in raw_string[begin..end].chars() { + string.value.extend(ch.escape_default()); + } + } + } + } + } + + let mut lit = segment::paste(&segments)?; + lit.insert(0, '"'); + lit.push('"'); + + let mut lit = TokenStream::from_str(&lit) + .unwrap() + .into_iter() + .next() + .unwrap(); + lit.set_span(span); + expanded.extend(iter::once(lit)); + Ok(expanded) +} + +fn is_stringlike(token: &TokenTree) -> bool { + match token { + TokenTree::Ident(_) => true, + TokenTree::Literal(literal) => { + let repr = literal.to_string(); + !repr.starts_with('b') && !repr.starts_with('\'') + } + TokenTree::Group(group) => { + if group.delimiter() != Delimiter::None { + return false; + } + let mut inner = group.stream().into_iter(); + match inner.next() { + Some(first) => inner.next().is_none() && is_stringlike(&first), + None => false, + } + } + TokenTree::Punct(punct) => punct.as_char() == '\'' || punct.as_char() == ':', + } +} diff --git a/src/doc.rs b/src/doc.rs deleted file mode 100644 index 5fa2ad9..0000000 --- a/src/doc.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::error::Result; -use crate::segment::{self, Segment}; -use proc_macro::{Delimiter, Span, TokenStream, TokenTree}; -use std::iter; -use std::mem; -use std::str::FromStr; - -pub fn is_pasted_doc(input: &TokenStream) -> bool { - #[derive(PartialEq)] - enum State { - Init, - Doc, - Equal, - First, - Rest, - } - - let mut state = State::Init; - for tt in input.clone() { - state = match (state, &tt) { - (State::Init, TokenTree::Ident(ident)) if ident.to_string() == "doc" => State::Doc, - (State::Doc, TokenTree::Punct(punct)) if punct.as_char() == '=' => State::Equal, - (State::Equal, tt) if is_stringlike(tt) => State::First, - (State::First, tt) | (State::Rest, tt) if is_stringlike(tt) => State::Rest, - _ => return false, - }; - } - - state == State::Rest -} - -pub fn do_paste_doc(attr: &TokenStream, span: Span) -> Result<TokenStream> { - let mut expanded = TokenStream::new(); - let mut tokens = attr.clone().into_iter().peekable(); - expanded.extend(tokens.by_ref().take(2)); // `doc =` - - let mut segments = segment::parse(&mut tokens)?; - - for segment in &mut segments { - if let Segment::String(string) = segment { - if let Some(open_quote) = string.value.find('"') { - if open_quote == 0 { - string.value.truncate(string.value.len() - 1); - string.value.remove(0); - } else { - let begin = open_quote + 1; - let end = string.value.rfind('"').unwrap(); - let raw_string = mem::replace(&mut string.value, String::new()); - for ch in raw_string[begin..end].chars() { - string.value.extend(ch.escape_default()); - } - } - } - } - } - - let mut lit = segment::paste(&segments)?; - lit.insert(0, '"'); - lit.push('"'); - - let mut lit = TokenStream::from_str(&lit) - .unwrap() - .into_iter() - .next() - .unwrap(); - lit.set_span(span); - expanded.extend(iter::once(lit)); - Ok(expanded) -} - -fn is_stringlike(token: &TokenTree) -> bool { - match token { - TokenTree::Ident(_) => true, - TokenTree::Literal(literal) => { - let repr = literal.to_string(); - !repr.starts_with('b') && !repr.starts_with('\'') - } - TokenTree::Group(group) => { - if group.delimiter() != Delimiter::None { - return false; - } - let mut inner = group.stream().into_iter(); - match inner.next() { - Some(first) => inner.next().is_none() && is_stringlike(&first), - None => false, - } - } - TokenTree::Punct(punct) => punct.as_char() == '\'' || punct.as_char() == ':', - } -} @@ -140,11 +140,11 @@ extern crate proc_macro; -mod doc; +mod attr; mod error; mod segment; -use crate::doc::{do_paste_doc, is_pasted_doc}; +use crate::attr::expand_attr; use crate::error::{Error, Result}; use crate::segment::Segment; use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; @@ -206,18 +206,17 @@ fn expand(input: TokenStream, contains_paste: &mut bool) -> Result<TokenStream> } else if delimiter == Delimiter::None && is_flat_group(&content) { expanded.extend(content); *contains_paste = true; - } else if delimiter == Delimiter::Bracket - && (lookbehind == Lookbehind::Pound || lookbehind == Lookbehind::PoundBang) - && is_pasted_doc(&content) - { - let pasted = do_paste_doc(&content, span)?; - let mut group = Group::new(delimiter, pasted); - group.set_span(span); - expanded.extend(iter::once(TokenTree::Group(group))); - *contains_paste = true; } else { let mut group_contains_paste = false; - let nested = expand(content, &mut group_contains_paste)?; + let nested = match delimiter { + Delimiter::Bracket if lookbehind == Lookbehind::Pound => { + expand_attr(content, span, &mut group_contains_paste)? + } + Delimiter::Bracket if lookbehind == Lookbehind::PoundBang => { + expand_attr(content, span, &mut group_contains_paste)? + } + _ => expand(content, &mut group_contains_paste)?, + }; let group = if group_contains_paste { let mut group = Group::new(delimiter, nested); group.set_span(span); diff --git a/tests/test_attr.rs b/tests/test_attr.rs new file mode 100644 index 0000000..fd67e2a --- /dev/null +++ b/tests/test_attr.rs @@ -0,0 +1,22 @@ +use paste::paste; + +#[test] +fn test_paste_cfg() { + macro_rules! m { + ($ret:ident, $width:expr) => { + paste! { + #[cfg(any(feature = "protocol_feature_" $ret:snake, target_pointer_width = "" $width))] + fn new() -> $ret { todo!() } + } + }; + } + + struct Paste; + + #[cfg(target_pointer_width = "64")] + m!(Paste, 64); + #[cfg(target_pointer_width = "32")] + m!(Paste, 32); + + let _ = new; +} |