diff options
author | Tuomas Siipola <tuomas@zpl.fi> | 2020-01-12 00:47:52 +0200 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2020-01-12 08:15:04 +0100 |
commit | 80148aa75335563106abae8680197e4adf3eb2eb (patch) | |
tree | d2c593be4240b086caa5557c150d3546f467322b | |
parent | 100679e69d37355f3683df43e58aab21312ea147 (diff) | |
download | askama-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.rs | 50 | ||||
-rw-r--r-- | testing/templates/literals-escape.html | 2 | ||||
-rw-r--r-- | testing/tests/simple.rs | 13 |
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♥'""\nA\n\r\t\\\0♥'"'" + ); +} + struct Holder { a: usize, } |