aboutsummaryrefslogtreecommitdiffstats
path: root/askama_parser/src/lib.rs
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 /askama_parser/src/lib.rs
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 'askama_parser/src/lib.rs')
-rw-r--r--askama_parser/src/lib.rs70
1 files changed, 65 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('"'),