-
-
Notifications
You must be signed in to change notification settings - Fork 313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add more complex functionlike!(...) procedural macro example(s) #492
Comments
Thanks, this is useful feedback. Regarding Block::parse_within, yes the documentation for that method says that it parses "the body of a block as zero or more statements, possibly including one trailing expression." In your case
You would parse the input into a TokenStream the same as you would parse it into any other syntax tree node: let tts: TokenStream = content.parse()?; Examples of this are
The API requires you to parse every token in the input, but you can effectively ignore some part of the input by parsing it to TokenStream and dropping the TokenStream. let name: Ident = input.parse()?;
let content;
braced!(content in input);
let _: TokenStream = content.parse()?; // ignore content
// keep going
let name2: Ident = input.parse()?;
I think you mostly got this. But when you wrote this line: let _ = content.parse()?; there is no way to infer what type this is supposed to parse. Is it parsing an expression? Is it parsing an attribute? Is it parsing an enum...? It is ambiguous, which is why we refused to compile it. |
Thanks! This makes things much more clear. The key points that helped me here:
When implementing your suggestion I first ran into an error that One final questions:
|
If the caller may want to trigger errors pointing to the brace, they need to be able to access the span of the brace token. return Err(Error::new(m.brace_token.span, "this error points to the brace token")); error: this error points to the brace token
--> src/main.rs:10:14
|
10 | SkipThis { AndAlsoThis => That }
| ^^^^^^^^^^^^^^^^^^^^^^^ Also we need the brace token for transforming the syntax tree back to a tokenstream when interpolated within a Lines 2101 to 2112 in 3db288c
|
Ah, got it. Thanks 👍 I'll close this issue, but maybe it's worth considering adding some of the pointers you gave somewhere in the documentation, as it instantly helped me move from struggling to find the correct solution to grasping the (simple parts of the) API and how it works. |
Will do! |
I don't really know if there's a better place to ask ad-hoc questions (somewhere on Discord perhaps?), so I'll just ask it here, and perhaps it can feed into some extended documentation: I have a I've gotten to: token::Brace::default().surround(&mut stream, |stream| {
stream;
}); which I believe wraps the braces around the TokenStream, but I still need to prepend it with I've looked at something like: let wrapped = quote!("mod");
wrapped.extend(stream); But that doesn't work as expected. Any hints/pointers would be appreciated. Don't feel obliged to answer though, if you get around to it great, if not, I'll continue to search around in the API docs to figure it out. |
Quote is the easiest way. https://github.com/dtolnay/quote let wrapped = quote! {
mod my_mod {
#stream
}
}; |
Ah of course, I can actually put a |
Another "learn as you go" question that might also help others: I have a Basically, I'm trying to do this: let tokens: TokenStream = quote!{ HelloWorld };
// something to go from TokenStream to ParseStream
let output = MyObject::parse(&stream).unwrap();
assert_eq!(output, MyObject { ... }) I tried the following, but quickly realised I was fighting with internals, and eventually ended up at a private API: // duplicating implementation from https://docs.rs/syn/0.15/src/syn/parse.rs.html#1075-1080
let buf = syn::buffer::TokenBuffer::new2(tokens);
let scope = Span::call_site();
let cursor = buf.begin();
let unexpected = Rc::new(Cell::new(None));
// ending up with a private API
let stream = syn::parse::ParseBuffer {
scope: scope,
cell: Cell::new(unsafe { mem::transmute::<Cursor, Cursor<'static>>(cursor) }),
marker: PhantomData,
unexpected: unexpected,
};
// field `scope` of struct `syn::parse::ParseBuffer` is private
// ... Either I'm missing an obvious API that helps me achieve this, or this isn't possible (yet), I suspect it's the former. |
I believe the let tokens = quote! { HelloWorld };
let output: MyObject = syn::parse2(tokens).unwrap(); Otherwise, effectively the function that you linked to: let tokens = quote! { HelloWorld };
let output = MyObject::parse.parse2(tokens).unwrap(); |
I'm learning how to use
syn
, and after starting with some simple examples, I'm now running into issues that relate to blocks, specifically, how to:TokenStream
of a block for laterI've got this simple example here:
https://gist.github.com/JeanMertz/ac3b5a1fcc351c8497aa6b3b68d94c87
The error reported there is I believe because
Block::parse_within
is the wrong thing to do, as it actually expects valid statements, while I'm using custom syntax.But there are also other examples such as
is_empty()
that show how to loop over the contents of a block:But if I do that with the above example, I get:
I haven't been able to find any good resources on how to handle structures like in my example. The
lazy-static
example is straight-forward, as it parses tokens in sequence from start to finish, and all returned tokens implementParse
, whereas (apparently) in my example that's not the case, but I'm unable to figure out how to detect that that's not the case, and/or how to deal with such situations (ie. being able to advance the cursor in such a case).The text was updated successfully, but these errors were encountered: