From 34f14dd41dafbae47917ddbbc1a719ad3558afa2 Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Thu, 5 Nov 2015 21:46:43 +1300 Subject: [PATCH] Don't choke on SubstNt tokens Closes #23 --- maud_macros/src/parse.rs | 22 ++++++++++++++++++++-- maud_macros/tests/tests.rs | 15 +++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 4d747fc..056684e 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -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!(_, _), ..] => { diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs index 2695e69..42eb731 100644 --- a/maud_macros/tests/tests.rs +++ b/maud_macros/tests/tests.rs @@ -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>"); +}