From 696561003d9caaf5d1fd537d6a0f4f88fccca8ce Mon Sep 17 00:00:00 2001 From: PizzasBear <43722034+PizzasBear@users.noreply.github.com> Date: Wed, 22 Nov 2023 17:09:33 +0200 Subject: Add better support for rust-like number literals (#908) Signed-off-by: max --- askama_parser/src/lib.rs | 70 ++++++++++++++++++++++++++++++++++--- testing/templates/num-literals.html | 11 ++++++ testing/tests/simple.rs | 23 ++++++++++++ 3 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 testing/templates/num-literals.html 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]", + ); +} -- cgit