Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to pass named arguments to macro calls #910

Merged
merged 3 commits into from
Nov 28, 2023

Conversation

GuillaumeGomez
Copy link
Contributor

Fixes #885.

Based on #909 (so only the last 3 commits are relevant to this PR).

I made a very permissive implementation which allows to mix named and non-named arguments. The only thing we need to check outside of the parser is that the named arguments actually have an equivalent in the called macro. For the rest, everything is checked in the parser directly, which allows nicer error messages.

@GuillaumeGomez GuillaumeGomez force-pushed the macro-named-args branch 3 times, most recently from d9aab11 to aa0f1e6 Compare November 20, 2023 09:46
@GuillaumeGomez
Copy link
Contributor Author

Rebased.

{
// First we check that all named arguments actually exist in the called item.
for arg in args.iter() {
if let Expr::NamedArgument(arg_name, _) = arg {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do let .. else for the outer branch here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really see how it would improve the code since there is no else clause here?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reduces rightward drift for the further check, so I would still like to do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now there is a good reason for it (the break which was added only recently) so adding it!

askama_derive/src/generator.rs Outdated Show resolved Hide resolved
askama_parser/src/expr.rs Show resolved Hide resolved
book/src/template_syntax.md Outdated Show resolved Hide resolved
@GuillaumeGomez GuillaumeGomez force-pushed the macro-named-args branch 2 times, most recently from c4334fb to 3ac9aa0 Compare November 20, 2023 12:55
@GuillaumeGomez
Copy link
Contributor Author

Is there anything else to be done here?

askama_parser/src/expr.rs Outdated Show resolved Hide resolved
askama_parser/src/expr.rs Outdated Show resolved Hide resolved
askama_parser/src/expr.rs Outdated Show resolved Hide resolved
askama_derive/src/generator.rs Outdated Show resolved Hide resolved
askama_derive/src/generator.rs Outdated Show resolved Hide resolved
@GuillaumeGomez
Copy link
Contributor Author

Updated! I applied your suggestions and also enforced that named arguments should always be the last arguments. As mentioned above, it allowed to remove a loop since we can check if we have named arguments by checking if the last argument is a named one.

askama_derive/src/generator.rs Outdated Show resolved Hide resolved
askama_parser/src/expr.rs Outdated Show resolved Hide resolved
@GuillaumeGomez
Copy link
Contributor Author

Squashed commits so named arguments coming last are now part of the first commit.

askama_derive/src/generator.rs Outdated Show resolved Hide resolved
askama_derive/src/generator.rs Outdated Show resolved Hide resolved
askama_parser/src/expr.rs Outdated Show resolved Hide resolved
@GuillaumeGomez GuillaumeGomez force-pushed the macro-named-args branch 3 times, most recently from 8dbb722 to 3ef34e5 Compare November 24, 2023 11:17
@GuillaumeGomez
Copy link
Contributor Author

The idea of using a HashMap was really good. I simplified the code quite a lot: I loop through the template arguments, for each of them, I check if there is a named argument with this name in the HashMap and if so use the associated Expr.

With this, we avoid allocating other Vecs and remove a few loops.

I updated the code comments as well.

{% macro heading(arg1, arg2, arg3, arg4) %}
{% endmacro %}

{% call heading("something", "b", arg4="ah", arg2="title") %}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, sorry, these aren't quite the semantics I was going for. The positional arguments should always retain their position, so it should not be allowed to specify arg2 by name here since the call also passes two positional arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That however seems a bit too much of a restriction imo. We can't mix named and unnamed arguments, so I would at least want to be able to specify some arguments by name (because it's not obvious what they are just from the value) whether or not it is one of the first arguments without having to specify all arguments as named ones. If that makes sense to you?

Copy link
Owner

@djc djc Nov 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No -- I feel quite strongly that arguments passed as positional should go into the expected positional argument slot, and should not be able to be displaced by later named arguments (IIRC there's precedence for this in how Python does it?).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree but it's your project so I'll update as such.

@GuillaumeGomez GuillaumeGomez force-pushed the macro-named-args branch 2 times, most recently from 941a6db to 28f3c4d Compare November 24, 2023 13:15
@GuillaumeGomez
Copy link
Contributor Author

Updated to follow what you asked, added a test to check the compilation error and updated documentation.

// * If there is one, we add it and move to the next argument.
// * If there isn't one, then we pick the next argument (we can do it without checking
// anything since named arguments are always last).
let mut args_iterator = args
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The args_iterator approach is unnecessarily complex. We can just have an allow_positional that is initialized to true which is changed to false on the first occurrence of a named argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll make less good error messages but as you prefer.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How less good? Do you have an example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before I could say it's bad to use named argument "x" here. Now I simply provide the argument name of the template macro. I could maybe provide the index too.

But I have to admit, before it was a bit strange too:

is taking the position of an unnamed argument

Not very clear.

@GuillaumeGomez
Copy link
Contributor Author

Updated!

Copy link
Owner

@djc djc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks for sticking with this, I think this is in a pretty good shape now!

@djc djc merged commit 21f840a into djc:main Nov 28, 2023
20 checks passed
@GuillaumeGomez GuillaumeGomez deleted the macro-named-args branch November 28, 2023 10:36
@GuillaumeGomez
Copy link
Contributor Author

Thanks for all the review rounds! I'll continue my docs.rs migration and come back here if anything else is missing. :)

@djc
Copy link
Owner

djc commented Nov 28, 2023

Sounds great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow to have named arguments in macro
2 participants