use syntax::ast::*;
use syntax::codemap::{ExpnId, Span};
use syntax::ext::base::{ExtCtxt};
use syntax::ext::build::{AstBuilder};
use syntax::ext::quote::rt::{BytePos};
use syntax::parse::token::{self, BinOpToken, DelimToken, Token};
use syntax::ptr::{P};
use syntax::symbol::{Symbol};
use syntax::tokenstream::{Delimited, TokenTree};
macro_rules! ast { ($($ident:expr), +) => (&["syntax", "ast", $($ident), *]); }
macro_rules! codemap { ($($ident:expr), +) => (&["syntax", "codemap", $($ident), *]); }
macro_rules! rt { ($($ident:expr), +) => (&["syntax", "ext", "quote", "rt", $($ident), *]); }
macro_rules! symbol { ($($ident:expr), +) => (&["syntax", "symbol", $($ident), *]); }
macro_rules! token { ($($ident:expr), +) => (&["syntax", "parse", "token", $($ident), *]); }
macro_rules! tokenstream { ($($ident:expr), +) => (&["syntax", "tokenstream", $($ident), *]); }
macro_rules! exprs {
($context:expr, $span:expr, [$($expr:expr), +]) => ({
vec![$($expr.to_expr($context, $span)), +]
});
}
macro_rules! fields {
($context:expr, $span:expr, $struct_:expr, [$($field:ident), +]) => ({
vec![$(mk_field($context, $span, stringify!($field), $struct_.$field.to_expr($context, $span))), +]
});
}
macro_rules! to_expr_primitive {
($ty:ty, $method:ident) => (
impl ToExpr for $ty {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
context.$method(span, *self)
}
}
)
}
pub trait ToExpr {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr>;
}
to_expr_primitive!(u32, expr_u32);
to_expr_primitive!(usize, expr_usize);
impl<'a> ToExpr for &'a str {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
context.expr_str(span, Symbol::intern(self))
}
}
impl<T: ToExpr> ToExpr for Option<T> {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
match *self {
Some(ref some) => context.expr_some(span, some.to_expr(context, span)),
None => context.expr_none(span),
}
}
}
impl<T: ToExpr> ToExpr for Vec<T> {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
let exprs = self.iter().map(|e| e.to_expr(context, span)).collect();
mk_expr_method_call(context, span, context.expr_vec(span, exprs), "to_vec", vec![])
}
}
impl ToExpr for String {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
mk_expr_method_call(context, span, (&self[..]).to_expr(context, span), "to_string", vec![])
}
}
impl ToExpr for BytePos {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
mk_expr_call(context, span, rt!["BytePos"], vec![self.0.to_expr(context, span)])
}
}
impl ToExpr for ExpnId {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
mk_expr_call(context, span, codemap!["ExpnId"], vec![self.0.to_expr(context, span)])
}
}
impl ToExpr for Span {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
mk_expr_struct(context, span, rt!["Span"], fields!(context, span, self, [lo, hi, expn_id]))
}
}
impl ToExpr for BinOpToken {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
mk_expr_path(context, span, token!["BinOpToken", &format!("{:?}", self)])
}
}
impl ToExpr for DelimToken {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
mk_expr_path(context, span, token!["DelimToken", &format!("{:?}", self)])
}
}
impl ToExpr for token::Lit {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
use syntax::parse::token::Lit;
let (variant, arguments) = match *self {
Lit::Byte(name) => ("Byte", exprs!(context, span, [name])),
Lit::Char(name) => ("Char", exprs!(context, span, [name])),
Lit::Integer(name) => ("Integer", exprs!(context, span, [name])),
Lit::Float(name) => ("Float", exprs!(context, span, [name])),
Lit::Str_(name) => ("Str_", exprs!(context, span, [name])),
Lit::StrRaw(name, size) => ("StrRaw", exprs!(context, span, [name, size])),
Lit::ByteStr(name) => ("ByteStr", exprs!(context, span, [name])),
Lit::ByteStrRaw(name, size) => ("ByteStrRaw", exprs!(context, span, [name, size])),
};
mk_expr_call(context, span, token!["Lit", variant], arguments)
}
}
impl ToExpr for Token {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
let (variant, arguments) = match *self {
Token::BinOp(binop) => ("BinOp", exprs!(context, span, [binop])),
Token::BinOpEq(binop) => ("BinOpEq", exprs!(context, span, [binop])),
Token::OpenDelim(delim) => ("OpenDelim", exprs!(context, span, [delim])),
Token::CloseDelim(delim) => ("CloseDelim", exprs!(context, span, [delim])),
Token::Literal(lit, suffix) => ("Literal", exprs!(context, span, [lit, suffix])),
Token::Ident(ref ident) => ("Ident", exprs!(context, span, [ident])),
Token::Lifetime(ref lifetime) => ("Lifetime", exprs!(context, span, [lifetime])),
Token::DocComment(comment) => ("DocComment", exprs!(context, span, [comment])),
Token::Interpolated(_) |
Token::SubstNt(_) |
Token::Shebang(_) => unreachable!("invalid quasiquoted token: {:?}", self),
_ => return mk_expr_path(context, span, token!["Token", &format!("{:?}", self)]),
};
mk_expr_call(context, span, token!["Token", variant], arguments)
}
}
impl ToExpr for Delimited {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
let fields = fields!(context, span, self, [delim, tts]);
mk_expr_struct(context, span, tokenstream!["Delimited"], fields)
}
}
impl ToExpr for TokenTree {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
mk_expr_tt(context, span, self, span.to_expr(context, span))
}
}
impl ToExpr for Ident {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
let arguments = vec![context.expr_str(span, self.name)];
mk_expr_call(context, span, ast!["Ident", "from_str"], arguments)
}
}
impl ToExpr for Symbol {
fn to_expr(&self, context: &ExtCtxt, span: Span) -> P<Expr> {
let arguments = vec![context.expr_str(span, *self)];
mk_expr_call(context, span, symbol!["Symbol", "intern"], arguments)
}
}
pub fn mk_expr_call(context: &ExtCtxt, span: Span, idents: &[&str], args: Vec<P<Expr>>) -> P<Expr> {
context.expr_call_global(span, mk_idents(context, idents), args)
}
pub fn mk_expr_method_call(
context: &ExtCtxt, span: Span, expr: P<Expr>, ident: &str, args: Vec<P<Expr>>
) -> P<Expr> {
context.expr_method_call(span, expr, context.ident_of(ident), args)
}
pub fn mk_expr_path(context: &ExtCtxt, span: Span, idents: &[&str]) -> P<Expr> {
context.expr_path(context.path_global(span, mk_idents(context, idents)))
}
pub fn mk_expr_struct(
context: &ExtCtxt, span: Span, idents: &[&str], fields: Vec<Field>
) -> P<Expr> {
context.expr_struct(span, context.path_global(span, mk_idents(context, idents)), fields)
}
pub fn mk_expr_tt(context: &ExtCtxt, span: Span, tt: &TokenTree, ttspan: P<Expr>) -> P<Expr> {
let (variant, argument) = match *tt {
TokenTree::Token(_, ref token) => ("Token", token.to_expr(context, span)),
TokenTree::Delimited(_, ref delimited) => ("Delimited", delimited.to_expr(context, span)),
};
mk_expr_call(context, span, tokenstream!["TokenTree", variant], vec![ttspan, argument])
}
pub fn mk_field(context: &ExtCtxt, span: Span, ident: &str, expr: P<Expr>) -> Field {
context.field_imm(span, context.ident_of(ident), expr)
}
pub fn mk_idents(context: &ExtCtxt, idents: &[&str]) -> Vec<Ident> {
idents.iter().map(|i| context.ident_of(i)).collect()
}