Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upproc_macro: implement `TokenTree`, `TokenKind`, hygienic `quote!`, and other API #40939
Conversation
rust-highfive
assigned
nrc
Mar 31, 2017
jseyfried
force-pushed the
jseyfried:proc_macro_api
branch
2 times, most recently
from
30f3956
to
40f81aa
Mar 31, 2017
This was referenced Mar 31, 2017
This comment has been minimized.
This comment has been minimized.
jseyfried
referenced this pull request
Mar 31, 2017
Merged
Initial implementation of declarative macros 2.0 #40847
This comment has been minimized.
This comment has been minimized.
|
Can't we call |
This comment has been minimized.
This comment has been minimized.
|
Nice! I like the overall approach, some comments on the details:
Would impls for
To me the word "symbol" evokes punctuation, excluding letters. Could this be called something else?
So the
I’d also add:
In #[unstable(feature = "proc_macro", issue = "38356")]
#[macro_export]
macro_rules! quote { () => {} }In macro_rules! quote {
() => { TokenStream::empty() };
($($t:tt)*) => { [ $( quote_tree!($t), )* ].iter().cloned().collect::<TokenStream>() };
}Why are there two |
This comment has been minimized.
This comment has been minimized.
|
I think this PR addresses all of my previous comments in #38356 (comment) |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
Do you mean w.r.t. the internals? I believe we can still use the internal flattened representation you proposed with this API (imo, would be nice but not high priority).
Yeah. Currently,
Yeah, it's
Yeah, I agree that we should have
The non-empty one is incomplete (by design) and only used to bootstrap the internal implementation of |
jseyfried
force-pushed the
jseyfried:proc_macro_api
branch
from
9999e58
to
6151672
Apr 3, 2017
This comment has been minimized.
This comment has been minimized.
|
|
nrc
reviewed
Apr 10, 2017
|
There's a bunch of changes requested, but most are just about docs, and I don't think there is anything major. Assuming all the fixes are straightforward, then r=me |
| pub struct TokenStream { | ||
| inner: TokenStream_, | ||
| } | ||
| pub struct TokenStream(tokenstream::TokenStream); |
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
Not this PR (and pretty nitty), but just pointing out that it should either token_stream or Tokenstream, currently the naming is inconsistent.
|
|
||
| /// An iterator over `TokenTree`s. | ||
| #[unstable(feature = "proc_macro", issue = "38356")] | ||
| pub struct TokenIter { |
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
Should we call this a TokenTreeIter? That leaves room for a flattening TokenIter and means the name and target correspond
This comment has been minimized.
This comment has been minimized.
| } | ||
|
|
||
| impl TokenTree { | ||
| fn from_raw(stream: tokenstream::TokenStream, next: &mut Option<tokenstream::TokenStream>) |
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
I don't like from_raw as a name - 'raw' can mean so many different things, and perhaps the most likely here is as in raw string which is wrong. How about from_internal or from_rustc_internal or something like that?
This comment has been minimized.
This comment has been minimized.
| TokenTree { span: Span(span), kind: kind } | ||
| } | ||
|
|
||
| fn to_raw(self) -> tokenstream::TokenStream { |
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
likewise here.
And somewhat connected, is there a way to mark the API which we expect macro authors to use? Is it all the pub API? Or is some of that transitional or only intended for the compiler to use?
This comment has been minimized.
This comment has been minimized.
jseyfried
Apr 10, 2017
Author
Contributor
It's all the pub API not in __internal (which is unusable without #![feature(proc_macro_internals)]).
| @@ -80,7 +524,11 @@ pub struct LexError { | |||
| /// all of the contents. | |||
| #[unstable(feature = "proc_macro_internals", issue = "27812")] | |||
| #[doc(hidden)] | |||
| #[path = ""] | |||
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
jseyfried
Apr 10, 2017
Author
Contributor
mod quote; in __internal; this allows the file to be libproc_macro/quote.rs. Thinking about this some more, I'll move mod quote into the crate root and remove the #[path = ""].
|
|
||
| //! # Quasiquoter | ||
| //! This file contains the implementation internals of the quasiquoter provided by `qquote!`. | ||
|
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| @@ -196,6 +201,10 @@ impl TokenStream { | |||
| } | |||
| } | |||
|
|
|||
| pub fn builder() -> TokenStreamBuilder { | |||
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
I think this would be better as a free function rather than a method on TokenStream
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
jseyfried
Apr 10, 2017
Author
Contributor
I'll change to TokenStreamBuilder::new() (motivation for TokenStream::builder() was to avoid making people use anything else into their scopes).
| @@ -225,13 +234,107 @@ impl TokenStream { | |||
| } | |||
| true | |||
| } | |||
|
|
|||
| pub fn as_tree(self) -> (TokenTree, bool /* joint? */) { | |||
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
Could these public methods get docs please? (In particular here, some more explanation of what joint means would be good).
This comment has been minimized.
This comment has been minimized.
lfairy
Apr 10, 2017
Contributor
Also, since this takes self by value, should this be named into_tree instead? Or are the conventions different for reference counted things
This comment has been minimized.
This comment has been minimized.
| @@ -8,47 +8,37 @@ | |||
| // option. This file may not be copied, modified, or distributed | |||
| // except according to those terms. | |||
|
|
|||
| #![feature(plugin, plugin_registrar, rustc_private)] | |||
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
It looks like anyone with an existing procedural macro is going to have to make some significant changes. Could you write up either here or on internals or somewhere, a guide to the changes needed to make a proc macro work after this PR please?
This comment has been minimized.
This comment has been minimized.
jseyfried
Apr 10, 2017
Author
Contributor
Existing procedural macros will lose the syntax::tokenstream::TokenStream quoter from proc_macro_internals, AFAIK other than that they won't have to make any changes. I could include a syntax::tokenstream::TokenStream quoter for back-compat.
How many people are actually using "existing procedural macros" though? This PR doesn't effect the widely used legacy plugin system; I didn't think many people were using SyntaxExtension::ProcMacro from #36154.
| @@ -455,3 +461,38 @@ pub fn is_op(tok: &Token) -> bool { | |||
| _ => true, | |||
| } | |||
| } | |||
|
|
|||
| #[derive(Clone, Eq, PartialEq, Debug)] | |||
| pub struct LazyTokenStream(RefCell<Option<TokenStream>>); | |||
This comment has been minimized.
This comment has been minimized.
nrc
Apr 10, 2017
Member
Is this meant to be used by macro authors? If so could you document with why and when.
This comment has been minimized.
This comment has been minimized.
jseyfried
Apr 10, 2017
Author
Contributor
No, nothing in libsyntax can be used by proc macro authors.
lfairy
reviewed
Apr 10, 2017
| } | ||
|
|
||
| #[derive(Clone, Eq, PartialEq, Debug)] | ||
| pub struct LazyTokenStream(RefCell<Option<TokenStream>>); |
This comment has been minimized.
This comment has been minimized.
lfairy
Apr 10, 2017
Contributor
As an aside: if the dynamic borrow checks end up too inefficient, then this could be re-implemented on top of MoveCell.
This comment has been minimized.
This comment has been minimized.
lfairy
reviewed
Apr 10, 2017
| let mut opt_stream = self.0.borrow_mut(); | ||
| if opt_stream.is_none() { | ||
| *opt_stream = Some(f()); | ||
| }; |
This comment has been minimized.
This comment has been minimized.
Mark-Simulacrum
added
the
S-waiting-on-author
label
Apr 14, 2017
This comment has been minimized.
This comment has been minimized.
|
Friendly ping that there are merge conflicts and some comments for you @jseyfried! |
lfairy
referenced this pull request
Apr 22, 2017
Closed
Build broken since rustc nightly-2017-03-04 #80
This comment has been minimized.
This comment has been minimized.
|
Should we use a different feature gate for the unstable APIs? I'm under the impression that language feature gates and library feature gates are meant to be distinct from each other, and |
abonander
referenced this pull request
Apr 23, 2017
Merged
Document the `proc_macro` feature in the Unstable Book #41476
This comment has been minimized.
This comment has been minimized.
|
Hmm, is there a strict separation between language/lib feature-gates? I wouldn't think so. |
This comment has been minimized.
This comment has been minimized.
|
It's kind of implied by the structure of the Unstable Book but that might be more of an issue for #41476 where this came up originally. |
jseyfried
referenced this pull request
Apr 24, 2017
Closed
warning: Quasi-quoting might make incremental compilation very inefficient: NtIdent(..) #40946
This comment has been minimized.
This comment has been minimized.
|
status: still waiting for #40847. |
abonander
referenced this pull request
Apr 30, 2017
Open
Improve diagnostics for parse errors in proc macro output #41663
This comment has been minimized.
This comment has been minimized.
|
status: still waiting for #40847. |
1 similar comment
This comment has been minimized.
This comment has been minimized.
|
status: still waiting for #40847. |
dtolnay
referenced this pull request
May 10, 2017
Closed
Misleading "not found in this scope" error #923
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton Awesome, thanks! For the record, the failing test was because tokens from a macros 1.1-style proc-macro (i.e. via Since we no longer have the extra expansion information, @nrc's I had to get rid of the expansion information for backwards compatibility -- if the expansion information showed that the span came from a procedural macro 2.0, then the underlying tokens would resolve hygienically (as per hygiene 2.0). This would be a backwards-incompatible change, and would mean that stringifying, reparsing and returning the input of a proc-macro would change its semantics, even if the input were entirely unexpanded. If we want to fix this, we could instead mark tokens from |
mystor
referenced this pull request
Jul 6, 2017
Closed
Actually test the `proc_macro` integration #3
kennytm
referenced this pull request
Jul 7, 2017
Merged
Only match a fragment specifier if it starts with certain tokens. #42913
This comment has been minimized.
This comment has been minimized.
|
The lack of expansion info broke clippy together with proc macros, since code inside derives will now trigger lints. Is there any new way to detect expanded code? If not, what needs to be done in order to create expansion info that doesn't influence save analysis. |
This comment has been minimized.
This comment has been minimized.
Ah, I wondered why I was seeing so many errors in the RLS :-( I think we must fix this. This feels like another reason not to conflate macro hygiene with expansion history. That might be too hard a way to fix this though.
Not using spans for hygiene seems a much nicer fix here - the span should reflect the expansion history and the hygiene should be altered (to erase hygiene, essentially). I expect we want the correct expansion info for errors as well as save-analysis. |
This comment has been minimized.
This comment has been minimized.
|
I already have a fix in #43179 |
This comment has been minimized.
This comment has been minimized.
|
@nrc That is, I don't think think hygiene bending requires us to split up span/hygiene info or construct an "fake" expansion history just for hygiene. I think it'd be nicer to have a single source of truth for expansion info that is expressive enough for hygiene bending. |
jseyfried commentedMar 31, 2017
•
edited
All new API is gated behind
#![feature(proc_macro)]and may be used with#[proc_macro],#[proc_macro_attribute], and#[proc_macro_derive]procedural macros.More specifically, this PR adds the following in
proc_macro:For details on
quote!hygiene, see this example and declarative macros 2.0.r? @nrc