aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar PizzasBear <43722034+PizzasBear@users.noreply.github.com>2023-11-22 17:09:33 +0200
committerLibravatar GitHub <noreply@github.com>2023-11-22 16:09:33 +0100
commit696561003d9caaf5d1fd537d6a0f4f88fccca8ce (patch)
tree7e62fd238049cbf6a6e615b7e19ce6079a5b4cee
parent48c6cd327d3c1df4218898be509250efcc56597c (diff)
downloadaskama-696561003d9caaf5d1fd537d6a0f4f88fccca8ce.tar.gz
askama-696561003d9caaf5d1fd537d6a0f4f88fccca8ce.tar.bz2
askama-696561003d9caaf5d1fd537d6a0f4f88fccca8ce.zip
Add better support for rust-like number literals (#908)
Signed-off-by: max <gmx.sht@gmail.com>
Diffstat (limited to '')
-rw-r--r--askama_parser/src/lib.rs70
-rw-r--r--testing/templates/num-literals.html11
-rw-r--r--testing/tests/simple.rs23
3 files changed, 99 insertions, 5 deletions
diff --git a/askama_parser/src/lib.rs b/askama_parser/src/lib.rs
index ff26483..4d27d70 100644
--- a/askama_parser/src/lib.rs
+++ b/askama_parser/src/lib.rs
@@ -7,11 +7,10 @@ use std::{fmt, str};
use nom::branch::alt;
use nom::bytes::complete::{escaped, is_not, tag, take_till};
-use nom::character::complete::char;
-use nom::character::complete::{anychar, digit1};
+use nom::character::complete::{anychar, char, one_of, satisfy};
use nom::combinator::{cut, eof, map, opt, recognize};
use nom::error::{Error, ErrorKind, FromExternalError};
-use nom::multi::many1;
+use nom::multi::{many0_count, many1};
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
use nom::{error_position, AsChar, InputTakeAtPosition};
@@ -250,13 +249,74 @@ fn bool_lit(i: &str) -> ParseResult<'_> {
}
fn num_lit(i: &str) -> ParseResult<'_> {
+ let integer_suffix = |i| {
+ alt((
+ tag("i8"),
+ tag("i16"),
+ tag("i32"),
+ tag("i64"),
+ tag("i128"),
+ tag("isize"),
+ tag("u8"),
+ tag("u16"),
+ tag("u32"),
+ tag("u64"),
+ tag("u128"),
+ tag("usize"),
+ ))(i)
+ };
+ let float_suffix = |i| alt((tag("f32"), tag("f64")))(i);
+
recognize(tuple((
opt(char('-')),
- digit1,
- opt(pair(char('.'), digit1)),
+ alt((
+ recognize(tuple((
+ char('0'),
+ alt((
+ recognize(tuple((char('b'), separated_digits(2, false)))),
+ recognize(tuple((char('o'), separated_digits(8, false)))),
+ recognize(tuple((char('x'), separated_digits(16, false)))),
+ )),
+ opt(integer_suffix),
+ ))),
+ recognize(tuple((
+ separated_digits(10, true),
+ opt(alt((
+ integer_suffix,
+ float_suffix,
+ recognize(tuple((
+ opt(tuple((char('.'), separated_digits(10, true)))),
+ one_of("eE"),
+ opt(one_of("+-")),
+ separated_digits(10, false),
+ opt(float_suffix),
+ ))),
+ recognize(tuple((
+ char('.'),
+ separated_digits(10, true),
+ opt(float_suffix),
+ ))),
+ ))),
+ ))),
+ )),
)))(i)
}
+/// Underscore separated digits of the given base, unless `start` is true this may start
+/// with an underscore.
+fn separated_digits(radix: u32, start: bool) -> impl Fn(&str) -> ParseResult<'_> {
+ move |i| {
+ recognize(tuple((
+ |i| match start {
+ true => Ok((i, 0)),
+ false => many0_count(char('_'))(i),
+ },
+ satisfy(|ch| ch.is_digit(radix)),
+ many0_count(satisfy(|ch| ch == '_' || ch.is_digit(radix))),
+ )))(i)
+ }
+}
+
fn str_lit(i: &str) -> ParseResult<'_> {
let (i, s) = delimited(
char('"'),
diff --git a/testing/templates/num-literals.html b/testing/templates/num-literals.html
new file mode 100644
index 0000000..90b07db
--- /dev/null
+++ b/testing/templates/num-literals.html
@@ -0,0 +1,11 @@
+{% let plain_int = 9__0__ -%}
+{% let neg_int = -9__0__isize -%}
+{% let suffix_int = 9__0__i32 -%}
+{% let bin_int = 0b__1__0__ -%}
+{% let oct_int = 0o__7__0__ -%}
+{% let hex_int = 0x__f__0__ -%}
+{% let plain_float = 1__0__.5__0__ -%}
+{% let suffix_float = 1__0__.5__0__f32 -%}
+{% let exp_float = 1__0__e+__1__0__f32 -%}
+{% let dotexp_float = 1__0__.5__0__e+__1__0__f32 -%}
+[{{ plain_int }}, {{ neg_int }}, {{ suffix_int }}, {{ bin_int }}, {{ oct_int }}, {{ hex_int }}, {{ plain_float }}, {{ suffix_float }}, {{ exp_float }}, {{ dotexp_float }}]
diff --git a/testing/tests/simple.rs b/testing/tests/simple.rs
index 627a8a3..f0f0a26 100644
--- a/testing/tests/simple.rs
+++ b/testing/tests/simple.rs
@@ -461,3 +461,26 @@ fn test_define_string_var() {
let template = DefineStringVar;
assert_eq!(template.render().unwrap(), "");
}
+
+#[derive(askama::Template)]
+#[template(source = "{% let x = 4.5 %}{{ x }}", ext = "html")]
+struct SimpleFloat;
+
+#[test]
+fn test_simple_float() {
+ let template = SimpleFloat;
+ assert_eq!(template.render().unwrap(), "4.5");
+}
+
+#[derive(askama::Template)]
+#[template(path = "num-literals.html")]
+struct NumLiterals;
+
+#[test]
+fn test_num_literals() {
+ let template = NumLiterals;
+ assert_eq!(
+ template.render().unwrap(),
+ "[90, -90, 90, 2, 56, 240, 10.5, 10.5, 100000000000, 105000000000]",
+ );
+}