From ed28f1c1bc94dd0c5a6bffd77b71155bdf82d906 Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Fri, 27 Feb 2015 09:27:45 +1300 Subject: [PATCH] Implement if/else --- maud_macros/src/parse.rs | 44 ++++++++++++++++++++++++++++++++++++-- maud_macros/tests/tests.rs | 20 +++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 261ec3a..0df8e59 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -4,7 +4,7 @@ use syntax::codemap::Span; use syntax::ext::base::ExtCtxt; use syntax::parse; use syntax::parse::parser::Parser as RustParser; -use syntax::parse::token; +use syntax::parse::token::{self, DelimToken}; use syntax::ptr::P; use super::render::{Escape, Renderer}; @@ -97,6 +97,11 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { self.shift(1); self.literal(tt, false) }, + // If + [dollar!(), ident!(sp, name), ..] if name.as_str() == "if" => { + self.shift(2); + self.if_expr(sp); + }, // Splice [ref tt @ dollar!(), dollar!(), ..] => { self.shift(2); @@ -140,6 +145,41 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { } } + fn if_expr(&mut self, sp: Span) { + let mut cond = vec![]; + let if_body; + loop { match self.input { + [TtDelimited(sp, ref d), ..] if d.delim == DelimToken::Brace => { + self.shift(1); + if_body = self.block(sp, &d.tts); + break; + }, + [ref tt, ..] => { + self.shift(1); + cond.push(tt.clone()); + }, + [] => self.render.cx.span_fatal(sp, "expected body for this $if"), + }} + let cond = self.new_rust_parser(cond).parse_expr(); + let else_body = match self.input { + [dollar!(), ident!(name), ..] if name.as_str() == "else" => { + self.shift(2); + let else_body = { + // Parse a single markup, but capture the result rather + // than emitting it right away + let mut render = self.render.fork(); + mem::swap(&mut self.render, &mut render); + self.markup(); + mem::swap(&mut self.render, &mut render); + render.into_stmts() + }; + Some(else_body) + }, + _ => None, + }; + self.render.emit_if(cond, if_body, else_body); + } + fn splice(&mut self, sp: Span) -> P<Expr> { let mut tts = vec![]; // First, munch a single token tree @@ -194,7 +234,7 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { self.render.attribute_start(name.as_str()); { // Parse a value under an attribute context - let in_attr = true; + let mut in_attr = true; mem::swap(&mut self.in_attr, &mut in_attr); self.markup(); mem::swap(&mut self.in_attr, &mut in_attr); diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs index 5ffffb2..56c0f0c 100644 --- a/maud_macros/tests/tests.rs +++ b/maud_macros/tests/tests.rs @@ -182,3 +182,23 @@ fn issue_1() { let markup = html! { "Test" }; let _ = markup.to_string(); } + +mod control { + #[test] + fn if_expr() { + for (number, &name) in (1..4).zip(["one", "two", "three"].iter()) { + let s = html! { + $if number == 1 { + "one" + } $else $if number == 2 { + "two" + } $else $if number == 3 { + "three" + } $else { + "oh noes" + } + }.to_string(); + assert_eq!(s, name); + } + } +}