do_with_in_internal_macros/
lib.rs1extern crate proc_macro;
2extern crate syn;
3#[macro_use] extern crate quote;
4extern crate proc_macro2;
5
6use proc_macro::{TokenStream, TokenTree};
7use proc_macro2::TokenTree as TokenTree2;
8use proc_macro2::TokenStream as TokenStream2;
9use quote::quote;
10use quote::ToTokens;
11use syn::{parse, Attribute, PathSegment, Result, Token};
12use syn::parse::{Parse, ParseStream, Parser, Peek};
13use syn::spanned::Spanned;
14use syn::{Expr, Ident, Type, Visibility};
15use syn::punctuated::Punctuated;
16use syn::parenthesized;
17use syn::token::Token;
18use syn::buffer::Cursor;
19
20use std::marker::PhantomData;
21
22use std::collections::HashMap;
23use std::fmt::format;
24
25use do_with_in_base::*;
26
27struct Fatuous {
28 fat: TokenStream,
29}
30
31impl Parse for Fatuous {
32 fn parse(input: ParseStream) -> Result<Self> {
33 let mut fat = TokenStream2::new();
34 input.step(|cursor| {
35 let mut rest = *cursor;
36 while let Some((tt, next)) = rest.token_tree() {
37 fat.extend(TokenStream2::from(tt).into_iter());
38 rest = next;
39 }
40 Ok(((), rest))
41 });
42 Ok(Fatuous { fat: fat.into() })
43 }
44}
45
46#[cfg(feature = "doc-kludge")]
47macro_rules! bleh {
48 () => {
49 ""
50 }
51}
52
53#[cfg(not(feature = "doc-kludge"))]
54macro_rules! bleh {
55 () => {
56 concat!(
57"This is the proc_macro most users of this crate will use.\n",
58"\n",
59" There is front matter, which can define the sigil and escaping style. Escaping doesn't actually do anything yet though.\n",
60" Then `do`, then after that is where the metaprogramming can happen.\n",
61"\n",
62" In the metaprogramming section, variables are identifiers with a sigil prepended. You can create and assign to them with `let` and `var` handlers.\n",
63" Numbers with a sigil prepended are special variables that can be set inside a handler; you cannot assign to them with `let` or `var`.\n",
64" Brackets with a sigil prepended start a handler invocation; the handler invoked will be the first token inside the brackets, which must be an identifier.\n",
65"\n",
66" For example, in the following code the sigil is `$`, `$correction_factor` is a normal variable, `$1`, `$2`, and `$3` are special variables set inside the `blah` handler,\n",
67" and `$(let ...)`, `$(mk ...)` and `$(blah ...)` are all handlers.\n",
68"\n",
69" ```rust\n",
70" # use do_with_in_internal_macros::do_with_in;\n",
71" # fn main() {\n",
72" do_with_in!{\n",
73" sigil: $\n",
74" do\n",
75" $(let correction_factor = {(-1)})\n",
76" $(mk blah\n",
77" $1 = $2 + $3 + $correction_factor;)\n",
78" $(blah {let mut d} 3 4)\n",
79" d += 1;\n",
80" let correction_factor = $correction_factor;\n",
81" };\n",
82" assert_eq!(d, 8 + correction_factor);\n",
83" # }\n",
84" ```\n",
85"\n",
86)
87 }
88}
89
90#[doc = bleh!()]
91#[proc_macro]
92pub fn do_with_in(t: TokenStream) -> TokenStream {
93 let f = file!();
96 let tempt: TokenStream2 = t.into();
97 let tt = quote!{
98 file: #f
99 #tempt
100 };
101 do_with_in_internal(tt).into()
102}
103
104
105#[proc_macro]
106pub fn do_with_in_explicit_internal(t: TokenStream) -> TokenStream {
107 let t_new: TokenStream2 = t.into();
108 quote! {
109 do_with_in_explicit(c, v, #t_new).into()
113 }.into()
114}
115
116#[proc_macro_attribute]
129pub fn do_with_in_izer(attr: TokenStream, inner: TokenStream) -> TokenStream {
130 let mut has_prelude = true;
131 let mut postlude_marker = quote!{DoMarker};
132 let default_default = quote!{Sigil::Dollar};
133 let mut default_sigil = default_default.clone();
134 let mut sigil = default_sigil.clone();
135 let a: TokenStream2 = attr.into();
136 let b: TokenStream2 = inner.into();
138 let mut b_it = b.into_iter();
140 b_it.next(); b_it.next(); let token = b_it.next();
143 if let Some(TokenTree2::Ident(name)) = token.clone() {
144 let real_name = proc_macro2::Ident::new(&format!{"{}!",name.to_string()}, proc_macro2::Span::call_site());
145 let func_arg_name = match b_it.next() {
146 Some(TokenTree2::Group(grp)) => {
147 if let Some(TokenTree2::Ident(it)) = grp.stream().into_iter().next() {
148 it
149 } else {
150 return quote!{compile_error!{ "Expected an argument list." }}.into()
151 }
152 },
153 Some(x) => {
154 let msg = format!("Expected a function argument list, got {}.", x);
155 return quote!{compile_error!{ #msg }}.into();
156 },
157 None => {
158 return quote!{compile_error!{ "Missing function for do_with_in_izer to be applied to." }}.into();
159 },
160 };
161 let mut body = TokenStream2::new();
162 body.extend(b_it);
163 return quote! {
165 #[proc_macro]
166 pub fn #real_name(t: TokenStream) -> TokenStream {
167 let tt: TokenStream2 = t.into();
168 let #func_arg_name = do_with_in_base::do_with_in_explicit(c, v, tt).<TokenStream2>::into();
173 #body
174 }
175 }.into()
176 } else {
177 let msg = format!("Expected a name for a function, got {:?}.", token);
178 return quote!{compile_error!{ #msg }}.into();
179 }
180}
181
182