1extern crate proc_macro;
2extern crate syn;
3#[macro_use] extern crate quote;
4extern crate proc_macro2;
5extern crate bimap;
6
7use proc_macro::{TokenStream, TokenTree};
8use proc_macro2::TokenTree as TokenTree2;
9use proc_macro2::TokenStream as TokenStream2;
10use quote::{quote, quote_spanned};
11use quote::ToTokens;
12use syn::{parse, Attribute, PathSegment, Result, Token};
13use syn::parse::{Parse, ParseStream, Parser, Peek};
14use syn::spanned::Spanned;
15use syn::{Expr, Ident, Type, Visibility};
16use syn::punctuated::Punctuated;
17use syn::parenthesized;
18use syn::token::Token;
19use syn::buffer::Cursor;
20
21use std::marker::PhantomData;
22
23use std::collections::HashMap;
24use std::fmt::format;
25
26use bimap::BiMap;
27
28#[derive(Debug,Copy,Clone,PartialEq,Eq)]
29pub enum Sigil {
30 Dollar,
31 Percent,
32 Hash,
33 Tilde,
34}
35
36#[derive(Debug,Clone)]
37pub struct Res {
38 pub to_insert: TokenStream2,
39 pub problem: Option<String>,
40}
41
42use std::fmt;
43impl fmt::Display for Sigil {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 let out = match self {
46 Sigil::Dollar => "$",
47 Sigil::Percent => "%",
48 Sigil::Hash => "#",
49 Sigil::Tilde => "~",
50 };
51 write!(f, "{}", out)
52 }
53}
54use quote::TokenStreamExt;
55impl ToTokens for Sigil {
56 fn to_tokens(&self, tokens: &mut TokenStream2) {
57 tokens.extend(match self {
58 Sigil::Dollar => quote!{do_with_in_base::Sigil::Dollar}, Sigil::Percent => quote!{do_with_in_base::Sigil::Percent}, Sigil::Hash => quote!{do_with_in_base::Sigil::Hash}, Sigil::Tilde => quote!{do_with_in_base::Sigil::Tilde}, });
63 }
64}
65
66impl Default for Sigil {
67 fn default() -> Self {
68 Sigil::Dollar
69 }
70}
71
72#[derive(Debug,Copy,Clone,PartialEq,Eq)]
73pub enum Escaping {
74 None,
75 Backslash,
76 Double,
77}
78
79impl ToTokens for Escaping {
80 fn to_tokens(&self, tokens: &mut TokenStream2) {
81 tokens.extend(match self {
82 Escaping::None => quote!{do_with_in_base::Escaping::None},
83 Escaping::Backslash => quote!{do_with_in_base::Escaping::Backslash},
84 Escaping::Double => quote!{do_with_in_base::Escaping::Double},
85 });
86 }
87}
88
89impl Default for Escaping {
90 fn default() -> Self {
91 Escaping::Double
92 }
93}
94
95#[derive(Debug,Clone)]
96pub struct Configuration<Start: StartMarker> where Start: Clone {
97 pub allow_prelude: bool,
98 pub sigil: Sigil,
99 pub escaping_style: Escaping,
100 pub file: Option<String>,
101 pub rest: Option<TokenStream2>,
102 _do: PhantomData<Start>,
103}
104
105impl<T> ToTokens for Configuration<T> where T: StartMarker + Clone {
106 fn to_tokens(&self, tokens: &mut TokenStream2) {
107 let c = self.clone();
108 let p = c.allow_prelude;
109 let s = c.sigil;
110 let e = c.escaping_style;
111 let f = match c.file {
112 Some(x) => quote! { Some(quote!{#x}) },
113 None => quote! { None },
114 };
115 let rest = match c.rest {
116 Some(x) => quote! { Some(quote!{#x}) },
117 None => quote! { None },
118 };
119 let t = T::token_token();
120
121 tokens.extend(quote!{
122 Configuration::<#t> {
123 allow_prelude: #p,
124 sigil: #s,
125 escaping_style: #e,
126 file: #f,
127 rest: #rest,
128 _do: PhantomData,
129 }
130 });
131 }
132}
133
134macro_rules! check_token {
135 ($y:pat, $z:expr, $err:literal, $v:expr, $err2: literal) => {
136 if let $y = $z {
137 if $v {
138 ()
139 } else {
140 return Err($err2);
141 }
142 } else {
143 return Err($err);
144 }
145 };
146}
147
148macro_rules! check_token_ret {
149 ($vars: expr, $y:pat, $z:expr, $err:literal, $v:expr, $err2: literal) => {
150 if let $y = $z {
151 if $v {
152 ()
153 } else {
154 return Err(($vars, quote!{compile_error!{ $err2 }}));
156 }
157 } else {
158 return Err(($vars, quote!{compile_error!{ $err }}));
160 }
161 };
162 ($vars: expr, $sp: expr, $y:pat, $z:expr, $err:literal, $v:expr, $err2: literal) => {
163 if let $y = $z {
164 if $v {
165 ()
166 } else {
167 let sp = $sp.span();
168 return Err(($vars, quote_spanned!{sp=> compile_error!{ $err2 }}));
170 }
171 } else {
172 return Err(($vars, quote!{compile_error!{ $err }}));
174 }
175 };
176 ($vars: expr, $sp_root:expr, $sp: expr, $y:pat, $z:expr, $err:literal, $v:expr, $err2: literal) => {
177 if let $y = $z {
178 if $v {
179 ()
180 } else {
181 let sp = $sp.span();
182 return Err(($vars, quote_spanned!{sp=> compile_error!{ $err2 }}));
184 }
185 } else {
186 let sp = $sp_root.span();
187 return Err(($vars, quote_spanned!{sp=> compile_error!{ $err }}));
189 }
190 };
191}
192
193fn unwrap_to<T>(x: std::result::Result<T, T>) -> (T, bool) {
194 match x {
195 Ok(a) => (a, true),
196 Err(a) => (a, false),
197 }
198}
199
200#[derive(Debug, Clone, Copy)]
201enum Offset {
202 Forward(usize),
203 Reverse(usize),
204 Head,
205 Tail,
206}
207
208macro_rules! pull_offset {
209 ($stream:ident, $anchor:expr, $out: ident, $v:ident) => {
210 match $stream.next() {
211 Some(TokenTree2::Literal(lit)) => {
212 let the_lit = lit.to_string();
213 $out = match syn::parse_str::<syn::LitInt>(&the_lit.clone()).map(|x| x.base10_parse::<i64>()).ok() {
214 Some(Ok(x)) if x >= 0 => Offset::Forward(x as usize),
215 Some(Ok(x)) => Offset::Reverse((x.abs() - 1) as usize),
216 _ => {
217 let msg = format!("Expected an offset, got {}", the_lit);
218 let sp = the_lit.span();
219 return Err(($v, quote_spanned!{sp=> compile_error!{ #msg }}));
220 },
221 };
222 },
223 Some(TokenTree2::Ident(it)) if it.to_string().as_str() == "head" => {
224 $out = Offset::Head;
225 },
226 Some(TokenTree2::Ident(it)) if it.to_string().as_str() == "tail" => {
227 $out = Offset::Tail;
228 },
229 Some(TokenTree2::Punct(minus)) if minus.as_char() == '-' => {
230 match $stream.next() {
232 Some(TokenTree2::Literal(lit)) => {
233 let the_lit = lit.to_string();
234 $out = match syn::parse_str::<syn::LitInt>(&the_lit.clone()).map(|x| x.base10_parse::<i64>()).ok() {
235 Some(Ok(x)) => Offset::Reverse((x.abs() - 1) as usize),
236 _ => {
237 let msg = format!("Expected an offset, got {}", the_lit);
238 let sp = the_lit.span();
239 return Err(($v, quote_spanned!{sp=> compile_error!{ #msg }}));
240 },
241 };
242 }
243 Some(x) => {
244 let msg = format!("Expected an offset, got -{}.", x);
245 let sp = x.span();
246 return Err(($v, quote_spanned!{sp=> compile_error!{ #msg }}));
247 },
248 None => {
249 let sp = minus.span();
250 return Err(($v, quote_spanned!{sp=> compile_error!{ "Expected an offset, but the argument list ended early (after a '-')." }}));
251 },
252 }
253 },
254 Some(x) => {
255 let msg = format!("Expected an offset, got {}.", x);
256 let sp = x.span();
257 return Err(($v, quote_spanned!{sp=> compile_error!{ #msg }}));
258 },
259 None => {
260 let foo = $anchor;
261 return Err(($v, quote_spanned!{foo=> compile_error!{ "Expected an offset, but the argument list ended early." }}));
262 },
263 }
264 };
265}
266
267macro_rules! pull_array_to_vec {
268 ($stream_next:expr, $out:expr, $v:expr, $q:expr, $s:expr) => {
269 let mut unwrapped = if $q {
272 match $s {
273 Sigil::Dollar => check_token_ret!($v, Some(TokenTree2::Punct(p)), $stream_next, "Expect a sigil (here, '$') to invoke quote.", p.as_char() == '$', "Expect a sigil (here, '$') to invoke quote."),
274 Sigil::Hash => check_token_ret!($v, Some(TokenTree2::Punct(p)), $stream_next, "Expect a sigil (here, '#') to invoke quote.", p.as_char() == '#', "Expect a sigil (here, '#') to invoke quote."),
275 Sigil::Percent => check_token_ret!($v, Some(TokenTree2::Punct(p)), $stream_next, "Expect a sigil (here, '%') to invoke quote.", p.as_char() == '%', "Expect a sigil (here, '%') to invoke quote."),
276 Sigil::Tilde => check_token_ret!($v, Some(TokenTree2::Punct(p)), $stream_next, "Expect a sigil (here, '~') to invoke quote.", p.as_char() == '~', "Expect a sigil (here, '~') to invoke quote."),
277 };
278 match $stream_next {
279 Some(TokenTree2::Group(grp)) => {
280 let mut inner = grp.stream().into_iter();
281 check_token_ret!($v, Some(TokenTree2::Ident(qu)), inner.next(), "Expecting 'quote'.", qu.to_string() == "quote", "Expecting 'quote'.");
282 match inner.next() {
283 Some(TokenTree2::Group(grp)) => {
284 grp.stream().into_iter()
285 },
286 Some(x) => {
287 let msg = format!("Expected a [...], got {}", x);
288 return Err(($v, quote!{ compile_error!{ #msg }}));
289 },
290 None => {
291 return Err(($v, quote!{ compile_error!{ "Expecting an array; argument list finished early." }}));
292 },
293 }
294 },
295 Some(x) => {
296 let msg = format!("Expected a ([...]), got {:?}", x);
297 return Err(($v, quote!{ compile_error!{ #msg }}));
298 },
299 None => {
300 return Err(($v, quote!{ compile_error!{ "Expecting an array; argument list finished early." }}));
301 },
302 }
303 } else {
304 match $stream_next {
305 Some(TokenTree2::Group(grp)) => {
306 grp.stream().into_iter()
307 },
308 Some(x) => {
309 let msg = format!("Expected a [...], got {}", x);
310 return Err(($v, quote!{ compile_error!{ #msg }}));
311 },
312 None => {
313 return Err(($v, quote!{ compile_error!{ "Expecting an array; argument list finished early." }}));
314 },
315 }
316 };
317 for item in unwrapped {
318 match item {
319 TokenTree2::Group(grp) => {
320 let mut it = TokenStream2::new();
321 it.extend(grp.stream());
322 $out.push(it);
323 },
324 x => {
325 let sp = x.span();
326 let msg = format!("Expected an array element (ie a {{...}}), got {:?}", x);
327 return Err(($v, quote_spanned!{sp=> compile_error!{ #msg }}));
328 },
329 }
330 }
331 };
332}
333
334#[derive(Debug,Clone)]
335struct ConfigurationChunks {
336 allow_prelude: Option<bool>,
337 sigil: Option<Sigil>,
338 escaping_style: Option<Escaping>,
339 file: Option<Option<String>>,
340 rest: Option<Option<TokenStream2>>,
341 marker: Vec<syn::Ident>,
342}
343
344enum Chunks {
345 AllowPrelude,
346 Sigil,
347 EscapingStyle,
348 File,
349 Rest,
350 Do,
351}
352
353enum GetSigil {
355 ExpectingColonsThenSigil,
356 ExpectingColonThenSigil,
357 ExpectingSigil,
358 ExpectingColonsThenEnd,
359 ExpectingColonThenEnd,
360 ExpectingEnd,
361}
362
363enum GetEscaping {
365 ExpectingColonsThenEscaping,
366 ExpectingColonThenEscaping,
367 ExpectingEscaping,
368 ExpectingColonsThenEnd,
369 ExpectingColonThenEnd,
370 ExpectingEnd,
371}
372
373enum GetChunk {
374 NothingYet,
375 ChunkType(Chunks),
376 Equals(Chunks),
377 Sigil(GetSigil), Escaping(GetEscaping),
379 Some, }
381
382macro_rules! unwrap_struct {
383 ($name:literal, $iter:ident, $part:ident, $get_type_bits:stmt) => {
384 {
385 check_token!(Some(TokenTree2::Ident(conf)), $iter.next(), "Expected struct name", conf.to_string() == $name, "Expected struct name");
386 check_token!(Some(TokenTree2::Punct(sc)), $iter.next(), "Expected ':' (first part of ::).", sc.as_char() == ':', "Expected ':' (first part of ::).");
387 check_token!(Some(TokenTree2::Punct(sc)), $iter.next(), "Expected ':' (second part of ::).", sc.as_char() == ':', "Expected ':' (second part of ::).");
388 check_token!(Some(TokenTree2::Punct(lt)), $iter.next(), "Expected '<'", lt.as_char() == '<', "Expected '<'.");
389 let mut cont = true;
391 let mut at_all = false;
392 let mut next: Option<TokenTree2> = $iter.next();
393 while cont {
394 if let Some(TokenTree2::Ident($part)) = next.clone() {
395 $get_type_bits;
396 at_all = true;
397 next = $iter.next();
398 match next {
399 Some(TokenTree2::Punct(s)) if s.as_char() == ':' => {
400 check_token!(Some(TokenTree2::Punct(sc)), $iter.next(), "Expected ':' (second part of ::), for type.", sc.as_char() == ':', "Expected ':' (second part of ::), for type.");
401 next = $iter.next();
402 },
403 x => {
404 next = x;
405 cont = false;
406 },
407 }
408 } else if at_all {
409 cont = false;
410 } else {
411 return Err("Expected a part of a type.");
412 }
413 }
414 check_token!(Some(TokenTree2::Punct(gt)), next, "Expected '>'", gt.as_char() == '>', "Expected '>'.");
415 let inner = if let Some(TokenTree2::Group(group)) = $iter.next() {
416 group.stream()
417 } else {
418 return Err("No group when one was expected.");
419 };
420 inner
421 }
422 }
423}
424
425impl<T> TryFrom<TokenStream2> for Configuration<T> where T: StartMarker + Clone {
426 type Error = &'static str;
427 fn try_from(value: TokenStream2) -> std::result::Result<Self, Self::Error> {
428 let mut cc = ConfigurationChunks { allow_prelude: None, sigil: None, escaping_style: None, file: None, rest: None, marker: Vec::new(), };
429 let mut iter = value.into_iter();
430 let inner = unwrap_struct!("Configuration", iter, x, cc.marker.push(x));
431 let mut progress = GetChunk::NothingYet;
432 for thing in inner.into_iter() {
433 match progress {
434 GetChunk::NothingYet => {
435 match thing {
436 TokenTree2::Ident(name) => {
437 progress = GetChunk::ChunkType(match name.to_string().as_str() {
438 "allow_prelude" => Chunks::AllowPrelude,
439 "sigil" => Chunks::Sigil,
440 "escaping_style" => Chunks::EscapingStyle,
441 "file" => Chunks::File,
442 "rest" => Chunks::Rest,
443 "_do" => Chunks::Do,
444 x => return Err("Expecting allow_prelude, sigil, escaping_style, or rest."),
445 });
446 },
447 TokenTree2::Punct(comma) if comma.as_char() == ',' => {
448 progress = GetChunk::NothingYet; },
450 _ => {
451 return Err("Expecting allow_prelude, sigil, escaping_style, or rest.");
452 },
453 }
454 },
455 GetChunk::ChunkType(chunk) => {
456 check_token!(TokenTree2::Punct(eq), thing, "Expected ':'", eq.as_char() == ':', "Expected ':'.");
457 progress = GetChunk::Equals(chunk);
458 },
459 GetChunk::Equals(Chunks::AllowPrelude) => {
460 if let TokenTree2::Ident(it) = thing {
461 cc.allow_prelude = Some(match it.to_string().as_str() {
462 "true" => true,
463 "false" => false,
464 _ => return Err("Expected 'true' or 'false'."),
465 });
466 progress = GetChunk::NothingYet;
467 } else {
468 return Err("Expected 'true' or 'false'");
469 }
470 },
471 GetChunk::Equals(Chunks::Sigil) => {
472 match thing {
473 TokenTree2::Punct(it) => {
474 cc.sigil = Some(match it.as_char() {
475 '$' => Sigil::Dollar,
476 '~' => Sigil::Tilde,
477 '%' => Sigil::Percent,
478 '#' => Sigil::Hash,
479 _ => return Err("Expected $, %, #, or ~."),
480 });
481 progress = GetChunk::NothingYet;
482 },
483 TokenTree2::Ident(it) => {
484 match it.to_string().as_str() {
485 "Tilde" => {
486 cc.sigil = Some(Sigil::Tilde);
487 progress = GetChunk::NothingYet;
488 },
489 "Hash" => {
490 cc.sigil = Some(Sigil::Hash);
491 progress = GetChunk::NothingYet;
492 },
493 "Dollar" => {
494 cc.sigil = Some(Sigil::Dollar);
495 progress = GetChunk::NothingYet;
496 },
497 "Percent" => {
498 cc.sigil = Some(Sigil::Percent);
499 progress = GetChunk::NothingYet;
500 },
501 "Sigil" => {
502 progress = GetChunk::Sigil(GetSigil::ExpectingColonsThenEnd);
503 },
504 "do_with_in_base" => {
505 progress = GetChunk::Sigil(GetSigil::ExpectingColonsThenSigil);
506 },
507 _ => return Err("Expected $, %, #, ~, Sigil::..., or do_with_in_base::Sigil::..."),
508 }
509 },
510 _ => {
511 return Err("Expected $, %, #, ~, Sigil::..., or do_with_in_base::Sigil::...");
512 },
513 };
514 },
515 GetChunk::Equals(Chunks::EscapingStyle) => {
516 match thing {
517 TokenTree2::Ident(it) => {
518 match it.to_string().as_str() {
519 "None" => {
520 cc.escaping_style = Some(Escaping::None);
521 progress = GetChunk::NothingYet;
522 },
523 "Double" => {
524 cc.escaping_style = Some(Escaping::Double);
525 progress = GetChunk::NothingYet;
526 },
527 "Backslash" => {
528 cc.escaping_style = Some(Escaping::Backslash);
529 progress = GetChunk::NothingYet;
530 },
531 "Escaping" => {
532 progress = GetChunk::Escaping(GetEscaping::ExpectingColonsThenEnd);
533 },
534 "do_with_in_base" => {
535 progress = GetChunk::Escaping(GetEscaping::ExpectingColonsThenEscaping);
536 },
537 _ => return Err("Expected do_with_in_base, Escaping, None, Double, or Backslash"),
538 }
539 },
540 x => return Err("Expected a chunk escaping style."),
541 };
542 },
543 GetChunk::Equals(Chunks::File) => {
544 match thing {
545 TokenTree2::Ident(it) if it.to_string().as_str() == "None" => {
546 cc.file = Some(None);
547 progress = GetChunk::NothingYet;
548 },
549 TokenTree2::Literal(it) => {
550 match syn::parse_str::<syn::Lit>(&it.clone().to_string()) {
551 Ok(syn::Lit::Str(lit)) => {
552 cc.file = Some(Some(lit.value()));
553 progress = GetChunk::NothingYet;
554 },
555 _ => return Err("Expected either a filename in a string literal or None."),
556 };
557 },
558 _ => return Err("Expected either a filename in a string literal or None."),
559 }
560 },
561 GetChunk::Equals(Chunks::Rest) => {
562 match thing {
563 TokenTree2::Ident(it) => {
564 match it.to_string().as_str() {
565 "Some" => progress = GetChunk::Some,
566 "None" => {
567 cc.rest = Some(None);
568 progress = GetChunk::NothingYet;
569 },
570 _ => {
571 return Err("Expected Some(...) or None.");
572 },
573 }
574 },
575 _ => {
576 return Err("Expected Some(...) or None.");
577 }
578 }
579 },
580 GetChunk::Equals(Chunks::Do) => {
581 check_token!(TokenTree2::Ident(doit), thing, "Expected 'PhantomData'.", doit.to_string() == "PhantomData", "Expected 'PhantomData'.");
582 progress = GetChunk::NothingYet;
583 },
584 GetChunk::Sigil(GetSigil::ExpectingColonsThenSigil) => {
585 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (first part of ::).", sc.as_char() == ':', "Expected ':' (first part of ::).");
586 progress = GetChunk::Sigil(GetSigil::ExpectingColonThenSigil);
587 },
588 GetChunk::Sigil(GetSigil::ExpectingColonThenSigil) => {
589 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (second part of ::).", sc.as_char() == ':', "Expected ':' (second part of ::).");
590 progress = GetChunk::Sigil(GetSigil::ExpectingSigil);
591 },
592 GetChunk::Sigil(GetSigil::ExpectingSigil) => {
593 check_token!(TokenTree2::Ident(id), thing, "Expected 'Sigil'.", id.to_string() == "Sigil", "Expected 'Sigil'.");
594 progress = GetChunk::Sigil(GetSigil::ExpectingColonsThenEnd);
595 },
596 GetChunk::Sigil(GetSigil::ExpectingColonsThenEnd) => {
597 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (first part of ::).", sc.as_char() == ':', "Expected ':' (first part of ::).");
598 progress = GetChunk::Sigil(GetSigil::ExpectingColonThenEnd);
599 },
600 GetChunk::Sigil(GetSigil::ExpectingColonThenEnd) => {
601 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (second part of ::).", sc.as_char() == ':', "Expected ':' (second part of ::).");
602 progress = GetChunk::Sigil(GetSigil::ExpectingEnd);
603 },
604 GetChunk::Sigil(GetSigil::ExpectingEnd) => {
605 cc.sigil = match thing.to_string().as_str() {
606 "Tilde" => {
607 Some(Sigil::Tilde)
608 },
609 "Hash" => {
610 Some(Sigil::Hash)
611 },
612 "Dollar" => {
613 Some(Sigil::Dollar)
614 },
615 "Percent" => {
616 Some(Sigil::Percent)
617 },
618 _ => {
619 return Err("Expecting Tilde, Hash, Dollar, or Percent.");
620 },
621 };
622 progress = GetChunk::NothingYet;
623 },
624 GetChunk::Escaping(GetEscaping::ExpectingColonsThenEscaping) => {
625 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (first part of ::).", sc.as_char() == ':', "Expected ':' (first part of ::).");
626 progress = GetChunk::Escaping(GetEscaping::ExpectingColonThenEscaping);
627 },
628 GetChunk::Escaping(GetEscaping::ExpectingColonThenEscaping) => {
629 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (second part of ::).", sc.as_char() == ':', "Expected ':' (second part of ::).");
630 progress = GetChunk::Escaping(GetEscaping::ExpectingEscaping);
631 },
632 GetChunk::Escaping(GetEscaping::ExpectingEscaping) => {
633 check_token!(TokenTree2::Ident(id), thing, "Expected 'Escaping'.", id.to_string() == "Escaping", "Expected 'Escaping'.");
634 progress = GetChunk::Escaping(GetEscaping::ExpectingColonsThenEnd);
635 },
636 GetChunk::Escaping(GetEscaping::ExpectingColonsThenEnd) => {
637 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (first part of ::).", sc.as_char() == ':', "Expected ':' (first part of ::).");
638 progress = GetChunk::Escaping(GetEscaping::ExpectingColonThenEnd);
639 },
640 GetChunk::Escaping(GetEscaping::ExpectingColonThenEnd) => {
641 check_token!(TokenTree2::Punct(sc), thing, "Expected ':' (second part of ::).", sc.as_char() == ':', "Expected ':' (second part of ::).");
642 progress = GetChunk::Escaping(GetEscaping::ExpectingEnd);
643 },
644 GetChunk::Escaping(GetEscaping::ExpectingEnd) => {
645 cc.escaping_style = match thing.to_string().as_str() {
646 "None" => {
647 Some(Escaping::None)
648 },
649 "Double" => {
650 Some(Escaping::Double)
651 },
652 "Backslash" => {
653 Some(Escaping::Backslash)
654 },
655 _ => {
656 return Err("Expecting one, Double, or Backslash.");
657 },
658 };
659 progress = GetChunk::NothingYet;
660 },
661 GetChunk::Some => {
662 cc.rest = Some(match thing {
664 TokenTree2::Group(group) => {
665 let mut inner = group.stream().into_iter();
666 check_token!(Some(TokenTree2::Ident(id)), inner.next(), "Expected 'quote!{...}'.", id.to_string() == "quote", "Expected 'quote!{...}'.");
667 check_token!(Some(TokenTree2::Punct(bang)), inner.next(), "Expected '!{...}'.", bang.as_char() == '!', "Expected '!{...}'.");
668 match inner.next() {
669 Some(TokenTree2::Group(actual)) => Some(actual.stream()),
670 _ => return Err("Expected {...}."),
671 }
672 },
673 _ => {
674 return Err("Expected quote!{...}.");
675 },
676 });
677 progress = GetChunk::NothingYet;
678 },
679 }
680 }
681 Ok(Configuration {
683 allow_prelude: cc.allow_prelude.ok_or("Needed 'allow_prelude'.")?,
684 sigil: cc.sigil.ok_or("Needed 'sigil'.")?,
685 escaping_style: cc.escaping_style.unwrap_or_default(),
686 file: cc.file.flatten(),
687 rest: cc.rest.ok_or("Needed 'rest'.")?,
688 _do: PhantomData,
689 })
690 }
691}
692
693#[test]
694fn test_configuration_level_passing() {
695 let conf1l = Configuration::<DoMarker> {
696 allow_prelude: true,
697 sigil: Sigil::Tilde,
698 escaping_style: Escaping::None,
699 file: None,
700 rest: None,
701 _do: PhantomData,
702 };
703 let conf2l = Configuration::<DoMarker> {
704 allow_prelude: false,
705 sigil: Sigil::Dollar,
706 escaping_style: Escaping::Double,
707 file: None,
708 rest: Some(quote!{foo bar baz(1, 2) () "bloop"}),
709 _do: PhantomData,
710 };
711 let conf1ra: Configuration::<DoMarker> = quote!{Configuration::<DoMarker> {
712 allow_prelude: true,
713 sigil: ~,
714 file: None,
715 escaping_style: Escaping::None,
716 rest: None,
717 }}.try_into().unwrap();
718 let conf1rb: Configuration::<DoMarker> = quote!{Configuration::<DoMarker> {
719 allow_prelude: true,
720 sigil: Tilde,
721 file: None,
722 escaping_style: Escaping::None,
723 rest: None,
724 }}.try_into().unwrap();
725 let tilde = Sigil::Tilde;
726 let dollar = Sigil::Dollar;
727 let escaping = Escaping::None;
728 let conf1rc: Configuration::<DoMarker> = quote!{Configuration::<DoMarker> {
729 allow_prelude: true,
730 sigil: #tilde,
731 escaping_style: #escaping,
732 file: None,
733 rest: None,
734 }}.try_into().unwrap();
735 let conf1rd: Configuration::<DoMarker> = quote!{#conf1l}.try_into().unwrap();
736 let conf2ra: Configuration::<DoMarker> = quote!{Configuration::<DoMarker> {
737 allow_prelude: false,
738 sigil: $,
739 file: None,
740 rest: Some(quote!{foo bar baz(1, 2) () "bloop"}),
741 }}.try_into().unwrap();
742 let conf2rb: Configuration::<DoMarker> = quote!{Configuration::<DoMarker> {
743 allow_prelude: false,
744 sigil: Sigil::Dollar,
745 file: None,
746 rest: Some(quote!{foo bar baz(1, 2) () "bloop"}),
747 }}.try_into().unwrap();
748 let conf2rc: Configuration::<DoMarker> = quote!{Configuration::<DoMarker> {
749 allow_prelude: false,
750 sigil: #dollar,
751 file: None,
752 rest: Some(quote!{foo bar baz(1, 2) () "bloop"}),
753 }}.try_into().unwrap();
754 let conf2rd: Configuration::<DoMarker> = quote!{#conf2l}.try_into().unwrap();
755 assert_eq!(format!("{:?}", conf1l), format!("{:?}", conf1ra));
756 assert_eq!(format!("{:?}", conf1l), format!("{:?}", conf1rb));
757 assert_eq!(format!("{:?}", conf1l), format!("{:?}", conf1rc));
758 assert_eq!(format!("{:?}", conf1l), format!("{:?}", conf1rd));
759 assert_eq!(format!("{:?}", conf2l), format!("{:?}", conf2ra));
760 assert_eq!(format!("{:?}", conf2l), format!("{:?}", conf2rb));
761 assert_eq!(format!("{:?}", conf2l), format!("{:?}", conf2rc));
762 assert_eq!(format!("{:?}", conf2l), format!("{:?}", conf2rd));
763}
764
765type PeekFn = fn(Cursor) -> bool;
766
767pub trait StartMarker {
768 fn name() -> Option<String>;
769 type token: Parse;fn tokenp() -> PeekFn;type tokend: Parse + ToString + Clone;
773 fn token_token() -> TokenStream2;
774}
775
776impl StartMarker for DoMarker {
777 fn name() -> Option<String> {
778 None }
780 type token = syn::token::Do;
784 fn tokenp() -> PeekFn {
785 syn::token::Do::peek
786 }
787 type tokend = syn::Ident;
788 fn token_token() -> TokenStream2 {
789 quote! { do_with_in::DoMarker }
790 }
791}
792
793#[derive(Debug,Clone)]
794pub struct DoMarker;
795
796impl<T: StartMarker + Clone> Default for Configuration<T> {
797 fn default() -> Self {
798 Configuration { allow_prelude: true, rest: None, file: None, sigil: Default::default(), escaping_style: Default::default(), _do: PhantomData, }
800 }
801}
802
803impl<T: StartMarker + Clone> Parse for Configuration<T> {
804 fn parse(input: ParseStream) -> Result<Self> {
805 let mut base_config: Configuration<T> = Default::default();
807 while !input.is_empty() {
809 let mut next: Option<&str> = None;
811 let mut foo: String = String::from("");
812 if let Some(name) = T::name() {
813 if let Ok(it) = input.parse::<T::tokend>() {
814 if it.to_string().as_str() == name {
815 break;
816 }
817 foo = it.to_string().clone();
818 next = Some(foo.as_str().clone());
819 }
820 } else if T::tokenp()(input.cursor()) {
821 if let Ok(it) = input.parse::<T::token>() {
823 break;
824 }
825 }
826 let mut st: String = String::from("");
827 let err_pos = input.fork();
828 let new_next = if let Some(it) = next { it } else if !input.is_empty() { st = input.parse::<Ident>().expect("blergh").to_string(); &st } else { break; };
829 match new_next {
830 "sigil" => {
831 input.parse::<Token![:]>()?;
833 if input.peek(Token![$]) {
834 input.parse::<Token![$]>()?;
835 base_config.sigil = Sigil::Dollar;
836 } else if input.peek(Token![%]) {
837 input.parse::<Token![%]>()?;
838 base_config.sigil = Sigil::Percent;
839 } else if input.peek(Token![#]) {
840 input.parse::<Token![#]>()?;
841 base_config.sigil = Sigil::Hash;
842 } else if input.peek(Token![~]) {
843 input.parse::<Token![~]>()?;
844 base_config.sigil = Sigil::Tilde;
845 }
846 },
847 "file" => {
848 input.parse::<Token![:]>()?;
849 let f = input.parse::<syn::LitStr>().expect("Quoted string containing a file path expected.").value();
850 base_config.file = Some(f);
851 },
852 "escaping_style" => {
853 input.parse::<Token![:]>()?;
854 let es = input.parse::<Ident>().expect("Double, Backslash, or None expected.").to_string();
855 match es.as_str() {
856 "Double" => {
857 base_config.escaping_style = Escaping::Double;
858 },
859 "Backslash" => {
860 base_config.escaping_style = Escaping::Backslash;
861 },
862 "None" => {
863 base_config.escaping_style = Escaping::None;
864 },
865 x => {
866 return Err(err_pos.error(format!("Bad escaping_style within configuration section; found {} when Double, Backslash, or None expected.", x)));
867 },
868 };
869 },
870 a => {return Err(err_pos.error(format!("Bad configuration section; found {} when sigil or end of prelude expected", a)));},
871 };
872 }
873 let mut fat = TokenStream2::new();
874 input.step(|cursor| {
875 let mut rest = *cursor;
876 while let Some((tt, next)) = rest.token_tree() {
877 fat.extend(TokenStream2::from(tt).into_iter());
878 rest = next;
879 }
880 Ok(((), rest))
881 });
882
883 base_config.rest = Some(fat.into());
884 Ok(base_config)
887 }
888}
889
890impl<T: StartMarker + Clone> Configuration<T> {
891 fn name(&self) -> Option<String> {
892 T::name()
893 }
894}
895
896#[derive(Clone)]
897pub struct Variables<'a, T: StartMarker + Clone> {
898 pub handlers: Handlers<'a, T>,
899 pub variables: HashMap<String, (TokenStream2, bool)>,
900}
901
902impl<'a, T: 'static + StartMarker + Clone> ToTokens for Variables<'a, T> {
903 fn to_tokens(&self, tokens: &mut TokenStream2) {
904 let t = T::token_token();
905 let va = self.variables.iter().map(|(k, (v, t))| quote!{ (#k, (quote!{#v}, #t)) });
906 let handlers = self.handlers.iter().map(|(k, (v, it))| {
907
908 quote!{ (#k, (Box::new(quote!{#it}), quote!{quote!{#it}})) }
909 });
910 tokens.extend(quote!{
911 Variables::<#t> {
912 handlers: HashMap::from([#(#handlers),*]),
913 variables: HashMap::from([#(#va),*]),
914 }
915 });
916 }
917}
918
919enum VariableOpts {
920 Handlers,
921 Vars,
922}
923
924enum VariableChunks {
925 NothingYet,
926 Name(VariableOpts),
927 Equals(VariableOpts),
928 HashMap(VariableOpts),
929 FirstColon(VariableOpts),
930 SecondColon(VariableOpts),
931 From(VariableOpts),
932}
933
934
935impl<'a, T> TryFrom<TokenStream2> for Variables<'a, T> where T: StartMarker + Clone {
936 type Error = &'static str;
937 fn try_from(value: TokenStream2) -> std::result::Result<Self, Self::Error> {
938 let mut vars = Variables::<'a, T> { handlers: HashMap::new(), variables: HashMap::new(), };
939 let mut iter = value.into_iter();
940 let inner = unwrap_struct!("Variables", iter, x, ());
941 let mut progress = VariableChunks::NothingYet;
942 for thing in inner.into_iter() {
943 match progress {
944 VariableChunks::NothingYet => {
945 match thing {
946 TokenTree2::Ident(name) => {
947 progress = VariableChunks::Name(match name.to_string().as_str() {
948 "handlers" => VariableOpts::Handlers,
949 "variables" => VariableOpts::Vars,
950 x => return Err("Expecting handlers, with_interp, or no_interp."),
951 });
952 },
953 TokenTree2::Punct(comma) if comma.as_char() == ',' => {
954 progress = VariableChunks::NothingYet; },
956 _ => {
957 return Err("Expecting handlers, with_interp, or no_interp.");
958 },
959 }
960 },
961 VariableChunks::Name(x) => {
962 check_token!(TokenTree2::Punct(eq), thing, "Expected ':'", eq.as_char() == ':', "Expected ':'.");
963 progress = VariableChunks::Equals(x);
964 },
965 VariableChunks::Equals(x) => {
966 check_token!(TokenTree2::Ident(conf), thing, "Expected 'HashMap'.", conf.to_string() == "HashMap", "Expected 'HashMap'.");
967 progress = VariableChunks::FirstColon(x);
968 },
969 VariableChunks::HashMap(x) => {
970 check_token!(TokenTree2::Punct(eq), thing, "Expected ':'", eq.as_char() == ':', "Expected ':'.");
971 progress = VariableChunks::FirstColon(x);
972 },
973 VariableChunks::FirstColon(x) => {
974 check_token!(TokenTree2::Punct(eq), thing, "Expected ':'", eq.as_char() == ':', "Expected ':'.");
975 progress = VariableChunks::SecondColon(x);
976 },
977 VariableChunks::SecondColon(x) => {
978 check_token!(TokenTree2::Ident(conf), thing, "Expected 'from'.", conf.to_string() == "from", "Expected 'from'.");
979 progress = VariableChunks::From(x);
980 },
981 VariableChunks::From(x) => {
982 match thing {
983 TokenTree2::Group(from_args) if from_args.delimiter() == proc_macro2::Delimiter::Parenthesis => {
984 match from_args.stream().into_iter().next() {
985 Some(TokenTree2::Group(array)) if array.delimiter() == proc_macro2::Delimiter::Bracket => {
986 },
988 _ => return Err("Expected [...]."),
989 }
990 },
991 _ => return Err("Expected (...)."),
992 }
993 progress = VariableChunks::NothingYet;
994 },
995 }
996 }
997 todo!();
998 return Ok(vars);
999 }
1000}
1001
1002impl<'a, T: 'static + StartMarker + Clone> Default for Variables<'a, T> {
1003 fn default() -> Self {
1004 Variables { handlers: genericDefaultHandlers::<'a, T>(), variables: HashMap::new(), }
1005 }
1006}
1007
1008pub type Handler<T: StartMarker + Clone> = dyn Fn(Configuration<T>, Variables<T>, Option<TokenStream2>, TokenStream2) -> StageResult<T>;
1009pub type Handlers<'a, T: StartMarker + Clone> = HashMap<String, (Box<&'a Handler<T>>, Option<TokenStream2>)>;
1010
1011pub fn ifHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1019 let mut stream = t.into_iter();
1020 let if_anchor = stream.next().span();
1021 let (test_sp, test) = match stream.next() {
1022 Some(TokenTree2::Group(x)) => {
1023 let ts = x.span();
1024 let mut inner_test = TokenStream2::new();
1025 inner_test.extend(x.stream());
1026 let out = do_with_in_explicit2(inner_test, c.clone(), v.clone());
1027 match out {
1028 Ok((v1, o1)) => (ts, o1),
1029 Err((v1, o1)) => {
1030 let mut conc = TokenStream2::new();
1031 conc.extend(o1);
1032 let sp = x.span();
1033 let msg = "Error inside test of if statement.";
1034 conc.extend(quote_spanned!{sp=> compile_error!{ #msg }});
1035 return Err((v1, conc));
1036 },
1037 }
1038 },
1039 Some(e) => {
1040 let msg = format!("Expected a group in the test position of an if; got {}.", e);
1041 let sp = e.span();
1042 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
1043 },
1044 None => {
1045 let msg = "Input inside 'if' ended early; still expecting a test and then two branches.";
1046 let sp = if_anchor.span();
1047 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
1048 },
1049 };
1050 let if_branch = match stream.next() {
1051 Some(TokenTree2::Group(x)) => {
1052 let mut inner_test = TokenStream2::new();
1053 inner_test.extend(x.stream());
1054 inner_test
1055 },
1056 Some(e) => {
1057 let msg = format!("Expected a group in the first branch position of an if; got {}.", e);
1058 let sp = e.span();
1059 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
1060 },
1061 None => {
1062 let msg = "Input inside 'if' ended early; still expecting either one or two branches.";
1063 let sp = if_anchor.span();
1064 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
1065 },
1066 };
1067 let else_branch = match stream.next() {
1068 Some(TokenTree2::Group(x)) => {
1069 let mut inner_test = TokenStream2::new();
1070 inner_test.extend(x.stream());
1071 inner_test
1072 },
1073 None => TokenStream2::new(),
1074 Some(e) => {
1075 let msg = format!("Expected a group in the second branch position of an if; got {}.", e);
1076 let sp = if_anchor.span();
1077 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
1078 },
1079 };
1080 match tokenstreamToBool(test.clone()) {
1081 Ok(true) => {
1082 let out = do_with_in_explicit2(if_branch, c.clone(), v.clone());
1083 out
1084 },
1085 Ok(false) => {
1086 let out = do_with_in_explicit2(else_branch, c.clone(), v.clone());
1087 out
1088 },
1089 Err(err) => {
1090 let msg = format!("Problem in if test; {}", err);
1091 Err((v, quote_spanned!{test_sp=> compile_error!{ #msg }}))
1092 },
1093 }
1094}
1095
1096fn tokenTreeToBool(tree: TokenTree2) -> std::result::Result<bool, String> {
1097 match tree {
1098 TokenTree2::Ident(x) if x.to_string() == "true" => Ok(true),
1099 TokenTree2::Ident(x) if x.to_string() == "false" => Ok(false),
1100 TokenTree2::Group(x) => tokenstreamToBool(x.stream()),
1101 x => {
1102 Err(format!("Bool expected, got {}.", x))
1103 },
1104 }
1105}
1106
1107fn tokenstreamToBool(stream: TokenStream2) -> std::result::Result<bool, String> {
1108 match stream.into_iter().next() {
1109 Some(x) => tokenTreeToBool(x),
1110 None => Err("Bool expected, got nothing.".to_string()),
1111 }
1112}
1113
1114pub fn concatHandlerInner<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, t: TokenStream2) -> syn::parse::Result<String> {
1115 let mut accumulator: Vec<String> = Vec::new();
1116 for token in t.into_iter() {
1117 if let TokenTree2::Literal(lit) = token.clone() {
1118 let real_lit = syn::parse_str::<syn::Lit>(&lit.clone().to_string());
1119 match real_lit {
1120 Ok(syn::Lit::Str(it)) => accumulator.push(it.value()),
1121 Ok(x) => accumulator.push(lit.to_string()),
1122 Err(err) => return Err(err),
1123 }
1124 } else if let TokenTree2::Group(grp) = token.clone() {
1126 match concatHandlerInner(c.clone(), v.clone(), grp.stream()) {
1128 Ok(it) => accumulator.push(it),
1129 Err(err) => return Err(err),
1130 }
1131 } else {
1132 let msg = format!("Expected a literal (literal string, number, character or etc), got {}.", token);
1133 return Err(syn::parse::Error::new_spanned(token, msg));
1134 }
1135 }
1136 let out_str: String = accumulator.into_iter().collect();
1137 return Ok(out_str);
1138}
1139
1140pub fn concatHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1146 let mut output = TokenStream2::new();
1147 let mut variables = v.clone();
1148 let mut stream = t.into_iter();
1149 let concat_token = stream.next();
1150 if let Some(TokenTree2::Ident(name)) = concat_token.clone() {
1151 let mut temp = TokenStream2::new();
1152 temp.extend(stream);
1153 let new_token_stream = do_with_in_explicit(temp, c.clone(), v.clone());
1154 match concatHandlerInner(c.clone(), v.clone(), new_token_stream) {
1155 Ok(it) => output.extend(TokenStream2::from(TokenTree2::Literal(proc_macro2::Literal::string(&it)))),
1156 Err(err) => return Err((v, err.to_compile_error())),
1157 }
1158 } else if let Some(it) = concat_token.clone() {
1159 let msg = format!("Expected 'concat' to absolutely start a concat expression, got {}.", it);
1160 let sp = concat_token.span();
1161 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
1162 }
1163 return Ok((v, output));
1164}
1165
1166pub fn naiveStringifierHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1173 let mut stream = match do_with_in_explicit2(t, c.clone(), v.clone()) {
1174 Ok((_, x)) => x,
1175 x => return x,
1176 }.into_iter();
1177 stream.next();
1178 let mut midput = TokenStream2::new();
1179 midput.extend(stream);
1180 let output = format!("{}", midput);
1181 Ok((v, quote!{ #output }))
1182}
1183
1184pub fn string_to_identHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1190 let mut output = TokenStream2::new();
1191 let mut variables = v.clone();
1192 let mut stream = t.into_iter();
1193 let string_to_ident_token = stream.next();
1194 if let Some(TokenTree2::Ident(name)) = string_to_ident_token.clone() {
1195 let mut temp = TokenStream2::new();
1196 temp.extend(stream);
1197 let mut new_token_stream_iter = do_with_in_explicit(temp, c.clone(), v.clone()).into_iter();
1198 match new_token_stream_iter.next() {
1199 Some(TokenTree2::Literal(lit)) => {
1200 let real_lit = syn::parse_str::<syn::Lit>(&lit.clone().to_string());
1201 match real_lit {
1202 Ok(syn::Lit::Str(it)) => output.extend(TokenStream2::from(TokenTree2::Ident(proc_macro2::Ident::new(&it.value(), lit.span())))),
1203 Ok(x) => return Err((v, quote!{compile_error!{ "Expected a string." }})),
1204 Err(err) => return Err((v, err.to_compile_error())),
1205 }
1206 },
1207 Some(x) => {
1208 let msg = format!("Expected a literal, got {}.", x);
1209 return Err((v, quote!{compile_error!{ #msg }}));
1210 },
1211 None => return Err((v, quote!{compile_error!{ "No string given; cannot create identifier." }})),
1212 }
1213 } else if let Some(it) = string_to_ident_token {
1214 let msg = format!("Expected 'string_to_ident' to absolutely start a string_to_ident expression, got {}.", it);
1215 return Err((v, quote!{compile_error!{ #msg }}));
1216 }
1217 return Ok((v, output));
1218}
1219
1220pub fn forHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1221 let mut output = TokenStream2::new();
1222 let mut variables = v.clone();
1223 let mut stream = t.into_iter();
1224 let for_token = stream.next();
1225 if let Some(TokenTree2::Ident(name)) = for_token.clone() {
1226 match stream.next() {
1227 Some(TokenTree2::Ident(var_token)) => {
1228 },
1230 Some(x) =>{},
1231 _ =>{},
1232 }
1233 } else if let Some(it) = for_token {
1234 let msg = format!("Expected 'for' to absolutely start a for expression, got {}.", it);
1235 return Err((v, quote!{compile_error!{ #msg }}));
1236 } else {
1237 return Err((v, quote!{compile_error!{ "For expression stream was unexpectedly empty." }}));
1238 }
1239 Ok((v, output))
1240}
1241
1242enum Operator {
1243 Plus,
1244 Times,
1245 Minus,
1246 Division,
1247 Remainder,
1248 ShiftLeft,
1249 ShiftRight,
1250 And,
1251 Xor,
1252 Or,
1253}
1254
1255
1256trait HoistAsFromUsize {
1257 fn fromUsize(it: usize) -> Self;
1258}
1259
1260macro_rules! mkHoistAsFromUsize {
1261 ($from: ty) => {
1262 impl HoistAsFromUsize for $from {
1263 fn fromUsize(it: usize) -> Self {
1264 it as $from
1265 }
1266 }
1267 }
1268}
1269
1270mkHoistAsFromUsize!(u8);
1271mkHoistAsFromUsize!(i8);
1272mkHoistAsFromUsize!(u16);
1273mkHoistAsFromUsize!(i16);
1274mkHoistAsFromUsize!(u32);
1275mkHoistAsFromUsize!(i32);
1276mkHoistAsFromUsize!(u64);
1277mkHoistAsFromUsize!(i64);
1278mkHoistAsFromUsize!(f32);
1279mkHoistAsFromUsize!(f64);
1280mkHoistAsFromUsize!(usize);
1281mkHoistAsFromUsize!(isize);
1282
1283#[derive(PartialEq, Eq)]
1284enum ArithmeticLeft<N: Copy + std::str::FromStr + std::ops::Add<Output=N> + std::ops::Div<Output=N> + std::ops::Mul<Output=N> + std::ops::Sub<Output=N> + std::ops::Rem<Output=N> + std::cmp::PartialOrd + std::cmp::PartialEq + HoistAsFromUsize + MaybeShiftable + std::fmt::Display> {
1285 None,
1286 Num(N),
1287 GetSize,
1288 Not,
1289}
1290
1291macro_rules! mkSizeOf {
1292 ($token: ident, $($cmd: literal, $it: ty),+) => {
1293 match $token.clone() {
1294 $(TokenTree2::Ident(ty) if ty.to_string() == $cmd => return Ok(N::fromUsize(std::mem::size_of::<$it>())),)+
1295 it => {
1296 let msg = format!("Expected the name of a primitive number type to get the size of, got {}", it);
1297 return Err(syn::parse::Error::new_spanned($token, msg));
1298 },
1299 }
1300 }
1301}
1302
1303trait MaybeShiftable: Sized {
1304 fn shl(self, right: Self) -> Option<Self>;
1305 fn shr(self, right: Self) -> Option<Self>;
1306 fn and(self, right: Self) -> Option<Self>;
1307 fn xor(self, right: Self) -> Option<Self>;
1308 fn or(self, right: Self) -> Option<Self>;
1309 fn not(self) -> Option<Self>;
1310 const shiftable: bool;
1311}
1312
1313macro_rules! can_shift {
1314 ($it: ty) => {
1315 impl MaybeShiftable for $it {
1316 const shiftable: bool = true;
1317 fn shl(self, right: Self) -> Option<Self> {
1318 Some(self << right)
1319 }
1320 fn shr(self, right: Self) -> Option<Self> {
1321 Some(self >> right)
1322 }
1323 fn and(self, right: Self) -> Option<Self> {
1324 Some(self & right)
1325 }
1326 fn xor(self, right: Self) -> Option<Self> {
1327 Some(self ^ right)
1328 }
1329 fn or(self, right: Self) -> Option<Self> {
1330 Some(self | right)
1331 }
1332 fn not(self) -> Option<Self> {
1333 Some(!self)
1334 }
1335 }
1336 }
1337}
1338
1339macro_rules! cannot_shift {
1340 ($it: ty) => {
1341 impl MaybeShiftable for $it {
1342 const shiftable: bool = false;
1343 fn shl(self, right: Self) -> Option<Self> {
1344 None
1345 }
1346 fn shr(self, right: Self) -> Option<Self> {
1347 None
1348 }
1349 fn and(self, right: Self) -> Option<Self> {
1350 None
1351 }
1352 fn xor(self, right: Self) -> Option<Self> {
1353 None
1354 }
1355 fn or(self, right: Self) -> Option<Self> {
1356 None
1357 }
1358 fn not(self) -> Option<Self> {
1359 None
1360 }
1361 }
1362 }
1363}
1364
1365can_shift!(u8);
1366can_shift!(i8);
1367can_shift!(u16);
1368can_shift!(i16);
1369can_shift!(u32);
1370can_shift!(i32);
1371can_shift!(u64);
1372can_shift!(i64);
1373can_shift!(usize);
1374can_shift!(isize);
1375cannot_shift!(f32);
1376cannot_shift!(f64);
1377
1378trait MaybeNegable: Sized {
1379 fn neg(self) -> Option<Self>;
1380 const negable: bool;
1381 fn name() -> &'static str;
1382}
1383
1384macro_rules! can_neg {
1385 ($it: ty, $name: ident) => {
1386 impl MaybeNegable for $it {
1387 const negable: bool = true;
1388 fn name() -> &'static str {
1389 $name
1390 }
1391 fn neg(self) -> Option<Self> {
1392 Some(<$it>::default() - self)
1393 }
1394 }
1395 }
1396}
1397
1398macro_rules! cannot_neg {
1399 ($it: ty, $name: ident) => {
1400 impl MaybeNegable for $it {
1401 const negable: bool = false;
1402 fn name() -> &'static str {
1403 $name
1404 }
1405 fn neg(self) -> Option<Self> {
1406 None
1407 }
1408 }
1409 }
1410}
1411
1412const name_u8: &str = "u8";
1413const name_i8: &str = "i8";
1414const name_u16: &str = "u16";
1415const name_i16: &str = "i16";
1416const name_u32: &str = "u32";
1417const name_i32: &str = "i32";
1418const name_u64: &str = "u64";
1419const name_i64: &str = "i64";
1420const name_usize: &str = "usize";
1421const name_isize: &str = "isize";
1422const name_f32: &str = "f32";
1423const name_f64: &str = "f64";
1424
1425cannot_neg!(u8, name_u8);
1426can_neg!(i8, name_i8);
1427cannot_neg!(u16, name_u16);
1428can_neg!(i16, name_i16);
1429cannot_neg!(u32, name_u32);
1430can_neg!(i32, name_i32);
1431cannot_neg!(u64, name_u64);
1432can_neg!(i64, name_i64);
1433cannot_neg!(usize, name_usize);
1434can_neg!(isize, name_isize);
1435can_neg!(f32, name_f32);
1436can_neg!(f64, name_f64);
1437
1438
1439
1440fn arithmeticInternal<T: StartMarker + Clone, N: Copy + std::str::FromStr + std::ops::Add<Output=N> + std::ops::Div<Output=N> + std::ops::Mul<Output=N> + std::ops::Sub<Output=N> + std::ops::Rem<Output=N> + std::cmp::PartialOrd + std::cmp::PartialEq + HoistAsFromUsize + MaybeShiftable + MaybeNegable + std::fmt::Display>(c: Configuration<T>, v: Variables<T>, t: TokenStream2) -> syn::parse::Result<N> where <N as std::str::FromStr>::Err: std::fmt::Display {
1441 let mut left: ArithmeticLeft<N> = ArithmeticLeft::None;
1442 let mut operator: Option<Operator> = None;
1443 let mut negation: bool = false;
1444 for token in t.clone().into_iter() {
1445 match left {
1446 ArithmeticLeft::None | ArithmeticLeft::Not => {
1447 let not = (left == ArithmeticLeft::Not);
1448 left = match token.clone() {
1449 TokenTree2::Punct(punct) if (punct.spacing() == proc_macro2::Spacing::Alone) && (punct.as_char() == '-') => {
1450 negation = !negation;
1451 left
1452 },
1453 TokenTree2::Literal(lit) => {
1454 ArithmeticLeft::Num(match syn::parse_str::<syn::LitInt>(&lit.to_string()) {
1455 Ok(x) => match x.base10_parse::<N>() {
1456 Ok(x) => if negation { match x.neg() {
1457 Some(x) => {
1458 negation = false;
1459 x
1460 },
1461 None => {
1462 let x_typename = N::name();
1463 let msg = format!("Tried to negate an unsigned number of type {}", x_typename);
1464 return Err(syn::parse::Error::new_spanned(token, msg));
1465 },
1466 } } else { x },
1467 Err(y) => {
1468 match syn::parse_str::<syn::LitFloat>(&lit.to_string()) {
1469 Ok(x) => match x.base10_parse::<N>() {
1470 Ok(x) => if negation { match x.neg() {
1471 Some(x) => {
1472 negation = false;
1473 x
1474 },
1475 None => {
1476 let x_typename = N::name();
1477 let msg = format!("Tried to negate an unsigned number of type {}", x_typename);
1478 return Err(syn::parse::Error::new_spanned(token, msg));
1479 },
1480 } } else { x },
1481 Err(y) => {
1482 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1483 return Err(syn::parse::Error::new_spanned(token, msg));
1484 },
1485 },
1486 Err(y) => {
1487 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1488 return Err(syn::parse::Error::new_spanned(token, msg));
1489 },
1490 }
1491 },
1492 },
1493 Err(y) => {
1494 match syn::parse_str::<syn::LitFloat>(&lit.to_string()) {
1495 Ok(x) => match x.base10_parse::<N>() {
1496 Ok(x) => if negation { match x.neg() {
1497 Some(x) => {
1498 negation = false;
1499 x
1500 },
1501 None => {
1502 let x_typename = N::name();
1503 let msg = format!("Tried to negate an unsigned number of type {}", x_typename);
1504 return Err(syn::parse::Error::new_spanned(token, msg));
1505 },
1506 } } else { x },
1507 Err(y) => {
1508 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1509 return Err(syn::parse::Error::new_spanned(token, msg));
1510 },
1511 },
1512 Err(y) => {
1513 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1514 return Err(syn::parse::Error::new_spanned(token, msg));
1515 },
1516 }
1517 },
1518 })
1519 },
1520 TokenTree2::Group(grp) => ArithmeticLeft::Num(arithmeticInternal::<T, N>(c.clone(), v.clone(), grp.stream())?),
1521 TokenTree2::Ident(op) if op.to_string() == "size_of" => ArithmeticLeft::GetSize,
1522 TokenTree2::Ident(op) if op.to_string() == "not" => ArithmeticLeft::Not,
1523 it => {
1524 let msg = format!("Expected number, got {}", it);
1525 return Err(syn::parse::Error::new_spanned(token, msg));
1526 },
1527 };
1528 left = (if not { match left {
1529 ArithmeticLeft::Num(x) => ArithmeticLeft::Num(x.not().unwrap()),
1530 x => x,
1531 } } else { left })
1532 },
1533 ArithmeticLeft::Num(num) => {
1534 match operator {
1535 None => {
1536 match token.clone() {
1537 TokenTree2::Punct(punct) => {
1538 match punct.as_char() {
1539 '+' if punct.spacing() == proc_macro2::Spacing::Alone => {
1540 operator = Some(Operator::Plus);
1541 },
1542 '-' if punct.spacing() == proc_macro2::Spacing::Alone => {
1543 operator = Some(Operator::Minus);
1544 },
1545 '*' if punct.spacing() == proc_macro2::Spacing::Alone => {
1546 operator = Some(Operator::Times);
1547 },
1548 '/' if punct.spacing() == proc_macro2::Spacing::Alone => {
1549 operator = Some(Operator::Division);
1550 },
1551 '%' if punct.spacing() == proc_macro2::Spacing::Alone => {
1552 operator = Some(Operator::Remainder);
1553 },
1554 '>' if punct.spacing() == proc_macro2::Spacing::Alone => {
1555 operator = Some(Operator::ShiftLeft);
1556 },
1557 '<' if punct.spacing() == proc_macro2::Spacing::Alone => {
1558 operator = Some(Operator::ShiftRight);
1559 },
1560 '&' if punct.spacing() == proc_macro2::Spacing::Alone => {
1561 operator = Some(Operator::And);
1562 },
1563 '^' if punct.spacing() == proc_macro2::Spacing::Alone => {
1564 operator = Some(Operator::Xor);
1565 },
1566 '|' if punct.spacing() == proc_macro2::Spacing::Alone => {
1567 operator = Some(Operator::Or);
1568 },
1569 it => {
1570 let msg = format!("Expected operator such as +, *, -, /, %, >, or <, got {}", it);
1571 return Err(syn::parse::Error::new_spanned(token, msg));
1572 },
1573 }
1574 left = ArithmeticLeft::Num(num);
1575 },
1576 it => {
1577 let msg = format!("Expected operator such as +, *, -, or /, got {}", it);
1578 return Err(syn::parse::Error::new_spanned(token, msg));
1579 },
1580 }
1581 },
1582 Some(ref op) => {
1583 let right = match token.clone() {
1584 TokenTree2::Punct(punct) if (punct.spacing() == proc_macro2::Spacing::Alone) && (punct.as_char() == '-') => {
1585 negation = !negation;
1586 continue
1587 },
1588 TokenTree2::Literal(lit) => {
1589 match syn::parse_str::<syn::LitInt>(&lit.to_string()) {
1590 Ok(x) => match x.base10_parse::<N>() {
1591 Ok(x) => if negation { match x.neg() {
1592 Some(x) => {
1593 negation = false;
1594 x
1595 },
1596 None => {
1597 let x_typename = N::name();
1598 let msg = format!("Tried to negate an unsigned number of type {}", x_typename);
1599 return Err(syn::parse::Error::new_spanned(token, msg));
1600 },
1601 } } else { x },
1602 Err(y) => {
1603 match syn::parse_str::<syn::LitFloat>(&lit.to_string()) {
1604 Ok(x) => match x.base10_parse::<N>() {
1605 Ok(x) => if negation { match x.neg() {
1606 Some(x) => {
1607 negation = false;
1608 x
1609 },
1610 None => {
1611 let x_typename = N::name();
1612 let msg = format!("Tried to negate an unsigned number of type {}", x_typename);
1613 return Err(syn::parse::Error::new_spanned(token, msg));
1614 },
1615 } } else { x },
1616 Err(y) => {
1617 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1618 return Err(syn::parse::Error::new_spanned(token, msg));
1619 },
1620 },
1621 Err(y) => {
1622 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1623 return Err(syn::parse::Error::new_spanned(token, msg));
1624 },
1625 }
1626 },
1627 },
1628 Err(y) => {
1629 match syn::parse_str::<syn::LitFloat>(&lit.to_string()) {
1630 Ok(x) => match x.base10_parse::<N>() {
1631 Ok(x) => if negation { match x.neg() {
1632 Some(x) => {
1633 negation = false;
1634 x
1635 },
1636 None => {
1637 let x_typename = N::name();
1638 let msg = format!("Tried to negate an unsigned number of type {}", x_typename);
1639 return Err(syn::parse::Error::new_spanned(token, msg));
1640 },
1641 } } else { x },
1642 Err(y) => {
1643 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1644 return Err(syn::parse::Error::new_spanned(token, msg));
1645 },
1646 },
1647 Err(y) => {
1648 let msg = format!("Expected a number inside an arithmetic handler, got {}", lit);
1649 return Err(syn::parse::Error::new_spanned(token, msg));
1650 },
1651 }
1652 },
1653 }
1654 },
1655 TokenTree2::Group(grp) => arithmeticInternal::<T, N>(c.clone(), v.clone(), grp.stream())?,
1656 it => {
1657 let msg = format!("Expected number, got {}", it);
1658 return Err(syn::parse::Error::new_spanned(token, msg));
1659 },
1660 };
1661 left = ArithmeticLeft::Num(match op {
1662 Operator::Plus => num + right,
1663 Operator::Times => num * right,
1664 Operator::Minus => num - right,
1665 Operator::Division => num / right,
1666 Operator::Remainder => num % right,
1667 Operator::ShiftLeft => match num.shl(right) {
1668 Some(n) => n,
1669 None => {
1670 let msg = format!("Tried to shift left {} by {}; this does not work - shift only works on integral types.", num, right);
1671 return Err(syn::parse::Error::new_spanned(token, msg));
1672 },
1673 },
1674 Operator::ShiftRight => match num.shr(right) {
1675 Some(n) => n,
1676 None => {
1677 let msg = format!("Tried to shift right {} by {}; this does not work - shift only works on integral types.", num, right);
1678 return Err(syn::parse::Error::new_spanned(token, msg));
1679 },
1680 },
1681 Operator::Xor => match num.xor(right) {
1682 Some(n) => n,
1683 None => {
1684 let msg = format!("Tried to xor {} by {}; this does not work - xor only works on integral types.", num, right);
1685 return Err(syn::parse::Error::new_spanned(token, msg));
1686 },
1687 },
1688 Operator::And => match num.and(right) {
1689 Some(n) => n,
1690 None => {
1691 let msg = format!("Tried to and {} by {}; this does not work - and only works on integral types.", num, right);
1692 return Err(syn::parse::Error::new_spanned(token, msg));
1693 },
1694 },
1695 Operator::Or => match num.or(right) {
1696 Some(n) => n,
1697 None => {
1698 let msg = format!("Tried to or {} by {}; this does not work - shift only works on integral types.", num, right);
1699 return Err(syn::parse::Error::new_spanned(token, msg));
1700 },
1701 },
1702 }); operator = None;
1704 },
1705 }
1706 },
1707 ArithmeticLeft::GetSize => {
1708 mkSizeOf!(token, "u8", u8, "u16", u16, "u32", u32, "u64", u64, "i8", i8, "i16", i16, "i32", i32, "i64", i64, "f32", f32, "f64", f64, "usize", usize, "isize", isize)
1709 },
1710 }
1711 }
1712 return match left {
1713 ArithmeticLeft::Num(n) => Ok(n),
1714 _ => Err(syn::parse::Error::new_spanned(t, "No numbers found.")),
1715 };
1716}
1717
1718pub fn arithmeticHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1789 let mut output = TokenStream2::new();
1790 let mut variables = v.clone();
1791 let mut stream = t.into_iter();
1792 let ar_token = stream.next();
1793 if let Some(TokenTree2::Ident(name)) = ar_token.clone() {
1794 let mut temp = TokenStream2::new();
1795 temp.extend(stream);
1796 let new_token_stream = match do_with_in_explicit2(temp, c.clone(), v.clone()) {
1797 Ok((_, a)) => a,
1798 e => return e,
1799 };
1800 let mut new_token_stream_iter = new_token_stream.into_iter();
1801 match new_token_stream_iter.next() {
1802 Some(TokenTree2::Ident(var_token)) => {
1803 let mut temp2 = TokenStream2::new();
1804 temp2.extend(new_token_stream_iter);
1805 match var_token.to_string().as_str() {
1807 a @ ("u64" | "u64u") => {
1808 let thing = if a == "u64" { proc_macro2::Literal::u64_suffixed } else { proc_macro2::Literal::u64_unsuffixed };
1809 let out = thing(match arithmeticInternal::<T, u64>(c.clone(), v.clone(), temp2) {
1810 Ok(x) => x,
1811 Err(err) => return Err((v, err.to_compile_error())),
1812 });
1813 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1814 },
1815 a @ ("u32" | "u32u") => {
1816 let thing = if a == "u32" { proc_macro2::Literal::u32_suffixed } else { proc_macro2::Literal::u32_unsuffixed };
1817 let out = thing(match arithmeticInternal::<T, u32>(c.clone(), v.clone(), temp2) {
1818 Ok(x) => x,
1819 Err(err) => return Err((v, err.to_compile_error())),
1820 });
1821 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1822 },
1823 a @ ("u16" | "u16u") => {
1824 let thing = if a == "u16" { proc_macro2::Literal::u16_suffixed } else { proc_macro2::Literal::u16_unsuffixed };
1825 let out = thing(match arithmeticInternal::<T, u16>(c.clone(), v.clone(), temp2) {
1826 Ok(x) => x,
1827 Err(err) => return Err((v, err.to_compile_error())),
1828 });
1829 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1830 },
1831 a @ ("u8" | "u8u") => {
1832 let thing = if a == "u8" { proc_macro2::Literal::u8_suffixed } else { proc_macro2::Literal::u8_unsuffixed };
1833 let out = thing(match arithmeticInternal::<T, u8>(c.clone(), v.clone(), temp2) {
1834 Ok(x) => x,
1835 Err(err) => return Err((v, err.to_compile_error())),
1836 });
1837 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1838 },
1839 a @ ("i64" | "i64u") => {
1840 let thing = if a == "i64" { proc_macro2::Literal::i64_suffixed } else { proc_macro2::Literal::i64_unsuffixed };
1841 let out = thing(match arithmeticInternal::<T, i64>(c.clone(), v.clone(), temp2) {
1842 Ok(x) => x,
1843 Err(err) => return Err((v, err.to_compile_error())),
1844 });
1845 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1846 },
1847 a @ ("i32" | "i32u") => {
1848 let thing = if a == "i32" { proc_macro2::Literal::i32_suffixed } else { proc_macro2::Literal::i32_unsuffixed };
1849 let out = thing(match arithmeticInternal::<T, i32>(c.clone(), v.clone(), temp2) {
1850 Ok(x) => x,
1851 Err(err) => return Err((v, err.to_compile_error())),
1852 });
1853 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1854 },
1855 a @ ("i16" | "i16u") => {
1856 let thing = if a == "i16" { proc_macro2::Literal::i16_suffixed } else { proc_macro2::Literal::i16_unsuffixed };
1857 let out = thing(match arithmeticInternal::<T, i16>(c.clone(), v.clone(), temp2) {
1858 Ok(x) => x,
1859 Err(err) => return Err((v, err.to_compile_error())),
1860 });
1861 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1862 },
1863 a @ ("i8" | "i8u") => {
1864 let thing = if a == "i8" { proc_macro2::Literal::i8_suffixed } else { proc_macro2::Literal::i8_unsuffixed };
1865 let out = thing(match arithmeticInternal::<T, i8>(c.clone(), v.clone(), temp2) {
1866 Ok(x) => x,
1867 Err(err) => return Err((v, err.to_compile_error())),
1868 });
1869 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1870 },
1871 a @ ("f64" | "f64u") => {
1872 let thing = if a == "f64" { proc_macro2::Literal::f64_suffixed } else { proc_macro2::Literal::f64_unsuffixed };
1873 let out = thing(match arithmeticInternal::<T, f64>(c.clone(), v.clone(), temp2) {
1874 Ok(x) => x,
1875 Err(err) => return Err((v, err.to_compile_error())),
1876 });
1877 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1878 },
1879 a @ ("f32" | "f32u") => {
1880 let thing = if a == "f32" { proc_macro2::Literal::f32_suffixed } else { proc_macro2::Literal::f32_unsuffixed };
1881 let out = thing(match arithmeticInternal::<T, f32>(c.clone(), v.clone(), temp2) {
1882 Ok(x) => x,
1883 Err(err) => return Err((v, err.to_compile_error())),
1884 });
1885 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1886 },
1887 a @ ("usize" | "usizeu") => {
1888 let thing = if a == "usize" { proc_macro2::Literal::usize_suffixed } else { proc_macro2::Literal::usize_unsuffixed };
1889 let out = thing(match arithmeticInternal::<T, usize>(c.clone(), v.clone(), temp2) {
1890 Ok(x) => x,
1891 Err(err) => return Err((v, err.to_compile_error())),
1892 });
1893 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1894 },
1895 a @ ("isize" | "isizeu") => {
1896 let thing = if a == "isize" { proc_macro2::Literal::isize_suffixed } else { proc_macro2::Literal::isize_unsuffixed };
1897 let out = thing(match arithmeticInternal::<T, isize>(c.clone(), v.clone(), temp2) {
1898 Ok(x) => x,
1899 Err(err) => return Err((v, err.to_compile_error())),
1900 });
1901 output.extend(TokenStream2::from(TokenTree2::Literal(out)).into_iter());
1902 },
1903 it => {
1904 let msg = format!("Expected number type (u64, i64, f64, etc), got {}.", it);
1905 let sp = var_token.span();
1906 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
1907 }
1908 }
1909 },
1910 Some(x) => {},
1911 _ => {},
1912 }
1913 } else if let Some(it) = ar_token {
1914 let msg = format!("Expected 'arithmetic' first, got {}.", it);
1915 return Err((v, quote!{compile_error!{ #msg }}));
1916 } else {
1917 return Err((v, quote!{compile_error!{ "Arithmetic expression stream was unexpectedly empty." }}));
1918 }
1919 Ok((v, output))
1920}
1921
1922pub fn withSigilHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1946 let mut temp = t.into_iter();
1947 let name_anchor = temp.next().span(); let c_out = match temp.next() {
1949 Some(TokenTree2::Punct(p)) if p.as_char() == '$' => {
1950 Configuration::<T> {
1951 sigil: Sigil::Dollar,
1952 ..c
1953 }
1954 },
1955 Some(TokenTree2::Punct(p)) if p.as_char() == '%' => {
1956 Configuration::<T> {
1957 sigil: Sigil::Percent,
1958 ..c
1959 }
1960 },
1961 Some(TokenTree2::Punct(p)) if p.as_char() == '~' => {
1962 Configuration::<T> {
1963 sigil: Sigil::Tilde,
1964 ..c
1965 }
1966 },
1967 Some(TokenTree2::Punct(p)) if p.as_char() == '#' => {
1968 Configuration::<T> {
1969 sigil: Sigil::Hash,
1970 ..c
1971 }
1972 },
1973 Some(x) => {
1974 let msg = format!("Expected a raw sigil ($, %, ~, #) for withSigil, got {}.", x);
1975 return Err((v, quote_spanned!{name_anchor=> compile_error!{ #msg }}));
1976 },
1977 None => {
1978 let msg = "Expected a raw sigil ($, %, ~, #) for withSigil (and then some code to run as the next argument), but the input stopped early.";
1979 return Err((v, quote_spanned!{name_anchor=> compile_error!{ #msg }}));
1980 },
1981 };
1982 let mut tokens = TokenStream2::new();
1983 tokens.extend(temp);
1984 do_with_in_explicit2(tokens, c_out, v.clone())
1985}
1986pub fn actually_escape<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1987 todo!()
1988}
1989pub fn escape<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
1990 let mut stream = t.into_iter();
1991 stream.next(); let mut out = TokenStream2::new();
1993 out.extend(stream);
1994 match c.escaping_style {
1995 Escaping::None => Ok((v, out)),
1996 Escaping::Double => actually_escape(c, v, data, quote!{ Double #out }),
1997 Escaping::Backslash => actually_escape(c, v, data, quote!{ Backslash #out }),
1998 }
1999}
2000
2001pub fn actually_unescape<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2002 todo!()
2003}
2004pub fn unescape<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2005 match c.escaping_style {
2006 Escaping::None => Ok((v, t)),
2007 Escaping::Double => actually_unescape(c, v, data, quote!{ Double #t }),
2008 Escaping::Backslash => actually_unescape(c, v, data, quote!{ Backslash #t }),
2009 }
2010}
2011
2012pub fn run<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2018 let mut temp = t.into_iter();
2019 temp.next();
2020 let mut code = TokenStream2::new();
2021 code.extend(temp);
2022 let (v2, in_it) = do_with_in_explicit2(code, c.clone(), v)?;
2023 do_with_in_explicit2(in_it, c.clone(), v2)
2024}
2025pub fn quote<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2032 let out = match c.sigil {
2034 Sigil::Dollar => quote!{ $(#t) },
2035 Sigil::Percent => quote!{ %(#t) },
2036 Sigil::Hash => quote!{ #(#t) },
2037 Sigil::Tilde => quote!{ ~(#t) },
2038 };
2039 Ok((v, out))
2040}
2041
2042pub fn unquote<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2048 let mut out: TokenStream2 = quote!{compile_error!{"Nothing here."}};
2049 let sig_char = match format!("{}", c.sigil).pop() {
2050 Some(x) => x,
2051 None => {
2052 let sp = t.span();
2053 return Err((v, quote_spanned!{sp=> compile_error!{ "Expected Sigil to have a character." }}));
2054 },
2055 };
2056 let mut stream = t.clone().into_iter();
2057 check_token_ret!(v, t, uq, Some(TokenTree2::Ident(uq)), stream.next(), "Expected 'unquote' to be the name of the handler called.", uq.to_string() == "unquote", "Expected 'unquote' to be the name of the handler called.");
2058 let mut temp = TokenStream2::new();
2059 temp.extend(stream);
2060 let (_, mut as_run) = do_with_in_explicit2(temp, c.clone(), v.clone())?;
2061 let mut stream = as_run.into_iter();
2062 check_token_ret!(v, t, sig, Some(TokenTree2::Punct(sig)), stream.next(), "Expected a quote.", sig.as_char() == sig_char, "Expected a quote.");
2063 let tc = stream.next();
2064 match tc.clone() {
2065 Some(TokenTree2::Group(the_call)) => {
2066 let mut inner_stream = the_call.stream().into_iter();
2067 check_token_ret!(v, t, q, Some(TokenTree2::Ident(q)), inner_stream.next(), "Expected 'quote'.", q.to_string() == "quote", "Expected 'quote'.");
2068 out = TokenStream2::new();
2069 out.extend(inner_stream);
2070 },
2071 Some(x) => {
2072 let msg = format!("Expected a call body, got {}.", x);
2073 let sp = t.span();
2074 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2075 },
2076 None => {
2077 let sp = t.span();
2078 return Err((v, quote_spanned!{sp=> compile_error!{ "Args ended early; still expecting a call body." }}));
2079 },
2080 };
2081 Ok((v, out))
2094}
2095
2096#[derive(Debug,Clone)]
2097enum LogicBoolOp {
2098 And,
2099 Or,
2100 Not,
2101 Equals,
2102 NotEquals,
2103}
2104fn logicInternalBool<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2105 let mut left: Option<bool> = None;
2106 let mut operator: Option<LogicBoolOp> = None;
2107 for token in t.clone().into_iter() {
2108 match left {
2109 None => {
2110 left = Some(match token.clone() {
2111 TokenTree2::Ident(x) if x.to_string() == "true" => true,
2112 TokenTree2::Ident(x) if x.to_string() == "false" => false,
2113 x => {
2114 let msg = format!{"Expected true or false on the lhs of a logic expression; got {}.", x};
2115 let sp = x.span();
2116 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2117 },
2118 });
2119 },
2120 Some(inner_left) => {
2121 match operator {
2122 None => {
2123 match token.clone() {
2124 TokenTree2::Punct(x) if x.as_char() == '&' => {
2125 operator = Some(LogicBoolOp::And);
2126 },
2127 TokenTree2::Punct(x) if x.as_char() == '|' => {
2128 operator = Some(LogicBoolOp::Or);
2129 },
2130 TokenTree2::Punct(x) if x.as_char() == '=' => {
2131 operator = Some(LogicBoolOp::Equals);
2132 },
2133 TokenTree2::Punct(x) if x.as_char() == '^' => {
2134 operator = Some(LogicBoolOp::NotEquals);
2135 },
2136 x => {
2137 let msg = format!{"Expected & | = or ^ in a logic expression; got {:?}.", x};
2138 let sp = x.span();
2139 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2140 },
2141 }
2142 },
2143 Some(op) => {
2144 let right = match token {
2146 TokenTree2::Ident(x) if x.to_string() == "true" => true,
2147 TokenTree2::Ident(x) if x.to_string() == "false" => false,
2148 TokenTree2::Group(inner) => {
2149 let mut rhs = TokenStream2::new();
2150 rhs.extend(inner.clone().stream());
2151 let (_, it) = logicInternal(c.clone(), v.clone(), data.clone(), rhs)?;
2152 let out = match it.into_iter().next() {
2153 Some(TokenTree2::Ident(x)) if x.to_string() == "true" => true,
2154 Some(TokenTree2::Ident(x)) if x.to_string() == "false" => false,
2155 Some(x) => {
2156 let msg = format!{"Expected true or false on the rhs of a logic expression; got {}.", x};
2157 let sp = x.span();
2158 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2159 },
2160 None => {
2161 let msg = "Expected true or false on the rhs of a logic expression; got nothing.";
2162 let sp = inner.span();
2163 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2164 },
2165 };
2166 out
2167 },
2168 x => {
2169 let msg = format!{"Expected true or false on the rhs of a logic expression; got {}.", x};
2170 let sp = x.span();
2171 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2172 },
2173 };
2174 let out = match op {
2175 LogicBoolOp::And => {
2176 inner_left & right
2177 },
2178 LogicBoolOp::Or => {
2179 inner_left | right
2180 },
2181 LogicBoolOp::Equals => {
2182 inner_left == right
2183 },
2184 LogicBoolOp::NotEquals => {
2185 inner_left != right
2186 },
2187 x => {
2188 let msg = format!{"Expected & | = or ^ in a logic expression; got {:?}.", x};
2189 return Err((v, quote!{compile_error!{ #msg }}));
2190 },
2191 };
2192 return Ok((v, quote!{#out}));
2193 },
2194 }
2195 },
2196 }
2197 };
2198 let out = match left {
2199 None => {
2200 let msg = format!{"Missed a turn somewhere; left = {:?}, operator = {:?}, t = {:?} .", left, operator, t};
2201 return Err((v, quote!{compile_error!{ #msg }}));
2202 },
2203 Some(x) => {
2204 quote!{#x}
2205 },
2206 };
2207 Ok((v, out))
2208}
2209
2210enum NumOp {
2211 Lt,
2212 Le,
2213 Gt,
2214 Ge,
2215 Equal,
2216 NotEqual,
2217}
2218
2219fn logicInternalNum<T: StartMarker + Clone, N: std::cmp::PartialOrd + std::cmp::PartialEq + std::str::FromStr>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2, _fake: N) -> StageResult<T> where <N as std::str::FromStr>::Err: std::fmt::Debug {
2220 let mut stream = t.clone().into_iter().peekable();
2221 let left: N = match stream.next() {
2222 None => {
2223 let msg = "No number on the left when trying to compare numbers.";
2224 let sp = t.span();
2225 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2226 },
2227 Some(TokenTree2::Literal(x)) => {
2228 let lit = x.to_string();
2229 let num: N = match N::from_str(&lit) {
2230 Ok(x) => x,
2231 Err(y) => {
2232 let msg = format!("Expected number, got {} with error {:?}", lit, y);
2233 let sp = x.span();
2234 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2235 },
2236 };
2237 num
2238 },
2239 Some(x) => {
2240 let msg = format!("No number on the left when trying to compare numbers; got {} instead.", x);
2241 let sp = x.span();
2242 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2243 },
2244 };
2245 let op: NumOp = match stream.next() {
2246 Some(TokenTree2::Punct(x)) if x.as_char() == '=' => {
2247 NumOp::Equal
2248 },
2249 Some(TokenTree2::Punct(x)) if x.as_char() == '<' => {
2250 if let Some(TokenTree2::Punct(eq)) = stream.peek() {
2251 if eq.as_char() == '=' {
2252 stream.next();
2253 NumOp::Le
2254 } else {
2255 let msg = format!("In logic, comparing two numbers, after '<', got Punct, expecting '=', actual: {}.", eq.clone());
2256 let sp = eq.span();
2257 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2258 }
2259 } else {
2260 NumOp::Lt
2261 }
2262 },
2263 Some(TokenTree2::Punct(x)) if x.as_char() == '>' => {
2264 if let Some(TokenTree2::Punct(eq)) = stream.peek() {
2265 if eq.as_char() == '=' {
2266 stream.next();
2267 NumOp::Ge
2268 } else {
2269 let msg = format!("In logic, comparing two numbers, after '>', got Punct, expecting '=', actual: {}.", eq.clone());
2270 let sp = eq.span();
2271 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2272 }
2273 } else {
2274 NumOp::Gt
2275 }
2276 },
2277 Some(TokenTree2::Punct(x)) if x.as_char() == '!' => {
2278 if let Some(TokenTree2::Punct(eq)) = stream.peek() {
2279 if eq.as_char() == '=' {
2280 stream.next();
2281 NumOp::NotEqual
2282 } else {
2283 let msg = format!("In logic, comparing two numbers, after '!', got Punct, expecting '=', actual: {}.", eq.clone());
2284 let sp = eq.span();
2285 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2286 }
2287 } else {
2288 let msg = format!("In logic, comparing two numbers, after '!', expected '=', but got {:?}.", stream.next());
2289 let sp = x.span();
2290 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2291 }
2292 },
2293 Some(x) => {
2294 let msg = format!("No recognised operator found to compare numbers; got {} instead.", x);
2295 let sp = x.span();
2296 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2297 },
2298 None => {
2299 let msg = "No operator when trying to compare numbers.";
2300 let sp = t.span();
2301 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2302 },
2303 };
2304 let result = match stream.next() {
2305 Some(TokenTree2::Literal(x)) => {
2306 let lit = x.clone().to_string();
2307 let right: N = match N::from_str(&lit) {
2308 Ok(x) => x,
2309 Err(e) => {
2310 let msg = format!("Expected number when doing numeric comparison. Got {} with error {:?}", lit, e);
2311 let sp = x.span();
2312 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2313 },
2314 };
2315 match op {
2316 NumOp::Lt => left < right,
2317 NumOp::Le => left <= right,
2318 NumOp::Gt => left > right,
2319 NumOp::Ge => left >= right,
2320 NumOp::Equal => left == right,
2321 NumOp::NotEqual => left != right,
2322 }
2323 },
2324 Some(x) => {
2325 let msg = format!("No number found on the right when trying to compare numbers; got {} instead.", x);
2326 let sp = x.span();
2327 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2328 },
2329 None => {
2330 let msg = "No number on the right when trying to compare numbers.";
2331 let sp = t.span();
2332 return Err((v, quote_spanned!{sp=> compile_error!{ #msg } }));
2333 },
2334 };
2335 Ok((v, quote!{ #result }))
2336}
2337
2338fn logicInternal<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2339 let (_, t) = do_with_in_explicit2(t, c.clone(), v.clone())?;
2340 let mut to_check = t.clone().into_iter();
2342 let all_span = t.clone().span();
2343 match to_check.next() {
2344 None => Err((v, quote_spanned!{all_span=> compile_error!{ "Empty logic expression." }})),
2345 Some(TokenTree2::Punct(x)) if x.as_char() == '!' => {
2346 let mut rest = TokenStream2::new();
2347 rest.extend(to_check);
2348 let (v, out) = logicInternal(c, v, data, rest)?;
2349 return match out.into_iter().next() {
2350 Some(TokenTree2::Ident(x)) if x.to_string() == "true" => Ok((v, quote!{ false })),
2351 Some(TokenTree2::Ident(x)) if x.to_string() == "false" => Ok((v, quote!{ true })),
2352 Some(y) => {
2353 let msg = format!{"Expected a boolean in a not clause, got {:}", y};
2354 let sp = y.span();
2355 Err((v, quote_spanned!{sp=> compile_error!{ #msg }}))
2356 },
2357 None => {
2358 let msg = "Empty not clause.";
2359 let sp = x.span();
2360 Err((v, quote_spanned!{sp=> compile_error!{ #msg }}))
2361 },
2362 };
2363 },
2364 Some(TokenTree2::Ident(x)) if (x.to_string() == "true") || (x.to_string() == "false") => logicInternalBool(c, v, data, t),
2365 Some(TokenTree2::Ident(x)) => {
2366 match x.to_string().as_str() {
2367 "i8" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0i8) },
2368 "u8" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0u8) },
2369 "i16" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0i16) },
2370 "u16" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0u16) },
2371 "i32" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0i32) },
2372 "u32" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0u32) },
2373 "i64" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0i64) },
2374 "u64" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0u64) },
2375 "i128" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0i128) },
2376 "u128" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0u128) },
2377 "f32" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0.0f32) },
2378 "f64" => { let mut lin = TokenStream2::new(); lin.extend(to_check); logicInternalNum(c, v, data, lin, 0.0f64) },
2379 "eq_str" => {
2380 let left: String = match to_check.next() {
2382 None => {
2383 let msg = format!("logic eq_str with no arguments; expected two strings to compare.");
2384 let sp = x.span();
2385 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2386 },
2387 Some(TokenTree2::Literal(x)) => {
2388 x.to_string()
2389 },
2390 Some(y) => {
2391 let msg = format!("Expected a string to compare, got {}.", y);
2392 let sp = y.span();
2393 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2394 },
2395 };
2396 let right: String = match to_check.next() {
2397 None => {
2398 let msg = format!("logic eq_str with only one argument; expected two strings to compare.");
2399 let sp = x.span();
2400 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2401 },
2402 Some(TokenTree2::Literal(x)) => {
2403 x.to_string()
2404 },
2405 Some(y) => {
2406 let msg = format!("Expected a string to compare, got {}.", y);
2407 let sp = y.span();
2408 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2409 },
2410 };
2411 let res = (left == right);
2412 let sp = x.span();
2413 return Ok((v, quote_spanned!{sp=> #res }));
2414 },
2415 y => {
2416 let msg = format!("Expected true, false, a literal number, a numeric type specifier, or 'eq_str'; got {}.", y);
2417 let sp = x.span();
2418 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2419 }
2420 }
2421 }
2422 Some(TokenTree2::Literal(x)) => logicInternalNum(c, v, data, t, 0i128),
2423 Some(TokenTree2::Group(x)) => {
2424 let mut inner = TokenStream2::new();
2425 inner.extend(x.stream());
2426 let (_, left) = logicInternal(c.clone(), v.clone(), data.clone(), inner)?;
2427 let left_first = left.into_iter().next();
2428 match left_first {
2429 None => {
2430 let sp = x.span();
2431 Err((v, quote_spanned!{sp=> compile_error!{ "Empty logic expression." }}))
2432 },
2433 Some(TokenTree2::Ident(x)) if (x.to_string() == "true") || (x.to_string() == "false") => {
2434 let mut new_stream = TokenStream2::new();
2435 new_stream.extend(TokenStream2::from(TokenTree2::Ident(x)));
2436 let mut skip_first = t.into_iter();
2437 skip_first.next();
2438 new_stream.extend(skip_first);
2439 logicInternalBool(c, v, data, new_stream)
2440 },
2441 Some(TokenTree2::Literal(x)) => {
2442 let mut new_stream = TokenStream2::new();
2443 new_stream.extend(TokenStream2::from(TokenTree2::Literal(x)));
2444 let mut skip_first = t.into_iter();
2445 skip_first.next();
2446 new_stream.extend(skip_first);
2447 logicInternalNum(c, v, data, new_stream, 0i128)
2448 },
2449 Some(x) => {
2450 let msg = format!("Problem in logic lhs; expected true, false, or a number, got {}.", x);
2451 let sp = x.span();
2452 Err((v, quote_spanned!{sp=> compile_error!{ #msg }}))
2453 },
2454 }
2455 },
2456 Some(x) => {
2457 let msg = format!("Problem in logic lhs; expected true, false, or a number, got {}.", x);
2458 let sp = x.span();
2459 Err((v, quote_spanned!{sp=> compile_error!{ #msg }}))
2460 }
2461 }
2462}
2463
2464pub fn logicHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data: Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2512 let mut output = TokenStream2::new();
2513 let mut variables = v.clone();
2514 let mut stream = t.into_iter();
2515 let ar_token = stream.next();
2516 if let Some(TokenTree2::Ident(name)) = ar_token.clone() {
2517 if name.to_string() == "logic" {
2518 let mut temp = TokenStream2::new();
2519 temp.extend(stream);
2520 let (_, new_token_stream) = do_with_in_explicit2(temp, c.clone(), v.clone())?;
2521 return logicInternal(c, v, data, new_token_stream);
2522 } else {
2523 let msg = format!("Expected 'logic' first, got {}.", name);
2524 return Err((v, quote!{compile_error!{ #msg }}));
2525 }
2526 } else if let Some(it) = ar_token {
2527 let msg = format!("Expected 'logic' first, got {}.", it);
2528 return Err((v, quote!{compile_error!{ #msg }}));
2529 } else {
2530 return Err((v, quote!{compile_error!{ "Logic expression stream was unexpectedly empty." }}));
2531 }
2532 Ok((v, output))
2533}
2534use std::str::FromStr;
2535use std::io;
2536use std::io::prelude::*;
2537use std::path::{Path, PathBuf};
2538use std::ffi::OsStr;
2539use std::fs::File;
2540macro_rules! getCode {
2541 ($stream: ident, $tokens: ident, $anchor_span: ident, $cnew: ident, $c: ident, $path: ident, $v: ident, $t: ident) => {
2542 let mut reset = false;
2543 let base = match $c.clone().file {
2544 Some(x) => x,
2545 None => file!().to_string(),
2546 };
2547 let mut $path = match Path::new(&base).parent() {
2548 Some(x) => x,
2549 None => {
2550 let msg = format!("'import' can only be invoked from a real file in a real directory; we could not make use of {}", file!());
2552 let sp = $t.span();
2553 return Err(($v, quote_spanned!{sp=> compile_error!{ #msg }}));
2554 },
2555 }.to_path_buf();
2556 let mut $stream = $t.into_iter();
2557 let $anchor_span = $stream.next().span(); let mut cont = true;
2559 let mut final_span = $anchor_span.clone();
2560 while cont {
2561 match $stream.next() {
2562 Some(TokenTree2::Literal(segment)) => {
2563 match syn::parse_str::<syn::LitStr>(&segment.clone().to_string()) {
2564 Ok(x) => {
2565 if reset {
2566 $path = Path::new(&x.value()).to_path_buf();
2567 reset = false;
2568 } else {
2569 $path.push(x.value());
2570 }
2571 },
2572 _ => {
2573 return Err(($v, quote_spanned!{final_span=> compile_error!{"Got a path segment that wasn't a String or Base."}}));
2574 },
2575 };
2576 },
2577 Some(TokenTree2::Ident(id)) if id.to_string() == "Base" => {
2578 final_span = id.span();
2579 reset = true;
2580 },
2581 _ => {
2582 cont = false;
2583 },
2584 };
2585 }
2586 if reset {
2587 return Err(($v, quote_spanned!{final_span=> compile_error!{ "Path finished with a 'Base'; we need an actual file reference." }}));
2588 };
2589 let mut f = match File::open($path.clone()) {
2590 Ok(s) => s,
2591 Err(e) => {
2592 let msg = format!("Failure to import; got error: {}\n Could not open file: {:?}", e, $path.into_os_string());
2593 return Err(($v, quote_spanned!{$anchor_span=> compile_error!{ #msg }}));
2594 },
2595 };
2596 let mut buffer = String::new();
2597 match f.read_to_string(&mut buffer) {
2598 Ok(_) => {},
2599 Err(x) => {
2600 let msg = format!("Failure to import; got error: {}\n Could not read from file: {:?}", x, $path.into_os_string());
2601 return Err(($v, quote_spanned!{$anchor_span=> compile_error!{ #msg }}));
2602 },
2603 };
2604 let $tokens = match TokenStream2::from_str(&buffer) {
2605 Ok(x) => x,
2606 Err(e) => {
2607 let msg = format!("Failure to import; got error: {}\n Could not parse file: {:?}", e, $path.into_os_string());
2608 return Err(($v, quote_spanned!{$anchor_span=> compile_error!{ #msg }}));
2609 },
2610 };
2611 let $cnew = Configuration::<T> {
2612 file: Some($path.display().to_string()),
2613 ..$c.clone()
2614 };
2615 };
2616}
2617pub fn importHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data: Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2628 getCode!(stream, tokens, anchor_span, cnew, c, path, v, t);
2629 let mut thing = TokenStream2::new();
2630 let (vout, out) = match do_with_in_explicit2(tokens, cnew, v.clone()) {
2631 Err((a,b)) => {
2632 thing.extend(b);
2633 let msg = format!("Problem encountered inside import {:?}.", path.into_os_string());
2634 thing.extend(quote_spanned!{anchor_span=> compile_error!{ #msg }});
2635 (a, thing)
2636 },
2637 x => return x,
2638 };
2639 Ok((vout, out))
2640}
2641
2642#[derive(Debug,Clone)]
2648enum FnDefineState {
2649 LessThanNothing,
2650 Nothing,
2651 Name(String),
2652 NameAnd(String, proc_macro2::Group),
2653}
2654
2655#[derive(Debug,Clone)]
2656enum FnCallState {
2657 Nothing,
2658 Name(String),
2659 NameArgs(String, proc_macro2::Group),
2660 NameArgsBody(String, proc_macro2::Group, proc_macro2::Group),
2661}
2662
2663#[derive(Debug,Clone)]
2664enum FnArg {
2665 NoDefault(String),
2666 Default(String, TokenStream2),
2667}
2668#[derive(Debug,Clone)]
2669struct FnArgs {
2670 positional: Vec<FnArg>,
2671 named: HashMap<String, FnArg>,
2672}
2673pub fn internalFnRunner<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data: Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2674 let mut state = FnCallState::Nothing;
2675 let core_anchor = t.span();
2676 match data.clone() {
2677 None => {
2678 let msg = format!("Expected a function body, got none, for function call {}", t);
2679 return Err((v, quote_spanned!{core_anchor=> compile_error!{ #msg }}));
2680 },
2681 Some(program) => {
2682 let mut stream = program.into_iter();
2684 if let Some(TokenTree2::Ident(name)) = stream.next() {
2685 state = FnCallState::Name(name.to_string());
2686 for token in stream {
2687 match state {
2688 FnCallState::Nothing => {
2689 return Err((v, quote_spanned!{core_anchor=> compile_error!{ "Confused state in internalFnRunner." }}))
2690 },
2691 FnCallState::Name(name) => {
2692 if let TokenTree2::Group(args) = token.clone() {
2693 state = FnCallState::NameArgs(name, args);
2694 } else {
2695 let msg = format!("Expected a function argument list in the function {} runner data; got {}", name, token);
2696 return Err((v, quote_spanned!{core_anchor=> compile_error!{ #msg }}));
2697 }
2698 },
2699 FnCallState::NameArgs(name, args) => {
2700 if let TokenTree2::Group(body) = token.clone() {
2701 state = FnCallState::NameArgsBody(name, args, body);
2702 } else {
2703 let msg = format!("Expected a function body in the function {} runner data; got {}", name, token);
2704 return Err((v, quote_spanned!{core_anchor=> compile_error!{ #msg }}));
2705 }
2706 },
2707 unexpected => {
2708 let msg = format!("Got more stuff in the function {} runner data; internal state {:?}, data {:?}", name, unexpected, token);
2709 return Err((v, quote_spanned!{core_anchor=> compile_error!{ #msg }}));
2710 },
2711 }
2712 }
2713 if let FnCallState::NameArgsBody(name, args, body) = state {
2714 let mut defaults_by_declaration_position: Vec<Option<TokenStream2>> = Vec::new();
2718 let mut thunks_by_invocation_position: Vec<Option<TokenStream2>> = Vec::new();
2719 let mut inner_names: BiMap<usize, String> = BiMap::<usize, String>::new();
2721 let mut outer_names: BiMap<usize, String> = BiMap::<usize, String>::new();
2722 let mut call_site_stream = t.clone().into_iter();
2736 call_site_stream.next(); if let Some(TokenTree2::Group(grp)) = call_site_stream.next() {
2738 let mut call_site_args = grp.stream().into_iter().peekable();
2739 let mut declaration_site_args = args.clone().stream().into_iter().peekable();
2740 let mut more = true;
2742 while more {
2743 let first = match declaration_site_args.next() {
2747 None => {more = false; continue},
2748 Some(TokenTree2::Punct(punct)) if punct.as_char() == ',' => continue,
2749 Some(TokenTree2::Punct(punct)) if punct.as_char() == '_' => None,
2750 Some(TokenTree2::Ident(ident)) => Some(ident.to_string()),
2751 Some(it) => {
2752 let msg = format!("Got ⌜{}⌝ in argument list for function \"{}\"; expected '_' or an ident.", it, name);
2753 let sp = it.span();
2754 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2755 },
2756 };
2757 let (has_second, might_have_third) = match declaration_site_args.peek() {
2758 None => {more = false; (false, false)},
2759 Some(TokenTree2::Punct(punct)) if punct.as_char() == ',' => (false, false),
2760 Some(TokenTree2::Punct(punct)) if punct.as_char() == '_' => (true, true),
2761 Some(TokenTree2::Ident(ident)) => (true, true),
2762 Some(TokenTree2::Punct(punct)) if punct.as_char() == '=' => (false, true),
2763 Some(it) => {
2764 let msg = format!("Got ⌜{}⌝ in argument list for function \"{}\"; expected '_' or an ident.", it, name);
2765 let sp = it.span();
2766 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2767 },
2768 };
2769 if has_second {
2770 } else {
2780 }
2782 if might_have_third {
2783 }
2784 }
2785 todo!()
2786 } else {
2787 let msg = format!("Did not get args in invocation of function {}.", name);
2788 return Err((v, quote_spanned!{core_anchor=> compile_error!{ #msg }}));
2789 }
2790 } else {
2791 let msg = format!("Did not have a body in the internal function runner's data; got {:?}.", state);
2792 return Err((v, quote_spanned!{core_anchor=> compile_error!{ #msg }}));
2793 }
2794 } else {
2795 return Err((v, quote_spanned!{core_anchor=> compile_error!{ "Expected a named function." }}));
2796 }
2797 },
2798 }
2799}
2800pub fn fnHandler<T: 'static + StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data: Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2801 let sp = t.clone().span();
2802 let mut variables = v.clone();
2803 let mut state: FnDefineState = FnDefineState::LessThanNothing;
2804 for token in t.into_iter() {
2805 match state.clone() {
2806 FnDefineState::LessThanNothing => {
2807 if let TokenTree2::Ident(name) = token.clone() {
2809 if name.to_string() == "fn" {
2810 state = FnDefineState::Nothing;
2811 } else {
2812 let msg = format!("Expected 'fn' to absolutely start a fn expression, got {}.", token);
2813 let sp = name.span();
2814 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2815 }
2816 } else {
2817 let msg = format!("Expected 'fn' to absolutely start a let expression, got {}.", token);
2818 let sp = token.span();
2819 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2820 }
2821 },
2822 FnDefineState::Nothing => {
2823 if let TokenTree2::Ident(name) = token {
2824 state = FnDefineState::Name(name.to_string());
2825 } else {
2826 let msg = format!("Expected a function name to start a fn expression, got {}.", token);
2827 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2828 }
2829 },
2830 FnDefineState::Name(name) => {
2831 if let TokenTree2::Group(args) = token {
2832 state = FnDefineState::NameAnd(name, args);
2833 } else {
2834 let msg = format!("Expected an arglist, got {}.", token);
2835 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2836 }
2837 },
2838 FnDefineState::NameAnd(name, args) => {
2839 if let TokenTree2::Group(body) = token {
2840 let mut stream = TokenStream2::new();
2841 stream.extend(TokenStream2::from(TokenTree2::Ident(Ident::new(&name, sp))));
2842 stream.extend(TokenStream2::from(TokenTree2::Group(args)).into_iter());
2843 stream.extend(TokenStream2::from(TokenTree2::Group(body)).into_iter());
2844 variables.handlers.insert(name.clone(), (Box::new(&internalFnRunner), Some(stream)));
2845 return Ok((variables, quote!{ } ))
2846 } else {
2847 let msg = format!("Expected a function body, got {}.", token);
2848 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2849 }
2850 },
2851 }
2852 }
2853
2854 Err((v, quote_spanned!{sp=> compile_error!{ "Input to function definition ended early." }}))
2855}
2856pub fn handleMkHandlerRunner<T: 'static + StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data: Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2857 let mut variables = v.clone();
2858 let mut stream = t.into_iter();
2859 let mk_ed_name = stream.next().unwrap(); let mut var_num = 1;
2861 let mut restore_args: Vec<(String, (TokenStream2, bool))> = Vec::new();
2862 for i in stream {
2863 if let Some(value) = variables.variables.remove(&var_num.to_string()) {
2864 restore_args.push((var_num.to_string(), value));
2865 }
2866 let sp = i.span();
2867 if let TokenTree2::Group(grp) = i {
2868 let ii = grp.stream();
2869 variables.variables.insert(var_num.to_string(), (quote_spanned!{sp=> #ii}, false));
2870 } else {
2871 variables.variables.insert(var_num.to_string(), (quote_spanned!{sp=> #i}, false));
2872 }
2873 var_num += 1;
2874 }
2875 if let Some(stuff) = data {
2876 let it = do_with_in_explicit2(stuff, c, variables);
2877 if let Ok((mut new_var, out)) = it {
2878 for (k, v) in restore_args.into_iter() {
2879 new_var.variables.insert(k, v);
2880 }
2881 return Ok((new_var, out));
2882 } else {
2883 return it;
2884 }
2885 } else {
2886 let msg = format!("There was no associated code found when trying to run the mk based handler called: {:?}", mk_ed_name);
2888 let sp = mk_ed_name.span();
2889 return Err((v, quote_spanned!{sp=> #msg }));
2890 }
2891}
2892pub fn mkHandler<T: 'static + StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data: Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2893 let mut variables = v.clone();
2894 let mut it = t.clone().into_iter();
2895 it.next();
2896 if let Some(TokenTree2::Ident(name)) = it.next() {
2897 let mut ts = TokenStream2::new();
2898 ts.extend(it);
2899 variables.handlers.insert(name.to_string(), (Box::new(&handleMkHandlerRunner), Some(ts)));
2900 return Ok((variables, quote!{ }));
2901 } else {
2902 let msg = format!("There was no name found when trying to construct a mk based handler.");
2903 let sp = t.span();
2904 return Err((v, quote_spanned!{sp=> #msg }));
2905 }
2906}
2907
2908#[derive(Debug,Clone,PartialEq,Eq)]
2909enum LetState {
2910 Nothing,
2911 Name(String),
2912 NamePostEquals(String),
2913}
2914pub fn assignmentInternalHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, t: TokenStream2, interp_first: bool, interp_after: bool) -> StageResult<T> {
2915 let mut variables = v.clone();
2916 let mut state: LetState = LetState::Nothing;
2917
2918 for token in t.into_iter() {
2919 match state.clone() {
2920 LetState::Nothing => {
2921 if let TokenTree2::Ident(name) = token {
2922 state = LetState::Name(name.to_string());
2923 } else {
2924 let msg = format!("Expected a variable name to start a let expression, got {}.", token);
2925 let sp = token.span();
2926 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2927 }
2928 },
2929 LetState::Name(var_name) => {
2930 if let TokenTree2::Punct(punct) = token.clone() {
2931 if punct.as_char() == '=' && punct.spacing() == proc_macro2::Spacing::Alone {
2932 state = LetState::NamePostEquals(var_name);
2933 } else {
2934 let msg = format!("Expected '=', got {}.", token);
2935 let sp = token.span();
2936 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2937 }
2938 } else {
2939 let msg = format!("Expected '=', got {}.", token);
2940 let sp = token.span();
2941 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2942 }
2943 },
2944 LetState::NamePostEquals(var_name) => {
2945 if let TokenTree2::Group(body) = token {
2946 let to_insert = if interp_first { do_with_in_explicit2(body.stream(), c.clone(), variables.clone())?.1 } else { body.stream() };
2947 variables.variables.insert(var_name, (to_insert, interp_after));
2948 state = LetState::Nothing;
2949 } else {
2950 let msg = format!("Expected a curly bracket surrounded expression (the value to put in the variable), got {}.", token);
2951 let sp = token.span();
2952 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
2953 }
2954 },
2955 }
2956 }
2957 Ok((variables, quote!{}))
2958}
2959pub fn letHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data: Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2967 let mut stream = t.into_iter();
2968 check_token_ret!(v, Some(TokenTree2::Ident(it)), stream.next(), "Expecting 'let'.", it.to_string() == "let", "Expecting 'let'.");
2969 let mut temp = TokenStream2::new();
2970 temp.extend(stream);
2971 assignmentInternalHandler(c, v, temp, false, false)
2972}
2973
2974pub fn varHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2982 let mut stream = t.into_iter();
2983 check_token_ret!(v, Some(TokenTree2::Ident(it)), stream.next(), "Expecting 'var'.", it.to_string() == "var", "Expecting 'var'.");
2984 let mut temp = TokenStream2::new();
2985 temp.extend(stream);
2986 assignmentInternalHandler(c, v, temp, true, true)
2987}
2988
2989macro_rules! q_or_unq {
2990 ($stream: ident, $v: ident, $c: ident, $item: ident, $q: expr) => {
2991 if $q {
2992 match $c.sigil {
2993 Sigil::Dollar => check_token_ret!($v, TokenTree2::Punct(p), $item, "Expect a sigil (here, '$') to invoke quote.", p.as_char() == '$', "Expect a sigil (here, '$') to invoke quote."),
2994 Sigil::Hash => check_token_ret!($v, TokenTree2::Punct(p), $item, "Expect a sigil (here, '#') to invoke quote.", p.as_char() == '#', "Expect a sigil (here, '#') to invoke quote."),
2995 Sigil::Percent => check_token_ret!($v, TokenTree2::Punct(p), $item, "Expect a sigil (here, '%') to invoke quote.", p.as_char() == '%', "Expect a sigil (here, '%') to invoke quote."),
2996 Sigil::Tilde => check_token_ret!($v, TokenTree2::Punct(p), $item, "Expect a sigil (here, '~') to invoke quote.", p.as_char() == '~', "Expect a sigil (here, '~') to invoke quote."),
2997 };
2998 match $stream.next() {
2999 Some(TokenTree2::Group(group)) => {
3000 let mut inner_stream = group.stream().into_iter();
3001 check_token_ret!($v, Some(TokenTree2::Ident(qu)), inner_stream.next(), "Expecting 'quote'.", qu.to_string() == "quote", "Expecting 'quote'.");
3002 if let Some(x) = inner_stream.next() {
3003 x
3004 } else {
3005 let sp = group.span();
3006 return Err(($v, quote_spanned!{sp=> compile_error!{ "Expecting a group to actually be a quote." }}));
3007 }
3008 },
3009 x => {
3010 return Err(($v, quote!{compile_error!{ "Expecting a group; got something else where a quote group should be." }}));
3011 },
3012 }
3013 } else {
3014 $item
3015 }
3016 };
3017}
3018
3019pub fn markerHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
3027 let root_anchor_span = t.clone().span();
3028 let mut stream = t.into_iter().peekable();
3029 check_token_ret!(v, root_anchor_span, name, Some(TokenTree2::Ident(name)), stream.next(), "Expected 'marker'", name.to_string() == "marker", "Expected 'marker'");
3030 Ok((v, quote!{}))
3034}
3035
3036pub fn runMarkersHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
3052 getCode!(stream, tokens, anchor_span, cnew, c, path, v, t);
3053 let limit = match stream.next() {
3056 None => None,
3057 Some(TokenTree2::Punct(p)) if p.as_char() == '>' => {
3058 match stream.next() {
3060 Some(TokenTree2::Literal(it)) => {
3061 Some(it.to_string())
3062 },
3063 None => {
3064 let sp = p.span();
3065 return Err((v, quote_spanned!{sp=> compile_error!{"Expected a name to limit which markers to run; got nothing."} }));
3066 },
3067 Some(x) => {
3068 let msg = format!("Expected a name to limit which markers to run; got {}", x);
3069 let sp = x.span();
3070 return Err((v, quote_spanned!{sp=> compile_error!{#msg} }));
3071 },
3072 }
3073 },
3074 Some(x) => {
3075 let msg = format!("Expected a => and then a name to limit which markers to run; got {}", x);
3076 let sp = x.span();
3077 return Err((v, quote_spanned!{sp=> compile_error!{#msg} }));
3078 },
3079 };
3080 let token_char = match c.clone().sigil {
3083 Sigil::Dollar => '$',
3084 Sigil::Percent => '%',
3085 Sigil::Hash => '#',
3086 Sigil::Tilde => '~',
3087 };
3088 fn collectMarkers(t: TokenStream2, token_char: char, limit: Option<String>) -> Vec<TokenStream2> {
3089 let mut accumulator: Vec<TokenStream2> = Vec::new();
3090 let mut expecting_variable = false;
3091 for token in t.into_iter() {
3092 match &token {
3093 TokenTree2::Punct(punct_char) if punct_char.spacing() == proc_macro2::Spacing::Alone && punct_char.as_char() == token_char => {
3094 if expecting_variable {
3095 expecting_variable = false;
3096 } else {
3097 expecting_variable = true;
3098 }
3099 },
3100 TokenTree2::Ident(ident) => {
3101 if expecting_variable {
3102 expecting_variable = false;
3103 }
3104 },
3105 TokenTree2::Literal(lit) if expecting_variable => {
3106 expecting_variable = false;
3107 },
3108 TokenTree2::Group(group) => {
3109 if expecting_variable {
3110 expecting_variable = false;
3111 let stream = group.clone().stream();
3113 if !stream.is_empty() {
3114 let mut iter = stream.clone().into_iter();
3115 if let Some(TokenTree2::Ident(first)) = iter.next() {
3116 if first.to_string() == "marker" {
3117 match limit.clone() {
3119 None => {
3120 match (iter.next(), iter.next()) {
3121 (Some(TokenTree2::Punct(x)), Some(TokenTree2::Punct(y))) if x.as_char() == '=' && y.as_char() == '>' => {
3122 let mut t = TokenStream2::new();
3123 t.extend(iter);
3124 accumulator.push(t);
3125 },
3126 (_, _) => {
3127 },
3129 }
3130 },
3131 Some(lim) => {
3132 match iter.next() {
3133 Some(TokenTree2::Literal(x)) if x.to_string() == lim => {
3134 iter.next();
3135 iter.next();
3136 let mut t = TokenStream2::new();
3137 t.extend(iter);
3138 accumulator.push(t);
3139 },
3140 _ => {
3141 },
3143 }
3144 },
3145 }
3146 } else {
3147 accumulator.extend(collectMarkers(group.stream(), token_char, limit.clone()).into_iter());
3148 }
3149 } else {
3150 accumulator.extend(collectMarkers(group.stream(), token_char, limit.clone()).into_iter());
3151 }
3152 }
3153 } else {
3154 accumulator.extend(collectMarkers(group.stream(), token_char, limit.clone()).into_iter());
3155 }
3156 },
3157 a => {
3158 if expecting_variable {
3159 expecting_variable = false;
3160 }
3161 },
3162 }
3163 }
3164 return accumulator;
3165 }
3166 let markers = collectMarkers(tokens, token_char, limit.clone());
3167 let mut v_out = v.clone();
3168 for to_run in markers.into_iter() {
3169 v_out = match do_with_in_explicit2(to_run.clone(), c.clone(), v_out.clone()) {
3170 Ok((it, _)) => it,
3171 Err((_, err)) => {
3172 let sp = to_run.span();
3173 let limit_text = match limit {
3174 None => String::from("all markers"),
3175 Some(x) => format!{"markers with limit {}", x},
3176 };
3177 let out_text = format!{"Encountered an error when processing {} for path {}.", limit_text, path.display()};
3178 return Err((v, quote_spanned!{sp=> compile_error!{ #out_text } #err}));
3179 },
3180 };
3181 }
3182 Ok((v_out, quote!{}))
3183}
3184
3185pub fn arrayHandler<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
3248 let root_anchor_span = t.clone().span();
3249 let mut stream = t.into_iter().peekable();
3250 check_token_ret!(v, root_anchor_span, name, Some(TokenTree2::Ident(name)), stream.next(), "Expected 'array'", name.to_string() == "array", "Expected 'array'");
3251 let q = if let Some(TokenTree2::Ident(is_q)) = stream.peek() {
3252 if is_q.to_string() == "q" {
3253 stream.next();
3254 true
3255 } else {
3256 false
3257 }
3258 } else {
3259 false
3260 };
3261 let (op, op_span) = if let Some(TokenTree2::Ident(x)) = stream.peek() {
3263 (x.to_string(), stream.peek().span())
3264 } else {
3265 let msg = format!("Expected an array op; ... got {:?}", stream.peek());
3266 let sp = stream.peek().span();
3267 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
3268 };
3269 let op_anchor = stream.next().span();
3270 match op.as_str() {
3271 "length" => {
3272 let mut arr_base = if q {
3273 let mut to_run_quoted_array = TokenStream2::new();
3274 to_run_quoted_array.extend(stream);
3275 let quoted_array = match do_with_in_explicit2(to_run_quoted_array, c.clone(), v.clone()) {
3276 Ok((_, x)) => x,
3277 Err((_, x)) => {
3278 let msg = "Problem with parsing array length arguments.";
3279 return Err((v, quote_spanned!{op_anchor=> compile_error!{ #msg } #x }));
3280 },
3281 };
3282 match uq(c.clone().sigil, quoted_array) {
3283 Ok(x) => {
3284 match x.into_iter().next() {
3285 Some(x) => x,
3286 None => return Err((v, quote_spanned!{root_anchor_span=> compile_error!{ "Argument list ended early; expected an array." }})),
3287 }
3288 },
3289 Err(x) => {
3290 return Err((v, quote_spanned!{root_anchor_span=> compile_error!{ #x }}));
3291 },
3292 }
3293 } else {
3294 let mut to_run = TokenStream2::new();
3295 to_run.extend(stream);
3296 let mut have_run = do_with_in_explicit2(to_run, c.clone(), v.clone())?.1.into_iter();
3297 match have_run.next() {
3298 Some(x) => x,
3299 None => return Err((v, quote_spanned!{root_anchor_span=> compile_error!{ "Argument list ended early; expected an array." }})),
3300 }
3301 };
3302 if let TokenTree2::Group(arr) = arr_base {
3303 let mut arr_stuff = arr.stream().into_iter();
3304 let mut len: u64 = 0;
3305 for _ in arr_stuff {
3306 len += 1;
3307 }
3308 let len_2 = proc_macro2::Literal::u64_unsuffixed(len);
3309 return Ok((v, quote!{ #len_2 }));
3310 } else {
3311 let msg = format!("Expected an array to get the length of; ... got {:?}", arr_base);
3312 let sp = arr_base.span();
3313 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
3314 }
3315 },
3316 "ith" => {
3317 let mut to_run = TokenStream2::new();
3319 to_run.extend(stream);
3320 let mut stream = do_with_in_explicit2(to_run, c.clone(), v.clone())?.1.into_iter().peekable();
3321 let sub_op = if let Some(TokenTree2::Ident(x)) = stream.peek() {
3323 x.to_string()
3324 } else {
3325 let msg = format!("Expected an array ith op; ... got {:?}", stream.peek());
3326 return Err((v, quote!{compile_error!{ #msg }}));
3327 };
3328 stream.next();
3329 let mut offset = Offset::Head;
3330 pull_offset!(stream, op_anchor, offset, v);
3333 match sub_op.as_str() {
3335 "get" => {
3336 let mut array: Vec<TokenStream2> = vec!();
3338 pull_array_to_vec!(stream.next(), array, v, q, c.sigil);
3339 let idx = convert_offset_to_usize(offset, array.len());
3340 if idx >= array.len() {
3341 let msg = format!("Attempt to access out of bounds; idx: {} for array: {:?}.", idx, array);
3342 return Err((v, quote_spanned!{op_anchor=> compile_error! { #msg }}));
3343 }
3344 let out = array[idx].clone();
3345 return Ok((v, out));
3346 },
3347 "set" => {
3348 let item = match stream.next() {
3350 Some(x) => x,
3351 None => return Err((v, quote!{compile_error!{ "Problem with array ith set???" }})),
3352 };
3353 let base_el = match q_or_unq!(stream, v, c, item, q) {
3354 TokenTree2::Group(grp) => TokenStream2::from(grp.stream()),
3355 _ => return Err((v, quote!{compile_error!{ "Expected a [...]. I am very confused." }})),
3356 };
3357 let mut array: Vec<TokenStream2> = vec!();
3358 pull_array_to_vec!(stream.next(), array, v, q, c.sigil);
3359 let idx = convert_offset_to_usize(offset, array.len());
3360 array[idx] = base_el;
3361 if q {
3362 return Ok((v, quote!{ $(quote [ #({#array})* ]) }));
3363 } else {
3364 return Ok((v, quote!{ [ #({#array})* ] }));
3365 }
3366 },
3367 "remove" => {
3368 let mut array: Vec<TokenStream2> = vec!();
3370 pull_array_to_vec!(stream.next(), array, v, q, c.sigil);
3371 let idx = convert_offset_to_usize(offset, array.len());
3372 array.remove(idx);
3373 if q {
3374 return Ok((v, quote!{ $(quote [ #({#array})* ]) }));
3375 } else {
3376 return Ok((v, quote!{ [ #({#array})* ] }));
3377 }
3378 },
3379 "insert" => {
3380 let item = match stream.next() {
3382 Some(x) => x,
3383 None => return Err((v, quote!{compile_error!{ "Problem with array ith set???" }})),
3384 };
3385 let base_el = match q_or_unq!(stream, v, c, item, q) {
3386 TokenTree2::Group(grp) => TokenStream2::from(grp.stream()),
3387 _ => return Err((v, quote!{compile_error!{ "Expected a [...]. I am very confused." }})),
3388 };
3389 let mut array: Vec<TokenStream2> = vec!();
3390 pull_array_to_vec!(stream.next(), array, v, q, c.sigil);
3391 let idx = convert_offset_to_usize(offset, array.len() + 1); array.insert(idx, base_el);
3393 if q {
3394 return Ok((v, quote!{ $(quote [ #({#array})* ]) }));
3395 } else {
3396 return Ok((v, quote!{ [ #({#array})* ] }));
3397 }
3398 },
3399 _ => todo!(),
3400 }
3401 },
3402 "slice" => {
3403 let sub_op = if let Some(TokenTree2::Ident(x)) = stream.peek() {
3405 x.to_string()
3406 } else {
3407 let msg = format!("Expected an array slice op; ... got {:?}", stream.peek());
3408 return Err((v, quote!{compile_error!{ #msg }}));
3409 };
3410 stream.next();
3411
3412 todo!();
3413 },
3414 "concat" => {
3415 let mut out: TokenStream2 = TokenStream2::new();
3416 let mut to_run = TokenStream2::new();
3417 to_run.extend(stream);
3418 let mut stream = do_with_in_explicit(to_run, c.clone(), v.clone()).into_iter();
3419 while let Some(item) = stream.next() {
3420 let it = q_or_unq!(stream, v, c, item, q);
3421 if let TokenTree2::Group(grp) = it.clone() {
3422 let mut grp_stream = grp.stream().into_iter();
3424 while let Some(element) = grp_stream.next() {
3425 check_token_ret!(v, TokenTree2::Group(_), element.clone(), "Expect item in array concat inner array to be an array element.", true, "Expect item in array concat inner array to be an array element.");
3426 out.extend(TokenStream2::from(element));
3427 }
3428 } else {
3429 let msg = format!("Expected an array element, got {:?}", it);
3430 let sp = it.span();
3431 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
3432 }
3433 }
3434 if q {
3435 let qout = match c.sigil {
3436 Sigil::Dollar => quote!{ $(quote [#out]) },
3437 Sigil::Percent => quote!{ %(quote [#out]) },
3438 Sigil::Hash => quote!{ #(quote [#out]) },
3439 Sigil::Tilde => quote!{ ~(quote [#out]) },
3440 };
3441 return Ok((v, qout));
3442 } else {
3443 return Ok((v, quote!{ [#out] }));
3444 }
3445 },
3446 "each" => {
3447 let mut to_run = TokenStream2::new();
3448 to_run.extend(stream);
3449 let mut stream = match do_with_in_explicit2(to_run, c.clone(), v.clone()) {
3450 Ok((x, y)) => y,
3451 z => return z,
3452 }.into_iter();
3453 let name = match stream.next() {
3454 None => return Err((v, quote_spanned!{root_anchor_span=> compile_error!{ "Arguments to 'array each' ended early; expected a name and an array." }})),
3455 Some(x) => match x {
3456 TokenTree2::Ident(it) => it,
3457 it => {
3458 let msg = format!("Expected a name, got {}", it);
3459 let sp = it.span();
3460 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
3461 },
3462 },
3463 };
3464 let mut array: Vec<TokenStream2> = vec!();
3465 pull_array_to_vec!(stream.next(), array, v, q, c.sigil);
3466 let mut out = TokenStream2::new();
3467 match c.sigil {
3468 Sigil::Dollar => {
3469 for i in array {
3470 let sp = i.span();
3471 out.extend(quote_spanned!{sp=> $(#name #i)});
3472 };
3473 },
3474 Sigil::Hash => {
3475 for i in array {
3476 let sp = i.span();
3477 out.extend(quote_spanned!{sp=> #(#name #i)});
3478 };
3479 },
3480 Sigil::Percent => {
3481 for i in array {
3482 let sp = i.span();
3483 out.extend(quote_spanned!{sp=> %(#name #i)});
3484 };
3485 },
3486 Sigil::Tilde => {
3487 for i in array {
3488 let sp = i.span();
3489 out.extend(quote_spanned!{sp=> ~(#name #i)});
3490 };
3491 },
3492 }
3493 return do_with_in_explicit2(out, c, v);
3494 },
3495 "map" => {
3496 let mut to_run = TokenStream2::new();
3498 to_run.extend(stream);
3499 let mut stream = match do_with_in_explicit2(to_run, c.clone(), v.clone()) {
3500 Ok((x, y)) => y,
3501 z => return z,
3502 }.into_iter();
3503 let isolate = match stream.next() {
3504 None => return Err((v, quote_spanned!{op_span=> compile_error!{ "Too few arguments; expected a bool (for whether to isolate), then a name, a group, and an array." }})),
3505 Some(x) => match tokenTreeToBool(x) {
3506 Ok(x) => x,
3507 Err(msg) => {
3508 return Err((v, quote_spanned!{op_span=> compile_error!{ #msg }}));
3509 },
3510 },
3511 };
3512 let name = match stream.next() {
3513 None => return Err((v, quote_spanned!{root_anchor_span=> compile_error!{ "Arguments to 'array each' ended early; expected a name, a group, and an array." }})),
3514 Some(x) => match x {
3515 TokenTree2::Ident(it) => it.to_string(),
3516 it => {
3517 let msg = format!("Expected a name, got {}", it);
3518 let sp = it.span();
3519 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
3520 },
3521 },
3522 };
3523 let code_segment = match stream.next() {
3524 None => return Err((v, quote_spanned!{root_anchor_span=> compile_error!{ "Arguments to 'array each' ended early; expected group and an array." }})),
3525 Some(TokenTree2::Group(it)) => {
3526 it.stream()
3527 },
3528 Some(it) => {
3529 let msg = format!("Expected a group, got {}", it);
3530 let sp = it.span();
3531 return Err((v, quote_spanned!{sp=> compile_error!{ #msg }}));
3532 },
3533 };
3534 let mut array: Vec<TokenStream2> = vec!();
3535 pull_array_to_vec!(stream.next(), array, v, q, c.sigil);
3536 let mut out = TokenStream2::new();
3537 let mut new_v = v.clone();
3538 let mut restore_old_name: Option<(TokenStream2, bool)> = None;
3539 for i in array {
3540 if isolate {
3541 new_v = v.clone();
3542 new_v.variables.insert(name.clone(), (i, true));
3543 restore_old_name = None;
3544 } else {
3545 restore_old_name = new_v.variables.insert(name.clone(), (i, true));
3546 }
3547
3548 match do_with_in_explicit2(code_segment.clone(), c.clone(), new_v.clone()) {
3549 Err((vn, o)) => {
3550 out.extend(o);
3551 return Err((vn, out));
3552 },
3553 Ok((vn, o)) => {
3554 out.extend(o);
3555 if !isolate {
3556 new_v = vn;
3557 match restore_old_name {
3558 None => new_v.variables.remove(&name),
3559 Some(x) => new_v.variables.insert(name.clone(), x),
3560 };
3561 } else {
3562 new_v = v.clone();
3563 };
3564 },
3565 };
3566 };
3567 return Ok((new_v, out));
3568 },
3569 "mk" => {
3570 let mut out = TokenStream2::new();
3574 while let Some(item) = stream.next() {
3575 let it = q_or_unq!(stream, v, c, item, q);
3576 check_token_ret!(v, TokenTree2::Group(_), it.clone(), "Expect item in array mk to be an array element.", true, "Expect item in array mk to be an array element.");
3577 out.extend(TokenStream2::from(it));
3578 }
3579 if q {
3580 let qout = match c.sigil {
3581 Sigil::Dollar => quote!{ $(quote [#out]) },
3582 Sigil::Percent => quote!{ %(quote [#out]) },
3583 Sigil::Hash => quote!{ #(quote [#out]) },
3584 Sigil::Tilde => quote!{ ~(quote [#out]) },
3585 };
3586 return Ok((v, qout));
3587 } else {
3588 return Ok((v, quote!{ [#out] }));
3589 }
3590 },
3591 x => {
3592 let msg = format!("Got an array operator I did not understand: {}", x);
3593 return Err((v, quote_spanned!{op_span=> compile_error!{ #msg }}));
3594 },
3595 };
3596
3597 todo!()
3598}
3599
3600fn convert_offset_to_usize(offset: Offset, len: usize) -> usize {
3601 match offset {
3602 Offset::Forward(x) => x,
3603 Offset::Reverse(x) => len - (x + 1),
3604 Offset::Head => 0,
3605 Offset::Tail => (len - 1),
3606 }
3607}
3608
3609fn uq(s: Sigil, t: TokenStream2) -> std::result::Result<TokenStream2, &'static str> {
3610 let mut stream = t.into_iter();
3611 match s {
3612 Sigil::Dollar => check_token!(Some(TokenTree2::Punct(p)), stream.next(), "Expect a sigil (here, '$') to invoke quote.", p.as_char() == '$', "Expect a sigil (here, '$') to invoke quote."),
3613 Sigil::Hash => check_token!(Some(TokenTree2::Punct(p)), stream.next(), "Expect a sigil (here, '#') to invoke quote.", p.as_char() == '#', "Expect a sigil (here, '#') to invoke quote."),
3614 Sigil::Percent => check_token!(Some(TokenTree2::Punct(p)), stream.next(), "Expect a sigil (here, '%') to invoke quote.", p.as_char() == '%', "Expect a sigil (here, '%') to invoke quote."),
3615 Sigil::Tilde => check_token!(Some(TokenTree2::Punct(p)), stream.next(), "Expect a sigil (here, '~') to invoke quote.", p.as_char() == '~', "Expect a sigil (here, '~') to invoke quote."),
3616 };
3617 match stream.next() {
3618 Some(TokenTree2::Group(group)) => {
3619 let mut inner_stream = group.stream().into_iter();
3620 check_token!(Some(TokenTree2::Ident(qu)), inner_stream.next(), "Expecting 'quote'.", qu.to_string() == "quote", "Expecting 'quote'.");
3621 let mut out = TokenStream2::new();
3622 out.extend(inner_stream);
3623 Ok(out)
3624 },
3625 x => {
3626 Err("Expecting a group to actually be a quote.")
3627 },
3628 }
3629}
3630
3631pub fn genericDefaultHandlers<'a, T: 'static + StartMarker + Clone>() -> Handlers<'a, T> {
3655 let mut m: HashMap<String, (Box<&Handler<T>>, Option<TokenStream2>)> = HashMap::new();
3656 m.insert(String::from("if"), ((Box::new(&ifHandler), None)));
3657 m.insert(String::from("let"), ((Box::new(&letHandler), None)));
3658 m.insert(String::from("var"), ((Box::new(&varHandler), None)));
3659 m.insert(String::from("concat"), ((Box::new(&concatHandler), None)));
3660 m.insert(String::from("naiveStringifier"), ((Box::new(&naiveStringifierHandler), None)));
3661 m.insert(String::from("string_to_ident"), ((Box::new(&string_to_identHandler), None)));
3662 m.insert(String::from("arithmetic"), ((Box::new(&arithmeticHandler), None)));
3663 m.insert(String::from("logic"), ((Box::new(&logicHandler), None)));
3664 m.insert(String::from("fn"), ((Box::new(&fnHandler), None)));
3665 m.insert(String::from("mk"), ((Box::new(&mkHandler), None)));
3666 m.insert(String::from("quote"), ((Box::new("e), None)));
3667 m.insert(String::from("unquote"), ((Box::new(&unquote), None)));
3668 m.insert(String::from("escape"), ((Box::new(&escape), None)));
3669 m.insert(String::from("unescape"), ((Box::new(&unescape), None)));
3670 m.insert(String::from("run"), ((Box::new(&run), None)));
3671 m.insert(String::from("array"), ((Box::new(&arrayHandler), None)));
3672 m.insert(String::from("import"), ((Box::new(&importHandler), None)));
3673 m.insert(String::from("runMarkers"), ((Box::new(&runMarkersHandler), None)));
3674 m.insert(String::from("marker"), ((Box::new(&markerHandler), None)));
3675 m.insert(String::from("withSigil"), ((Box::new(&withSigilHandler), None)));
3676 m
3677}
3678
3679pub fn do_with_in_internal(t: TokenStream2) -> TokenStream2 {
3680 match syn::parse2::<Configuration<DoMarker>>(t) {
3682 Ok(it) => {
3683 let mut configuration = it.clone();
3684
3685 let out = match configuration.clone().rest {
3686 Some(out) => out,
3687 None => TokenStream2::new().into(),
3688 };
3689 configuration.rest = None;
3691 configuration.file = match configuration.clone().file {
3692 Some(x) => Some(x),
3693 None => Some(file!().to_string()),
3694 };
3695 do_with_in_explicit(TokenStream2::from(out), configuration, Variables::default()).into()
3696 },
3697 Err(it) => it.to_compile_error().into() }
3699}
3700
3701
3702pub fn do_with_in_explicit<'a, T: StartMarker + Clone>(t: TokenStream2, c: Configuration<T>, v: Variables<'a, T>) -> TokenStream2 {
3703 match do_with_in_explicit2(t, c, v) {
3704 Ok((_, ts)) => ts,
3705 Err((_, ts)) => ts,
3706 }
3707}
3708
3709type Thing<'a, T: StartMarker + Clone> = (Variables<'a, T>, TokenStream2);
3710type StageResult<'a, T: StartMarker + Clone> = std::result::Result<Thing<'a, T>, Thing<'a, T>>;
3711
3712#[cfg(feature = "doc-kludge")]
3713macro_rules! bleh {
3714 () => {
3715 ""
3716 }
3717}
3718
3719#[cfg(not(feature = "doc-kludge"))]
3720macro_rules! bleh {
3721 () => {
3722r" The function used to actually run a stage.
3723
3724 The tokens in `t` are run, using sigils and so on specified in `c` and variables and handlers specified in `v`.
3725 This can be used directly inside a proc_macro to give it the features of the `do_with_in!` proc_macro (defined in the crate `do-with-in-internal-macros`); that proc_macro is in fact
3726 essentially a thin wrapper around [do_with_in_internal], which is a configuration parsing wrapper around this function. If you are
3727 using it this way, you can also change the default variables and handlers which are available by passing in your own `v`.
3728 [genericDefaultHandlers] gives a list of the default handlers, and the source of that function shows how to create the handlers;
3729 [Variables] implements `Default`, so you can easily get a 'batteries included' version to extend."
3730 }
3731}
3732
3733#[doc = bleh!()]
3734pub fn do_with_in_explicit2<'a, T: StartMarker + Clone>(t: TokenStream2, c: Configuration<T>, v: Variables<'a, T>) -> StageResult<'a, T> {
3735 let mut err = false;
3736 let mut output = TokenStream2::new();
3737 let c = match c.clone().file {
3738 Some(x) => c,
3739 None =>
3740 Configuration::<T> {
3741 file: Some(file!().to_string()),
3742 ..c
3743 },
3744 };
3745 let mut use_vars = v;
3746 let token_char = match c.clone().sigil {
3750 Sigil::Dollar => '$',
3751 Sigil::Percent => '%',
3752 Sigil::Hash => '#',
3753 Sigil::Tilde => '~',
3754 };
3755 let mut expecting_variable = false;
3756 for token in t.into_iter() {
3757 match &token {
3758 TokenTree2::Punct(punct_char) if punct_char.spacing() == proc_macro2::Spacing::Alone && punct_char.as_char() == token_char => {
3759 if expecting_variable {
3760 expecting_variable = false;
3761 let out: TokenStream2 = TokenStream2::from(TokenTree2::Punct(punct_char.clone()));
3762 output.extend(out.into_iter());
3763 } else {
3764 expecting_variable = true;
3765 }
3766 },
3767 TokenTree2::Ident(ident) => {
3768 if expecting_variable {
3769 expecting_variable = false;
3770 let var_name = ident.to_string();
3771 if let Some((replace, interp)) = use_vars.variables.get(&var_name) {
3773 if *interp {
3774 output.extend(TokenStream2::from(do_with_in_explicit2(replace.clone(), c.clone(), use_vars.clone())?.1));
3775 } else {
3776 output.extend(replace.clone().into_iter());
3777 }
3778 } else {
3779 let msg = format!("No such variable: {} defined.", var_name);
3780 let sp = ident.span();
3781 output.extend(quote_spanned! {sp=> compile_error!{ #msg }});
3782 err = true;
3783 }
3784 } else {
3785 output.extend(TokenStream2::from(TokenTree2::Ident(ident.clone())).into_iter());
3786 }
3787 },
3788 TokenTree2::Literal(lit) if expecting_variable => {
3789 let var_name = lit.to_string();
3790 expecting_variable = false;
3791 if let Some((replace, interp)) = use_vars.variables.get(&var_name) {
3793 if *interp {
3794 output.extend(TokenStream2::from(do_with_in_explicit2(replace.clone(), c.clone(), use_vars.clone())?.1));
3795 } else {
3796 output.extend(replace.clone().into_iter());
3797 }
3798 } else {
3799 let msg = format!("No such variable: {} defined.", var_name);
3800 let sp = lit.span();
3801 output.extend(quote_spanned! {sp=> compile_error!{ #msg }});
3802 err = true;
3803 }
3804 },
3805 TokenTree2::Group(group) => {
3806 if expecting_variable {
3807 expecting_variable = false;
3808 let stream = group.stream();
3810 if !stream.is_empty() {
3811 let mut iter = stream.clone().into_iter();
3812 if let Some(TokenTree2::Ident(first)) = iter.next().clone() {
3813 if let Some((handler, data)) = use_vars.clone().handlers.get(&first.to_string()) {
3814 let ((new_vars, more_output), is_ok) = unwrap_to(handler(c.clone(), use_vars.clone(), data.clone(), stream));
3815 err = err | (!is_ok);
3816 use_vars = new_vars;
3817 output.extend(more_output);
3818 } else {
3819 err = true;
3820 let mut keys = String::from("");
3821 for key in use_vars.clone().handlers.keys() {
3822 keys += &format!(", \"{}\"", key);
3823 }
3824 let msg = format!("Undefined handler referenced: {}\nList of all known handlers: {}", &first.to_string(), keys);
3825 let sp = group.span();
3826 output.extend(quote_spanned!{sp=> compile_error!{ #msg }});
3827 }
3828 }
3829
3830 }
3832 } else {
3833 let delim = group.clone().delimiter();
3834 output.extend(TokenStream2::from(TokenTree2::Group(
3835 proc_macro2::Group::new(delim, do_with_in_explicit2(group.stream(), c.clone(), use_vars.clone())?.1)
3836 )));
3837 }
3838 },
3839 a => {
3840 if expecting_variable {
3841 expecting_variable = false;
3842 let out: TokenStream2 = TokenStream2::from(TokenTree2::Punct(proc_macro2::Punct::new(token_char.clone(), proc_macro2::Spacing::Alone)));
3843 output.extend(out.into_iter());
3844 }
3845 output.extend(TokenStream2::from(a.clone()).into_iter());
3846 },
3847 }
3848 }
3849 if err {
3850 StageResult::Err((use_vars, output.into()))
3851 } else {
3852 StageResult::Ok((use_vars, output.into()))
3853 }
3854}
3855
3856#[test]
3879fn conf_test_panic1() {
3880 let input: TokenStream2 = quote! {sigil: % ow2eihf do wiwlkef }.into();
3881 let output = do_with_in_internal(input);
3882 assert_eq!(format!("{}", output), format!("{}", TokenStream2::from(quote! {::core::compile_error!{ "Bad configuration section; found ow2eihf when sigil or end of prelude expected" }} )));
3883}
3884
3885