aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Tuomas Siipola <tuomas@zpl.fi>2020-01-12 00:47:52 +0200
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2020-01-12 08:15:04 +0100
commit80148aa75335563106abae8680197e4adf3eb2eb (patch)
treed2c593be4240b086caa5557c150d3546f467322b
parent100679e69d37355f3683df43e58aab21312ea147 (diff)
downloadaskama-80148aa75335563106abae8680197e4adf3eb2eb.tar.gz
askama-80148aa75335563106abae8680197e4adf3eb2eb.tar.bz2
askama-80148aa75335563106abae8680197e4adf3eb2eb.zip
Support escaping in string literals
Do not attempt to parse escape sequences thoroughly. Instead let the Rust compiler to check the string literals and provide nice error messages if necessary.
-rw-r--r--askama_derive/src/parser.rs50
-rw-r--r--testing/templates/literals-escape.html2
-rw-r--r--testing/tests/simple.rs13
3 files changed, 45 insertions, 20 deletions
diff --git a/askama_derive/src/parser.rs b/askama_derive/src/parser.rs
index 91c2d6a..910815a 100644
--- a/askama_derive/src/parser.rs
+++ b/askama_derive/src/parser.rs
@@ -1,6 +1,6 @@
use nom::branch::alt;
-use nom::bytes::complete::{is_not, tag, take_until};
-use nom::character::complete::{char, digit1};
+use nom::bytes::complete::{escaped, is_not, tag, take_until};
+use nom::character::complete::{anychar, char, digit1};
use nom::combinator::{complete, map, opt};
use nom::error::ParseError;
use nom::multi::{many0, many1, separated_list, separated_nonempty_list};
@@ -251,40 +251,50 @@ fn param_num_lit(i: &[u8]) -> IResult<&[u8], MatchParameter> {
map(num_lit, |s| MatchParameter::NumLit(s))(i)
}
+fn str_lit(i: &[u8]) -> IResult<&[u8], &str> {
+ map(
+ delimited(
+ char('\"'),
+ opt(escaped(is_not("\\\""), '\\', anychar)),
+ char('\"'),
+ ),
+ |s| s.map(|s| str::from_utf8(s).unwrap()).unwrap_or(""),
+ )(i)
+}
+
fn expr_str_lit(i: &[u8]) -> IResult<&[u8], Expr> {
- map(delimited(char('"'), take_until("\""), char('"')), |s| {
- Expr::StrLit(str::from_utf8(s).unwrap())
- })(i)
+ map(str_lit, |s| Expr::StrLit(s))(i)
}
fn variant_str_lit(i: &[u8]) -> IResult<&[u8], MatchVariant> {
- map(delimited(char('"'), is_not("\""), char('"')), |s| {
- MatchVariant::StrLit(str::from_utf8(s).unwrap())
- })(i)
+ map(str_lit, |s| MatchVariant::StrLit(s))(i)
}
fn param_str_lit(i: &[u8]) -> IResult<&[u8], MatchParameter> {
- map(delimited(char('"'), is_not("\""), char('"')), |s| {
- MatchParameter::StrLit(str::from_utf8(s).unwrap())
- })(i)
+ map(str_lit, |s| MatchParameter::StrLit(s))(i)
+}
+
+fn char_lit(i: &[u8]) -> IResult<&[u8], &str> {
+ map(
+ delimited(
+ char('\''),
+ opt(escaped(is_not("\\\'"), '\\', anychar)),
+ char('\''),
+ ),
+ |s| s.map(|s| str::from_utf8(s).unwrap()).unwrap_or(""),
+ )(i)
}
fn expr_char_lit(i: &[u8]) -> IResult<&[u8], Expr> {
- map(delimited(char('\''), take_until("'"), char('\'')), |s| {
- Expr::CharLit(str::from_utf8(s).unwrap())
- })(i)
+ map(char_lit, |s| Expr::CharLit(s))(i)
}
fn variant_char_lit(i: &[u8]) -> IResult<&[u8], MatchVariant> {
- map(delimited(char('\''), is_not("'"), char('\'')), |s| {
- MatchVariant::CharLit(str::from_utf8(s).unwrap())
- })(i)
+ map(char_lit, |s| MatchVariant::CharLit(s))(i)
}
fn param_char_lit(i: &[u8]) -> IResult<&[u8], MatchParameter> {
- map(delimited(char('\''), is_not("'"), char('\'')), |s| {
- MatchParameter::CharLit(str::from_utf8(s).unwrap())
- })(i)
+ map(char_lit, |s| MatchParameter::CharLit(s))(i)
}
fn expr_var(i: &[u8]) -> IResult<&[u8], Expr> {
diff --git a/testing/templates/literals-escape.html b/testing/templates/literals-escape.html
new file mode 100644
index 0000000..4886cfb
--- /dev/null
+++ b/testing/templates/literals-escape.html
@@ -0,0 +1,2 @@
+{{ '\x41' }}{{ '\n' }}{{ '\r' }}{{ '\t' }}{{ '\\' }}{{ '\0' }}{{ '\u{2665}' }}{{ '\'' }}{{ '\"' }}{{ '"' }}
+{{ "\x41\n\r\t\\\0\u{2665}\'\"'" }}
diff --git a/testing/tests/simple.rs b/testing/tests/simple.rs
index 53f1122..a075d26 100644
--- a/testing/tests/simple.rs
+++ b/testing/tests/simple.rs
@@ -122,6 +122,19 @@ fn test_literals() {
assert_eq!(s.render().unwrap(), "a\na\ntrue\nfalse");
}
+#[derive(Template)]
+#[template(path = "literals-escape.html")]
+struct LiteralsEscapeTemplate {}
+
+#[test]
+fn test_literals_escape() {
+ let s = LiteralsEscapeTemplate {};
+ assert_eq!(
+ s.render().unwrap(),
+ "A\n\r\t\\\0♥&#x27;&quot;&quot;\nA\n\r\t\\\0♥&#x27;&quot;&#x27;"
+ );
+}
+
struct Holder {
a: usize,
}