Skip to content

Commit

Permalink
Merge pull request #31 from Nemo157/change-symbology
Browse files Browse the repository at this point in the history
Change symbology
  • Loading branch information
lambda-fairy committed Feb 8, 2016
2 parents 6b14129 + 1b30744 commit f113623
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 57 deletions.
11 changes: 11 additions & 0 deletions maud/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ impl<T: fmt::Display + ?Sized> Render for T {
}
}

/// Represents a type that can be rendered as HTML just once.
pub trait RenderOnce {
fn render_once(self, &mut fmt::Write) -> fmt::Result;
}

impl<'a, T: Render + ?Sized> RenderOnce for &'a T {
fn render_once(self, w: &mut fmt::Write) -> fmt::Result {
Render::render(self, w)
}
}

/// A wrapper that renders the inner value without escaping.
#[derive(Debug)]
pub struct PreEscaped<T>(pub T);
Expand Down
58 changes: 25 additions & 33 deletions maud_macros/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ macro_rules! parse_error {
($self_:expr, $sp:expr, $msg:expr) => (error!($self_.render.cx, $sp, $msg))
}

macro_rules! dollar {
() => (TokenTree::Token(_, Token::Dollar))
}
macro_rules! pound {
() => (TokenTree::Token(_, Token::Pound))
macro_rules! at {
() => (TokenTree::Token(_, Token::At))
}
macro_rules! dot {
() => (TokenTree::Token(_, Token::Dot))
Expand All @@ -53,6 +50,9 @@ macro_rules! minus {
macro_rules! slash {
() => (TokenTree::Token(_, Token::BinOp(BinOpToken::Slash)))
}
macro_rules! caret {
() => (TokenTree::Token(_, Token::BinOp(BinOpToken::Caret)))
}
macro_rules! literal {
() => (TokenTree::Token(_, Token::Literal(..)))
}
Expand Down Expand Up @@ -156,35 +156,27 @@ impl<'cx, 'i> Parser<'cx, 'i> {
try!(self.literal(tt, false))
},
// If
[pound!(), keyword!(sp, k), ..] if k.is_keyword(Keyword::If) => {
[at!(), keyword!(sp, k), ..] if k.is_keyword(Keyword::If) => {
self.shift(2);
try!(self.if_expr(sp));
},
// For
[pound!(), keyword!(sp, k), ..] if k.is_keyword(Keyword::For) => {
[at!(), keyword!(sp, k), ..] if k.is_keyword(Keyword::For) => {
self.shift(2);
try!(self.for_expr(sp));
},
// Call
[pound!(), ident!(sp, name), ..] if name.name.as_str() == "call" => {
[at!(), ident!(sp, name), ..] if name.name.as_str() == "call" => {
self.shift(2);
let func = try!(self.splice(sp));
self.render.emit_call(func);
},
// Splice
[ref tt @ dollar!(), ..] => {
[ref tt @ caret!(), ..] => {
self.shift(1);
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 = TokenTree::Token(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());
Expand Down Expand Up @@ -222,9 +214,9 @@ impl<'cx, 'i> Parser<'cx, 'i> {
Ok(())
}

/// Parses and renders an `#if` expression.
/// Parses and renders an `@if` expression.
///
/// The leading `#if` should already be consumed.
/// The leading `@if` should already be consumed.
fn if_expr(&mut self, sp: Span) -> PResult<()> {
// Parse the initial if
let mut if_cond = vec![];
Expand All @@ -239,11 +231,11 @@ impl<'cx, 'i> Parser<'cx, 'i> {
self.shift(1);
if_cond.push(tt.clone());
},
[] => parse_error!(self, sp, "expected body for this #if"),
[] => parse_error!(self, sp, "expected body for this @if"),
}}
// Parse the (optional) else
// Parse the (optional) @else
let else_body = match self.input {
[pound!(), keyword!(_, k), ..] if k.is_keyword(Keyword::Else) => {
[at!(), keyword!(_, k), ..] if k.is_keyword(Keyword::Else) => {
self.shift(2);
match self.input {
[keyword!(sp, k), ..] if k.is_keyword(Keyword::If) => {
Expand All @@ -263,7 +255,7 @@ impl<'cx, 'i> Parser<'cx, 'i> {
self.shift(1);
Some(try!(self.block(sp, &d.tts)))
},
_ => parse_error!(self, sp, "expected body for this #else"),
_ => parse_error!(self, sp, "expected body for this @else"),
}
},
_ => None,
Expand All @@ -272,9 +264,9 @@ impl<'cx, 'i> Parser<'cx, 'i> {
Ok(())
}

/// Parses and renders a `#for` expression.
/// Parses and renders a `@for` expression.
///
/// The leading `#for` should already be consumed.
/// The leading `@for` should already be consumed.
fn for_expr(&mut self, sp: Span) -> PResult<()> {
let mut pattern = vec![];
loop { match self.input {
Expand All @@ -286,7 +278,7 @@ impl<'cx, 'i> Parser<'cx, 'i> {
self.shift(1);
pattern.push(tt.clone());
},
_ => parse_error!(self, sp, "invalid #for"),
_ => parse_error!(self, sp, "invalid @for"),
}}
let pattern = try!(self.with_rust_parser(pattern, RustParser::parse_pat));
let mut iterable = vec![];
Expand All @@ -301,16 +293,16 @@ impl<'cx, 'i> Parser<'cx, 'i> {
self.shift(1);
iterable.push(tt.clone());
},
_ => parse_error!(self, sp, "invalid #for"),
_ => parse_error!(self, sp, "invalid @for"),
}}
let iterable = try!(self.with_rust_parser(iterable, RustParser::parse_expr));
self.render.emit_for(pattern, iterable, body);
Ok(())
}

/// Parses and renders a `$splice`.
/// Parses and renders a `^splice`.
///
/// The leading `$` should already be consumed.
/// The leading `^` should already be consumed.
fn splice(&mut self, sp: Span) -> PResult<P<Expr>> {
// First, munch a single token tree
let prefix = match self.input {
Expand All @@ -323,24 +315,24 @@ impl<'cx, 'i> Parser<'cx, 'i> {
self.splice_with_prefix(prefix)
}

/// Parses and renders a `$splice`, given a prefix that we've already
/// 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`
// 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 tuple attribute lookups e.g. `$person.1.2`
// Munch tuple attribute lookups e.g. `^person.1.2`
[ref dot @ dot!(), ref num @ integer!(), ..] => {
self.shift(2);
tts.push(dot.clone());
tts.push(num.clone());
},
// Munch path lookups e.g. `$some_mod::Struct`
// Munch path lookups e.g. `^some_mod::Struct`
[ref sep @ modsep!(), ref ident @ ident!(_, _), ..] => {
self.shift(2);
tts.push(sep.clone());
Expand Down
2 changes: 1 addition & 1 deletion maud_macros/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl<'cx> Renderer<'cx> {
/// Appends the result of an expression, with the specified escaping method.
pub fn splice(&mut self, expr: P<Expr>) {
let w = self.writer;
let expr = quote_expr!(self.cx, ::maud::Render::render(&$expr, &mut *$w));
let expr = quote_expr!(self.cx, { use ::maud::RenderOnce; $expr.render_once(&mut *$w) });
let stmt = self.wrap_try(expr);
self.push(stmt);
}
Expand Down
Loading

0 comments on commit f113623

Please sign in to comment.