Normally, in Rust, I do "something \" wrong". But if I used that in a proc macro, it was expanded to "something \\\" wrong".
How should I make it work?
--- Update:
I am using proc macro with lib d-plaindoux/celma. Sample code:
parsec_rules!(
let bash_plain:{StringPart} = s=^("${" | "\"")* -> {mk_plain_part(s)}
)
It did not match anything. So I used https://github.com/dtolnay/cargo-expand to see the actual code (to be compiled), in the result of cargo expand, the escaped double quote was in form of | "\\\""). (other part of the code was omit).
Have you tried to produce a string literal with content something " wrong, literally? I guess the cooked string literals(standard notation to refer non-raw string literal) are internally stored as escaped form.
If I understand you correctly, I do not think so. I used cargo expand to get the source that would be compiled by rustc, in that source, it showed \\\". And interestingly, since the macro processor takes \ and " separately, I tried "something " wrong", it did not work at all.
But on the other hand, '\"' is handled as expected.
So the issue does not come from proc-macros in general, but from a particular proc-macro-based library. Looking at their code, the following can be found:
So, as you can see, if their macro encounters an escape char (which they have special-cased), they ... simply treat it as a non-escape char (in other words, given what it currently does, they could have skipped that branch ).
I think you should submit an issue (or a PR fixing it, if you can do that) to their repo mentioning this bug. For instance, it could be that a simple:
} else if c.unwrap() == '\\' {
let (c, nsp) = nsp.next();
- rs.push('\\');
rs.push(c.unwrap());
would do the trick (for the \" case only, though).
Ideally, I even think they should rather be doing:
} else if c.unwrap() == '\\' {
let (c, nsp) = nsp.next();
rs.push(match c {
Some('\\') => '\\',
Some('"') => '"',
Some('n') => '\n',
Some('t') => '\t',
// etc. (see https://doc.rust-lang.org/reference/tokens.html#ascii-escapes)
_ => return Reject(s, false),
});
So, given this suggested change, a good thing for you to try, is to:
Should it be successful, you can immediately use that fork to submit a PR to the repo;
Should it be not, "fallback" to submitting an issue, in which you should mention this thread and what you tested with your fork.