Don't choke on SubstNt tokens

Closes 
This commit is contained in:
Chris Wong 2015-11-05 21:46:43 +13:00
parent 2e0aa3e433
commit 34f14dd41d
2 changed files with 35 additions and 2 deletions
maud_macros

View file

@ -55,6 +55,9 @@ macro_rules! literal {
macro_rules! ident {
($sp:pat, $x:pat) => (TtToken($sp, Token::Ident($x, IdentStyle::Plain)))
}
macro_rules! substnt {
($sp:pat, $x:pat) => (TtToken($sp, Token::SubstNt($x, IdentStyle::Plain)))
}
macro_rules! keyword {
($sp:pat, $x:ident) => (TtToken($sp, ref $x @ Token::Ident(..)))
}
@ -167,6 +170,14 @@ impl<'cx, 'i> Parser<'cx, 'i> {
let expr = try!(self.splice(tt.get_span()));
self.render.splice(expr);
},
[substnt!(sp, ident), ..] => {
self.shift(1);
// Parse `SubstNt` as `[Dollar, Ident]`
// See <https://github.com/lfairy/maud/issues/23>
let prefix = TtToken(sp, Token::Ident(ident, IdentStyle::Plain));
let expr = try!(self.splice_with_prefix(prefix));
self.render.splice(expr);
},
// Element
[ident!(sp, _), ..] => {
let name = try!(self.name());
@ -295,13 +306,20 @@ impl<'cx, 'i> Parser<'cx, 'i> {
/// The leading `$` should already be consumed.
fn splice(&mut self, sp: Span) -> PResult<P<Expr>> {
// First, munch a single token tree
let mut tts = match self.input {
let prefix = match self.input {
[ref tt, ..] => {
self.shift(1);
vec![tt.clone()]
tt.clone()
},
[] => parse_error!(self, sp, "expected expression for this splice"),
};
self.splice_with_prefix(prefix)
}
/// Parses and renders a `$splice`, given a prefix that we've already
/// consumed.
fn splice_with_prefix(&mut self, prefix: TokenTree) -> PResult<P<Expr>> {
let mut tts = vec![prefix];
loop { match self.input {
// Munch attribute lookups e.g. `$person.address.street`
[ref dot @ dot!(), ref ident @ ident!(_, _), ..] => {

View file

@ -294,3 +294,18 @@ fn call() {
}).unwrap();
assert_eq!(s, "DucksGeeseSwans");
}
#[test]
fn issue_23() {
macro_rules! to_string {
($($x:tt)*) => {{
let mut s = String::new();
html!(s, $($x)*).unwrap();
s
}}
}
let name = "Lyra";
let s = to_string!(p { "Hi, " $name "!" });
assert_eq!(s, "<p>Hi, Lyra!</p>");
}