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

Rust macro has no access to parameters passed into {% macro f(param) %} #966

Closed
jonathanslenders opened this issue Feb 23, 2024 · 6 comments · Fixed by #967
Closed

Rust macro has no access to parameters passed into {% macro f(param) %} #966

jonathanslenders opened this issue Feb 23, 2024 · 6 comments · Fixed by #967

Comments

@jonathanslenders
Copy link

Not sure if this is a question, feature request or a bug.

From the documentation it's not clear to me in what scope rust macros are evaluated.
For instance, I have this Askama macro, which calls a Rust macro internally:

{% macro stop(entity) %}
    {{ create_action!(entity, LightOn, {brightness:Some(0.1), color_temperature: None})|json }}
{% endmacro %}

In some situations this works perfectly, while in other situations this does not and results in a "cannot find value entity in this scope". (entity being the argument passed to the Askama macro.)

It does work for one situation where this macro is called in another template within a loop like this: {% for entity in entities.values() %}. In any case, I've the impression that it doesn't pick up the argument passed to the Askama macro.

Is that understanding correct? Is there something we can improve here to make this possible?

@djc
Copy link
Owner

djc commented Feb 23, 2024

That certainly sounds surprising. Do you have a minimal reproducing example?

@jonathanslenders
Copy link
Author

This is the simplest reproducing example I could get:

macro_rules! test_macro{
    ($entity:expr) => {
        {
            println!("{:?}", &$entity);
        }
    }
}

#[derive(Template)]
#[template(source = "{{ test_macro!(entity) }}", ext = "txt")]
struct TestTemplate<'a> {
    entity: &'a str,
}

which results in:

error[E0425]: cannot find value `entity` in this scope
  --> src/.../main.rs:29:10
   |
29 | #[derive(Template)]

It looks like it works if I call the macro using self.entity, but this is not what I want, because I'd like to reuse the template in a situation where it's nested in a loop.

@GuillaumeGomez
Copy link
Contributor

Oh I see the issue. Since it's a macro, we can't know if entity is from self or just a token (for a name you're generating for example?). I think this code would work in all cases:

let entity = entity;
{{ test_macro!(entity) }}

@jonathanslenders
Copy link
Author

I assume you meant:

{% let entity = entity; %}
{{ test_macro!(entity) }}

which seems to work indeed.

Would it be possible for Askama to automatically bind all struct fields from the template struct to local variables with the same name so that macros will work automatically?

@GuillaumeGomez
Copy link
Contributor

I assume you meant:
...

Yes I did. ^^'

Would it be possible for Askama to automatically bind all struct fields from the template struct to local variables with the same name so that macros will work automatically?

It'd be problematic for different reasons:

  • If you have a big struct, it'll generate a lot of variables that might not be used. Lot of dead code in short, meaning bigger code to compile, meaning longer compile time.
  • It could lead to surprising/unwanted usage of variables. For example you use a variable named x in a template you include. Variable you're supposed to define yourself which you do normally because of the error. But if you type has an x field, then it'll just be a surprising (and likely unwanted) result.

What I suggest is instead to add your use case as an example for macros in the askama book. What do you think?

@jonathanslenders
Copy link
Author

Thanks for the feedback! I understand. Feel free to add it to the book!

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 a pull request may close this issue.

3 participants