Add syntax extensions for lowercasing/uppercasing strings (Fixes #16607)#16636
Add syntax extensions for lowercasing/uppercasing strings (Fixes #16607)#16636Manishearth wants to merge 1 commit intorust-lang:masterfrom
Conversation
|
#16607 calls them |
src/libsyntax/ext/source_util.rs
Outdated
There was a problem hiding this comment.
If multiple expressions are provided, this will happily process the first and ignore the rest. It should expressly test how many expressions it got.
There was a problem hiding this comment.
Would a test for iter.next().is_some() be okay style-wise?
The PR currently uses |
src/libsyntax/ext/source_util.rs
Outdated
There was a problem hiding this comment.
This is hard to read, with all the rightward drift. Ideally you could compress this into a single match, but I don't think you can match the Gc in ExprLit. We can at least get rid of one of the match levels, and remove the return from the inside of this big beast:
let s = match es.move_iter().next() {
Some(codemap::Spanned { node: ast::ExprLit(lit), .. }) => match lit.node {
ast::LitStr(ref s, _) => Some(s),
_ => None
},
_ => None
};
match s {
Some(s) => {
let new_s = s.get().chars().map(transform).collect::<String>();
base::MacExpr::new(cx.expr_str(sp, token::intern_and_get_ident(new_s.as_slice())))
}
None => {
cx.span_err(sp, "expected a string literal");
base::DummyResult::expr(sp)
}
}There was a problem hiding this comment.
You should also probably pull the span off of the first expression, instead of using the span for the whole macro.
There was a problem hiding this comment.
Yeah, the Gc was giving problems. I couldn't find any way of destructuring the @ (I was surprised that syntax still exists)
This seems like a better option, thanks :)
There was a problem hiding this comment.
I tried this, there's another Gc on Expr, so I had to use the following (one extra match):
let s = match iter.next() {
Some(expr) => {
match *expr {
ast::Expr { node: ast::ExprLit(lit), span: sp2 , ..} => {
sp = sp2;
match lit.node {
ast::LitStr(ref s, _) => Some(s),
_ => None
}
},
_ => None
}
},
_ => None
};
node doesn't live long enough so I'll have to use s.clone() if I don't want to nest the matches further. Should I? Seems a bit unnecessary.
There was a problem hiding this comment.
It occurs to me the ref s isn't going to work, since it's a reference to a moved value. We can skip the move, though, and we can also produce a better error for providing the wrong argument type vs not providing the right number of arguments. Something like:
let mut it = es.iter();
let res = match it.next() {
Some(&codemap::Spanned { node: ast::ExprLit(ref lit), .. }) => match lit.node {
ast::LitStr(ref s, span) => Some((s, span)),
_ => {
cx.span_err(span, "expected a string literal");
None
}
},
_ => {
cx.span_err(sp, "expected 1 argument, found 0");
None
}
};
match (res,it.count()) {
(Some((s,span)),0) => {
let new_s = s.get().chars().map(transform).collect::<String>();
base::MacExpr::new(cx.expr_str(sp, token::intern_and_get_ident(new_s.as_slice())))
}
(_, rest) => {
if rest > 0 {
cx.span_err(sp, format!("expected 1 argument, found {}", rest+1).as_slice());
}
base::DummyResult::expr(sp)
}
}There was a problem hiding this comment.
Why is there a codemap::Spanned there? Shouldn't it be an ast::Ext?
There was a problem hiding this comment.
Because I was assuming that Expr was a Spanned<Expr_>. It actually isn't, which is surprising, and is apparently due to the need for a separate id field. Anyway, I'm guessing the following should work:
fn expand_cased(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree], transform: |char| -> char)
-> Box<base::MacResult> {
let es = match base::get_exprs_from_tts(cx, sp, tts) {
Some(e) => e,
None => return base::DummyResult::expr(sp)
};
let mut it = es.iter();
let res = match it.next() {
// FIXME (#13910): nested matches are necessary to get through Gc<>
Some(expr) => match expr.node {
ast::ExprLit(ref lit) => match lit.node {
ast::LitStr(ref s, span) => Some((s, span)),
_ => {
cx.span_err(span, "expected a string literal");
None
}
}
_ => {
cx.span_err(expr.span, "expected a string literal");
None
}
},
None => {
cx.span_err(sp, "expected 1 argument, found 0");
None
}
};
match (res,it.count()) {
(Some((s,span)),0) => {
let new_s = s.get().chars().map(transform).collect::<String>();
base::MacExpr::new(cx.expr_str(span, token::intern_and_get_ident(new_s.as_slice())))
}
(_, rest) => {
if rest > 0 {
cx.span_err(sp, format!("expected 1 argument, found {}", rest+1).as_slice());
}
base::DummyResult::expr(sp)
}
}
}There was a problem hiding this comment.
Ok, thanks. Should the sp in the final MacExpr be sp or span? It might end up with the wrong span on expansion -- I'm not entirely clear on how ExtCtxt works to be sure of this, and I'd rather not wait for two full builds to see ;)
There was a problem hiding this comment.
Good catch, I meant to make that span. I'll edit my comment.
There was a problem hiding this comment.
There were more issues with span being taken from the wrong place (should
be lit.span, not the second value of ExprLit), but I fixed that.
Thanks for the help!
-Manish Goregaokar
On Thu, Aug 21, 2014 at 4:59 AM, Kevin Ballard notifications@github.com
wrote:
In src/libsyntax/ext/source_util.rs:
- };
- match es.move_iter().next() {
Some(expr) => {match expr.node {ast::ExprLit(lit) => match lit.node {ast::LitStr(ref s, _) => {return base::MacExpr::new(cx.expr_str(sp,token::intern_and_get_ident(s.get().chars().map(transform).collect::<String>().as_slice())))},_ => ()},_ => ()}},_ => ()- }
Good catch, I meant to make that span. I'll edit my comment.
—
Reply to this email directly or view it on GitHub
https://github.com/rust-lang/rust/pull/16636/files#r16512839.
|
@SimonSapin Ok, fair enough. |
|
From chatting on IRC with @Manishearth: either kind of lower casing works for Servo’s use case since they behave the same when the input is within ASCII, which we know because it’s compile time (no arbitrary input from web content). |
|
@SimonSapin I can add to_ascii_* variants if we want, since all I have to do is add variants of the With some changes (accept a closure that transforms on the whole string isntead of individual chars) I can add titlecasing (and snakecasing) support as well, if these would be useful. |
|
@Manishearth I don't think there's a need for the |
|
Updated with the style changes. I'll look into adding |
|
This is an addition to the prelude for all rust programs in existence, and should be considered with the gravity as such. Currently we require any modifications of the prelude (additions or removals) such as this to go through the RFC process. This is also why we have created a plugin infrastructure for developing extensions such as this out of tree. |
|
Alright, I'll draft up an RFC when I get time. -Manish Goregaokar On Thu, Aug 21, 2014 at 9:51 PM, Alex Crichton notifications@github.com
|
|
Alternatively, Servo could define these syntax extensions itself in its |
|
That would work. I'll have a go. -Manish Goregaokar On Thu, Aug 21, 2014 at 9:57 PM, Simon Sapin notifications@github.com
|
|
It sounds like this may be able to live outside the compiler in servo, so I'm going to close this for now. Feel free to reopen if any surprises arise! |
The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to @Manishearth
The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to @Manishearth
The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to @Manishearth
The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to @Manishearth
The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to @Manishearth
…28 (from Swatinem:lowercasegetters); r=Manishearth The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to @Manishearth Source-Repo: https://github.com/servo/servo Source-Revision: 902c16497c40684930819693a7e90f0862eb7f56
|
What's the current status on getting lowercase / uppercase / kebab-case / title-case / etc. variants of strings in macros? I have a lot of use cases for this in various libraries where I often need to create an enum, and then derive both |
|
You could write a custom proc macro for this and use it.
(One may exist already)
…On Wed, Dec 12, 2018, 6:13 PM Michael Murphy ***@***.*** wrote:
What's the current status on getting lowercase / uppercase / kebab-case /
title-case / etc. variants of strings in macros? I have a lot of use cases
for this in various libraries where I often need to create an enum, and
then derive both impl From<Enum> for &'static str and impl FromStr for
Enum; or when interacting with a JSON API that uses kebab case.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#16636 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABivSE8WAx6VNNzxoe6bSj46B9UClqx8ks5u4beugaJpZM4CZb4_>
.
|
…28 (from Swatinem:lowercasegetters); r=Manishearth The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to Manishearth Source-Repo: https://github.com/servo/servo Source-Revision: 902c16497c40684930819693a7e90f0862eb7f56 UltraBlame original commit: 1b9c7a69c746676dcf68b519877913b5b2186a56
…28 (from Swatinem:lowercasegetters); r=Manishearth The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to Manishearth Source-Repo: https://github.com/servo/servo Source-Revision: 902c16497c40684930819693a7e90f0862eb7f56 UltraBlame original commit: 1b9c7a69c746676dcf68b519877913b5b2186a56
…28 (from Swatinem:lowercasegetters); r=Manishearth The implementation was copied directly from rust-lang/rust#16636 and updated for rust changes, so the credit goes to Manishearth Source-Repo: https://github.com/servo/servo Source-Revision: 902c16497c40684930819693a7e90f0862eb7f56 UltraBlame original commit: 1b9c7a69c746676dcf68b519877913b5b2186a56
…dy::stmt_at` (rust-lang#16636) changelog: none
``` $ git log --oneline 85eff7c80277b57f78b11e28d14154ab12fcf643..292f395c297d4f99171325b0842ac4ea4ff3b386 292f395c2 (HEAD) [stable 1.94] Fix symlink_and_directory when running in a long target dir name (rust-lang#16777) d00475981 Fix symlink_and_directory when running in a long target dir name (rust-lang#16775) ce98781f7 [stable 1.94] Update tar to 0.4.45 (rust-lang#16769) fec7f9297 Update tar to 0.4.45 5e256e377 Add a test for a tar file with a symlink and directory of the same name 1ed92053d test: Remove unused docker ip_address (rust-lang#16636) d7a2a0307 Increase cache_lock test timeout (rust-lang#16545) 95d93fb89 Don't check the specific build-std output dfbe729f6 chore: Updated compiler errors for Rust 1.93 (rust-lang#16543) cb03b21f6 Update cargo-semver-checks to 0.47.0 f7777c4f9 test(build-std): Update error message (rust-lang#16658) a56abe18a Disable custom target JSON spec test 634668d49 fix: `--remap-path-scope` stabilized in 1.95-nightly (rust-lang#16536) d428eaa44 fix(script): surpress `unused_features` lint for embedded (rust-lang#16714) e7b27c7f9 test(git): Mark a test as non-deterministic (rust-lang#16706) 38922ca44 test(replace): Mark a test as non-deterministic (rust-lang#16700) ```
Testcase: