parent
a3908faf24
commit
39602a075c
3 changed files with 70 additions and 0 deletions
maud_macros
|
@ -156,6 +156,11 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
|
||||||
self.shift(2);
|
self.shift(2);
|
||||||
self.match_expr(sp)?;
|
self.match_expr(sp)?;
|
||||||
},
|
},
|
||||||
|
// Let
|
||||||
|
[at!(), keyword!(sp, k), ..] if k.is_keyword(keywords::Let) => {
|
||||||
|
self.shift(2);
|
||||||
|
self.let_expr(sp)?;
|
||||||
|
}
|
||||||
// Element
|
// Element
|
||||||
[ident!(sp, _), ..] => {
|
[ident!(sp, _), ..] => {
|
||||||
let name = self.namespaced_name().unwrap();
|
let name = self.namespaced_name().unwrap();
|
||||||
|
@ -402,6 +407,42 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
|
||||||
Ok(body)
|
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.
|
/// Parses and renders an element node.
|
||||||
///
|
///
|
||||||
/// The element name should already be consumed.
|
/// The element name should already be consumed.
|
||||||
|
|
|
@ -156,6 +156,11 @@ impl<'cx, 'a> Renderer<'cx, 'a> {
|
||||||
let stmt = quote_stmt!(self.cx, match $match_var { $match_body }).unwrap();
|
let stmt = quote_stmt!(self.cx, match $match_var { $match_body }).unwrap();
|
||||||
self.push(stmt);
|
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 {
|
fn html_escape(s: &str) -> String {
|
||||||
|
|
|
@ -131,3 +131,27 @@ fn match_in_attribute() {
|
||||||
assert_eq!(s, output);
|
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."));
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue