Skip to content

Commit

Permalink
Implement let expressions
Browse files Browse the repository at this point in the history
Closes #57
  • Loading branch information
lambda-fairy committed Nov 12, 2016
1 parent a3908fa commit 39602a0
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
41 changes: 41 additions & 0 deletions maud_macros/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
self.shift(2);
self.match_expr(sp)?;
},
// Let
[at!(), keyword!(sp, k), ..] if k.is_keyword(keywords::Let) => {
self.shift(2);
self.let_expr(sp)?;
}
// Element
[ident!(sp, _), ..] => {
let name = self.namespaced_name().unwrap();
Expand Down Expand Up @@ -402,6 +407,42 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
Ok(body)
}

/// Parses and renders a `@let` expression.
///
/// The leading `@let` should already be consumed.
fn let_expr(&mut self, sp: Span) -> PResult<()> {
let mut pattern = vec![];
loop { match *self.input {
[eq!(), ..] => {
self.shift(1);
break;
},
[ref tt, ..] => {
self.shift(1);
pattern.push(tt.clone());
},
_ => parse_error!(self, sp, "invalid @let"),
}}
let pattern = self.with_rust_parser(pattern, RustParser::parse_pat)?;
let mut rhs = vec![];
let body;
loop { match *self.input {
[TokenTree::Delimited(sp, ref d), ..] if d.delim == DelimToken::Brace => {
self.shift(1);
body = self.block(sp, &d.tts)?;
break;
},
[ref tt, ..] => {
self.shift(1);
rhs.push(tt.clone());
},
_ => parse_error!(self, sp, "invalid @let"),
}}
let rhs = self.with_rust_parser(rhs, RustParser::parse_expr)?;
self.render.emit_let(pattern, rhs, body);
Ok(())
}

/// Parses and renders an element node.
///
/// The element name should already be consumed.
Expand Down
5 changes: 5 additions & 0 deletions maud_macros/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ impl<'cx, 'a> Renderer<'cx, 'a> {
let stmt = quote_stmt!(self.cx, match $match_var { $match_body }).unwrap();
self.push(stmt);
}

pub fn emit_let(&mut self, pattern: P<Pat>, rhs: P<Expr>, body: Vec<Stmt>) {
let stmt = quote_stmt!(self.cx, { let $pattern = $rhs; $body }).unwrap();
self.push(stmt);
}
}

fn html_escape(s: &str) -> String {
Expand Down
24 changes: 24 additions & 0 deletions maud_macros/tests/control_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,27 @@ fn match_in_attribute() {
assert_eq!(s, output);
}
}

#[test]
fn let_expr() {
let s = html! {
@let x = 42 {
"I have " (x) " cupcakes!"
}
}.into_string();
assert_eq!(s, "I have 42 cupcakes!");
}

#[test]
fn let_lexical_scope() {
let x = 42;
let s = html! {
@let x = 99 {
"Twilight thought I had " (x) " cupcakes, "
}
"but I only had " (x) "."
}.into_string();
assert_eq!(s, concat!(
"Twilight thought I had 99 cupcakes, ",
"but I only had 42."));
}

0 comments on commit 39602a0

Please sign in to comment.