Skip to content

Commit

Permalink
Only allow named arguments as last arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Nov 23, 2023
1 parent 1a7f2bd commit 4ce1fd4
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 9 deletions.
7 changes: 5 additions & 2 deletions askama_derive/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,9 +736,12 @@ impl<'a> Generator<'a> {
// are passed in the right order). To ensure we won't accidentally pass a named argument,
// we split named and unnamed arguments in two vectors before starting.
let mut output_args = Vec::new();
// Since named arguments can only be passed last, we only need to check if the last argument
// is a named one.
let args = if args
.iter()
.any(|arg| matches!(arg, Expr::NamedArgument(_, _)))
.last()
.map(|arg| matches!(arg, Expr::NamedArgument(_, _)))
.unwrap_or(false)
{
// We have named arguments, so we need to ensure that they are passed in the right
// order.
Expand Down
14 changes: 12 additions & 2 deletions askama_parser/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,20 @@ impl<'a> Expr<'a> {
start: &'a str,
is_template_macro: bool,
) -> ParseResult<'a, Self> {
alt((
let has_named_arguments = !named_arguments.is_empty();

let (i, expr) = alt((
move |i| Self::named_argument(i, level, named_arguments, start, is_template_macro),
move |i| Self::parse(i, level),
))(i)
))(i)?;
if has_named_arguments && !matches!(expr, Self::NamedArgument(_, _)) {
Err(nom::Err::Failure(ErrorContext {
input: start,
message: Some(Cow::Borrowed("named arguments must always be passed last")),
}))
} else {
Ok((i, expr))
}
}

fn named_argument(
Expand Down
6 changes: 4 additions & 2 deletions book/src/template_syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,17 +609,19 @@ You can use whitespace characters around `=`:
You can mix named and non-named arguments when calling a macro:

```
{% call heading(bold="something", "title") %}
{% call heading("title", bold="something") %}
```

However please note than named arguments must always come **last**.

In this case, the named arguments will be passed to the related parameter and then the other
arguments will be placed in what remains. Let's explain it in code:

```
{% macro heading(arg1, arg2, arg3, arg4) %}
{% endmacro %}
{% call heading("something", arg2="title", arg4="ah", "b") %}
{% call heading("something", "b", arg4="ah", arg2="title") %}
```

First it'll be replaced like this:
Expand Down
2 changes: 0 additions & 2 deletions testing/tests/macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ fn test_macro_self_arg() {
{%- call thrice(param1=2, param2=3) -%}
{%- call thrice(param2=3, param1=2) -%}
{%- call thrice(param2=3, 2) -%}
{%- call thrice(3, param1=2) -%}
",
ext = "html"
Expand All @@ -121,7 +120,6 @@ fn test_named_argument() {
2 3
2 3
2 3
2 3
"
);
}
11 changes: 10 additions & 1 deletion testing/tests/ui/macro_named_argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@ struct InvalidNamedArg2;
{{ param1 }} {{ param2 }}
{%- endmacro -%}
{%- call thrice(param1=2, 3) | filter(param1=12) -%}", ext = "html")]
{%- call thrice(3, param1=2) | filter(param1=12) -%}", ext = "html")]
struct InvalidNamedArg3;

// Ensures that named arguments can only be passed last.
#[derive(Template)]
#[template(source = "{%- macro thrice(param1, param2) -%}
{{ param1 }} {{ param2 }}
{%- endmacro -%}
{%- call thrice(param1=2, 3) -%}", ext = "html")]
struct InvalidNamedArg4;

fn main() {
}
10 changes: 10 additions & 0 deletions testing/tests/ui/macro_named_argument.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,13 @@ error: problems parsing template source at row 5, column 29 near:
| ^^^^^^^^
|
= note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

error: named arguments must always be passed last
problems parsing template source at row 5, column 15 near:
"(param1=2, 3) -%}"
--> tests/ui/macro_named_argument.rs:29:10
|
29 | #[derive(Template)]
| ^^^^^^^^
|
= note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

0 comments on commit 4ce1fd4

Please sign in to comment.