[−][src]Macro genco::quote
quote!() { /* proc-macro */ }
Language neutral, whitespace sensitive quasi-quoting for GenCo.
Simple Interpolation
Elements are interpolated using #
, so to include the variable test
,
you could write #test
. Returned elements must implement FormatTokens.
#
can be escaped by repeating it twice in case it's needed in the target
language. So ##
would produce a single #
.
use genco::prelude::*; let field_ty = rust::imported("std::collections", "HashMap").with_arguments((rust::U32, rust::U32)); let tokens: rust::Tokens = quote! { struct Quoted { field: #field_ty, } }; assert_eq!( vec![ "use std::collections::HashMap;", "", "struct Quoted {", " field: HashMap<u32, u32>,", "}", ], tokens.to_file_vec().unwrap(), );
Inline code can be evaluated using #(<stmt>)
.
Note that this is evaluated in the same scope as where the macro is invoked,
so you can make use of keywords like ?
(try) when appropriate.
use genco::prelude::*; let world = "world"; let tokens: genco::Tokens = quote!(hello #(world.to_uppercase())); assert_eq!("hello WORLD", tokens.to_string().unwrap());
Esacping Whitespace
Because this macro is whitespace sensitive, it might sometimes be necessary to provide hints of where they should be inserted.
The macro trims any trailing and leading whitespace that it sees. So
quote!(Hello )
is the same as quote!(Hello)
. To include a spacing at the
end, we can use the special #<space>
escape sequence: quote!(Hello#<space>)
.
The available escape sequences are:
#<space>
for inserting a spacing between tokens. This corresponds to the Tokens::spacing function.#<push>
for inserting a push operation. Push operations makes sure that any following tokens are on their own dedicated line. This corresponds to the Tokens::push function.#<line>
for inserting a line operation. Line operations makes sure that any following tokens have an empty line separating them. This corresponds to the Tokens::line function.
use genco::prelude::*; let numbers = 3..=5; let tokens: Tokens<()> = quote!(foo#<push>bar#<line>baz#<space>biz); assert_eq!("foo\nbar\n\nbaz biz", tokens.to_string().unwrap());
Repetitions
To repeat a pattern you can use #(<bindings> in <expr> => <quoted>)
, where
<quoted>
will be treated as a quoted expression, so anything which works
during regular quoting will work here as well, with the addition that
anything defined in <bindings>
will be made available to the statement.
use genco::prelude::*; let numbers = 3..=5; let tokens: Tokens<()> = quote! { Your numbers are: #(n in numbers => #n#<space>) }; assert_eq!("Your numbers are: 3 4 5 ", tokens.to_string().unwrap());
Note how we had to escape the tail spacing (#<space>
) to have it included, and
we also got a spacing at the end that we probably don't want. To avoid
this we can instead to a joined repetition.
Joining Repetitions
It's a common need to join repetitions of tokens. To do this, you can
add join (<quoted>)
to the end of a repitition specification.
One difference with the <quoted>
section with the regular [quote!] macro
is that it is whitespace sensitive at the tail of the expression.
So (,)
would be different from (, )
, which would have a spacing at the
end.
With that in mind, let's redo the numbers example above.
use genco::prelude::*; let numbers = 3..=5; let tokens: Tokens<()> = quote! { Your numbers are: #(n in numbers join (, ) => #n). }; assert_eq!("Your numbers are: 3, 4, 5.", tokens.to_string().unwrap());
Scopes
You can use #(<binding> => <stmt>)
to gain mutable access to the current
token stream. This is a great alternative if you want to do more complex
logic during evaluation.
Note that this can cause borrowing issues if the underlying stream is
already a mutable reference. To work around this you can specify
*<binding>
to cause it to reborrow.
For more information, see [quote_in!].
use genco::prelude::*; fn quote_greeting(surname: &str, lastname: Option<&str>) -> rust::Tokens { quote! { Hello #surname#(toks => { if let Some(lastname) = lastname { toks.space(); toks.append(lastname); } }) } } assert_eq!("Hello John", quote_greeting("John", None).to_string().unwrap()); assert_eq!("Hello John Doe", quote_greeting("John", Some("Doe")).to_string().unwrap());