diff options
Diffstat (limited to 'proc-macro2/src')
-rw-r--r-- | proc-macro2/src/fallback.rs | 1458 | ||||
-rw-r--r-- | proc-macro2/src/lib.rs | 1199 | ||||
-rw-r--r-- | proc-macro2/src/strnom.rs | 391 | ||||
-rw-r--r-- | proc-macro2/src/wrapper.rs | 927 |
4 files changed, 3975 insertions, 0 deletions
diff --git a/proc-macro2/src/fallback.rs b/proc-macro2/src/fallback.rs new file mode 100644 index 0000000..9762d3b --- /dev/null +++ b/proc-macro2/src/fallback.rs @@ -0,0 +1,1458 @@ +#[cfg(span_locations)] +use std::cell::RefCell; +#[cfg(span_locations)] +use std::cmp; +use std::fmt; +use std::iter; +use std::ops::RangeBounds; +#[cfg(procmacro2_semver_exempt)] +use std::path::Path; +use std::path::PathBuf; +use std::str::FromStr; +use std::vec; + +use crate::strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult}; +use crate::{Delimiter, Punct, Spacing, TokenTree}; +use unicode_xid::UnicodeXID; + +#[derive(Clone)] +pub struct TokenStream { + inner: Vec<TokenTree>, +} + +#[derive(Debug)] +pub struct LexError; + +impl TokenStream { + pub fn new() -> TokenStream { + TokenStream { inner: Vec::new() } + } + + pub fn is_empty(&self) -> bool { + self.inner.len() == 0 + } +} + +#[cfg(span_locations)] +fn get_cursor(src: &str) -> Cursor { + // Create a dummy file & add it to the source map + SOURCE_MAP.with(|cm| { + let mut cm = cm.borrow_mut(); + let name = format!("<parsed string {}>", cm.files.len()); + let span = cm.add_file(&name, src); + Cursor { + rest: src, + off: span.lo, + } + }) +} + +#[cfg(not(span_locations))] +fn get_cursor(src: &str) -> Cursor { + Cursor { rest: src } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result<TokenStream, LexError> { + // Create a dummy file & add it to the source map + let cursor = get_cursor(src); + + match token_stream(cursor) { + Ok((input, output)) => { + if skip_whitespace(input).len() != 0 { + Err(LexError) + } else { + Ok(output) + } + } + Err(LexError) => Err(LexError), + } + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut joint = false; + for (i, tt) in self.inner.iter().enumerate() { + if i != 0 && !joint { + write!(f, " ")?; + } + joint = false; + match *tt { + TokenTree::Group(ref tt) => { + let (start, end) = match tt.delimiter() { + Delimiter::Parenthesis => ("(", ")"), + Delimiter::Brace => ("{", "}"), + Delimiter::Bracket => ("[", "]"), + Delimiter::None => ("", ""), + }; + if tt.stream().into_iter().next().is_none() { + write!(f, "{} {}", start, end)? + } else { + write!(f, "{} {} {}", start, tt.stream(), end)? + } + } + TokenTree::Ident(ref tt) => write!(f, "{}", tt)?, + TokenTree::Punct(ref tt) => { + write!(f, "{}", tt.as_char())?; + match tt.spacing() { + Spacing::Alone => {} + Spacing::Joint => joint = true, + } + } + TokenTree::Literal(ref tt) => write!(f, "{}", tt)?, + } + } + + Ok(()) + } +} + +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("TokenStream ")?; + f.debug_list().entries(self.clone()).finish() + } +} + +#[cfg(use_proc_macro)] +impl From<proc_macro::TokenStream> for TokenStream { + fn from(inner: proc_macro::TokenStream) -> TokenStream { + inner + .to_string() + .parse() + .expect("compiler token stream parse failed") + } +} + +#[cfg(use_proc_macro)] +impl From<TokenStream> for proc_macro::TokenStream { + fn from(inner: TokenStream) -> proc_macro::TokenStream { + inner + .to_string() + .parse() + .expect("failed to parse to compiler tokens") + } +} + +impl From<TokenTree> for TokenStream { + fn from(tree: TokenTree) -> TokenStream { + TokenStream { inner: vec![tree] } + } +} + +impl iter::FromIterator<TokenTree> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self { + let mut v = Vec::new(); + + for token in streams.into_iter() { + v.push(token); + } + + TokenStream { inner: v } + } +} + +impl iter::FromIterator<TokenStream> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { + let mut v = Vec::new(); + + for stream in streams.into_iter() { + v.extend(stream.inner); + } + + TokenStream { inner: v } + } +} + +impl Extend<TokenTree> for TokenStream { + fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) { + self.inner.extend(streams); + } +} + +impl Extend<TokenStream> for TokenStream { + fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) { + self.inner + .extend(streams.into_iter().flat_map(|stream| stream)); + } +} + +pub type TokenTreeIter = vec::IntoIter<TokenTree>; + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + self.inner.into_iter() + } +} + +#[derive(Clone, PartialEq, Eq)] +pub struct SourceFile { + path: PathBuf, +} + +impl SourceFile { + /// Get the path to this source file as a string. + pub fn path(&self) -> PathBuf { + self.path.clone() + } + + pub fn is_real(&self) -> bool { + // XXX(nika): Support real files in the future? + false + } +} + +impl fmt::Debug for SourceFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SourceFile") + .field("path", &self.path()) + .field("is_real", &self.is_real()) + .finish() + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LineColumn { + pub line: usize, + pub column: usize, +} + +#[cfg(span_locations)] +thread_local! { + static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap { + // NOTE: We start with a single dummy file which all call_site() and + // def_site() spans reference. + files: vec![{ + #[cfg(procmacro2_semver_exempt)] + { + FileInfo { + name: "<unspecified>".to_owned(), + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + } + } + + #[cfg(not(procmacro2_semver_exempt))] + { + FileInfo { + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + } + } + }], + }); +} + +#[cfg(span_locations)] +struct FileInfo { + #[cfg(procmacro2_semver_exempt)] + name: String, + span: Span, + lines: Vec<usize>, +} + +#[cfg(span_locations)] +impl FileInfo { + fn offset_line_column(&self, offset: usize) -> LineColumn { + assert!(self.span_within(Span { + lo: offset as u32, + hi: offset as u32 + })); + let offset = offset - self.span.lo as usize; + match self.lines.binary_search(&offset) { + Ok(found) => LineColumn { + line: found + 1, + column: 0, + }, + Err(idx) => LineColumn { + line: idx, + column: offset - self.lines[idx - 1], + }, + } + } + + fn span_within(&self, span: Span) -> bool { + span.lo >= self.span.lo && span.hi <= self.span.hi + } +} + +/// Computesthe offsets of each line in the given source string. +#[cfg(span_locations)] +fn lines_offsets(s: &str) -> Vec<usize> { + let mut lines = vec![0]; + let mut prev = 0; + while let Some(len) = s[prev..].find('\n') { + prev += len + 1; + lines.push(prev); + } + lines +} + +#[cfg(span_locations)] +struct SourceMap { + files: Vec<FileInfo>, +} + +#[cfg(span_locations)] +impl SourceMap { + fn next_start_pos(&self) -> u32 { + // Add 1 so there's always space between files. + // + // We'll always have at least 1 file, as we initialize our files list + // with a dummy file. + self.files.last().unwrap().span.hi + 1 + } + + fn add_file(&mut self, name: &str, src: &str) -> Span { + let lines = lines_offsets(src); + let lo = self.next_start_pos(); + // XXX(nika): Shouild we bother doing a checked cast or checked add here? + let span = Span { + lo, + hi: lo + (src.len() as u32), + }; + + #[cfg(procmacro2_semver_exempt)] + self.files.push(FileInfo { + name: name.to_owned(), + span, + lines, + }); + + #[cfg(not(procmacro2_semver_exempt))] + self.files.push(FileInfo { span, lines }); + let _ = name; + + span + } + + fn fileinfo(&self, span: Span) -> &FileInfo { + for file in &self.files { + if file.span_within(span) { + return file; + } + } + panic!("Invalid span with no related FileInfo!"); + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Span { + #[cfg(span_locations)] + lo: u32, + #[cfg(span_locations)] + hi: u32, +} + +impl Span { + #[cfg(not(span_locations))] + pub fn call_site() -> Span { + Span {} + } + + #[cfg(span_locations)] + pub fn call_site() -> Span { + Span { lo: 0, hi: 0 } + } + + #[cfg(procmacro2_semver_exempt)] + pub fn def_site() -> Span { + Span::call_site() + } + + #[cfg(procmacro2_semver_exempt)] + pub fn resolved_at(&self, _other: Span) -> Span { + // Stable spans consist only of line/column information, so + // `resolved_at` and `located_at` only select which span the + // caller wants line/column information from. + *self + } + + #[cfg(procmacro2_semver_exempt)] + pub fn located_at(&self, other: Span) -> Span { + other + } + + #[cfg(procmacro2_semver_exempt)] + pub fn source_file(&self) -> SourceFile { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + let fi = cm.fileinfo(*self); + SourceFile { + path: Path::new(&fi.name).to_owned(), + } + }) + } + + #[cfg(span_locations)] + pub fn start(&self) -> LineColumn { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + let fi = cm.fileinfo(*self); + fi.offset_line_column(self.lo as usize) + }) + } + + #[cfg(span_locations)] + pub fn end(&self) -> LineColumn { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + let fi = cm.fileinfo(*self); + fi.offset_line_column(self.hi as usize) + }) + } + + #[cfg(not(span_locations))] + pub fn join(&self, _other: Span) -> Option<Span> { + Some(Span {}) + } + + #[cfg(span_locations)] + pub fn join(&self, other: Span) -> Option<Span> { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + // If `other` is not within the same FileInfo as us, return None. + if !cm.fileinfo(*self).span_within(other) { + return None; + } + Some(Span { + lo: cmp::min(self.lo, other.lo), + hi: cmp::max(self.hi, other.hi), + }) + }) + } + + #[cfg(not(span_locations))] + fn first_byte(self) -> Self { + self + } + + #[cfg(span_locations)] + fn first_byte(self) -> Self { + Span { + lo: self.lo, + hi: cmp::min(self.lo.saturating_add(1), self.hi), + } + } + + #[cfg(not(span_locations))] + fn last_byte(self) -> Self { + self + } + + #[cfg(span_locations)] + fn last_byte(self) -> Self { + Span { + lo: cmp::max(self.hi.saturating_sub(1), self.lo), + hi: self.hi, + } + } +} + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(procmacro2_semver_exempt)] + return write!(f, "bytes({}..{})", self.lo, self.hi); + + #[cfg(not(procmacro2_semver_exempt))] + write!(f, "Span") + } +} + +pub fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { + if cfg!(procmacro2_semver_exempt) { + debug.field("span", &span); + } +} + +#[derive(Clone)] +pub struct Group { + delimiter: Delimiter, + stream: TokenStream, + span: Span, +} + +impl Group { + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { + Group { + delimiter, + stream, + span: Span::call_site(), + } + } + + pub fn delimiter(&self) -> Delimiter { + self.delimiter + } + + pub fn stream(&self) -> TokenStream { + self.stream.clone() + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn span_open(&self) -> Span { + self.span.first_byte() + } + + pub fn span_close(&self) -> Span { + self.span.last_byte() + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +impl fmt::Display for Group { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (left, right) = match self.delimiter { + Delimiter::Parenthesis => ("(", ")"), + Delimiter::Brace => ("{", "}"), + Delimiter::Bracket => ("[", "]"), + Delimiter::None => ("", ""), + }; + + f.write_str(left)?; + self.stream.fmt(f)?; + f.write_str(right)?; + + Ok(()) + } +} + +impl fmt::Debug for Group { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Group"); + debug.field("delimiter", &self.delimiter); + debug.field("stream", &self.stream); + #[cfg(procmacro2_semver_exempt)] + debug.field("span", &self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub struct Ident { + sym: String, + span: Span, + raw: bool, +} + +impl Ident { + fn _new(string: &str, raw: bool, span: Span) -> Ident { + validate_ident(string); + + Ident { + sym: string.to_owned(), + span, + raw, + } + } + + pub fn new(string: &str, span: Span) -> Ident { + Ident::_new(string, false, span) + } + + pub fn new_raw(string: &str, span: Span) -> Ident { + Ident::_new(string, true, span) + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +fn is_ident_start(c: char) -> bool { + ('a' <= c && c <= 'z') + || ('A' <= c && c <= 'Z') + || c == '_' + || (c > '\x7f' && UnicodeXID::is_xid_start(c)) +} + +fn is_ident_continue(c: char) -> bool { + ('a' <= c && c <= 'z') + || ('A' <= c && c <= 'Z') + || c == '_' + || ('0' <= c && c <= '9') + || (c > '\x7f' && UnicodeXID::is_xid_continue(c)) +} + +fn validate_ident(string: &str) { + let validate = string; + if validate.is_empty() { + panic!("Ident is not allowed to be empty; use Option<Ident>"); + } + + if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') { + panic!("Ident cannot be a number; use Literal instead"); + } + + fn ident_ok(string: &str) -> bool { + let mut chars = string.chars(); + let first = chars.next().unwrap(); + if !is_ident_start(first) { + return false; + } + for ch in chars { + if !is_ident_continue(ch) { + return false; + } + } + true + } + + if !ident_ok(validate) { + panic!("{:?} is not a valid Ident", string); + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.sym == other.sym && self.raw == other.raw + } +} + +impl<T> PartialEq<T> for Ident +where + T: ?Sized + AsRef<str>, +{ + fn eq(&self, other: &T) -> bool { + let other = other.as_ref(); + if self.raw { + other.starts_with("r#") && self.sym == other[2..] + } else { + self.sym == other + } + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.raw { + "r#".fmt(f)?; + } + self.sym.fmt(f) + } +} + +impl fmt::Debug for Ident { + // Ident(proc_macro), Ident(r#union) + #[cfg(not(procmacro2_semver_exempt))] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug = f.debug_tuple("Ident"); + debug.field(&format_args!("{}", self)); + debug.finish() + } + + // Ident { + // sym: proc_macro, + // span: bytes(128..138) + // } + #[cfg(procmacro2_semver_exempt)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug = f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", self)); + debug.field("span", &self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub struct Literal { + text: String, + span: Span, +} + +macro_rules! suffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + Literal::_new(format!(concat!("{}", stringify!($kind)), n)) + } + )*) +} + +macro_rules! unsuffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + Literal::_new(n.to_string()) + } + )*) +} + +impl Literal { + fn _new(text: String) -> Literal { + Literal { + text, + span: Span::call_site(), + } + } + + suffixed_numbers! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, + + f32_suffixed => f32, + f64_suffixed => f64, + } + + unsuffixed_numbers! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, + } + + pub fn f32_unsuffixed(f: f32) -> Literal { + let mut s = f.to_string(); + if !s.contains(".") { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub fn f64_unsuffixed(f: f64) -> Literal { + let mut s = f.to_string(); + if !s.contains(".") { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub fn string(t: &str) -> Literal { + let mut text = String::with_capacity(t.len() + 2); + text.push('"'); + for c in t.chars() { + if c == '\'' { + // escape_default turns this into "\'" which is unnecessary. + text.push(c); + } else { + text.extend(c.escape_default()); + } + } + text.push('"'); + Literal::_new(text) + } + + pub fn character(t: char) -> Literal { + let mut text = String::new(); + text.push('\''); + if t == '"' { + // escape_default turns this into '\"' which is unnecessary. + text.push(t); + } else { + text.extend(t.escape_default()); + } + text.push('\''); + Literal::_new(text) + } + + pub fn byte_string(bytes: &[u8]) -> Literal { + let mut escaped = "b\"".to_string(); + for b in bytes { + match *b { + b'\0' => escaped.push_str(r"\0"), + b'\t' => escaped.push_str(r"\t"), + b'\n' => escaped.push_str(r"\n"), + b'\r' => escaped.push_str(r"\r"), + b'"' => escaped.push_str("\\\""), + b'\\' => escaped.push_str("\\\\"), + b'\x20'..=b'\x7E' => escaped.push(*b as char), + _ => escaped.push_str(&format!("\\x{:02X}", b)), + } + } + escaped.push('"'); + Literal::_new(escaped) + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } + + pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> { + None + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.text.fmt(f) + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Literal"); + debug.field("lit", &format_args!("{}", self.text)); + #[cfg(procmacro2_semver_exempt)] + debug.field("span", &self.span); + debug.finish() + } +} + +fn token_stream(mut input: Cursor) -> PResult<TokenStream> { + let mut trees = Vec::new(); + loop { + let input_no_ws = skip_whitespace(input); + if input_no_ws.rest.len() == 0 { + break; + } + if let Ok((a, tokens)) = doc_comment(input_no_ws) { + input = a; + trees.extend(tokens); + continue; + } + + let (a, tt) = match token_tree(input_no_ws) { + Ok(p) => p, + Err(_) => break, + }; + trees.push(tt); + input = a; + } + Ok((input, TokenStream { inner: trees })) +} + +#[cfg(not(span_locations))] +fn spanned<'a, T>( + input: Cursor<'a>, + f: fn(Cursor<'a>) -> PResult<'a, T>, +) -> PResult<'a, (T, crate::Span)> { + let (a, b) = f(skip_whitespace(input))?; + Ok((a, ((b, crate::Span::_new_stable(Span::call_site()))))) +} + +#[cfg(span_locations)] +fn spanned<'a, T>( + input: Cursor<'a>, + f: fn(Cursor<'a>) -> PResult<'a, T>, +) -> PResult<'a, (T, crate::Span)> { + let input = skip_whitespace(input); + let lo = input.off; + let (a, b) = f(input)?; + let hi = a.off; + let span = crate::Span::_new_stable(Span { lo, hi }); + Ok((a, (b, span))) +} + +fn token_tree(input: Cursor) -> PResult<TokenTree> { + let (rest, (mut tt, span)) = spanned(input, token_kind)?; + tt.set_span(span); + Ok((rest, tt)) +} + +named!(token_kind -> TokenTree, alt!( + map!(group, |g| TokenTree::Group(crate::Group::_new_stable(g))) + | + map!(literal, |l| TokenTree::Literal(crate::Literal::_new_stable(l))) // must be before symbol + | + map!(op, TokenTree::Punct) + | + symbol_leading_ws +)); + +named!(group -> Group, alt!( + delimited!( + punct!("("), + token_stream, + punct!(")") + ) => { |ts| Group::new(Delimiter::Parenthesis, ts) } + | + delimited!( + punct!("["), + token_stream, + punct!("]") + ) => { |ts| Group::new(Delimiter::Bracket, ts) } + | + delimited!( + punct!("{"), + token_stream, + punct!("}") + ) => { |ts| Group::new(Delimiter::Brace, ts) } +)); + +fn symbol_leading_ws(input: Cursor) -> PResult<TokenTree> { + symbol(skip_whitespace(input)) +} + +fn symbol(input: Cursor) -> PResult<TokenTree> { + let raw = input.starts_with("r#"); + let rest = input.advance((raw as usize) << 1); + + let (rest, sym) = symbol_not_raw(rest)?; + + if !raw { + let ident = crate::Ident::new(sym, crate::Span::call_site()); + return Ok((rest, ident.into())); + } + + if sym == "_" { + return Err(LexError); + } + + let ident = crate::Ident::_new_raw(sym, crate::Span::call_site()); + Ok((rest, ident.into())) +} + +fn symbol_not_raw(input: Cursor) -> PResult<&str> { + let mut chars = input.char_indices(); + + match chars.next() { + Some((_, ch)) if is_ident_start(ch) => {} + _ => return Err(LexError), + } + + let mut end = input.len(); + for (i, ch) in chars { + if !is_ident_continue(ch) { + end = i; + break; + } + } + + Ok((input.advance(end), &input.rest[..end])) +} + +fn literal(input: Cursor) -> PResult<Literal> { + let input_no_ws = skip_whitespace(input); + + match literal_nocapture(input_no_ws) { + Ok((a, ())) => { + let start = input.len() - input_no_ws.len(); + let len = input_no_ws.len() - a.len(); + let end = start + len; + Ok((a, Literal::_new(input.rest[start..end].to_string()))) + } + Err(LexError) => Err(LexError), + } +} + +named!(literal_nocapture -> (), alt!( + string + | + byte_string + | + byte + | + character + | + float + | + int +)); + +named!(string -> (), alt!( + quoted_string + | + preceded!( + punct!("r"), + raw_string + ) => { |_| () } +)); + +named!(quoted_string -> (), do_parse!( + punct!("\"") >> + cooked_string >> + tag!("\"") >> + option!(symbol_not_raw) >> + (()) +)); + +fn cooked_string(input: Cursor) -> PResult<()> { + let mut chars = input.char_indices().peekable(); + while let Some((byte_offset, ch)) = chars.next() { + match ch { + '"' => { + return Ok((input.advance(byte_offset), ())); + } + '\r' => { + if let Some((_, '\n')) = chars.next() { + // ... + } else { + break; + } + } + '\\' => match chars.next() { + Some((_, 'x')) => { + if !backslash_x_char(&mut chars) { + break; + } + } + Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\')) + | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {} + Some((_, 'u')) => { + if !backslash_u(&mut chars) { + break; + } + } + Some((_, '\n')) | Some((_, '\r')) => { + while let Some(&(_, ch)) = chars.peek() { + if ch.is_whitespace() { + chars.next(); + } else { + break; + } + } + } + _ => break, + }, + _ch => {} + } + } + Err(LexError) +} + +named!(byte_string -> (), alt!( + delimited!( + punct!("b\""), + cooked_byte_string, + tag!("\"") + ) => { |_| () } + | + preceded!( + punct!("br"), + raw_string + ) => { |_| () } +)); + +fn cooked_byte_string(mut input: Cursor) -> PResult<()> { + let mut bytes = input.bytes().enumerate(); + 'outer: while let Some((offset, b)) = bytes.next() { + match b { + b'"' => { + return Ok((input.advance(offset), ())); + } + b'\r' => { + if let Some((_, b'\n')) = bytes.next() { + // ... + } else { + break; + } + } + b'\\' => match bytes.next() { + Some((_, b'x')) => { + if !backslash_x_byte(&mut bytes) { + break; + } + } + Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\')) + | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {} + Some((newline, b'\n')) | Some((newline, b'\r')) => { + let rest = input.advance(newline + 1); + for (offset, ch) in rest.char_indices() { + if !ch.is_whitespace() { + input = rest.advance(offset); + bytes = input.bytes().enumerate(); + continue 'outer; + } + } + break; + } + _ => break, + }, + b if b < 0x80 => {} + _ => break, + } + } + Err(LexError) +} + +fn raw_string(input: Cursor) -> PResult<()> { + let mut chars = input.char_indices(); + let mut n = 0; + while let Some((byte_offset, ch)) = chars.next() { + match ch { + '"' => { + n = byte_offset; + break; + } + '#' => {} + _ => return Err(LexError), + } + } + for (byte_offset, ch) in chars { + match ch { + '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => { + let rest = input.advance(byte_offset + 1 + n); + return Ok((rest, ())); + } + '\r' => {} + _ => {} + } + } + Err(LexError) +} + +named!(byte -> (), do_parse!( + punct!("b") >> + tag!("'") >> + cooked_byte >> + tag!("'") >> + (()) +)); + +fn cooked_byte(input: Cursor) -> PResult<()> { + let mut bytes = input.bytes().enumerate(); + let ok = match bytes.next().map(|(_, b)| b) { + Some(b'\\') => match bytes.next().map(|(_, b)| b) { + Some(b'x') => backslash_x_byte(&mut bytes), + Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'') + | Some(b'"') => true, + _ => false, + }, + b => b.is_some(), + }; + if ok { + match bytes.next() { + Some((offset, _)) => { + if input.chars().as_str().is_char_boundary(offset) { + Ok((input.advance(offset), ())) + } else { + Err(LexError) + } + } + None => Ok((input.advance(input.len()), ())), + } + } else { + Err(LexError) + } +} + +named!(character -> (), do_parse!( + punct!("'") >> + cooked_char >> + tag!("'") >> + (()) +)); + +fn cooked_char(input: Cursor) -> PResult<()> { + let mut chars = input.char_indices(); + let ok = match chars.next().map(|(_, ch)| ch) { + Some('\\') => match chars.next().map(|(_, ch)| ch) { + Some('x') => backslash_x_char(&mut chars), + Some('u') => backslash_u(&mut chars), + Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => { + true + } + _ => false, + }, + ch => ch.is_some(), + }; + if ok { + match chars.next() { + Some((idx, _)) => Ok((input.advance(idx), ())), + None => Ok((input.advance(input.len()), ())), + } + } else { + Err(LexError) + } +} + +macro_rules! next_ch { + ($chars:ident @ $pat:pat $(| $rest:pat)*) => { + match $chars.next() { + Some((_, ch)) => match ch { + $pat $(| $rest)* => ch, + _ => return false, + }, + None => return false + } + }; +} + +fn backslash_x_char<I>(chars: &mut I) -> bool +where + I: Iterator<Item = (usize, char)>, +{ + next_ch!(chars @ '0'..='7'); + next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); + true +} + +fn backslash_x_byte<I>(chars: &mut I) -> bool +where + I: Iterator<Item = (usize, u8)>, +{ + next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F'); + next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F'); + true +} + +fn backslash_u<I>(chars: &mut I) -> bool +where + I: Iterator<Item = (usize, char)>, +{ + next_ch!(chars @ '{'); + next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); + loop { + let c = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F' | '_' | '}'); + if c == '}' { + return true; + } + } +} + +fn float(input: Cursor) -> PResult<()> { + let (mut rest, ()) = float_digits(input)?; + if let Some(ch) = rest.chars().next() { + if is_ident_start(ch) { + rest = symbol_not_raw(rest)?.0; + } + } + word_break(rest) +} + +fn float_digits(input: Cursor) -> PResult<()> { + let mut chars = input.chars().peekable(); + match chars.next() { + Some(ch) if ch >= '0' && ch <= '9' => {} + _ => return Err(LexError), + } + + let mut len = 1; + let mut has_dot = false; + let mut has_exp = false; + while let Some(&ch) = chars.peek() { + match ch { + '0'..='9' | '_' => { + chars.next(); + len += 1; + } + '.' => { + if has_dot { + break; + } + chars.next(); + if chars + .peek() + .map(|&ch| ch == '.' || is_ident_start(ch)) + .unwrap_or(false) + { + return Err(LexError); + } + len += 1; + has_dot = true; + } + 'e' | 'E' => { + chars.next(); + len += 1; + has_exp = true; + break; + } + _ => break, + } + } + + let rest = input.advance(len); + if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) { + return Err(LexError); + } + + if has_exp { + let mut has_exp_value = false; + while let Some(&ch) = chars.peek() { + match ch { + '+' | '-' => { + if has_exp_value { + break; + } + chars.next(); + len += 1; + } + '0'..='9' => { + chars.next(); + len += 1; + has_exp_value = true; + } + '_' => { + chars.next(); + len += 1; + } + _ => break, + } + } + if !has_exp_value { + return Err(LexError); + } + } + + Ok((input.advance(len), ())) +} + +fn int(input: Cursor) -> PResult<()> { + let (mut rest, ()) = digits(input)?; + if let Some(ch) = rest.chars().next() { + if is_ident_start(ch) { + rest = symbol_not_raw(rest)?.0; + } + } + word_break(rest) +} + +fn digits(mut input: Cursor) -> PResult<()> { + let base = if input.starts_with("0x") { + input = input.advance(2); + 16 + } else if input.starts_with("0o") { + input = input.advance(2); + 8 + } else if input.starts_with("0b") { + input = input.advance(2); + 2 + } else { + 10 + }; + + let mut len = 0; + let mut empty = true; + for b in input.bytes() { + let digit = match b { + b'0'..=b'9' => (b - b'0') as u64, + b'a'..=b'f' => 10 + (b - b'a') as u64, + b'A'..=b'F' => 10 + (b - b'A') as u64, + b'_' => { + if empty && base == 10 { + return Err(LexError); + } + len += 1; + continue; + } + _ => break, + }; + if digit >= base { + return Err(LexError); + } + len += 1; + empty = false; + } + if empty { + Err(LexError) + } else { + Ok((input.advance(len), ())) + } +} + +fn op(input: Cursor) -> PResult<Punct> { + let input = skip_whitespace(input); + match op_char(input) { + Ok((rest, '\'')) => { + symbol(rest)?; + Ok((rest, Punct::new('\'', Spacing::Joint))) + } + Ok((rest, ch)) => { + let kind = match op_char(rest) { + Ok(_) => Spacing::Joint, + Err(LexError) => Spacing::Alone, + }; + Ok((rest, Punct::new(ch, kind))) + } + Err(LexError) => Err(LexError), + } +} + +fn op_char(input: Cursor) -> PResult<char> { + if input.starts_with("//") || input.starts_with("/*") { + // Do not accept `/` of a comment as an op. + return Err(LexError); + } + + let mut chars = input.chars(); + let first = match chars.next() { + Some(ch) => ch, + None => { + return Err(LexError); + } + }; + let recognized = "~!@#$%^&*-=+|;:,<.>/?'"; + if recognized.contains(first) { + Ok((input.advance(first.len_utf8()), first)) + } else { + Err(LexError) + } +} + +fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> { + let mut trees = Vec::new(); + let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?; + trees.push(TokenTree::Punct(Punct::new('#', Spacing::Alone))); + if inner { + trees.push(Punct::new('!', Spacing::Alone).into()); + } + let mut stream = vec![ + TokenTree::Ident(crate::Ident::new("doc", span)), + TokenTree::Punct(Punct::new('=', Spacing::Alone)), + TokenTree::Literal(crate::Literal::string(comment)), + ]; + for tt in stream.iter_mut() { + tt.set_span(span); + } + let group = Group::new(Delimiter::Bracket, stream.into_iter().collect()); + trees.push(crate::Group::_new_stable(group).into()); + for tt in trees.iter_mut() { + tt.set_span(span); + } + Ok((rest, trees)) +} + +named!(doc_comment_contents -> (&str, bool), alt!( + do_parse!( + punct!("//!") >> + s: take_until_newline_or_eof!() >> + ((s, true)) + ) + | + do_parse!( + option!(whitespace) >> + peek!(tag!("/*!")) >> + s: block_comment >> + ((s, true)) + ) + | + do_parse!( + punct!("///") >> + not!(tag!("/")) >> + s: take_until_newline_or_eof!() >> + ((s, false)) + ) + | + do_parse!( + option!(whitespace) >> + peek!(tuple!(tag!("/**"), not!(tag!("*")))) >> + s: block_comment >> + ((s, false)) + ) +)); diff --git a/proc-macro2/src/lib.rs b/proc-macro2/src/lib.rs new file mode 100644 index 0000000..bbfb375 --- /dev/null +++ b/proc-macro2/src/lib.rs @@ -0,0 +1,1199 @@ +//! A wrapper around the procedural macro API of the compiler's [`proc_macro`] +//! crate. This library serves two purposes: +//! +//! [`proc_macro`]: https://doc.rust-lang.org/proc_macro/ +//! +//! - **Bring proc-macro-like functionality to other contexts like build.rs and +//! main.rs.** Types from `proc_macro` are entirely specific to procedural +//! macros and cannot ever exist in code outside of a procedural macro. +//! Meanwhile `proc_macro2` types may exist anywhere including non-macro code. +//! By developing foundational libraries like [syn] and [quote] against +//! `proc_macro2` rather than `proc_macro`, the procedural macro ecosystem +//! becomes easily applicable to many other use cases and we avoid +//! reimplementing non-macro equivalents of those libraries. +//! +//! - **Make procedural macros unit testable.** As a consequence of being +//! specific to procedural macros, nothing that uses `proc_macro` can be +//! executed from a unit test. In order for helper libraries or components of +//! a macro to be testable in isolation, they must be implemented using +//! `proc_macro2`. +//! +//! [syn]: https://github.com/dtolnay/syn +//! [quote]: https://github.com/dtolnay/quote +//! +//! # Usage +//! +//! The skeleton of a typical procedural macro typically looks like this: +//! +//! ``` +//! extern crate proc_macro; +//! +//! # const IGNORE: &str = stringify! { +//! #[proc_macro_derive(MyDerive)] +//! # }; +//! # #[cfg(wrap_proc_macro)] +//! pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +//! let input = proc_macro2::TokenStream::from(input); +//! +//! let output: proc_macro2::TokenStream = { +//! /* transform input */ +//! # input +//! }; +//! +//! proc_macro::TokenStream::from(output) +//! } +//! ``` +//! +//! If parsing with [Syn], you'll use [`parse_macro_input!`] instead to +//! propagate parse errors correctly back to the compiler when parsing fails. +//! +//! [`parse_macro_input!`]: https://docs.rs/syn/1.0/syn/macro.parse_macro_input.html +//! +//! # Unstable features +//! +//! The default feature set of proc-macro2 tracks the most recent stable +//! compiler API. Functionality in `proc_macro` that is not yet stable is not +//! exposed by proc-macro2 by default. +//! +//! To opt into the additional APIs available in the most recent nightly +//! compiler, the `procmacro2_semver_exempt` config flag must be passed to +//! rustc. We will polyfill those nightly-only APIs back to Rust 1.31.0. As +//! these are unstable APIs that track the nightly compiler, minor versions of +//! proc-macro2 may make breaking changes to them at any time. +//! +//! ```sh +//! RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build +//! ``` +//! +//! Note that this must not only be done for your crate, but for any crate that +//! depends on your crate. This infectious nature is intentional, as it serves +//! as a reminder that you are outside of the normal semver guarantees. +//! +//! Semver exempt methods are marked as such in the proc-macro2 documentation. +//! +//! # Thread-Safety +//! +//! Most types in this crate are `!Sync` because the underlying compiler +//! types make use of thread-local memory, meaning they cannot be accessed from +//! a different thread. + +// Proc-macro2 types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.7")] +#![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))] +#![cfg_attr(super_unstable, feature(proc_macro_raw_ident, proc_macro_def_site))] + +#[cfg(use_proc_macro)] +extern crate proc_macro; + +use std::cmp::Ordering; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; +use std::marker; +use std::ops::RangeBounds; +#[cfg(procmacro2_semver_exempt)] +use std::path::PathBuf; +use std::rc::Rc; +use std::str::FromStr; + +#[macro_use] +mod strnom; +mod fallback; + +#[cfg(not(wrap_proc_macro))] +use crate::fallback as imp; +#[path = "wrapper.rs"] +#[cfg(wrap_proc_macro)] +mod imp; + +/// An abstract stream of tokens, or more concretely a sequence of token trees. +/// +/// This type provides interfaces for iterating over token trees and for +/// collecting token trees into one stream. +/// +/// Token stream is both the input and output of `#[proc_macro]`, +/// `#[proc_macro_attribute]` and `#[proc_macro_derive]` definitions. +#[derive(Clone)] +pub struct TokenStream { + inner: imp::TokenStream, + _marker: marker::PhantomData<Rc<()>>, +} + +/// Error returned from `TokenStream::from_str`. +pub struct LexError { + inner: imp::LexError, + _marker: marker::PhantomData<Rc<()>>, +} + +impl TokenStream { + fn _new(inner: imp::TokenStream) -> TokenStream { + TokenStream { + inner, + _marker: marker::PhantomData, + } + } + + fn _new_stable(inner: fallback::TokenStream) -> TokenStream { + TokenStream { + inner: inner.into(), + _marker: marker::PhantomData, + } + } + + /// Returns an empty `TokenStream` containing no token trees. + pub fn new() -> TokenStream { + TokenStream::_new(imp::TokenStream::new()) + } + + /// Checks if this `TokenStream` is empty. + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +/// `TokenStream::default()` returns an empty stream, +/// i.e. this is equivalent with `TokenStream::new()`. +impl Default for TokenStream { + fn default() -> Self { + TokenStream::new() + } +} + +/// Attempts to break the string into tokens and parse those tokens into a token +/// stream. +/// +/// May fail for a number of reasons, for example, if the string contains +/// unbalanced delimiters or characters not existing in the language. +/// +/// NOTE: Some errors may cause panics instead of returning `LexError`. We +/// reserve the right to change these errors into `LexError`s later. +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result<TokenStream, LexError> { + let e = src.parse().map_err(|e| LexError { + inner: e, + _marker: marker::PhantomData, + })?; + Ok(TokenStream::_new(e)) + } +} + +#[cfg(use_proc_macro)] +impl From<proc_macro::TokenStream> for TokenStream { + fn from(inner: proc_macro::TokenStream) -> TokenStream { + TokenStream::_new(inner.into()) + } +} + +#[cfg(use_proc_macro)] +impl From<TokenStream> for proc_macro::TokenStream { + fn from(inner: TokenStream) -> proc_macro::TokenStream { + inner.inner.into() + } +} + +impl From<TokenTree> for TokenStream { + fn from(token: TokenTree) -> Self { + TokenStream::_new(imp::TokenStream::from(token)) + } +} + +impl Extend<TokenTree> for TokenStream { + fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) { + self.inner.extend(streams) + } +} + +impl Extend<TokenStream> for TokenStream { + fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) { + self.inner + .extend(streams.into_iter().map(|stream| stream.inner)) + } +} + +/// Collects a number of token trees into a single stream. +impl FromIterator<TokenTree> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self { + TokenStream::_new(streams.into_iter().collect()) + } +} +impl FromIterator<TokenStream> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { + TokenStream::_new(streams.into_iter().map(|i| i.inner).collect()) + } +} + +/// Prints the token stream as a string that is supposed to be losslessly +/// convertible back into the same token stream (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative +/// numeric literals. +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// Prints token in a form convenient for debugging. +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// The source file of a given `Span`. +/// +/// This type is semver exempt and not exposed by default. +#[cfg(procmacro2_semver_exempt)] +#[derive(Clone, PartialEq, Eq)] +pub struct SourceFile { + inner: imp::SourceFile, + _marker: marker::PhantomData<Rc<()>>, +} + +#[cfg(procmacro2_semver_exempt)] +impl SourceFile { + fn _new(inner: imp::SourceFile) -> Self { + SourceFile { + inner, + _marker: marker::PhantomData, + } + } + + /// Get the path to this source file. + /// + /// ### Note + /// + /// If the code span associated with this `SourceFile` was generated by an + /// external macro, this may not be an actual path on the filesystem. Use + /// [`is_real`] to check. + /// + /// Also note that even if `is_real` returns `true`, if + /// `--remap-path-prefix` was passed on the command line, the path as given + /// may not actually be valid. + /// + /// [`is_real`]: #method.is_real + pub fn path(&self) -> PathBuf { + self.inner.path() + } + + /// Returns `true` if this source file is a real source file, and not + /// generated by an external macro's expansion. + pub fn is_real(&self) -> bool { + self.inner.is_real() + } +} + +#[cfg(procmacro2_semver_exempt)] +impl fmt::Debug for SourceFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// A line-column pair representing the start or end of a `Span`. +/// +/// This type is semver exempt and not exposed by default. +#[cfg(span_locations)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct LineColumn { + /// The 1-indexed line in the source file on which the span starts or ends + /// (inclusive). + pub line: usize, + /// The 0-indexed column (in UTF-8 characters) in the source file on which + /// the span starts or ends (inclusive). + pub column: usize, +} + +/// A region of source code, along with macro expansion information. +#[derive(Copy, Clone)] +pub struct Span { + inner: imp::Span, + _marker: marker::PhantomData<Rc<()>>, +} + +impl Span { + fn _new(inner: imp::Span) -> Span { + Span { + inner, + _marker: marker::PhantomData, + } + } + + fn _new_stable(inner: fallback::Span) -> Span { + Span { + inner: inner.into(), + _marker: marker::PhantomData, + } + } + + /// The span of the invocation of the current procedural macro. + /// + /// Identifiers created with this span will be resolved as if they were + /// written directly at the macro call location (call-site hygiene) and + /// other code at the macro call site will be able to refer to them as well. + pub fn call_site() -> Span { + Span::_new(imp::Span::call_site()) + } + + /// A span that resolves at the macro definition site. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn def_site() -> Span { + Span::_new(imp::Span::def_site()) + } + + /// Creates a new span with the same line/column information as `self` but + /// that resolves symbols as though it were at `other`. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn resolved_at(&self, other: Span) -> Span { + Span::_new(self.inner.resolved_at(other.inner)) + } + + /// Creates a new span with the same name resolution behavior as `self` but + /// with the line/column information of `other`. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn located_at(&self, other: Span) -> Span { + Span::_new(self.inner.located_at(other.inner)) + } + + /// Convert `proc_macro2::Span` to `proc_macro::Span`. + /// + /// This method is available when building with a nightly compiler, or when + /// building with rustc 1.29+ *without* semver exempt features. + /// + /// # Panics + /// + /// Panics if called from outside of a procedural macro. Unlike + /// `proc_macro2::Span`, the `proc_macro::Span` type can only exist within + /// the context of a procedural macro invocation. + #[cfg(wrap_proc_macro)] + pub fn unwrap(self) -> proc_macro::Span { + self.inner.unwrap() + } + + // Soft deprecated. Please use Span::unwrap. + #[cfg(wrap_proc_macro)] + #[doc(hidden)] + pub fn unstable(self) -> proc_macro::Span { + self.unwrap() + } + + /// The original source file into which this span points. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn source_file(&self) -> SourceFile { + SourceFile::_new(self.inner.source_file()) + } + + /// Get the starting line/column in the source file for this span. + /// + /// This method requires the `"span-locations"` feature to be enabled. + #[cfg(span_locations)] + pub fn start(&self) -> LineColumn { + let imp::LineColumn { line, column } = self.inner.start(); + LineColumn { line, column } + } + + /// Get the ending line/column in the source file for this span. + /// + /// This method requires the `"span-locations"` feature to be enabled. + #[cfg(span_locations)] + pub fn end(&self) -> LineColumn { + let imp::LineColumn { line, column } = self.inner.end(); + LineColumn { line, column } + } + + /// Create a new span encompassing `self` and `other`. + /// + /// Returns `None` if `self` and `other` are from different files. + /// + /// Warning: the underlying [`proc_macro::Span::join`] method is + /// nightly-only. When called from within a procedural macro not using a + /// nightly compiler, this method will always return `None`. + /// + /// [`proc_macro::Span::join`]: https://doc.rust-lang.org/proc_macro/struct.Span.html#method.join + pub fn join(&self, other: Span) -> Option<Span> { + self.inner.join(other.inner).map(Span::_new) + } + + /// Compares two spans to see if they're equal. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn eq(&self, other: &Span) -> bool { + self.inner.eq(&other.inner) + } +} + +/// Prints a span in a form convenient for debugging. +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). +#[derive(Clone)] +pub enum TokenTree { + /// A token stream surrounded by bracket delimiters. + Group(Group), + /// An identifier. + Ident(Ident), + /// A single punctuation character (`+`, `,`, `$`, etc.). + Punct(Punct), + /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. + Literal(Literal), +} + +impl TokenTree { + /// Returns the span of this tree, delegating to the `span` method of + /// the contained token or a delimited stream. + pub fn span(&self) -> Span { + match *self { + TokenTree::Group(ref t) => t.span(), + TokenTree::Ident(ref t) => t.span(), + TokenTree::Punct(ref t) => t.span(), + TokenTree::Literal(ref t) => t.span(), + } + } + + /// Configures the span for *only this token*. + /// + /// Note that if this token is a `Group` then this method will not configure + /// the span of each of the internal tokens, this will simply delegate to + /// the `set_span` method of each variant. + pub fn set_span(&mut self, span: Span) { + match *self { + TokenTree::Group(ref mut t) => t.set_span(span), + TokenTree::Ident(ref mut t) => t.set_span(span), + TokenTree::Punct(ref mut t) => t.set_span(span), + TokenTree::Literal(ref mut t) => t.set_span(span), + } + } +} + +impl From<Group> for TokenTree { + fn from(g: Group) -> TokenTree { + TokenTree::Group(g) + } +} + +impl From<Ident> for TokenTree { + fn from(g: Ident) -> TokenTree { + TokenTree::Ident(g) + } +} + +impl From<Punct> for TokenTree { + fn from(g: Punct) -> TokenTree { + TokenTree::Punct(g) + } +} + +impl From<Literal> for TokenTree { + fn from(g: Literal) -> TokenTree { + TokenTree::Literal(g) + } +} + +/// Prints the token tree as a string that is supposed to be losslessly +/// convertible back into the same token tree (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative +/// numeric literals. +impl fmt::Display for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TokenTree::Group(ref t) => t.fmt(f), + TokenTree::Ident(ref t) => t.fmt(f), + TokenTree::Punct(ref t) => t.fmt(f), + TokenTree::Literal(ref t) => t.fmt(f), + } + } +} + +/// Prints token tree in a form convenient for debugging. +impl fmt::Debug for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Each of these has the name in the struct type in the derived debug, + // so don't bother with an extra layer of indirection + match *self { + TokenTree::Group(ref t) => t.fmt(f), + TokenTree::Ident(ref t) => { + let mut debug = f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", t)); + imp::debug_span_field_if_nontrivial(&mut debug, t.span().inner); + debug.finish() + } + TokenTree::Punct(ref t) => t.fmt(f), + TokenTree::Literal(ref t) => t.fmt(f), + } + } +} + +/// A delimited token stream. +/// +/// A `Group` internally contains a `TokenStream` which is surrounded by +/// `Delimiter`s. +#[derive(Clone)] +pub struct Group { + inner: imp::Group, +} + +/// Describes how a sequence of token trees is delimited. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Delimiter { + /// `( ... )` + Parenthesis, + /// `{ ... }` + Brace, + /// `[ ... ]` + Bracket, + /// `Ø ... Ø` + /// + /// An implicit delimiter, that may, for example, appear around tokens + /// coming from a "macro variable" `$var`. It is important to preserve + /// operator priorities in cases like `$var * 3` where `$var` is `1 + 2`. + /// Implicit delimiters may not survive roundtrip of a token stream through + /// a string. + None, +} + +impl Group { + fn _new(inner: imp::Group) -> Self { + Group { inner } + } + + fn _new_stable(inner: fallback::Group) -> Self { + Group { + inner: inner.into(), + } + } + + /// Creates a new `Group` with the given delimiter and token stream. + /// + /// This constructor will set the span for this group to + /// `Span::call_site()`. To change the span you can use the `set_span` + /// method below. + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { + Group { + inner: imp::Group::new(delimiter, stream.inner), + } + } + + /// Returns the delimiter of this `Group` + pub fn delimiter(&self) -> Delimiter { + self.inner.delimiter() + } + + /// Returns the `TokenStream` of tokens that are delimited in this `Group`. + /// + /// Note that the returned token stream does not include the delimiter + /// returned above. + pub fn stream(&self) -> TokenStream { + TokenStream::_new(self.inner.stream()) + } + + /// Returns the span for the delimiters of this token stream, spanning the + /// entire `Group`. + /// + /// ```text + /// pub fn span(&self) -> Span { + /// ^^^^^^^ + /// ``` + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Returns the span pointing to the opening delimiter of this group. + /// + /// ```text + /// pub fn span_open(&self) -> Span { + /// ^ + /// ``` + pub fn span_open(&self) -> Span { + Span::_new(self.inner.span_open()) + } + + /// Returns the span pointing to the closing delimiter of this group. + /// + /// ```text + /// pub fn span_close(&self) -> Span { + /// ^ + /// ``` + pub fn span_close(&self) -> Span { + Span::_new(self.inner.span_close()) + } + + /// Configures the span for this `Group`'s delimiters, but not its internal + /// tokens. + /// + /// This method will **not** set the span of all the internal tokens spanned + /// by this group, but rather it will only set the span of the delimiter + /// tokens at the level of the `Group`. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner) + } +} + +/// Prints the group as a string that should be losslessly convertible back +/// into the same group (modulo spans), except for possibly `TokenTree::Group`s +/// with `Delimiter::None` delimiters. +impl fmt::Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.inner, formatter) + } +} + +impl fmt::Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, formatter) + } +} + +/// An `Punct` is an single punctuation character like `+`, `-` or `#`. +/// +/// Multicharacter operators like `+=` are represented as two instances of +/// `Punct` with different forms of `Spacing` returned. +#[derive(Clone)] +pub struct Punct { + op: char, + spacing: Spacing, + span: Span, +} + +/// Whether an `Punct` is followed immediately by another `Punct` or followed by +/// another token or whitespace. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Spacing { + /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`. + Alone, + /// E.g. `+` is `Joint` in `+=` or `'` is `Joint` in `'#`. + /// + /// Additionally, single quote `'` can join with identifiers to form + /// lifetimes `'ident`. + Joint, +} + +impl Punct { + /// Creates a new `Punct` from the given character and spacing. + /// + /// The `ch` argument must be a valid punctuation character permitted by the + /// language, otherwise the function will panic. + /// + /// The returned `Punct` will have the default span of `Span::call_site()` + /// which can be further configured with the `set_span` method below. + pub fn new(op: char, spacing: Spacing) -> Punct { + Punct { + op, + spacing, + span: Span::call_site(), + } + } + + /// Returns the value of this punctuation character as `char`. + pub fn as_char(&self) -> char { + self.op + } + + /// Returns the spacing of this punctuation character, indicating whether + /// it's immediately followed by another `Punct` in the token stream, so + /// they can potentially be combined into a multicharacter operator + /// (`Joint`), or it's followed by some other token or whitespace (`Alone`) + /// so the operator has certainly ended. + pub fn spacing(&self) -> Spacing { + self.spacing + } + + /// Returns the span for this punctuation character. + pub fn span(&self) -> Span { + self.span + } + + /// Configure the span for this punctuation character. + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +/// Prints the punctuation character as a string that should be losslessly +/// convertible back into the same character. +impl fmt::Display for Punct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.op.fmt(f) + } +} + +impl fmt::Debug for Punct { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Punct"); + debug.field("op", &self.op); + debug.field("spacing", &self.spacing); + imp::debug_span_field_if_nontrivial(&mut debug, self.span.inner); + debug.finish() + } +} + +/// A word of Rust code, which may be a keyword or legal variable name. +/// +/// An identifier consists of at least one Unicode code point, the first of +/// which has the XID_Start property and the rest of which have the XID_Continue +/// property. +/// +/// - The empty string is not an identifier. Use `Option<Ident>`. +/// - A lifetime is not an identifier. Use `syn::Lifetime` instead. +/// +/// An identifier constructed with `Ident::new` is permitted to be a Rust +/// keyword, though parsing one through its [`Parse`] implementation rejects +/// Rust keywords. Use `input.call(Ident::parse_any)` when parsing to match the +/// behaviour of `Ident::new`. +/// +/// [`Parse`]: https://docs.rs/syn/1.0/syn/parse/trait.Parse.html +/// +/// # Examples +/// +/// A new ident can be created from a string using the `Ident::new` function. +/// A span must be provided explicitly which governs the name resolution +/// behavior of the resulting identifier. +/// +/// ``` +/// use proc_macro2::{Ident, Span}; +/// +/// fn main() { +/// let call_ident = Ident::new("calligraphy", Span::call_site()); +/// +/// println!("{}", call_ident); +/// } +/// ``` +/// +/// An ident can be interpolated into a token stream using the `quote!` macro. +/// +/// ``` +/// use proc_macro2::{Ident, Span}; +/// use quote::quote; +/// +/// fn main() { +/// let ident = Ident::new("demo", Span::call_site()); +/// +/// // Create a variable binding whose name is this ident. +/// let expanded = quote! { let #ident = 10; }; +/// +/// // Create a variable binding with a slightly different name. +/// let temp_ident = Ident::new(&format!("new_{}", ident), Span::call_site()); +/// let expanded = quote! { let #temp_ident = 10; }; +/// } +/// ``` +/// +/// A string representation of the ident is available through the `to_string()` +/// method. +/// +/// ``` +/// # use proc_macro2::{Ident, Span}; +/// # +/// # let ident = Ident::new("another_identifier", Span::call_site()); +/// # +/// // Examine the ident as a string. +/// let ident_string = ident.to_string(); +/// if ident_string.len() > 60 { +/// println!("Very long identifier: {}", ident_string) +/// } +/// ``` +#[derive(Clone)] +pub struct Ident { + inner: imp::Ident, + _marker: marker::PhantomData<Rc<()>>, +} + +impl Ident { + fn _new(inner: imp::Ident) -> Ident { + Ident { + inner, + _marker: marker::PhantomData, + } + } + + /// Creates a new `Ident` with the given `string` as well as the specified + /// `span`. + /// + /// The `string` argument must be a valid identifier permitted by the + /// language, otherwise the function will panic. + /// + /// Note that `span`, currently in rustc, configures the hygiene information + /// for this identifier. + /// + /// As of this time `Span::call_site()` explicitly opts-in to "call-site" + /// hygiene meaning that identifiers created with this span will be resolved + /// as if they were written directly at the location of the macro call, and + /// other code at the macro call site will be able to refer to them as well. + /// + /// Later spans like `Span::def_site()` will allow to opt-in to + /// "definition-site" hygiene meaning that identifiers created with this + /// span will be resolved at the location of the macro definition and other + /// code at the macro call site will not be able to refer to them. + /// + /// Due to the current importance of hygiene this constructor, unlike other + /// tokens, requires a `Span` to be specified at construction. + /// + /// # Panics + /// + /// Panics if the input string is neither a keyword nor a legal variable + /// name. If you are not sure whether the string contains an identifier and + /// need to handle an error case, use + /// <a href="https://docs.rs/syn/1.0/syn/fn.parse_str.html"><code + /// style="padding-right:0;">syn::parse_str</code></a><code + /// style="padding-left:0;">::<Ident></code> + /// rather than `Ident::new`. + pub fn new(string: &str, span: Span) -> Ident { + Ident::_new(imp::Ident::new(string, span.inner)) + } + + /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn new_raw(string: &str, span: Span) -> Ident { + Ident::_new_raw(string, span) + } + + fn _new_raw(string: &str, span: Span) -> Ident { + Ident::_new(imp::Ident::new_raw(string, span.inner)) + } + + /// Returns the span of this `Ident`. + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Configures the span of this `Ident`, possibly changing its hygiene + /// context. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.inner == other.inner + } +} + +impl<T> PartialEq<T> for Ident +where + T: ?Sized + AsRef<str>, +{ + fn eq(&self, other: &T) -> bool { + self.inner == other + } +} + +impl Eq for Ident {} + +impl PartialOrd for Ident { + fn partial_cmp(&self, other: &Ident) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Ident { + fn cmp(&self, other: &Ident) -> Ordering { + self.to_string().cmp(&other.to_string()) + } +} + +impl Hash for Ident { + fn hash<H: Hasher>(&self, hasher: &mut H) { + self.to_string().hash(hasher) + } +} + +/// Prints the identifier as a string that should be losslessly convertible back +/// into the same identifier. +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// A literal string (`"hello"`), byte string (`b"hello"`), character (`'a'`), +/// byte character (`b'a'`), an integer or floating point number with or without +/// a suffix (`1`, `1u8`, `2.3`, `2.3f32`). +/// +/// Boolean literals like `true` and `false` do not belong here, they are +/// `Ident`s. +#[derive(Clone)] +pub struct Literal { + inner: imp::Literal, + _marker: marker::PhantomData<Rc<()>>, +} + +macro_rules! suffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new suffixed integer literal with the specified value. + /// + /// This function will create an integer like `1u32` where the integer + /// value specified is the first part of the token and the integral is + /// also suffixed at the end. Literals created from negative numbers may + /// not survive rountrips through `TokenStream` or strings and may be + /// broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +macro_rules! unsuffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new unsuffixed integer literal with the specified value. + /// + /// This function will create an integer like `1` where the integer + /// value specified is the first part of the token. No suffix is + /// specified on this token, meaning that invocations like + /// `Literal::i8_unsuffixed(1)` are equivalent to + /// `Literal::u32_unsuffixed(1)`. Literals created from negative numbers + /// may not survive rountrips through `TokenStream` or strings and may + /// be broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +impl Literal { + fn _new(inner: imp::Literal) -> Literal { + Literal { + inner, + _marker: marker::PhantomData, + } + } + + fn _new_stable(inner: fallback::Literal) -> Literal { + Literal { + inner: inner.into(), + _marker: marker::PhantomData, + } + } + + suffixed_int_literals! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, + } + + unsuffixed_int_literals! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, + } + + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed` where + /// the float's value is emitted directly into the token but no suffix is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and + /// positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f64_unsuffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_unsuffixed(f)) + } + + /// Creates a new suffixed floating-point literal. + /// + /// This constructor will create a literal like `1.0f64` where the value + /// specified is the preceding part of the token and `f64` is the suffix of + /// the token. This token will always be inferred to be an `f64` in the + /// compiler. Literals created from negative numbers may not survive + /// rountrips through `TokenStream` or strings and may be broken into two + /// tokens (`-` and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f64_suffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_suffixed(f)) + } + + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed` where + /// the float's value is emitted directly into the token but no suffix is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and + /// positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f32_unsuffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_unsuffixed(f)) + } + + /// Creates a new suffixed floating-point literal. + /// + /// This constructor will create a literal like `1.0f32` where the value + /// specified is the preceding part of the token and `f32` is the suffix of + /// the token. This token will always be inferred to be an `f32` in the + /// compiler. Literals created from negative numbers may not survive + /// rountrips through `TokenStream` or strings and may be broken into two + /// tokens (`-` and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f32_suffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_suffixed(f)) + } + + /// String literal. + pub fn string(string: &str) -> Literal { + Literal::_new(imp::Literal::string(string)) + } + + /// Character literal. + pub fn character(ch: char) -> Literal { + Literal::_new(imp::Literal::character(ch)) + } + + /// Byte string literal. + pub fn byte_string(s: &[u8]) -> Literal { + Literal::_new(imp::Literal::byte_string(s)) + } + + /// Returns the span encompassing this literal. + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Configures the span associated for this literal. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } + + /// Returns a `Span` that is a subset of `self.span()` containing only + /// the source bytes in range `range`. Returns `None` if the would-be + /// trimmed span is outside the bounds of `self`. + /// + /// Warning: the underlying [`proc_macro::Literal::subspan`] method is + /// nightly-only. When called from within a procedural macro not using a + /// nightly compiler, this method will always return `None`. + /// + /// [`proc_macro::Literal::subspan`]: https://doc.rust-lang.org/proc_macro/struct.Literal.html#method.subspan + pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> { + self.inner.subspan(range).map(Span::_new) + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// Public implementation details for the `TokenStream` type, such as iterators. +pub mod token_stream { + use std::fmt; + use std::marker; + use std::rc::Rc; + + pub use crate::TokenStream; + use crate::{imp, TokenTree}; + + /// An iterator over `TokenStream`'s `TokenTree`s. + /// + /// The iteration is "shallow", e.g. the iterator doesn't recurse into + /// delimited groups, and returns whole groups as token trees. + #[derive(Clone)] + pub struct IntoIter { + inner: imp::TokenTreeIter, + _marker: marker::PhantomData<Rc<()>>, + } + + impl Iterator for IntoIter { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + self.inner.next() + } + } + + impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } + } + + impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.inner.into_iter(), + _marker: marker::PhantomData, + } + } + } +} diff --git a/proc-macro2/src/strnom.rs b/proc-macro2/src/strnom.rs new file mode 100644 index 0000000..eb7d0b8 --- /dev/null +++ b/proc-macro2/src/strnom.rs @@ -0,0 +1,391 @@ +//! Adapted from [`nom`](https://github.com/Geal/nom). + +use crate::fallback::LexError; +use std::str::{Bytes, CharIndices, Chars}; +use unicode_xid::UnicodeXID; + +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Cursor<'a> { + pub rest: &'a str, + #[cfg(span_locations)] + pub off: u32, +} + +impl<'a> Cursor<'a> { + #[cfg(not(span_locations))] + pub fn advance(&self, amt: usize) -> Cursor<'a> { + Cursor { + rest: &self.rest[amt..], + } + } + #[cfg(span_locations)] + pub fn advance(&self, amt: usize) -> Cursor<'a> { + Cursor { + rest: &self.rest[amt..], + off: self.off + (amt as u32), + } + } + + pub fn find(&self, p: char) -> Option<usize> { + self.rest.find(p) + } + + pub fn starts_with(&self, s: &str) -> bool { + self.rest.starts_with(s) + } + + pub fn is_empty(&self) -> bool { + self.rest.is_empty() + } + + pub fn len(&self) -> usize { + self.rest.len() + } + + pub fn as_bytes(&self) -> &'a [u8] { + self.rest.as_bytes() + } + + pub fn bytes(&self) -> Bytes<'a> { + self.rest.bytes() + } + + pub fn chars(&self) -> Chars<'a> { + self.rest.chars() + } + + pub fn char_indices(&self) -> CharIndices<'a> { + self.rest.char_indices() + } +} + +pub type PResult<'a, O> = Result<(Cursor<'a>, O), LexError>; + +pub fn whitespace(input: Cursor) -> PResult<()> { + if input.is_empty() { + return Err(LexError); + } + + let bytes = input.as_bytes(); + let mut i = 0; + while i < bytes.len() { + let s = input.advance(i); + if bytes[i] == b'/' { + if s.starts_with("//") + && (!s.starts_with("///") || s.starts_with("////")) + && !s.starts_with("//!") + { + if let Some(len) = s.find('\n') { + i += len + 1; + continue; + } + break; + } else if s.starts_with("/**/") { + i += 4; + continue; + } else if s.starts_with("/*") + && (!s.starts_with("/**") || s.starts_with("/***")) + && !s.starts_with("/*!") + { + let (_, com) = block_comment(s)?; + i += com.len(); + continue; + } + } + match bytes[i] { + b' ' | 0x09..=0x0d => { + i += 1; + continue; + } + b if b <= 0x7f => {} + _ => { + let ch = s.chars().next().unwrap(); + if is_whitespace(ch) { + i += ch.len_utf8(); + continue; + } + } + } + return if i > 0 { Ok((s, ())) } else { Err(LexError) }; + } + Ok((input.advance(input.len()), ())) +} + +pub fn block_comment(input: Cursor) -> PResult<&str> { + if !input.starts_with("/*") { + return Err(LexError); + } + + let mut depth = 0; + let bytes = input.as_bytes(); + let mut i = 0; + let upper = bytes.len() - 1; + while i < upper { + if bytes[i] == b'/' && bytes[i + 1] == b'*' { + depth += 1; + i += 1; // eat '*' + } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { + depth -= 1; + if depth == 0 { + return Ok((input.advance(i + 2), &input.rest[..i + 2])); + } + i += 1; // eat '/' + } + i += 1; + } + Err(LexError) +} + +pub fn skip_whitespace(input: Cursor) -> Cursor { + match whitespace(input) { + Ok((rest, _)) => rest, + Err(LexError) => input, + } +} + +fn is_whitespace(ch: char) -> bool { + // Rust treats left-to-right mark and right-to-left mark as whitespace + ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}' +} + +pub fn word_break(input: Cursor) -> PResult<()> { + match input.chars().next() { + Some(ch) if UnicodeXID::is_xid_continue(ch) => Err(LexError), + Some(_) | None => Ok((input, ())), + } +} + +macro_rules! named { + ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => { + fn $name<'a>(i: Cursor<'a>) -> $crate::strnom::PResult<'a, $o> { + $submac!(i, $($args)*) + } + }; +} + +macro_rules! alt { + ($i:expr, $e:ident | $($rest:tt)*) => { + alt!($i, call!($e) | $($rest)*) + }; + + ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => { + match $subrule!($i, $($args)*) { + res @ Ok(_) => res, + _ => alt!($i, $($rest)*) + } + }; + + ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => { + match $subrule!($i, $($args)*) { + Ok((i, o)) => Ok((i, $gen(o))), + Err(LexError) => alt!($i, $($rest)*) + } + }; + + ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => { + alt!($i, call!($e) => { $gen } | $($rest)*) + }; + + ($i:expr, $e:ident => { $gen:expr }) => { + alt!($i, call!($e) => { $gen }) + }; + + ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => { + match $subrule!($i, $($args)*) { + Ok((i, o)) => Ok((i, $gen(o))), + Err(LexError) => Err(LexError), + } + }; + + ($i:expr, $e:ident) => { + alt!($i, call!($e)) + }; + + ($i:expr, $subrule:ident!( $($args:tt)*)) => { + $subrule!($i, $($args)*) + }; +} + +macro_rules! do_parse { + ($i:expr, ( $($rest:expr),* )) => { + Ok(($i, ( $($rest),* ))) + }; + + ($i:expr, $e:ident >> $($rest:tt)*) => { + do_parse!($i, call!($e) >> $($rest)*) + }; + + ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, _)) => do_parse!(i, $($rest)*), + } + }; + + ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => { + do_parse!($i, $field: call!($e) >> $($rest)*) + }; + + ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => { + let $field = o; + do_parse!(i, $($rest)*) + }, + } + }; +} + +macro_rules! peek { + ($i:expr, $submac:ident!( $($args:tt)* )) => { + match $submac!($i, $($args)*) { + Ok((_, o)) => Ok(($i, o)), + Err(LexError) => Err(LexError), + } + }; +} + +macro_rules! call { + ($i:expr, $fun:expr $(, $args:expr)*) => { + $fun($i $(, $args)*) + }; +} + +macro_rules! option { + ($i:expr, $f:expr) => { + match $f($i) { + Ok((i, o)) => Ok((i, Some(o))), + Err(LexError) => Ok(($i, None)), + } + }; +} + +macro_rules! take_until_newline_or_eof { + ($i:expr,) => {{ + if $i.len() == 0 { + Ok(($i, "")) + } else { + match $i.find('\n') { + Some(i) => Ok(($i.advance(i), &$i.rest[..i])), + None => Ok(($i.advance($i.len()), &$i.rest[..$i.len()])), + } + } + }}; +} + +macro_rules! tuple { + ($i:expr, $($rest:tt)*) => { + tuple_parser!($i, (), $($rest)*) + }; +} + +/// Do not use directly. Use `tuple!`. +macro_rules! tuple_parser { + ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => { + tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*) + }; + + ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => tuple_parser!(i, (o), $($rest)*), + } + }; + + ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => tuple_parser!(i, ($($parsed)* , o), $($rest)*), + } + }; + + ($i:expr, ($($parsed:tt),*), $e:ident) => { + tuple_parser!($i, ($($parsed),*), call!($e)) + }; + + ($i:expr, (), $submac:ident!( $($args:tt)* )) => { + $submac!($i, $($args)*) + }; + + ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => Ok((i, ($($parsed),*, o))) + } + }; + + ($i:expr, ($($parsed:expr),*)) => { + Ok(($i, ($($parsed),*))) + }; +} + +macro_rules! not { + ($i:expr, $submac:ident!( $($args:tt)* )) => { + match $submac!($i, $($args)*) { + Ok((_, _)) => Err(LexError), + Err(LexError) => Ok(($i, ())), + } + }; +} + +macro_rules! tag { + ($i:expr, $tag:expr) => { + if $i.starts_with($tag) { + Ok(($i.advance($tag.len()), &$i.rest[..$tag.len()])) + } else { + Err(LexError) + } + }; +} + +macro_rules! punct { + ($i:expr, $punct:expr) => { + $crate::strnom::punct($i, $punct) + }; +} + +/// Do not use directly. Use `punct!`. +pub fn punct<'a>(input: Cursor<'a>, token: &'static str) -> PResult<'a, &'a str> { + let input = skip_whitespace(input); + if input.starts_with(token) { + Ok((input.advance(token.len()), token)) + } else { + Err(LexError) + } +} + +macro_rules! preceded { + ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => { + match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { + Ok((remaining, (_, o))) => Ok((remaining, o)), + Err(LexError) => Err(LexError), + } + }; + + ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { + preceded!($i, $submac!($($args)*), call!($g)) + }; +} + +macro_rules! delimited { + ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => { + match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) { + Err(LexError) => Err(LexError), + Ok((i1, (_, o, _))) => Ok((i1, o)) + } + }; +} + +macro_rules! map { + ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => Ok((i, call!(o, $g))) + } + }; + + ($i:expr, $f:expr, $g:expr) => { + map!($i, call!($f), $g) + }; +} diff --git a/proc-macro2/src/wrapper.rs b/proc-macro2/src/wrapper.rs new file mode 100644 index 0000000..552b938 --- /dev/null +++ b/proc-macro2/src/wrapper.rs @@ -0,0 +1,927 @@ +use std::fmt; +use std::iter; +use std::ops::RangeBounds; +use std::panic::{self, PanicInfo}; +#[cfg(super_unstable)] +use std::path::PathBuf; +use std::str::FromStr; + +use crate::{fallback, Delimiter, Punct, Spacing, TokenTree}; + +#[derive(Clone)] +pub enum TokenStream { + Compiler(DeferredTokenStream), + Fallback(fallback::TokenStream), +} + +// Work around https://github.com/rust-lang/rust/issues/65080. +// In `impl Extend<TokenTree> for TokenStream` which is used heavily by quote, +// we hold on to the appended tokens and do proc_macro::TokenStream::extend as +// late as possible to batch together consecutive uses of the Extend impl. +#[derive(Clone)] +pub struct DeferredTokenStream { + stream: proc_macro::TokenStream, + extra: Vec<proc_macro::TokenTree>, +} + +pub enum LexError { + Compiler(proc_macro::LexError), + Fallback(fallback::LexError), +} + +fn nightly_works() -> bool { + use std::sync::atomic::*; + use std::sync::Once; + + static WORKS: AtomicUsize = AtomicUsize::new(0); + static INIT: Once = Once::new(); + + match WORKS.load(Ordering::SeqCst) { + 1 => return false, + 2 => return true, + _ => {} + } + + // Swap in a null panic hook to avoid printing "thread panicked" to stderr, + // then use catch_unwind to determine whether the compiler's proc_macro is + // working. When proc-macro2 is used from outside of a procedural macro all + // of the proc_macro crate's APIs currently panic. + // + // The Once is to prevent the possibility of this ordering: + // + // thread 1 calls take_hook, gets the user's original hook + // thread 1 calls set_hook with the null hook + // thread 2 calls take_hook, thinks null hook is the original hook + // thread 2 calls set_hook with the null hook + // thread 1 calls set_hook with the actual original hook + // thread 2 calls set_hook with what it thinks is the original hook + // + // in which the user's hook has been lost. + // + // There is still a race condition where a panic in a different thread can + // happen during the interval that the user's original panic hook is + // unregistered such that their hook is incorrectly not called. This is + // sufficiently unlikely and less bad than printing panic messages to stderr + // on correct use of this crate. Maybe there is a libstd feature request + // here. For now, if a user needs to guarantee that this failure mode does + // not occur, they need to call e.g. `proc_macro2::Span::call_site()` from + // the main thread before launching any other threads. + INIT.call_once(|| { + type PanicHook = dyn Fn(&PanicInfo) + Sync + Send + 'static; + + let null_hook: Box<PanicHook> = Box::new(|_panic_info| { /* ignore */ }); + let sanity_check = &*null_hook as *const PanicHook; + let original_hook = panic::take_hook(); + panic::set_hook(null_hook); + + let works = panic::catch_unwind(|| proc_macro::Span::call_site()).is_ok(); + WORKS.store(works as usize + 1, Ordering::SeqCst); + + let hopefully_null_hook = panic::take_hook(); + panic::set_hook(original_hook); + if sanity_check != &*hopefully_null_hook { + panic!("observed race condition in proc_macro2::nightly_works"); + } + }); + nightly_works() +} + +fn mismatch() -> ! { + panic!("stable/nightly mismatch") +} + +impl DeferredTokenStream { + fn new(stream: proc_macro::TokenStream) -> Self { + DeferredTokenStream { + stream, + extra: Vec::new(), + } + } + + fn is_empty(&self) -> bool { + self.stream.is_empty() && self.extra.is_empty() + } + + fn evaluate_now(&mut self) { + self.stream.extend(self.extra.drain(..)); + } + + fn into_token_stream(mut self) -> proc_macro::TokenStream { + self.evaluate_now(); + self.stream + } +} + +impl TokenStream { + pub fn new() -> TokenStream { + if nightly_works() { + TokenStream::Compiler(DeferredTokenStream::new(proc_macro::TokenStream::new())) + } else { + TokenStream::Fallback(fallback::TokenStream::new()) + } + } + + pub fn is_empty(&self) -> bool { + match self { + TokenStream::Compiler(tts) => tts.is_empty(), + TokenStream::Fallback(tts) => tts.is_empty(), + } + } + + fn unwrap_nightly(self) -> proc_macro::TokenStream { + match self { + TokenStream::Compiler(s) => s.into_token_stream(), + TokenStream::Fallback(_) => mismatch(), + } + } + + fn unwrap_stable(self) -> fallback::TokenStream { + match self { + TokenStream::Compiler(_) => mismatch(), + TokenStream::Fallback(s) => s, + } + } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result<TokenStream, LexError> { + if nightly_works() { + Ok(TokenStream::Compiler(DeferredTokenStream::new( + src.parse()?, + ))) + } else { + Ok(TokenStream::Fallback(src.parse()?)) + } + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) => tts.clone().into_token_stream().fmt(f), + TokenStream::Fallback(tts) => tts.fmt(f), + } + } +} + +impl From<proc_macro::TokenStream> for TokenStream { + fn from(inner: proc_macro::TokenStream) -> TokenStream { + TokenStream::Compiler(DeferredTokenStream::new(inner)) + } +} + +impl From<TokenStream> for proc_macro::TokenStream { + fn from(inner: TokenStream) -> proc_macro::TokenStream { + match inner { + TokenStream::Compiler(inner) => inner.into_token_stream(), + TokenStream::Fallback(inner) => inner.to_string().parse().unwrap(), + } + } +} + +impl From<fallback::TokenStream> for TokenStream { + fn from(inner: fallback::TokenStream) -> TokenStream { + TokenStream::Fallback(inner) + } +} + +// Assumes nightly_works(). +fn into_compiler_token(token: TokenTree) -> proc_macro::TokenTree { + match token { + TokenTree::Group(tt) => tt.inner.unwrap_nightly().into(), + TokenTree::Punct(tt) => { + let spacing = match tt.spacing() { + Spacing::Joint => proc_macro::Spacing::Joint, + Spacing::Alone => proc_macro::Spacing::Alone, + }; + let mut op = proc_macro::Punct::new(tt.as_char(), spacing); + op.set_span(tt.span().inner.unwrap_nightly()); + op.into() + } + TokenTree::Ident(tt) => tt.inner.unwrap_nightly().into(), + TokenTree::Literal(tt) => tt.inner.unwrap_nightly().into(), + } +} + +impl From<TokenTree> for TokenStream { + fn from(token: TokenTree) -> TokenStream { + if nightly_works() { + TokenStream::Compiler(DeferredTokenStream::new(into_compiler_token(token).into())) + } else { + TokenStream::Fallback(token.into()) + } + } +} + +impl iter::FromIterator<TokenTree> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self { + if nightly_works() { + TokenStream::Compiler(DeferredTokenStream::new( + trees.into_iter().map(into_compiler_token).collect(), + )) + } else { + TokenStream::Fallback(trees.into_iter().collect()) + } + } +} + +impl iter::FromIterator<TokenStream> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { + let mut streams = streams.into_iter(); + match streams.next() { + Some(TokenStream::Compiler(mut first)) => { + first.evaluate_now(); + first.stream.extend(streams.map(|s| match s { + TokenStream::Compiler(s) => s.into_token_stream(), + TokenStream::Fallback(_) => mismatch(), + })); + TokenStream::Compiler(first) + } + Some(TokenStream::Fallback(mut first)) => { + first.extend(streams.map(|s| match s { + TokenStream::Fallback(s) => s, + TokenStream::Compiler(_) => mismatch(), + })); + TokenStream::Fallback(first) + } + None => TokenStream::new(), + } + } +} + +impl Extend<TokenTree> for TokenStream { + fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) { + match self { + TokenStream::Compiler(tts) => { + // Here is the reason for DeferredTokenStream. + tts.extra + .extend(streams.into_iter().map(into_compiler_token)); + } + TokenStream::Fallback(tts) => tts.extend(streams), + } + } +} + +impl Extend<TokenStream> for TokenStream { + fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) { + match self { + TokenStream::Compiler(tts) => { + tts.evaluate_now(); + tts.stream + .extend(streams.into_iter().map(|stream| stream.unwrap_nightly())); + } + TokenStream::Fallback(tts) => { + tts.extend(streams.into_iter().map(|stream| stream.unwrap_stable())); + } + } + } +} + +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) => tts.clone().into_token_stream().fmt(f), + TokenStream::Fallback(tts) => tts.fmt(f), + } + } +} + +impl From<proc_macro::LexError> for LexError { + fn from(e: proc_macro::LexError) -> LexError { + LexError::Compiler(e) + } +} + +impl From<fallback::LexError> for LexError { + fn from(e: fallback::LexError) -> LexError { + LexError::Fallback(e) + } +} + +impl fmt::Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LexError::Compiler(e) => e.fmt(f), + LexError::Fallback(e) => e.fmt(f), + } + } +} + +#[derive(Clone)] +pub enum TokenTreeIter { + Compiler(proc_macro::token_stream::IntoIter), + Fallback(fallback::TokenTreeIter), +} + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + match self { + TokenStream::Compiler(tts) => { + TokenTreeIter::Compiler(tts.into_token_stream().into_iter()) + } + TokenStream::Fallback(tts) => TokenTreeIter::Fallback(tts.into_iter()), + } + } +} + +impl Iterator for TokenTreeIter { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + let token = match self { + TokenTreeIter::Compiler(iter) => iter.next()?, + TokenTreeIter::Fallback(iter) => return iter.next(), + }; + Some(match token { + proc_macro::TokenTree::Group(tt) => crate::Group::_new(Group::Compiler(tt)).into(), + proc_macro::TokenTree::Punct(tt) => { + let spacing = match tt.spacing() { + proc_macro::Spacing::Joint => Spacing::Joint, + proc_macro::Spacing::Alone => Spacing::Alone, + }; + let mut o = Punct::new(tt.as_char(), spacing); + o.set_span(crate::Span::_new(Span::Compiler(tt.span()))); + o.into() + } + proc_macro::TokenTree::Ident(s) => crate::Ident::_new(Ident::Compiler(s)).into(), + proc_macro::TokenTree::Literal(l) => crate::Literal::_new(Literal::Compiler(l)).into(), + }) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + match self { + TokenTreeIter::Compiler(tts) => tts.size_hint(), + TokenTreeIter::Fallback(tts) => tts.size_hint(), + } + } +} + +impl fmt::Debug for TokenTreeIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TokenTreeIter").finish() + } +} + +#[derive(Clone, PartialEq, Eq)] +#[cfg(super_unstable)] +pub enum SourceFile { + Compiler(proc_macro::SourceFile), + Fallback(fallback::SourceFile), +} + +#[cfg(super_unstable)] +impl SourceFile { + fn nightly(sf: proc_macro::SourceFile) -> Self { + SourceFile::Compiler(sf) + } + + /// Get the path to this source file as a string. + pub fn path(&self) -> PathBuf { + match self { + SourceFile::Compiler(a) => a.path(), + SourceFile::Fallback(a) => a.path(), + } + } + + pub fn is_real(&self) -> bool { + match self { + SourceFile::Compiler(a) => a.is_real(), + SourceFile::Fallback(a) => a.is_real(), + } + } +} + +#[cfg(super_unstable)] +impl fmt::Debug for SourceFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SourceFile::Compiler(a) => a.fmt(f), + SourceFile::Fallback(a) => a.fmt(f), + } + } +} + +#[cfg(any(super_unstable, feature = "span-locations"))] +pub struct LineColumn { + pub line: usize, + pub column: usize, +} + +#[derive(Copy, Clone)] +pub enum Span { + Compiler(proc_macro::Span), + Fallback(fallback::Span), +} + +impl Span { + pub fn call_site() -> Span { + if nightly_works() { + Span::Compiler(proc_macro::Span::call_site()) + } else { + Span::Fallback(fallback::Span::call_site()) + } + } + + #[cfg(super_unstable)] + pub fn def_site() -> Span { + if nightly_works() { + Span::Compiler(proc_macro::Span::def_site()) + } else { + Span::Fallback(fallback::Span::def_site()) + } + } + + #[cfg(super_unstable)] + pub fn resolved_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.resolved_at(b)), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.resolved_at(b)), + _ => mismatch(), + } + } + + #[cfg(super_unstable)] + pub fn located_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.located_at(b)), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.located_at(b)), + _ => mismatch(), + } + } + + pub fn unwrap(self) -> proc_macro::Span { + match self { + Span::Compiler(s) => s, + Span::Fallback(_) => panic!("proc_macro::Span is only available in procedural macros"), + } + } + + #[cfg(super_unstable)] + pub fn source_file(&self) -> SourceFile { + match self { + Span::Compiler(s) => SourceFile::nightly(s.source_file()), + Span::Fallback(s) => SourceFile::Fallback(s.source_file()), + } + } + + #[cfg(any(super_unstable, feature = "span-locations"))] + pub fn start(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span)] + Span::Compiler(s) => { + let proc_macro::LineColumn { line, column } = s.start(); + LineColumn { line, column } + } + #[cfg(not(proc_macro_span))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, + Span::Fallback(s) => { + let fallback::LineColumn { line, column } = s.start(); + LineColumn { line, column } + } + } + } + + #[cfg(any(super_unstable, feature = "span-locations"))] + pub fn end(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span)] + Span::Compiler(s) => { + let proc_macro::LineColumn { line, column } = s.end(); + LineColumn { line, column } + } + #[cfg(not(proc_macro_span))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, + Span::Fallback(s) => { + let fallback::LineColumn { line, column } = s.end(); + LineColumn { line, column } + } + } + } + + pub fn join(&self, other: Span) -> Option<Span> { + let ret = match (self, other) { + #[cfg(proc_macro_span)] + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.join(b)?), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.join(b)?), + _ => return None, + }; + Some(ret) + } + + #[cfg(super_unstable)] + pub fn eq(&self, other: &Span) -> bool { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => a.eq(b), + (Span::Fallback(a), Span::Fallback(b)) => a.eq(b), + _ => false, + } + } + + fn unwrap_nightly(self) -> proc_macro::Span { + match self { + Span::Compiler(s) => s, + Span::Fallback(_) => mismatch(), + } + } +} + +impl From<proc_macro::Span> for crate::Span { + fn from(proc_span: proc_macro::Span) -> crate::Span { + crate::Span::_new(Span::Compiler(proc_span)) + } +} + +impl From<fallback::Span> for Span { + fn from(inner: fallback::Span) -> Span { + Span::Fallback(inner) + } +} + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Span::Compiler(s) => s.fmt(f), + Span::Fallback(s) => s.fmt(f), + } + } +} + +pub fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { + match span { + Span::Compiler(s) => { + debug.field("span", &s); + } + Span::Fallback(s) => fallback::debug_span_field_if_nontrivial(debug, s), + } +} + +#[derive(Clone)] +pub enum Group { + Compiler(proc_macro::Group), + Fallback(fallback::Group), +} + +impl Group { + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { + match stream { + TokenStream::Compiler(tts) => { + let delimiter = match delimiter { + Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis, + Delimiter::Bracket => proc_macro::Delimiter::Bracket, + Delimiter::Brace => proc_macro::Delimiter::Brace, + Delimiter::None => proc_macro::Delimiter::None, + }; + Group::Compiler(proc_macro::Group::new(delimiter, tts.into_token_stream())) + } + TokenStream::Fallback(stream) => { + Group::Fallback(fallback::Group::new(delimiter, stream)) + } + } + } + + pub fn delimiter(&self) -> Delimiter { + match self { + Group::Compiler(g) => match g.delimiter() { + proc_macro::Delimiter::Parenthesis => Delimiter::Parenthesis, + proc_macro::Delimiter::Bracket => Delimiter::Bracket, + proc_macro::Delimiter::Brace => Delimiter::Brace, + proc_macro::Delimiter::None => Delimiter::None, + }, + Group::Fallback(g) => g.delimiter(), + } + } + + pub fn stream(&self) -> TokenStream { + match self { + Group::Compiler(g) => TokenStream::Compiler(DeferredTokenStream::new(g.stream())), + Group::Fallback(g) => TokenStream::Fallback(g.stream()), + } + } + + pub fn span(&self) -> Span { + match self { + Group::Compiler(g) => Span::Compiler(g.span()), + Group::Fallback(g) => Span::Fallback(g.span()), + } + } + + pub fn span_open(&self) -> Span { + match self { + #[cfg(proc_macro_span)] + Group::Compiler(g) => Span::Compiler(g.span_open()), + #[cfg(not(proc_macro_span))] + Group::Compiler(g) => Span::Compiler(g.span()), + Group::Fallback(g) => Span::Fallback(g.span_open()), + } + } + + pub fn span_close(&self) -> Span { + match self { + #[cfg(proc_macro_span)] + Group::Compiler(g) => Span::Compiler(g.span_close()), + #[cfg(not(proc_macro_span))] + Group::Compiler(g) => Span::Compiler(g.span()), + Group::Fallback(g) => Span::Fallback(g.span_close()), + } + } + + pub fn set_span(&mut self, span: Span) { + match (self, span) { + (Group::Compiler(g), Span::Compiler(s)) => g.set_span(s), + (Group::Fallback(g), Span::Fallback(s)) => g.set_span(s), + _ => mismatch(), + } + } + + fn unwrap_nightly(self) -> proc_macro::Group { + match self { + Group::Compiler(g) => g, + Group::Fallback(_) => mismatch(), + } + } +} + +impl From<fallback::Group> for Group { + fn from(g: fallback::Group) -> Self { + Group::Fallback(g) + } +} + +impl fmt::Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) => group.fmt(formatter), + Group::Fallback(group) => group.fmt(formatter), + } + } +} + +impl fmt::Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) => group.fmt(formatter), + Group::Fallback(group) => group.fmt(formatter), + } + } +} + +#[derive(Clone)] +pub enum Ident { + Compiler(proc_macro::Ident), + Fallback(fallback::Ident), +} + +impl Ident { + pub fn new(string: &str, span: Span) -> Ident { + match span { + Span::Compiler(s) => Ident::Compiler(proc_macro::Ident::new(string, s)), + Span::Fallback(s) => Ident::Fallback(fallback::Ident::new(string, s)), + } + } + + pub fn new_raw(string: &str, span: Span) -> Ident { + match span { + Span::Compiler(s) => { + let p: proc_macro::TokenStream = string.parse().unwrap(); + let ident = match p.into_iter().next() { + Some(proc_macro::TokenTree::Ident(mut i)) => { + i.set_span(s); + i + } + _ => panic!(), + }; + Ident::Compiler(ident) + } + Span::Fallback(s) => Ident::Fallback(fallback::Ident::new_raw(string, s)), + } + } + + pub fn span(&self) -> Span { + match self { + Ident::Compiler(t) => Span::Compiler(t.span()), + Ident::Fallback(t) => Span::Fallback(t.span()), + } + } + + pub fn set_span(&mut self, span: Span) { + match (self, span) { + (Ident::Compiler(t), Span::Compiler(s)) => t.set_span(s), + (Ident::Fallback(t), Span::Fallback(s)) => t.set_span(s), + _ => mismatch(), + } + } + + fn unwrap_nightly(self) -> proc_macro::Ident { + match self { + Ident::Compiler(s) => s, + Ident::Fallback(_) => mismatch(), + } + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + match (self, other) { + (Ident::Compiler(t), Ident::Compiler(o)) => t.to_string() == o.to_string(), + (Ident::Fallback(t), Ident::Fallback(o)) => t == o, + _ => mismatch(), + } + } +} + +impl<T> PartialEq<T> for Ident +where + T: ?Sized + AsRef<str>, +{ + fn eq(&self, other: &T) -> bool { + let other = other.as_ref(); + match self { + Ident::Compiler(t) => t.to_string() == other, + Ident::Fallback(t) => t == other, + } + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) => t.fmt(f), + Ident::Fallback(t) => t.fmt(f), + } + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) => t.fmt(f), + Ident::Fallback(t) => t.fmt(f), + } + } +} + +#[derive(Clone)] +pub enum Literal { + Compiler(proc_macro::Literal), + Fallback(fallback::Literal), +} + +macro_rules! suffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +macro_rules! unsuffixed_integers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +impl Literal { + suffixed_numbers! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, + + f32_suffixed => f32, + f64_suffixed => f64, + } + + unsuffixed_integers! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, + } + + pub fn f32_unsuffixed(f: f32) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::f32_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f32_unsuffixed(f)) + } + } + + pub fn f64_unsuffixed(f: f64) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::f64_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f64_unsuffixed(f)) + } + } + + pub fn string(t: &str) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::string(t)) + } else { + Literal::Fallback(fallback::Literal::string(t)) + } + } + + pub fn character(t: char) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::character(t)) + } else { + Literal::Fallback(fallback::Literal::character(t)) + } + } + + pub fn byte_string(bytes: &[u8]) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::byte_string(bytes)) + } else { + Literal::Fallback(fallback::Literal::byte_string(bytes)) + } + } + + pub fn span(&self) -> Span { + match self { + Literal::Compiler(lit) => Span::Compiler(lit.span()), + Literal::Fallback(lit) => Span::Fallback(lit.span()), + } + } + + pub fn set_span(&mut self, span: Span) { + match (self, span) { + (Literal::Compiler(lit), Span::Compiler(s)) => lit.set_span(s), + (Literal::Fallback(lit), Span::Fallback(s)) => lit.set_span(s), + _ => mismatch(), + } + } + + pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> { + match self { + #[cfg(proc_macro_span)] + Literal::Compiler(lit) => lit.subspan(range).map(Span::Compiler), + #[cfg(not(proc_macro_span))] + Literal::Compiler(_lit) => None, + Literal::Fallback(lit) => lit.subspan(range).map(Span::Fallback), + } + } + + fn unwrap_nightly(self) -> proc_macro::Literal { + match self { + Literal::Compiler(s) => s, + Literal::Fallback(_) => mismatch(), + } + } +} + +impl From<fallback::Literal> for Literal { + fn from(s: fallback::Literal) -> Literal { + Literal::Fallback(s) + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) => t.fmt(f), + Literal::Fallback(t) => t.fmt(f), + } + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) => t.fmt(f), + Literal::Fallback(t) => t.fmt(f), + } + } +} |