Switch to new splice syntax using parentheses

Closes 
This commit is contained in:
Chris Wong 2016-08-18 22:12:14 +12:00
parent 61791a6aef
commit 6a6b23d8ae
4 changed files with 56 additions and 80 deletions

View file

@ -1,6 +1,6 @@
use std::mem;
use std::rc::Rc;
use syntax::ast::{Expr, ExprKind, Lit, LitKind, Stmt};
use syntax::ast::{Expr, Lit, LitKind, Stmt};
use syntax::ext::quote::rt::ToTokens;
use syntax::codemap::Span;
use syntax::errors::{DiagnosticBuilder, FatalError};
@ -64,9 +64,6 @@ 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(..)))
}
@ -190,24 +187,24 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
let func = self.splice(tt.get_span())?;
self.render.emit_call(func);
},
// Splice
[ref tt @ caret!(), ..] => {
self.shift(1);
let expr = self.splice(tt.get_span())?;
self.render.splice(expr);
},
// Element
[ident!(sp, _), ..] => {
let name = self.namespaced_name().unwrap();
self.element(sp, &name)?;
},
// Splice
[TokenTree::Delimited(_, ref d), ..] if d.delim == DelimToken::Paren => {
self.shift(1);
let expr = self.with_rust_parser(d.tts.clone(), RustParser::parse_expr)?;
self.render.splice(expr);
}
// Block
[TokenTree::Delimited(_, ref d), ..] if d.delim == DelimToken::Brace => {
self.shift(1);
{
// Parse the contents of the block, emitting the
// result inline
let mut i = &*d.tts;
let mut i = &d.tts[..];
mem::swap(&mut self.input, &mut i);
self.markups()?;
mem::swap(&mut self.input, &mut i);
@ -502,21 +499,23 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
(Ok(name), &[question!(), ..]) => {
// Empty attribute
self.shift(1);
if let [ref tt @ eq!(), ..] = *self.input {
// Toggle the attribute based on a boolean expression
self.shift(1);
let cond = self.splice(tt.get_span())?;
// Silence "unnecessary parentheses" warnings
let cond = strip_outer_parens(cond).to_tokens(self.render.cx);
let body = {
let mut r = self.render.fork();
r.attribute_empty(&name);
r.into_stmts()
};
self.render.emit_if(cond, body, None);
} else {
// Write the attribute unconditionally
self.render.attribute_empty(&name);
match *self.input {
[TokenTree::Delimited(_, ref d), ..] if d.delim == DelimToken::Paren => {
// Toggle the attribute based on a boolean expression
self.shift(1);
let cond = self.with_rust_parser(d.tts.clone(), RustParser::parse_expr)?;
let cond = cond.to_tokens(self.render.cx);
let body = {
let mut r = self.render.fork();
r.attribute_empty(&name);
r.into_stmts()
};
self.render.emit_if(cond, body, None);
},
_ => {
// Write the attribute unconditionally
self.render.attribute_empty(&name);
},
}
},
(Err(_), &[dot!(), ident!(_, _), ..]) => {
@ -619,11 +618,3 @@ fn lit_to_string(cx: &ExtCtxt, lit: Lit, minus: bool) -> PResult<String> {
};
Ok(result)
}
/// If the expression is wrapped in parentheses, strip them off.
fn strip_outer_parens(expr: P<Expr>) -> P<Expr> {
expr.and_then(|expr| match expr {
Expr { node: ExprKind::Paren(inner), .. } => inner,
expr => P(expr),
})
}

View file

@ -30,7 +30,7 @@ fn if_let() {
let mut s = String::new();
html!(s, {
@if let Some(value) = input {
^value
(value)
} @else {
"oh noes"
}
@ -45,7 +45,7 @@ fn for_expr() {
let mut s = String::new();
html!(s, {
ul @for pony in &ponies {
li ^pony
li (pony)
}
}).unwrap();
assert_eq!(s, concat!(
@ -63,7 +63,7 @@ fn match_expr() {
html!(s, {
@match input {
Some(value) => {
div { ^value }
div (value)
},
None => {
"oh noes"
@ -80,8 +80,8 @@ fn match_expr_without_delims() {
let mut s = String::new();
html!(s, {
@match input {
Some(value) => ^value,
None => span { "oh noes" },
Some(value) => (value),
None => span "oh noes",
}
}).unwrap();
assert_eq!(s, output);
@ -95,7 +95,7 @@ fn match_expr_with_guards() {
html!(s, {
@match input {
Some(value) if value == 1 => "one",
Some(value) => ^value,
Some(value) => (value),
None => "none",
}
}).unwrap();
@ -112,7 +112,7 @@ fn match_in_attribute() {
1 => "one",
2 => "two",
_ => "many",
} { ^input }
} { (input) }
}).unwrap();
assert_eq!(s, output);
}
@ -141,7 +141,7 @@ fn call() {
fn assert_cute<'a>(name: &'a str) -> impl maud::Template + 'a {
template! {
p {
^name " is the cutest"
(name) " is the cutest"
}
}
}

View file

@ -16,7 +16,7 @@ fn html_utf8() {
fn issue_13() {
let owned = String::from("yay");
let mut s = String::new();
html!(s, ^owned).unwrap();
html!(s, (owned)).unwrap();
// Make sure the `html!` call didn't move it
let _owned = owned;
}
@ -27,7 +27,7 @@ fn issue_21() {
() => ({
let mut result = String::new();
let name = "Pinkie Pie";
html!(result, p { "Hello, " ^name "!" }).map(|()| result)
html!(result, p { "Hello, " (name) "!" }).map(|()| result)
})
}
@ -40,7 +40,7 @@ fn issue_21_2() {
macro_rules! greet {
($name:expr) => ({
let mut result = String::new();
html!(result, p { "Hello, " ^$name "!" }).map(|()| result)
html!(result, p { "Hello, " ($name) "!" }).map(|()| result)
})
}
@ -59,7 +59,7 @@ fn issue_23() {
}
let name = "Lyra";
let s = to_string!(p { "Hi, " ^name "!" });
let s = to_string!(p { "Hi, " (name) "!" });
assert_eq!(s, "<p>Hi, Lyra!</p>");
}
@ -74,7 +74,7 @@ fn issue_26() {
}
let name = "Lyra";
let s = to_string!(p { "Hi, " ^(name) "!" });
let s = to_string!(p { "Hi, " (name) "!" });
assert_eq!(s, "<p>Hi, Lyra!</p>");
}
@ -89,22 +89,7 @@ fn issue_26_2() {
}
let name = "Lyra";
let s = to_string!(p { "Hi, " ^("person called ".to_string() + name) "!" });
assert_eq!(s, "<p>Hi, person called Lyra!</p>");
}
#[test]
fn issue_26_3() {
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, " ^{"person called ".to_string() + name} "!" });
let s = to_string!(p { "Hi, " ("person called ".to_string() + name) "!" });
assert_eq!(s, "<p>Hi, person called Lyra!</p>");
}
@ -121,8 +106,8 @@ fn render_impl() {
let r = R("pinkie");
// Since `R` is not `Copy`, this shows that Maud will auto-ref splice
// arguments to find a `Render` impl
html!(s, ^r).unwrap();
html!(s, ^r).unwrap();
html!(s, (r)).unwrap();
html!(s, (r)).unwrap();
assert_eq!(s, "pinkiepinkie");
}
@ -137,6 +122,6 @@ fn render_once_impl() {
let mut s = String::new();
let once = Once(String::from("pinkie"));
html!(s, ^once).unwrap();
html!(s, (once)).unwrap();
assert_eq!(s, "pinkie");
}

View file

@ -6,7 +6,7 @@ extern crate maud;
#[test]
fn literals() {
let mut s = String::new();
html!(s, ^"<pinkie>").unwrap();
html!(s, ("<pinkie>")).unwrap();
assert_eq!(s, "&lt;pinkie&gt;");
}
@ -14,7 +14,7 @@ fn literals() {
fn raw_literals() {
use maud::PreEscaped;
let mut s = String::new();
html!(s, ^PreEscaped("<pinkie>")).unwrap();
html!(s, (PreEscaped("<pinkie>"))).unwrap();
assert_eq!(s, "<pinkie>");
}
@ -22,13 +22,13 @@ fn raw_literals() {
fn blocks() {
let mut s = String::new();
html!(s, {
^{
({
let mut result = 1i32;
for i in 2..11 {
result *= i;
}
result
}
})
}).unwrap();
assert_eq!(s, "3628800");
}
@ -38,10 +38,10 @@ fn attributes() {
let rocks = true;
let mut s = String::new();
html!(s, {
input checked?=true /
input checked?=false /
input checked?=rocks /
input checked?=(!rocks) /
input checked?(true) /
input checked?(false) /
input checked?(rocks) /
input checked?(!rocks) /
}).unwrap();
assert_eq!(s, concat!(
r#"<input checked>"#,
@ -55,7 +55,7 @@ static BEST_PONY: &'static str = "Pinkie Pie";
#[test]
fn statics() {
let mut s = String::new();
html!(s, ^BEST_PONY).unwrap();
html!(s, (BEST_PONY)).unwrap();
assert_eq!(s, "Pinkie Pie");
}
@ -63,7 +63,7 @@ fn statics() {
fn locals() {
let best_pony = "Pinkie Pie";
let mut s = String::new();
html!(s, ^best_pony).unwrap();
html!(s, (best_pony)).unwrap();
assert_eq!(s, "Pinkie Pie");
}
@ -90,7 +90,7 @@ fn structs() {
};
let mut s = String::new();
html!(s, {
"Name: " ^pinkie.name ". Rating: " ^pinkie.repugnance()
"Name: " (pinkie.name) ". Rating: " (pinkie.repugnance())
}).unwrap();
assert_eq!(s, "Name: Pinkie Pie. Rating: 1");
}
@ -99,7 +99,7 @@ fn structs() {
fn tuple_accessors() {
let mut s = String::new();
let a = ("ducks", "geese");
html!(s, ^a.0).unwrap();
html!(s, (a.0)).unwrap();
assert_eq!(s, "ducks");
}
@ -111,7 +111,7 @@ fn splice_with_path() {
}
}
let mut s = String::new();
html!(s, ^inner::name()).unwrap();
html!(s, (inner::name())).unwrap();
assert_eq!(s, "Maud");
}
@ -119,6 +119,6 @@ fn splice_with_path() {
fn nested_macro_invocation() {
let best_pony = "Pinkie Pie";
let mut s = String::new();
html!(s, ^(format!("{}", best_pony))).unwrap();
html!(s, (format!("{}", best_pony))).unwrap();
assert_eq!(s, "Pinkie Pie");
}