Epic refactor of doom

* Use `&ExtCtxt` instead of `&mut ExtCtxt`

* Take statements vector by value instead of by reference

* Make control structures easier to write
This commit is contained in:
Chris Wong 2015-01-30 18:43:53 +13:00
parent 9ee1c76e93
commit 110930a558
2 changed files with 49 additions and 50 deletions
maud_macros/src

View file

@ -40,25 +40,25 @@ macro_rules! ident {
($sp:pat, $x:pat) => (TtToken($sp, token::Ident($x, token::IdentStyle::Plain))) ($sp:pat, $x:pat) => (TtToken($sp, token::Ident($x, token::IdentStyle::Plain)))
} }
pub fn parse(cx: &mut ExtCtxt, input: &[TokenTree], sp: Span) -> P<Expr> { pub fn parse(cx: &ExtCtxt, input: &[TokenTree], sp: Span) -> P<Expr> {
Renderer::with(cx, |render| { let mut render = Renderer::new(cx);
Parser { Parser {
in_attr: false, in_attr: false,
input: input, input: input,
span: sp, span: sp,
render: render, render: &mut render,
}.markups(); }.markups();
}) render.into_expr()
} }
struct Parser<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> { struct Parser<'cx: 'r, 's: 'cx, 'i, 'r> {
in_attr: bool, in_attr: bool,
input: &'i [TokenTree], input: &'i [TokenTree],
span: Span, span: Span,
render: &'r mut Renderer<'cx, 's, 'o>, render: &'r mut Renderer<'cx, 's>,
} }
impl<'cx, 's, 'i, 'r, 'o> Parser<'cx, 's, 'i, 'r, 'o> { impl<'cx, 's, 'i, 'r> Parser<'cx, 's, 'i, 'r> {
/// Consume `n` items from the input. /// Consume `n` items from the input.
fn shift(&mut self, n: usize) { fn shift(&mut self, n: usize) {
self.input = &self.input[n..]; self.input = &self.input[n..];
@ -221,7 +221,7 @@ impl<'cx, 's, 'i, 'r, 'o> Parser<'cx, 's, 'i, 'r, 'o> {
} }
/// Convert a literal to a string. /// Convert a literal to a string.
fn lit_to_string(cx: &mut ExtCtxt, lit: Lit, minus: bool) -> Option<String> { fn lit_to_string(cx: &ExtCtxt, lit: Lit, minus: bool) -> Option<String> {
use syntax::ast::Lit_::*; use syntax::ast::Lit_::*;
let mut result = String::new(); let mut result = String::new();
if minus { if minus {

View file

@ -13,27 +13,23 @@ pub enum Escape {
Escape, Escape,
} }
pub struct Renderer<'cx, 's: 'cx, 'o> { pub struct Renderer<'cx, 's: 'cx> {
pub cx: &'cx mut ExtCtxt<'s>, pub cx: &'cx ExtCtxt<'s>,
stmts: &'o mut Vec<P<Stmt>>, stmts: Vec<P<Stmt>>,
w: Ident, w: Ident,
} }
impl<'cx, 's, 'o> Renderer<'cx, 's, 'o> { impl<'cx, 's> Renderer<'cx, 's> {
pub fn with<F>(cx: &'cx mut ExtCtxt<'s>, f: F) -> P<Expr> where pub fn new(cx: &'cx ExtCtxt<'s>) -> Renderer<'cx, 's> {
F: for<'o_> FnOnce(&mut Renderer<'cx, 's, 'o_>) Renderer {
{ cx: cx,
let mut stmts = vec![]; stmts: vec![],
let w = Ident::new(token::intern("w")); w: Ident::new(token::intern("w")),
let cx = { }
let mut render = Renderer { }
cx: cx,
stmts: &mut stmts, pub fn into_expr(self) -> P<Expr> {
w: w, let Renderer { cx, stmts, w } = self;
};
f(&mut render);
render.cx
};
quote_expr!(cx, quote_expr!(cx,
::maud::rt::make_markup(|&: $w: &mut ::std::fmt::Writer| -> Result<(), ::std::fmt::Error> { ::maud::rt::make_markup(|&: $w: &mut ::std::fmt::Writer| -> Result<(), ::std::fmt::Error> {
$stmts $stmts
@ -41,22 +37,29 @@ impl<'cx, 's, 'o> Renderer<'cx, 's, 'o> {
})) }))
} }
/// Push an expression statement, also wrapping it with `try!`. fn make_stmts<F>(&self, f: F) -> Vec<P<Stmt>> where
fn push(&mut self, expr: P<Expr>) { F: FnOnce(&mut Renderer<'cx, 's>)
let stmt = self.make_stmt(expr); {
self.stmts.push(stmt); let mut render = Renderer {
cx: self.cx,
stmts: vec![],
w: self.w,
};
f(&mut render);
render.stmts
} }
/// Create an expression statement, also wrapping it with `try!`. /// Push an expression statement, also wrapping it with `try!`.
fn make_stmt(&mut self, expr: P<Expr>) -> P<Stmt> { fn push_try(&mut self, expr: P<Expr>) {
self.cx.stmt_expr(self.cx.expr_try(expr.span, expr)) let stmt = self.cx.stmt_expr(self.cx.expr_try(expr.span, expr));
self.stmts.push(stmt);
} }
/// Append a literal pre-escaped string. /// Append a literal pre-escaped string.
fn write(&mut self, s: &str) { fn write(&mut self, s: &str) {
let w = self.w; let w = self.w;
let expr = quote_expr!(self.cx, $w.write_str($s)); let expr = quote_expr!(self.cx, $w.write_str($s));
self.push(expr); self.push_try(expr);
} }
/// Append a literal string, with the specified escaping method. /// Append a literal string, with the specified escaping method.
@ -80,7 +83,7 @@ impl<'cx, 's, 'o> Renderer<'cx, 's, 'o> {
&mut ::maud::rt::Escaper { inner: $w }, &mut ::maud::rt::Escaper { inner: $w },
$expr)), $expr)),
}; };
self.push(expr); self.push_try(expr);
} }
pub fn element_open_start(&mut self, name: &str) { pub fn element_open_start(&mut self, name: &str) {
@ -100,21 +103,17 @@ impl<'cx, 's, 'o> Renderer<'cx, 's, 'o> {
} }
pub fn attribute_empty_if(&mut self, name: &str, expr: P<Expr>) { pub fn attribute_empty_if(&mut self, name: &str, expr: P<Expr>) {
let s: String = [" ", name].concat();
let s = &s[];
let w = self.w;
// Silence "unnecessary parentheses" warnings // Silence "unnecessary parentheses" warnings
let expr = match expr.node { let expr = match expr.node {
ExprParen(ref inner) => inner.clone(), ExprParen(ref inner) => inner.clone(),
_ => expr.clone(), _ => expr.clone(),
}; };
let expr = quote_expr!(self.cx, let stmts = self.make_stmts(|r| {
if $expr { r.write(" ");
$w.write_str($s) r.write(name);
} else { });
Ok(()) let stmt = quote_stmt!(self.cx, if $expr { $stmts });
}); self.stmts.push(stmt);
self.push(expr);
} }
pub fn attribute_end(&mut self) { pub fn attribute_end(&mut self) {