Implement let expressions

Closes 
This commit is contained in:
Chris Wong 2016-11-12 14:46:49 +13:00
parent a3908faf24
commit 39602a075c
3 changed files with 70 additions and 0 deletions

View file

@ -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();
@ -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.

View file

@ -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 {

View file

@ -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."));
}