Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

mashing up idents with strings #11

Closed
softprops opened this issue Oct 1, 2018 · 6 comments · Fixed by #12
Closed

mashing up idents with strings #11

softprops opened this issue Oct 1, 2018 · 6 comments · Fixed by #12

Comments

@softprops
Copy link
Contributor

Thanks for publishing this for those awaiting concat_indents on stable. I have a usecase where I'd like to be able to materialize an indent from a crate name and idents. I'm not sure if that's outside the scope of this crate but I wanted to reach out in case this was already possible I just wasn't seeing it.

It's a problem not just a problem that's specific to me but also with rust cpython crates in general

https://dgrunwald.github.io/rust-cpython/doc/cpython/macro.py_module_initializer.html

specifically I'd like to be able to express something like this.

       mashup! {
            m["modulename"] = lib env!("CARGO_PKG_NAME");
            m["py2_init"] =  initlib env!("CARGO_PKG_NAME");
            m["py3_init"] =  PyInit_lib env!("CARGO_PKG_NAME");
        }

I feel like this should be solvable but maybe just not with the rust of today.

@softprops softprops changed the title mashing up indents with strings mashing up idents with strings Oct 1, 2018
@dtolnay
Copy link
Owner

dtolnay commented Oct 1, 2018

I would accept a PR to add support for env!. Mashup will need to translate those invocations into std::env::var.

@softprops
Copy link
Contributor Author

awesome! knowing that this is possible makes me a very happy camper. I'll see what I can do. thanks @dtolnay

@softprops
Copy link
Contributor Author

When running the tests as is locally I ran into the following error. Should this crate work on stable rust?

   Compiling mashup v0.1.7 (file:///Users/dougtangren/code/rust/mashup)
error[E0658]: raw identifiers are experimental and subject to change (see issue #48589)
 --> tests/conditional/test_raw_identifiers.rs:4:20
  |
4 |         m["x"] = F r#move;
  |                    ^^^^^^

error[E0658]: raw identifiers are experimental and subject to change (see issue #48589)
 --> tests/conditional/test_raw_identifiers.rs:3:5
  |
3 | /     mashup! {
4 | |         m["x"] = F r#move;
5 | |     }
  | |_____^
  |
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error: aborting due to 2 previous errors

@softprops
Copy link
Contributor Author

found a work around in your travis.yml file

@softprops
Copy link
Contributor Author

@dtolnay I got something working, but I wanted to give you an early heads up that I found an unrelated bug along the way. I learned a lot in this fun little exercise. You're macro for macro powers are quite impressive! The bug I ran into has has to do with literal strings and chars.

I found that even after resolving an env var, the way the Concat mashes up all collected TokenTree types by just calling to_string on them generated invalid identifiers for the collected literal strings and chars. Since quotes are part of the TokenTree::Literal to_string result, the resulting mashup identifiers looked something like this "foo\"bar\"" :)

I haven't found a great way to work around that other than to call trim_matches in Concat#mashup to strip them out. Let me know if you have other ideas.

 impl Concat {
     fn mashup(&self) -> String {
-        self.pieces.iter().map(ToString::to_string).collect()
+        self.pieces
+            .iter()
+            .map(|tt| match tt {
+                TokenTree::Literal(_) => tt.to_string().trim_matches('"').trim_matches('\'').into(),
+                _ => tt.to_string(),
+            }).collect()

without any another additional changes I was able to make a failing test and then make it pass with this change.

+#[test]
+fn test_lit_str() {
+    mashup! {
+        m["x"] = Foo "Bar";
+    }
+
+    m! {
+        struct "x";
+    }
+
+    let _ = FooBar;
+}

Something of note for the m["x"] = env!("TEST"); case is that I it will change the expectation of the test harness in that it will need to provide an env var I can test with. I've tried to ::std::env::set_var("FOO", "Bar") inside my test but since the macro gets expanded before the runtime :) it isn't set when the macro is expanding.

I should be able to have something pull worthy by tomorrow. I have a working test

+#[test]
+fn test_env_present() {
+    ::std::env::set_var("FOO", "bar"); // <- this doesn't do anything for our test :)
+    mashup! {
+        m["x"] = Lib env!("FOO");
+    }
+
+    m! {
+        struct "x";
+    }
+
+    let _ = Libbar;
+}
+

I just need to clean up the tokentree matching code. It works, but it could use some teeth cleaning :)

@softprops
Copy link
Contributor Author

scratch the note on changing test env expectations. I'll just use a var provided by cargo

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants