blob: 9a648d419ec5c9a47ca2d357b8af6d0c56c49c11 [file] [log] [blame]
use super::*;
/// Represents a macro invocation. The Path indicates which macro
/// is being invoked, and the vector of token-trees contains the source
/// of the macro invocation.
///
/// NB: the additional ident for a `macro_rules`-style macro is actually
/// stored in the enclosing item. Oog.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Mac {
pub path: Path,
pub tts: Vec<TokenTree>,
}
/// When the main rust parser encounters a syntax-extension invocation, it
/// parses the arguments to the invocation as a token-tree. This is a very
/// loose structure, such that all sorts of different AST-fragments can
/// be passed to syntax extensions using a uniform type.
///
/// If the syntax extension is an MBE macro, it will attempt to match its
/// LHS token tree against the provided token tree, and if it finds a
/// match, will transcribe the RHS token tree, splicing in any captured
/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
///
/// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
/// Nothing special happens to misnamed or misplaced `SubstNt`s.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum TokenTree {
/// A single token
Token(Token),
/// A delimited sequence of token trees
Delimited(Delimited),
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Delimited {
/// The type of delimiter
pub delim: DelimToken,
/// The delimited sequence of token trees
pub tts: Vec<TokenTree>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Token {
// Expression-operator symbols.
Eq,
Lt,
Le,
EqEq,
Ne,
Ge,
Gt,
AndAnd,
OrOr,
Not,
Tilde,
BinOp(BinOpToken),
BinOpEq(BinOpToken),
// Structural symbols
At,
Dot,
DotDot,
DotDotDot,
Comma,
Semi,
Colon,
ModSep,
RArrow,
LArrow,
FatArrow,
Pound,
Dollar,
Question,
// Literals
Literal(Lit),
// Name components
Ident(Ident),
Underscore,
Lifetime(Ident),
DocComment(String),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum BinOpToken {
Plus,
Minus,
Star,
Slash,
Percent,
Caret,
And,
Or,
Shl,
Shr,
}
/// A delimiter token
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum DelimToken {
/// A round parenthesis: `(` or `)`
Paren,
/// A square bracket: `[` or `]`
Bracket,
/// A curly brace: `{` or `}`
Brace,
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use Lifetime;
use generics::parsing::lifetime;
use ident::parsing::word;
use lit::parsing::lit;
use synom::space::{block_comment, whitespace};
use ty::parsing::path;
named!(pub mac -> Mac, do_parse!(
what: path >>
punct!("!") >>
body: delimited >>
(Mac {
path: what,
tts: vec![TokenTree::Delimited(body)],
})
));
named!(pub token_trees -> Vec<TokenTree>, many0!(token_tree));
named!(pub delimited -> Delimited, alt!(
delimited!(
punct!("("),
token_trees,
punct!(")")
) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
|
delimited!(
punct!("["),
token_trees,
punct!("]")
) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
|
delimited!(
punct!("{"),
token_trees,
punct!("}")
) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
));
named!(pub token_tree -> TokenTree, alt!(
map!(token, TokenTree::Token)
|
map!(delimited, TokenTree::Delimited)
));
named!(token -> Token, alt!(
keyword!("_") => { |_| Token::Underscore }
|
punct!("&&") => { |_| Token::AndAnd } // must be before BinOp
|
punct!("||") => { |_| Token::OrOr } // must be before BinOp
|
punct!("->") => { |_| Token::RArrow } // must be before BinOp
|
punct!("<-") => { |_| Token::LArrow } // must be before Lt
|
punct!("=>") => { |_| Token::FatArrow } // must be before Eq
|
punct!("...") => { |_| Token::DotDotDot } // must be before DotDot
|
punct!("..") => { |_| Token::DotDot } // must be before Dot
|
punct!(".") => { |_| Token::Dot }
|
map!(doc_comment, Token::DocComment) // must be before bin_op
|
map!(bin_op_eq, Token::BinOpEq) // must be before bin_op
|
map!(bin_op, Token::BinOp)
|
map!(lit, Token::Literal)
|
map!(word, Token::Ident)
|
map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
|
punct!("<=") => { |_| Token::Le }
|
punct!("==") => { |_| Token::EqEq }
|
punct!("!=") => { |_| Token::Ne }
|
punct!(">=") => { |_| Token::Ge }
|
punct!("::") => { |_| Token::ModSep }
|
punct!("=") => { |_| Token::Eq }
|
punct!("<") => { |_| Token::Lt }
|
punct!(">") => { |_| Token::Gt }
|
punct!("!") => { |_| Token::Not }
|
punct!("~") => { |_| Token::Tilde }
|
punct!("@") => { |_| Token::At }
|
punct!(",") => { |_| Token::Comma }
|
punct!(";") => { |_| Token::Semi }
|
punct!(":") => { |_| Token::Colon }
|
punct!("#") => { |_| Token::Pound }
|
punct!("$") => { |_| Token::Dollar }
|
punct!("?") => { |_| Token::Question }
));
named!(bin_op -> BinOpToken, alt!(
punct!("+") => { |_| BinOpToken::Plus }
|
punct!("-") => { |_| BinOpToken::Minus }
|
punct!("*") => { |_| BinOpToken::Star }
|
punct!("/") => { |_| BinOpToken::Slash }
|
punct!("%") => { |_| BinOpToken::Percent }
|
punct!("^") => { |_| BinOpToken::Caret }
|
punct!("&") => { |_| BinOpToken::And }
|
punct!("|") => { |_| BinOpToken::Or }
|
punct!("<<") => { |_| BinOpToken::Shl }
|
punct!(">>") => { |_| BinOpToken::Shr }
));
named!(bin_op_eq -> BinOpToken, alt!(
punct!("+=") => { |_| BinOpToken::Plus }
|
punct!("-=") => { |_| BinOpToken::Minus }
|
punct!("*=") => { |_| BinOpToken::Star }
|
punct!("/=") => { |_| BinOpToken::Slash }
|
punct!("%=") => { |_| BinOpToken::Percent }
|
punct!("^=") => { |_| BinOpToken::Caret }
|
punct!("&=") => { |_| BinOpToken::And }
|
punct!("|=") => { |_| BinOpToken::Or }
|
punct!("<<=") => { |_| BinOpToken::Shl }
|
punct!(">>=") => { |_| BinOpToken::Shr }
));
named!(doc_comment -> String, alt!(
do_parse!(
punct!("//!") >>
content: take_until!("\n") >>
(format!("//!{}", content))
)
|
do_parse!(
option!(whitespace) >>
peek!(tag!("/*!")) >>
com: block_comment >>
(com.to_owned())
)
|
do_parse!(
punct!("///") >>
not!(peek!(tag!("/"))) >>
content: take_until!("\n") >>
(format!("///{}", content))
)
|
do_parse!(
option!(whitespace) >>
peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
com: block_comment >>
(com.to_owned())
)
));
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use quote::{Tokens, ToTokens};
impl ToTokens for Mac {
fn to_tokens(&self, tokens: &mut Tokens) {
self.path.to_tokens(tokens);
tokens.append("!");
for tt in &self.tts {
tt.to_tokens(tokens);
}
}
}
impl ToTokens for TokenTree {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
TokenTree::Token(ref token) => token.to_tokens(tokens),
TokenTree::Delimited(ref delimited) => delimited.to_tokens(tokens),
}
}
}
impl DelimToken {
fn open(&self) -> &'static str {
match *self {
DelimToken::Paren => "(",
DelimToken::Bracket => "[",
DelimToken::Brace => "{",
}
}
fn close(&self) -> &'static str {
match *self {
DelimToken::Paren => ")",
DelimToken::Bracket => "]",
DelimToken::Brace => "}",
}
}
}
impl ToTokens for Delimited {
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append(self.delim.open());
for tt in &self.tts {
tt.to_tokens(tokens);
}
tokens.append(self.delim.close());
}
}
impl ToTokens for Token {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
Token::Eq => tokens.append("="),
Token::Lt => tokens.append("<"),
Token::Le => tokens.append("<="),
Token::EqEq => tokens.append("=="),
Token::Ne => tokens.append("!="),
Token::Ge => tokens.append(">="),
Token::Gt => tokens.append(">"),
Token::AndAnd => tokens.append("&&"),
Token::OrOr => tokens.append("||"),
Token::Not => tokens.append("!"),
Token::Tilde => tokens.append("~"),
Token::BinOp(binop) => tokens.append(binop.op()),
Token::BinOpEq(binop) => tokens.append(binop.assign_op()),
Token::At => tokens.append("@"),
Token::Dot => tokens.append("."),
Token::DotDot => tokens.append(".."),
Token::DotDotDot => tokens.append("..."),
Token::Comma => tokens.append(","),
Token::Semi => tokens.append(";"),
Token::Colon => tokens.append(":"),
Token::ModSep => tokens.append("::"),
Token::RArrow => tokens.append("->"),
Token::LArrow => tokens.append("<-"),
Token::FatArrow => tokens.append("=>"),
Token::Pound => tokens.append("#"),
Token::Dollar => tokens.append("$"),
Token::Question => tokens.append("?"),
Token::Literal(ref lit) => lit.to_tokens(tokens),
Token::Ident(ref ident) |
Token::Lifetime(ref ident) => ident.to_tokens(tokens),
Token::Underscore => tokens.append("_"),
Token::DocComment(ref com) => {
tokens.append(&format!("{}\n", com));
}
}
}
}
impl BinOpToken {
fn op(&self) -> &'static str {
match *self {
BinOpToken::Plus => "+",
BinOpToken::Minus => "-",
BinOpToken::Star => "*",
BinOpToken::Slash => "/",
BinOpToken::Percent => "%",
BinOpToken::Caret => "^",
BinOpToken::And => "&",
BinOpToken::Or => "|",
BinOpToken::Shl => "<<",
BinOpToken::Shr => ">>",
}
}
fn assign_op(&self) -> &'static str {
match *self {
BinOpToken::Plus => "+=",
BinOpToken::Minus => "-=",
BinOpToken::Star => "*=",
BinOpToken::Slash => "/=",
BinOpToken::Percent => "%=",
BinOpToken::Caret => "^=",
BinOpToken::And => "&=",
BinOpToken::Or => "|=",
BinOpToken::Shl => "<<=",
BinOpToken::Shr => ">>=",
}
}
}
impl ToTokens for BinOpToken {
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append(self.op());
}
}
}