mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-24 06:24:35 +00:00
151 lines
4.2 KiB
Rust
151 lines
4.2 KiB
Rust
//@ force-host
|
|
//@ no-prefer-dynamic
|
|
|
|
#![crate_type = "proc-macro"]
|
|
|
|
extern crate proc_macro;
|
|
|
|
use proc_macro::{TokenStream, TokenTree, Delimiter, Literal, Spacing, Group};
|
|
|
|
#[proc_macro_attribute]
|
|
pub fn foo(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|
assert!(attr.is_empty());
|
|
let input = input.into_iter().collect::<Vec<_>>();
|
|
{
|
|
let mut cursor = &input[..];
|
|
assert_inline(&mut cursor);
|
|
assert_doc(&mut cursor);
|
|
assert_inline(&mut cursor);
|
|
assert_doc(&mut cursor);
|
|
assert_foo(&mut cursor);
|
|
assert!(cursor.is_empty());
|
|
}
|
|
fold_stream(input.into_iter().collect())
|
|
}
|
|
|
|
#[proc_macro_attribute]
|
|
pub fn bar(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|
assert!(attr.is_empty());
|
|
let input = input.into_iter().collect::<Vec<_>>();
|
|
{
|
|
let mut cursor = &input[..];
|
|
assert_inline(&mut cursor);
|
|
assert_doc(&mut cursor);
|
|
assert_invoc(&mut cursor);
|
|
assert_inline(&mut cursor);
|
|
assert_doc(&mut cursor);
|
|
assert_foo(&mut cursor);
|
|
assert!(cursor.is_empty());
|
|
}
|
|
input.into_iter().collect()
|
|
}
|
|
|
|
fn assert_inline(slice: &mut &[TokenTree]) {
|
|
match &slice[0] {
|
|
TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
|
|
_ => panic!("expected '#' char"),
|
|
}
|
|
match &slice[1] {
|
|
TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket),
|
|
_ => panic!("expected brackets"),
|
|
}
|
|
*slice = &slice[2..];
|
|
}
|
|
|
|
fn assert_doc(slice: &mut &[TokenTree]) {
|
|
match &slice[0] {
|
|
TokenTree::Punct(tt) => {
|
|
assert_eq!(tt.as_char(), '#');
|
|
assert_eq!(tt.spacing(), Spacing::Alone);
|
|
}
|
|
_ => panic!("expected #"),
|
|
}
|
|
let inner = match &slice[1] {
|
|
TokenTree::Group(tt) => {
|
|
assert_eq!(tt.delimiter(), Delimiter::Bracket);
|
|
tt.stream()
|
|
}
|
|
_ => panic!("expected brackets"),
|
|
};
|
|
let tokens = inner.into_iter().collect::<Vec<_>>();
|
|
let tokens = &tokens[..];
|
|
|
|
if tokens.len() != 3 {
|
|
panic!("expected three tokens in doc")
|
|
}
|
|
|
|
match &tokens[0] {
|
|
TokenTree::Ident(tt) => assert_eq!("doc", &*tt.to_string()),
|
|
_ => panic!("expected `doc`"),
|
|
}
|
|
match &tokens[1] {
|
|
TokenTree::Punct(tt) => {
|
|
assert_eq!(tt.as_char(), '=');
|
|
assert_eq!(tt.spacing(), Spacing::Alone);
|
|
}
|
|
_ => panic!("expected equals"),
|
|
}
|
|
match tokens[2] {
|
|
TokenTree::Literal(_) => {}
|
|
_ => panic!("expected literal"),
|
|
}
|
|
|
|
*slice = &slice[2..];
|
|
}
|
|
|
|
fn assert_invoc(slice: &mut &[TokenTree]) {
|
|
match &slice[0] {
|
|
TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
|
|
_ => panic!("expected '#' char"),
|
|
}
|
|
match &slice[1] {
|
|
TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket),
|
|
_ => panic!("expected brackets"),
|
|
}
|
|
*slice = &slice[2..];
|
|
}
|
|
|
|
fn assert_foo(slice: &mut &[TokenTree]) {
|
|
match &slice[0] {
|
|
TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "fn"),
|
|
_ => panic!("expected fn"),
|
|
}
|
|
match &slice[1] {
|
|
TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "foo"),
|
|
_ => panic!("expected foo"),
|
|
}
|
|
match &slice[2] {
|
|
TokenTree::Group(tt) => {
|
|
assert_eq!(tt.delimiter(), Delimiter::Parenthesis);
|
|
assert!(tt.stream().is_empty());
|
|
}
|
|
_ => panic!("expected parens"),
|
|
}
|
|
match &slice[3] {
|
|
TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Brace),
|
|
_ => panic!("expected braces"),
|
|
}
|
|
*slice = &slice[4..];
|
|
}
|
|
|
|
fn fold_stream(input: TokenStream) -> TokenStream {
|
|
input.into_iter().map(fold_tree).collect()
|
|
}
|
|
|
|
fn fold_tree(input: TokenTree) -> TokenTree {
|
|
match input {
|
|
TokenTree::Group(b) => {
|
|
TokenTree::Group(Group::new(b.delimiter(), fold_stream(b.stream())))
|
|
}
|
|
TokenTree::Punct(b) => TokenTree::Punct(b),
|
|
TokenTree::Ident(a) => TokenTree::Ident(a),
|
|
TokenTree::Literal(a) => {
|
|
if a.to_string() != "\"foo\"" {
|
|
TokenTree::Literal(a)
|
|
} else {
|
|
TokenTree::Literal(Literal::i32_unsuffixed(3))
|
|
}
|
|
}
|
|
}
|
|
}
|