Generate fn args with macro

Is it possible to generate args in fn with macro like
fn a (macro!(a), macro!(b, c))) {..... }

It seems not, but I prefer ask other rustaceans before.

[side question: what is a 'pattern', like the pat type in macro ??; and what kind of ast item would be a single fn argument?]

Macro's can expand to expressions, so yes this is possible.

OK first off, those aren't types (you can't write eg let a: pat = ...;), instead they're specifiers of what kind of source code snippets to accept.

With that in mind, a pattern is pretty much anything that can appear to the left of the => in a match expression, and generally they look either like literals or like creating a new value of a struct/enum, except that the arguments to the "constructor" are either patterns themselves, or they are literals or bindings.

Patterns can also appear in other locations, eg in if let and while let. They can also appear in the position of fn arguments as well as in let itself, but only if the patterns are irrefutable i.e. only if the compiler can prove that that pattern match is always valid.

1 Like

Thanks for the explanation :slight_smile:

so "Macro's can expand to expressions, so yes this is possible", but maybe I wasnt clear.
Expressions should work for calling a function, but I was meaning defining a function ?

I seem unable to expand the type like $ident:$type function argument signature...

You're welcome :slight_smile:

I don't think that it's possible to generate only an arg: T snippet at present, no. Even proc macros would have trouble with that.

However, a macro can also expand to an item, so a macro could expand to a complete fn definition.

What is it you're trying to accomplish? There may be a better way to accomplish it.

1 Like

The result of a macro must always be either a valid expression or a valid item. To this point, it's impossible to expand to $ident:$type.

The most common workaround is to have the macro surround the entire item - in this case, the function definition, and then to have the macro consume & process each part individually, before spitting out the entire result. This would enable something like

macro! {
    fn a (@(a), @(b, c)) { ... }

(@ is used purely as a placeholder here - it'll be consumed by macro! and could be any token)

The biggest part of this strategy would be a tt muncher. If you want to do this with macro_rules macros, I highly recommend reading that chapter, as well as the rest of The Little Book of Rust Macros.

ok, thank you guys !

Here is what I wanna do

The idea is to have a DSL with templates and default args.
generate! {Name(a:f32=0.0, b:T, c:i64=1) }

That would extend into a struct with a default ctor like

struct Name<T> {
  a:f32, b:T, c:i64
impl<T> Name {pub fn new(b:T) -> Self { Self{ b, a:0.0, c:1} }}

all the point is that the args in the 'new fn' would be required only if there is no =value default. That is where I am stuck.

Here is where I am

I can generate from

macro! {
        a : f32 = 43.0 , b : f32,
        c : f32 = 42.0 , d : f32,
        { println!("{} {}", a, c)}
fn io() {
    let a: f32 = 43.0;
    let c: f32 = 42.0;


which is not exactly what I want, but close. I would just put the let inside the function arg signature (& only for the 'no default' vals) but I have trouble calling macro to define args inside function signature.
I will check with a level of abstraction more :wink:

TBH for this kind of intricate machinery, personally I'd reach for a procedural macro rather than a macro_rules one. The reason is that while a proc_macro is more work, ultimately it will be easier for you to get this done. And that is assuming that a macro_rules macro even can get this done, which I'm not sure is true.

Yes for sure, I'm kinda new, but I guess I have to dig inside this :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.