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:
parent
9ee1c76e93
commit
110930a558
2 changed files with 49 additions and 50 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue