#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", deny(clippy))]
#![cfg_attr(not(feature = "with-syntex"), feature(plugin_registrar, rustc_private))]
#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;
#[cfg(not(feature = "with-syntex"))]
extern crate syntax;
#[cfg(feature = "with-syntex")]
extern crate syntex;
#[cfg(feature = "with-syntex")]
extern crate syntex_syntax as syntax;
extern crate unindent;
use unindent::*;
#[cfg(feature = "with-syntex")]
use std::path::Path;
use syntax::codemap::Span;
use syntax::parse;
use syntax::parse::token::{Lit, Literal};
use syntax::ast::{LitKind, StrStyle};
use syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult};
use syntax::ext::build::AstBuilder; use syntax::symbol::Symbol;
use syntax::tokenstream::TokenTree;
#[cfg(not(feature = "with-syntex"))]
#[plugin_registrar]
#[doc(hidden)]
pub fn register(reg: &mut rustc_plugin::Registry) {
reg.register_macro("indoc", expand_indoc);
}
#[cfg(feature = "with-syntex")]
#[doc(hidden)]
pub fn register(reg: &mut syntex::Registry) {
reg.add_macro("indoc", expand_indoc);
}
#[cfg(feature = "with-syntex")]
#[doc(hidden)]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
where S: AsRef<Path>,
D: AsRef<Path>,
{
let mut registry = syntex::Registry::new();
register(&mut registry);
registry.expand("", src.as_ref(), dst.as_ref())
}
fn expand_indoc<'a>(
cx: &'a mut ExtCtxt,
sp: Span,
args: &[TokenTree]
) -> Box<MacResult + 'a> {
if args.len() != 1 {
cx.span_err(sp,
&format!("argument must be a single string literal, but \
got {} arguments",
args.len()));
return DummyResult::any(sp);
}
let lit = match args[0] {
TokenTree::Token(_, Literal(lit, _name)) => lit,
_ => {
cx.span_err(sp, "argument must be a single string literal");
return DummyResult::any(sp);
}
};
let result = match lit {
Lit::Str_(name) => {
let unindented = parse::str_lit(&unindent(&name.as_str()));
let interned = Symbol::intern(&unindented);
LitKind::Str(interned, StrStyle::Cooked)
}
Lit::StrRaw(name, hashes) => {
let unindented = parse::raw_str_lit(&unindent(&name.as_str()));
let interned = Symbol::intern(&unindented);
LitKind::Str(interned, StrStyle::Raw(hashes))
}
Lit::ByteStr(name) |
Lit::ByteStrRaw(name, _) => {
let unindented = parse::byte_str_lit(&unindent(&name.as_str()));
LitKind::ByteStr(unindented)
}
_ => {
cx.span_err(sp, "argument must be a single string literal");
return DummyResult::any(sp);
}
};
MacEager::expr(cx.expr_lit(sp, result))
}