I spent a lot of time thinking about what the syntax should be. IMO, it should:
Compatible with existing syntax and design language (i.e. use # to indicate interpolation)
Allow users to easily tell if a block is quoted vs interpolated
Allow users to easily tell where the start and end of that block is
Be intuitive and does not invent a very different syntax
Does not introduce ambiguity or tricky edge cases
I started with #{ ... }, went though many iterations and in the end settled on #@{ ... }@:
It uses # to indicate start interpolating, which is consistent with other interpolation pattern
@ and {} are commonly used for interpolation
It doesn't have edge cases like chaining the end of a block into the start of another
Proposed Behavior
There are 2 ways where this could be implemented, with different behaviors:
A separated pass to extract all interpolation block, and execute them before the second pass to process idents and repetitions
Still keep the single pass design, and execute the block where it's at and add the output to the running TokenStream
I chose 2 since the implementation is way simpler, and probably more intuitive when composed with #( ... )*. This implementation also allows the blocks to access the bindings generated by #( ... )*, which becomes useful if we make RepInterp implement Deref. Just a dummy example:
let a = quote! { a };
let b = quote! { b };
let ids2 = vec![ vec![&a, &b], vec![&b, &a] ];
let tokens = quote! {
#(
invoke(#(#ids2),*);
#@{
let mut t = TokenStream::new();
t.extend(ids2[0].clone());
t.extend(quote! { + });
t.extend(ids2[1].clone());
t
}@
)*
};
// output: invoke (a, b) ; a + b invoke (b, a) ; b + a
Also, for ergonomic reasons, it's ideal for the macro to handle both when the block outputs a ToTokens or an iterator of them. This is implemented with a same trick used for repetition where a to_tokens method shadows the trait method if the trait is not implemented
This is my design/attempt at implementing #275
Proposed Syntax
I spent a lot of time thinking about what the syntax should be. IMO, it should:
#
to indicate interpolation)I started with
#{ ... }
, went though many iterations and in the end settled on#@{ ... }@
:#
to indicate start interpolating, which is consistent with other interpolation pattern@
and{}
are commonly used for interpolationProposed Behavior
There are 2 ways where this could be implemented, with different behaviors:
TokenStream
I chose 2 since the implementation is way simpler, and probably more intuitive when composed with
#( ... )*
. This implementation also allows the blocks to access the bindings generated by#( ... )*
, which becomes useful if we makeRepInterp
implementDeref
. Just a dummy example:Also, for ergonomic reasons, it's ideal for the macro to handle both when the block outputs a
ToTokens
or an iterator of them. This is implemented with a same trick used for repetition where ato_tokens
method shadows the trait method if the trait is not implementedOther
Deref
forRepInterp
?Please let me know if there are other concerns
Tasks