diff --git a/maud_macros/src/lib.rs b/maud_macros/src/lib.rs index 2f27d9b..09253d2 100644 --- a/maud_macros/src/lib.rs +++ b/maud_macros/src/lib.rs @@ -7,35 +7,65 @@ extern crate syntax; extern crate rustc; extern crate maud; -use syntax::ast::TokenTree; -use syntax::codemap::Span; +use syntax::ast::{Expr, TokenTree, TtToken}; +use syntax::codemap::{DUMMY_SP, Span}; use syntax::ext::base::{ExtCtxt, MacEager, MacResult}; +use syntax::parse::token; use syntax::print::pprust; +use syntax::ptr::P; use rustc::plugin::Registry; mod parse; mod render; -fn expand_html_common<'cx>(cx: &'cx mut ExtCtxt, sp: Span, args: &[TokenTree], - debug: bool) -> Box<MacResult + 'cx> { - let expr = parse::parse(cx, args, sp); - if debug { - cx.span_note(sp, &format!("expansion:\n{}", - pprust::expr_to_string(&expr))); +fn _expand_html(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> P<Expr> { + let (write, input) = parse::split_comma(cx, sp, args); + parse::parse(cx, sp, write, input) +} + +fn _expand_write_html(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> P<Expr> { + let (io_write, input) = parse::split_comma(cx, sp, args); + let io_write = io_write.to_vec(); + let fmt_write = token::gensym_ident("__maud_utf8_writer"); + let fmt_write = vec![ + TtToken(DUMMY_SP, token::Ident(fmt_write, token::IdentStyle::Plain))]; + let expr = parse::parse(cx, sp, &fmt_write, input); + quote_expr!(cx, + match ::maud::Utf8Writer::new(&mut $io_write) { + mut $fmt_write => { + let _ = $expr; + $fmt_write.into_result() + } + }) +} + +macro_rules! expand { + ($name:ident $debug_name:ident $inner_fn:ident) => { + fn $name<'cx>(cx: &'cx mut ExtCtxt, sp: Span, args: &[TokenTree]) + -> Box<MacResult + 'cx> + { + let expr = $inner_fn(cx, sp, args); + MacEager::expr(expr) + } + + fn $debug_name<'cx>(cx: &'cx mut ExtCtxt, sp: Span, args: &[TokenTree]) + -> Box<MacResult + 'cx> + { + let expr = $inner_fn(cx, sp, args); + cx.span_note(sp, &format!("expansion:\n{}", + pprust::expr_to_string(&expr))); + MacEager::expr(expr) + } } - MacEager::expr(expr) } -fn expand_html<'cx>(cx: &'cx mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box<MacResult + 'cx> { - expand_html_common(cx, sp, args, false) -} - -fn expand_html_debug<'cx>(cx: &'cx mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box<MacResult + 'cx> { - expand_html_common(cx, sp, args, true) -} +expand!(expand_html expand_html_debug _expand_html); +expand!(expand_write_html expand_write_html_debug _expand_write_html); #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.register_macro("html", expand_html); reg.register_macro("html_debug", expand_html_debug); + reg.register_macro("write_html", expand_write_html); + reg.register_macro("write_html_debug", expand_write_html_debug); } diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 7250698..ac5034e 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -42,8 +42,9 @@ macro_rules! ident { ($sp:pat, $x:pat) => (TtToken($sp, token::Ident($x, token::IdentStyle::Plain))) } -pub fn parse(cx: &ExtCtxt, input: &[TokenTree], sp: Span) -> P<Expr> { - let (write, input) = split_comma(cx, input, sp); +pub fn parse(cx: &ExtCtxt, sp: Span, write: &[TokenTree], input: &[TokenTree]) + -> P<Expr> +{ let mut parser = Parser { in_attr: false, input: input, @@ -54,15 +55,15 @@ pub fn parse(cx: &ExtCtxt, input: &[TokenTree], sp: Span) -> P<Expr> { parser.into_render().into_expr(write.to_vec()) } -fn split_comma<'a>(cx: &ExtCtxt, input: &'a [TokenTree], sp: Span) -> (&'a [TokenTree], &'a [TokenTree]) { +pub fn split_comma<'a>(cx: &ExtCtxt, sp: Span, args: &'a [TokenTree]) -> (&'a [TokenTree], &'a [TokenTree]) { fn is_comma(t: &TokenTree) -> bool { match *t { TtToken(_, token::Comma) => true, _ => false, } } - match input.iter().position(is_comma) { - Some(i) => (&input[..i], &input[1+i..]), + match args.iter().position(is_comma) { + Some(i) => (&args[..i], &args[1+i..]), None => cx.span_fatal(sp, "expected two arguments to `html!`"), } } diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs index a1f0eb1..6568bc8 100644 --- a/maud_macros/tests/tests.rs +++ b/maud_macros/tests/tests.rs @@ -250,11 +250,8 @@ mod control { } #[test] -fn utf8_writer() { - use maud::Utf8Writer; - let mut w = Utf8Writer::new(vec![]); - let _ = html!(w, p "hello"); - let (buf, r) = w.into_inner(); - r.unwrap(); +fn write_html() { + let mut buf = vec![]; + write_html!(buf, p "hello").unwrap(); assert_eq!(buf, b"<p>hello</p>"); }