1#![recursion_limit = "256"]
2
3extern crate proc_macro;
4
5use proc_macro2::{LineColumn, Span, Delimiter, Group, TokenTree, TokenStream};
6use syn::{LitStr, parse_macro_input, Result};
7use syn::parse::{ParseStream, Parse};
8use std::iter::FromIterator;
9use std::collections::VecDeque;
10
11#[proc_macro]
60pub fn quote(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
61 let Tokens(registers, output) = parse_macro_input!(input as Tokens);
62
63 let output = TokenStream::from_iter(output);
64
65 let gen = quote::quote! {{
66 let mut __toks = genco::Tokens::new();
67 #(#registers;)*
68 #output
69 __toks
70 }};
71
72 gen.into()
73}
74
75struct Tokens(Vec<TokenStream>, Vec<TokenTree>);
76
77#[derive(Clone, Copy, Debug)]
78struct Cursor {
79 start: LineColumn,
80 end: LineColumn,
81}
82
83impl Cursor {
84 fn start_character(self) -> Self {
86 Cursor {
87 start: self.start,
88 end: LineColumn {
89 line: self.start.line,
90 column: self.start.column + 1,
91 },
92 }
93 }
94
95 fn end_character(self) -> Self {
97 Cursor {
98 start: LineColumn {
99 line: self.end.line,
100 column: self.end.column - 1,
101 },
102 end: self.end,
103 }
104 }
105}
106
107impl From<Span> for Cursor {
108 fn from(span: Span) -> Self {
109 Self {
110 start: span.start(),
111 end: span.end(),
112 }
113 }
114}
115
116impl<'a> From<&'a Span> for Cursor {
117 fn from(span: &'a Span) -> Self {
118 Self {
119 start: span.start(),
120 end: span.end(),
121 }
122 }
123}
124
125impl Parse for Tokens {
126 fn parse(input: ParseStream) -> Result<Self> {
127 use std::iter::from_fn;
128
129 let mut registers = Vec::new();
130
131 let mut tokens = Vec::new();
132
133 let mut cursor = Cursor::from(input.span());
134 let mut last_column = cursor.start.column;
135
136 let mut queued = Vec::new();
137 let mut queue = VecDeque::new();
138
139 let mut item_buffer = ItemBuffer::new();
140
141 process_expressions(|item| queue.push_back(item), from_fn(move || {
142 if !input.is_empty() {
143 Some(input.parse::<TokenTree>())
144 } else {
145 None
146 }
147 }))?;
148
149 while let Some(item) = queue.pop_front() {
150 let next = item.cursor();
151
152 if cursor.start.line != next.start.line {
153 item_buffer.flush(&mut tokens);
154
155 debug_assert!(next.start.line > cursor.start.line);
156
157 let stream = if next.start.line - cursor.start.line > 1 {
158 quote::quote!(__toks.line_spacing();)
159 } else {
160 quote::quote!(__toks.push_spacing();)
161 };
162
163 tokens.push(TokenTree::Group(Group::new(Delimiter::None, stream)));
164
165 if last_column < next.start.column {
166 let stream = quote::quote!(__toks.indent(););
167 tokens.push(TokenTree::Group(Group::new(Delimiter::None, stream)));
168 } else if last_column > next.start.column {
169 let stream = quote::quote!(__toks.unindent(););
170 tokens.push(TokenTree::Group(Group::new(Delimiter::None, stream)));
171 }
172
173 last_column = next.start.column;
174 } else {
175 if cursor.end.column < next.start.column && last_column != next.start.column {
177 item_buffer.flush(&mut tokens);
178
179 let stream = quote::quote!(__toks.spacing(););
180 tokens.push(TokenTree::Group(Group::new(Delimiter::None, stream)));
181 }
182 }
183
184 cursor = next;
185
186 match item {
187 Item::Tree(tt) => {
188 match tt {
189 TokenTree::Group(group) => {
190 process_expressions(|item| queued.push(item), group.stream().into_iter().map(Ok))?;
191
192 match group.delimiter() {
193 Delimiter::Parenthesis => item_buffer.push('('),
194 Delimiter::Brace => item_buffer.push('{'),
195 Delimiter::Bracket => item_buffer.push('['),
196 _ => (),
197 }
198
199 let span_cursor = Cursor::from(group.span());
200 queue.push_front(Item::DelimiterClose(span_cursor.end_character(), group.delimiter()));
201 cursor = span_cursor.start_character();
202
203 while let Some(item) = queued.pop() {
204 queue.push_front(item);
205 }
206 }
207 other => {
208 item_buffer.push_str(&other.to_string());
209 }
210 }
211 }
212 Item::Expression(span, expr) => {
213 item_buffer.flush(&mut tokens);
214
215 let group = Group::new(Delimiter::None, quote::quote_spanned!(span => __toks.append(Clone::clone(&#expr));));
216 tokens.push(TokenTree::Group(group));
217 }
218 Item::Register(span, expr) => {
219 registers.push(quote::quote_spanned!(span => __toks.register(#expr)));
220 }
221 Item::DelimiterClose(_, delimiter) => {
222 match delimiter {
223 Delimiter::Parenthesis => item_buffer.push(')'),
224 Delimiter::Brace => item_buffer.push('}'),
225 Delimiter::Bracket => item_buffer.push(']'),
226 _ => (),
227 }
228 }
229 }
230 }
231
232 item_buffer.flush(&mut tokens);
233 Ok(Self(registers, tokens))
234 }
235}
236
237struct ItemBuffer {
238 buffer: String,
239}
240
241impl ItemBuffer {
242 fn new() -> Self {
244 Self {
245 buffer: String::new(),
246 }
247 }
248
249 fn push(&mut self, c: char) {
251 self.buffer.push(c);
252 }
253
254 fn push_str(&mut self, s: &str) {
256 self.buffer.push_str(s);
257 }
258
259 fn flush(&mut self, tokens: &mut Vec<TokenTree>) {
261 if !self.buffer.is_empty() {
262 let s = LitStr::new(&self.buffer, Span::call_site());
263 let group = Group::new(Delimiter::None, quote::quote!(__toks.append(#s);));
264 tokens.push(TokenTree::Group(group));
265 self.buffer.clear();
266 }
267 }
268}
269
270#[derive(Debug)]
272enum Item {
273 Tree(TokenTree),
274 Expression(Span, TokenTree),
275 Register(Span, TokenTree),
276 DelimiterClose(Cursor, Delimiter),
277}
278
279impl Item {
280 fn cursor(&self) -> Cursor {
281 match self {
282 Self::Tree(tt) => Cursor::from(tt.span()),
283 Self::Expression(span, ..) => Cursor::from(span),
284 Self::Register(span, ..) => Cursor::from(span),
285 Self::DelimiterClose(cursor, ..) => *cursor,
286 }
287 }
288}
289
290fn process_expressions(mut queue: impl FnMut(Item), mut it: impl Iterator<Item = Result<TokenTree>>) -> Result<()> {
292 let mut n1 = it.next().transpose()?;
293
294 while let Some(n0) = std::mem::replace(&mut n1, it.next().transpose()?) {
295 n1 = match (n0, n1) {
296 (TokenTree::Punct(mut a), Some(TokenTree::Punct(b))) if a.as_char() == '#' && b.as_char() == '#' => {
298 let span = a.span().join(b.span()).expect("failed to join spans");
299 a.set_span(span);
300 queue(Item::Tree(TokenTree::Punct(a)));
301 it.next().transpose()?
302 }
303 (TokenTree::Punct(mut a), Some(TokenTree::Punct(b))) if a.as_char() == '@' && b.as_char() == '@' => {
305 let span = a.span().join(b.span()).expect("failed to join spans");
306 a.set_span(span);
307 queue(Item::Tree(TokenTree::Punct(a)));
308 it.next().transpose()?
309 }
310 (TokenTree::Punct(first), Some(argument)) if first.as_char() == '#' => {
312 let span = first.span().join(argument.span()).expect("failed to join spans");
313
314 match argument {
315 other => {
316 queue(Item::Expression(span, other));
317 it.next().transpose()?
318 }
319 }
320 }
321 (TokenTree::Punct(first), Some(argument)) if first.as_char() == '@' => {
323 let span = first.span().join(argument.span()).expect("failed to join spans");
324
325 match argument {
326 other => {
327 queue(Item::Register(span, other));
328 it.next().transpose()?
329 }
330 }
331 }
332 (tt, next) => {
333 queue(Item::Tree(tt));
334 next
335 }
336 }
337 }
338
339 if let Some(tt) = n1 {
340 queue(Item::Tree(tt));
341 }
342
343 Ok(())
344}