diff --git a/rinja_parser/src/lib.rs b/rinja_parser/src/lib.rs index b625d7c5..fc809e24 100644 --- a/rinja_parser/src/lib.rs +++ b/rinja_parser/src/lib.rs @@ -416,23 +416,36 @@ 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("f16"), tag("f32"), tag("f64"), tag("f128")))(i); + const INTEGER_SUFFIX: &[&str] = &[ + "i8", "i16", "i32", "i64", "i128", "isize", "u8", "u16", "u32", "u64", "u128", "usize", + ]; + const FLOAT_SUFFIX: &[&str] = &["f16", "f32", "f64", "f128"]; + + fn suffix<'a>( + start: &'a str, + kind: &'a str, + list: &'a [&[&str]], + ignore: &'a [&str], + ) -> impl Fn(&'a str) -> ParseResult<'a> + Copy + 'a { + move |i| { + let (i, suffix) = identifier(i)?; + if list.iter().flat_map(|&i| i).any(|&item| item == suffix) { + Ok((i, suffix)) + } else if ignore.contains(&suffix) { + // no need for a message, this case only occures in an `opt(…)` + Err(nom::Err::Error(ErrorContext::new("", i))) + } else { + Err(nom::Err::Failure(ErrorContext::new( + format!("unknown {kind} suffix `{suffix}`"), + start, + ))) + } + } + } + + let integer_suffix = suffix(i, "integer", &[INTEGER_SUFFIX], &[]); + let float_suffix = suffix(i, "float", &[FLOAT_SUFFIX], &["e"]); + let either_suffix = suffix(i, "number", &[INTEGER_SUFFIX, FLOAT_SUFFIX], &["e"]); recognize(tuple(( opt(char('-')), @@ -449,8 +462,7 @@ fn num_lit(i: &str) -> ParseResult<'_> { recognize(tuple(( separated_digits(10, true), opt(alt(( - integer_suffix, - float_suffix, + either_suffix, recognize(tuple(( opt(tuple((char('.'), separated_digits(10, true)))), one_of("eE"), diff --git a/testing/tests/ui/num-suffix.rs b/testing/tests/ui/num-suffix.rs new file mode 100644 index 00000000..0a218061 --- /dev/null +++ b/testing/tests/ui/num-suffix.rs @@ -0,0 +1,26 @@ +use rinja::Template; + +#[allow(non_camel_case_types)] +#[derive(Template)] +#[template( + ext = "html", + source = "{{ 0x0x }}", +)] +struct IntSuffix; + +#[derive(Template)] +#[template( + ext = "html", + source = "{{ 0.0_f127 }}", +)] +struct FloatSuffix; + +#[derive(Template)] +#[template( + ext = "html", + source = "{{ 654u321 }}", +)] +struct EitherSuffix; + +fn main() { +} diff --git a/testing/tests/ui/num-suffix.stderr b/testing/tests/ui/num-suffix.stderr new file mode 100644 index 00000000..4ee8d382 --- /dev/null +++ b/testing/tests/ui/num-suffix.stderr @@ -0,0 +1,29 @@ +error: unknown integer suffix `x` + failed to parse template source at row 1, column 3 near: + "0x0x }}" + --> tests/ui/num-suffix.rs:4:10 + | +4 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unknown float suffix `f127` + failed to parse template source at row 1, column 3 near: + "0.0_f127 }}" + --> tests/ui/num-suffix.rs:11:10 + | +11 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unknown number suffix `u321` + failed to parse template source at row 1, column 3 near: + "654u321 }}" + --> tests/ui/num-suffix.rs:18:10 + | +18 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)