blob: 4bffb55942796daea2890699983e51186f5f53aa [file] [log] [blame]
// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::*;
use proc_macro2::TokenStream;
#[cfg(feature = "parsing")]
use proc_macro2::{Delimiter, TokenTree};
use token::{Brace, Bracket, Paren};
#[cfg(feature = "parsing")]
use parse::{ParseStream, Result};
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};
#[cfg(feature = "extra-traits")]
use tt::TokenStreamHelper;
ast_struct! {
/// A macro invocation: `println!("{}", mac)`.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
pub struct Macro #manual_extra_traits {
pub path: Path,
pub bang_token: Token![!],
pub delimiter: MacroDelimiter,
pub tts: TokenStream,
}
}
ast_enum! {
/// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
pub enum MacroDelimiter {
Paren(Paren),
Brace(Brace),
Bracket(Bracket),
}
}
#[cfg(feature = "extra-traits")]
impl Eq for Macro {}
#[cfg(feature = "extra-traits")]
impl PartialEq for Macro {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
&& self.bang_token == other.bang_token
&& self.delimiter == other.delimiter
&& TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
}
}
#[cfg(feature = "extra-traits")]
impl Hash for Macro {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.path.hash(state);
self.bang_token.hash(state);
self.delimiter.hash(state);
TokenStreamHelper(&self.tts).hash(state);
}
}
#[cfg(feature = "parsing")]
pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
input.step(|cursor| {
if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
let span = g.span();
let delimiter = match g.delimiter() {
Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
Delimiter::None => {
return Err(cursor.error("expected delimiter"));
}
};
Ok(((delimiter, g.stream().clone()), rest))
} else {
Err(cursor.error("expected delimiter"))
}
})
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use parse::{Parse, ParseStream, Result};
impl Parse for Macro {
fn parse(input: ParseStream) -> Result<Self> {
let tts;
Ok(Macro {
path: input.call(Path::parse_mod_style)?,
bang_token: input.parse()?,
delimiter: {
let (delimiter, content) = parse_delimiter(input)?;
tts = content;
delimiter
},
tts: tts,
})
}
}
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use proc_macro2::TokenStream;
use quote::ToTokens;
impl ToTokens for Macro {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.path.to_tokens(tokens);
self.bang_token.to_tokens(tokens);
match self.delimiter {
MacroDelimiter::Paren(ref paren) => {
paren.surround(tokens, |tokens| self.tts.to_tokens(tokens));
}
MacroDelimiter::Brace(ref brace) => {
brace.surround(tokens, |tokens| self.tts.to_tokens(tokens));
}
MacroDelimiter::Bracket(ref bracket) => {
bracket.surround(tokens, |tokens| self.tts.to_tokens(tokens));
}
}
}
}
}