From 2250c2e9616a5615f0792176f98a442ab5c9650a Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Sun, 18 Jan 2015 20:18:21 +1300 Subject: [PATCH] Make splices a bit nicer to use --- maud_macros/src/parse.rs | 42 ++++++++++++++++++++++++++++---------- maud_macros/tests/tests.rs | 27 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 7555afc..4d89bbc 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -11,6 +11,9 @@ use super::render::{Escape, Renderer}; macro_rules! dollar { () => (TtToken(_, token::Dollar)) } +macro_rules! dot { + () => (TtToken(_, token::Dot)) +} macro_rules! eq { () => (TtToken(_, token::Eq)) } @@ -125,17 +128,34 @@ impl<'cx, 's, 'i, 'r, 'o> Parser<'cx, 's, 'i, 'r, 'o> { } fn splice(&mut self, escape: Escape, sp: Span) { - let tt = match self.input { - [ref tt, ..] => { - self.shift(1); - self.new_rust_parser(vec![tt.clone()]).parse_expr() - }, - _ => { - self.render.cx.span_err(sp, "expected expression for this splice"); - return; - }, - }; - self.render.splice(tt, escape); + let mut tts = vec![]; + // First, munch a single token tree + if let [ref tt, ..] = self.input { + self.shift(1); + tts.push(tt.clone()); + } + loop { + match self.input { + // Munch attribute lookups e.g. `$person.address.street` + [ref dot @ dot!(), ref ident @ ident!(_), ..] => { + self.shift(2); + tts.push(dot.clone()); + tts.push(ident.clone()); + }, + // Munch function calls `()` and indexing operations `[]` + [TtDelimited(sp, ref d), ..] if d.delim != token::DelimToken::Brace => { + self.shift(1); + tts.push(TtDelimited(sp, d.clone())); + }, + _ => break, + } + } + if tts.is_empty() { + self.render.cx.span_err(sp, "expected expression for this splice"); + } else { + let expr = self.new_rust_parser(tts).parse_expr(); + self.render.splice(expr, escape); + } } fn element(&mut self, name: &str, sp: Span) { diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs index 2d94c2f..25a936b 100644 --- a/maud_macros/tests/tests.rs +++ b/maud_macros/tests/tests.rs @@ -123,6 +123,33 @@ mod splices { assert_eq!(s, "Pinkie Pie"); } + /// An example struct, for testing purposes only + struct Creature { + name: &'static str, + /// Rating out of 10, where: + /// * 0 is a naked mole rat with dysentery + /// * 10 is Sweetie Belle in a milkshake + adorableness: u8, + } + + impl Creature { + fn repugnance(&self) -> u8 { + 10 - self.adorableness + } + } + + #[test] + fn structs() { + let pinkie = Creature { + name: "Pinkie Pie", + adorableness: 9, + }; + let s = html! { + "Name: " $pinkie.name ". Rating: " $pinkie.repugnance() + }.render(); + assert_eq!(s, "Name: Pinkie Pie. Rating: 1"); + } + // FIXME: See <https://github.com/rust-lang/rust/issues/16617> // for why this is commented out /*