From 333eb46c3a46f7605dbf17aaec5de6bce58901b8 Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Sun, 15 Mar 2015 16:23:19 +1300 Subject: [PATCH] Support `if let` --- maud_macros/src/parse.rs | 8 ++++---- maud_macros/src/render.rs | 8 ++++++-- maud_macros/tests/tests.rs | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 26c1460..0fba573 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -1,5 +1,6 @@ use std::mem; use syntax::ast::{Expr, ExprParen, Lit, Stmt, TokenTree, TtDelimited, TtToken}; +use syntax::ext::quote::rt::ToTokens; use syntax::codemap::Span; use syntax::ext::base::ExtCtxt; use syntax::parse; @@ -152,7 +153,7 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { fn if_expr(&mut self, sp: Span) { // Parse the initial if - let mut cond_tts = vec![]; + let mut if_cond = vec![]; let if_body; loop { match self.input { [TtDelimited(sp, ref d), ..] if d.delim == DelimToken::Brace => { @@ -162,11 +163,10 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { }, [ref tt, ..] => { self.shift(1); - cond_tts.push(tt.clone()); + if_cond.push(tt.clone()); }, [] => self.render.cx.span_fatal(sp, "expected body for this $if"), }} - let if_cond = self.new_rust_parser(cond_tts).parse_expr(); // Parse the (optional) else let else_body = match self.input { [dollar!(), ident!(else_), ..] if else_.as_str() == "else" => { @@ -298,7 +298,7 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { self.shift(1); let cond = self.splice(tt.get_span()); // Silence "unnecessary parentheses" warnings - let cond = strip_outer_parens(cond); + let cond = strip_outer_parens(cond).to_tokens(self.render.cx); let body = { let mut r = self.render.fork(); r.attribute_empty(name.as_str()); diff --git a/maud_macros/src/render.rs b/maud_macros/src/render.rs index 20b9810..de3972f 100644 --- a/maud_macros/src/render.rs +++ b/maud_macros/src/render.rs @@ -1,4 +1,4 @@ -use syntax::ast::{Expr, Ident, Pat, Stmt}; +use syntax::ast::{Expr, Ident, Pat, Stmt, TokenTree}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::parse::token; @@ -126,7 +126,11 @@ impl<'cx, 's> Renderer<'cx, 's> { self.write(">"); } - pub fn emit_if(&mut self, if_cond: P<Expr>, if_body: Vec<P<Stmt>>, + /// Emit an `if` expression. + /// + /// The condition is a token tree (not an expression) so we don't + /// need to special-case `if let`. + pub fn emit_if(&mut self, if_cond: Vec<TokenTree>, if_body: Vec<P<Stmt>>, else_body: Option<Vec<P<Stmt>>>) { let stmt = match else_body { None => quote_stmt!(self.cx, if $if_cond { $if_body }), diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs index 4ce1763..8defeec 100644 --- a/maud_macros/tests/tests.rs +++ b/maud_macros/tests/tests.rs @@ -202,6 +202,20 @@ mod control { } } + #[test] + fn if_let() { + for &(input, output) in [(Some("yay"), "yay"), (None, "oh noes")].iter() { + let s = html! { + $if let Some(value) = input { + $value + } $else { + "oh noes" + } + }.to_string(); + assert_eq!(s, output); + } + } + #[test] fn for_expr() { let ponies = ["Apple Bloom", "Scootaloo", "Sweetie Belle"];