do_with_in_base/
lib.rs

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},  //Ident::new("do_with_in_base::Sigil::Dollar", proc_macro2::Span::call_site()),
59      Sigil::Percent => quote!{do_with_in_base::Sigil::Percent}, //Ident::new("do_with_in_base::Sigil::Percent", proc_macro2::Span::call_site()),
60      Sigil::Hash    => quote!{do_with_in_base::Sigil::Hash},    //Ident::new("do_with_in_base::Sigil::Hash", proc_macro2::Span::call_site()),
61      Sigil::Tilde   => quote!{do_with_in_base::Sigil::Tilde},   //Ident::new("do_with_in_base::Sigil::Tilde", proc_macro2::Span::call_site()),
62    });
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        //let msg = $err2;
155        return Err(($vars, quote!{compile_error!{ $err2 }}));
156      }
157    } else {
158        //let msg = $err;
159        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        //let msg = $err2;
169        return Err(($vars, quote_spanned!{sp=> compile_error!{ $err2 }}));
170      }
171    } else {
172        //let msg = $err;
173        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        //let msg = $err2;
183        return Err(($vars, quote_spanned!{sp=> compile_error!{ $err2 }}));
184      }
185    } else {
186      let sp = $sp_root.span();
187      //let msg = $err;
188      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        // We have to do this because of a bit of Rust misdesign, as Rust represents negative numbers in a bad way
231        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    // $out must start as a mut Vec
270    // $q is a boolean, which is whether we are in quote mode
271    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
353// ~, or Tilde, or Sigil::Tilde, or do_with_in_base::Sigil::Tilde
354enum GetSigil {
355  ExpectingColonsThenSigil,
356  ExpectingColonThenSigil,
357  ExpectingSigil,
358  ExpectingColonsThenEnd,
359  ExpectingColonThenEnd,
360  ExpectingEnd,
361}
362
363// Double, or Expecting::Double, or do_with_in_base::Expecting::Double
364enum 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), //We get the first part of sigil from Equals(Sigil), then pass to the relevant kind of Sigil(GetSigil)
378  Escaping(GetEscaping),
379  Some, //Some should only be present when we are expecting a TokenStream2 after Equals(Rest) found a 'Some'
380}
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      // This bit is a bit tricky, as we expect ⌜ident (colon colon ident)*⌝
390      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; // We stay at this point in the state machine
449            },
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          // The new TokenStream must be contained inside a TokenTree2:Group
663          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    // We actually ignore cc.marker, as we ~ assume that T is correct
682    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  //fn type() -> Self::token;
770  type token: Parse;// = syn::token::Do;
771  fn tokenp() -> PeekFn;// = syn::token::Do;
772  type tokend: Parse + ToString + Clone;
773  fn token_token() -> TokenStream2;
774}
775
776impl StartMarker for DoMarker {
777  fn name() -> Option<String> {
778    None //Some(String::from("do"))
779  }
780  //fn type() -> Self::token {
781  //  return (Token![do])
782  //}
783  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    //dbg!("Configuration<T>::default()");
799    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    //dbg!("Start of parsing configuration.");
806    let mut base_config: Configuration<T> = Default::default();
807    //dbg!("Made base config.");
808    while !input.is_empty() {
809      //dbg!("Start of while.");
810      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          //dbg!("iwhflwhedflowhedfl");
822          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          //dbg!("sigil found");
832          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    //while(input.parse
885    //dbg!("End of parsing configuration.");
886    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; // We stay at this point in the state machine
955            },
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                  //
987                },
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
1011/// Conditionally execute one of two branches, depending on the result of a test expression.
1012/// 
1013/// *Syntax*: `$(if {<testBlock>} {<trueBlock>} {<falseBlock})`
1014/// 
1015/// The test will often be either a variable that has been set elsewhere or a `$(logic ...)` block.
1016/// It *must* evaluate to either `true` or `false`.
1017/// Only one of the branches is expanded and executed, so this can be used to protect the other branch from blowing up.
1018pub 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      //accumulator.push(lit.to_string());
1125    } else if let TokenTree2::Group(grp) = token.clone() {
1126      // Recurse into groups
1127      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
1140/// Concatenate two or more values together into a string.
1141/// 
1142/// *Syntax*: `%(concat <v1> <v2>...)`
1143/// 
1144/// Calls `to_string` method on values that are not string literals.
1145pub 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
1166/// Return a string representation of a `do-with-in!` value.
1167/// 
1168/// *Syntax*: `$(naiveStringifier <value>)`
1169/// 
1170/// As the name implies, not all cases may be elegantly handled, and the output from this handler may change without warning.
1171/// Potentially useful nonetheless for print debugging of complex structures and the like.
1172pub 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
1184/// Turn a string into a named identifier.
1185/// 
1186/// *Syntax*: `$(string_to_ident <stringValue>)`
1187/// 
1188/// This allows the creation and reference of dynamic identifier names. Argument must be a string or an object with the `to_string` method.
1189pub 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        //variables.with_interp.insert(var_token.to_string(), 
1229      },
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            }); //replace with: left = Some(result) 
1703            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
1718/// Perform basic arithmetic calculations.
1719/// 
1720/// Because of a lack of type inference, you have to specify your desired return type at the start of any use of this handler.
1721/// By default this will be a suffix-annotated literal (e.g. `5i8`, `1_i32`); append a `u` to the type name to return an unsuffixed literal.
1722/// See [Rust by Example](https://doc.rust-lang.org/rust-by-example/primitives.html) for further reference.
1723/// 
1724/// Take care to ensure that the literal values you use are within the bounds of the specified return type:
1725/// don't use negative numbers in an unsigned context; and 
1726/// don't use values too large for the specified type (e.g. `1000i8`)
1727///
1728/// ## Supported Operators
1729/// 
1730/// | Operator | Operation | Notes |
1731/// | -------- | --------- | ----- |
1732/// | `+`       | Addition              |  |
1733/// | `-`       | Subtraction           |  |
1734/// | `*`       | Multiplication        |  |
1735/// | `/`       | Division              |  |
1736/// | `%`       | Modulo/Remainder      |  |
1737/// | `\|`      | Bitwise OR            |  |
1738/// | `^`       | Bitwise XOR           |  |
1739/// | `&`       | Bitwise AND           |  |
1740/// | `>`       | Bitwise right shift   | Note single `>` rather than more conventional `>>` |
1741/// | `<`       | Bitwise left shift    | Note single `<` rather than more conventional `<<` |
1742/// | `not`     | Bitwise NOT           | Unary. |
1743/// | `size_of` | Size of type in bytes | Unary. Uses [https://doc.rust-lang.org/std/mem/fn.size_of.html] |
1744/// 
1745/// Bitwise operators are only supported for integer types, not floats.
1746/// 
1747/// ## Full grammar in Extended Backus-Naur format
1748/// 
1749/// The following grammar represents a tradeoff between legibility and strict correctness.
1750/// Specifically, its production rules are not limited to type-correct expressions.
1751/// 
1752///     <arithmetic_expression> ::= <output_specifier> <ws>+ <command>
1753///     <output_specifier> ::= <type> | <unsuffixed_literal>
1754///     <unsuffixed_literal> ::= <type>  "u"
1755///     <type> ::= <integer_type> | <float_type>
1756///     <integer_type> ::= <signed_integer_type> | <unsigned_integer_type>
1757///     <signed_integer_type> ::= "i8" | "i16" | "i32" | "i64" | "isize"
1758///     <unsigned_integer_type> ::= "u8" | "u16" | "u32" | "u64" | "usize"
1759///     <float_type> ::= "f32" | "f64"
1760///     <command> ::= <binary_expr> | <unary_expr>
1761///     <unary_expr> ::= <unary_operator> <ws>+ <val>
1762///     <unary_operator> ::= "not" | "size_of"
1763///     <binary_expr> ::= <val> <ws>+ <binary_operator> <ws>+ <val>
1764///     <binary_operator> ::= "+" | "-" | "*" | "/" | "%" | "|" | "^" | "&" | ">" | "<"
1765///     <val> ::= <ws>* (<sub_expr> | <number>) <ws>*
1766///     <sub_expr> ::= "(" <command> ")"
1767///     <number> ::= (<signed_integer> | <unsigned_integer> | <float>)
1768///     <float> ::= <signed_integer> <fraction>? <exponent>? ("_"? <float_type>)?
1769///     <fraction> ::= "." <digit>+
1770///     <signed_integer> ::= "-"? <dec_integer_unsigned> ("_"? <signed_integer_type>)?
1771///     <unsigned_integer> ::= <dec_integer_unsigned> | <hex_integer> | <bin_integer> ("_"? <unsigned_integer_type>)?
1772///     <dec_integer_unsigned> ::= (<digit> | <one_to_nine> ("_"? <digit>)+)
1773///     <hex_integer> ::= "0" ("x" | "X") ("_"? <hex_digit>)+
1774///     <hex_digit> ::= <digit> | [a-f] | [A-F]
1775///     <bin_integer> ::= "0" ("b" | "B") ("_"? <bin_digit>)+
1776///     <bin_digit> ::= "0" | "1"
1777///     <digit> ::= "0" | <one_to_nine>
1778///     <one_to_nine> ::= [1-9]
1779///     <exponent> ::= ("e" | "E") ("+" | "-")? <digit>+
1780///     <ws> ::= ? Rust-accepted whitespace tokens ?
1781/// 
1782/// # Examples
1783/// 
1784/// ```rust,ignore
1785/// let x = $(arithmetic u64 1 + 2 + 3);
1786/// assert_eq!(x, 6);
1787/// ```
1788pub 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       //variables.with_interp.insert(var_token.to_string(), 
1806        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
1922/// Redefine which sigil to use within the scope of the handler.
1923/// 
1924/// *Syntax*: `$(withSigil <newSigil> <codeUsingNewSigil>)`
1925///
1926/// In a context where the sigil was `$` and you want to complicatedly generate a lot of macro_rules! code based on some table, you might use it like so
1927/// 
1928/// ```rust,ignore
1929/// // various other code
1930/// $(withSigil %
1931///     %(var
1932///       table = {%(array mk ...)} // The multidimensional table data, which will be nested arrays
1933///     )
1934///     %(let
1935///       pattern = {...} // The template inner macro code for each arm
1936///       macro_rules_inner = { %(arg_pattern %(array ith get 0 %inner_table) %(array ith get 1 %inner_table)) => { %(inner_pattern %inner_table) } }
1937///     )
1938///     %(mk arg_pattern ($ %1:item, $ %(string_to_ident %(concat "real_" $(run %1))):item, $real:item, %(array map true item %pattern %(run %2))))
1939///     %(mk macro_rules macro_rules! %(run %1) { %(array map true inner_table %(run %2) %(run %3)) })
1940///     %(array each macro_rules %table))
1941/// ```
1942///
1943/// It is also useful to import code that uses a different sigil; for example, if you have a shared header that defines some common handlers and data,
1944/// but it is used in invocations that use different sigils, you can wrap the `import` in a `withSigil` matching the sigil the imported file uses.
1945pub 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(); // Skip call
1948  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(); // Skip over `escape`
1992  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
2012/// Evaluate block of code in place.
2013/// 
2014/// *Syntax*: $(run {<code>})
2015/// 
2016/// Useful for pass-through arguments when building handlers, or to evaluate an unquoted array.
2017pub 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}
2025// TODO: Remeber to check for whether 'quote' ends up stacking up due to everything inside the $(...) being passed through the t
2026/// In the lisp sense; renders its argument inert.
2027/// 
2028/// *Syntax*: `$(quote <arg>)`
2029/// 
2030/// Allows an expression to be created in one place, passed around as-is, and eventually unwrapped with [unquote] for expansion and evaluation.
2031pub fn quote<T: StartMarker + Clone>(c: Configuration<T>, v: Variables<T>, data:Option<TokenStream2>, t: TokenStream2) -> StageResult<T> {
2032  // Remember that the first token of t should already be 'quote'
2033  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
2042/// In the lisp sense; renders its argument ert.
2043/// 
2044/// *Syntax*: `$(unquote <quotedArg>)`
2045/// 
2046/// Unwraps an expression created with [quote], allowing it to be expanded and run in a different context from its definition.
2047pub 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  /*
2082  if let Some(TokenTree2::Punct(p)) = tok.clone() {
2083    let p_c = p.as_char();
2084    if p_c == sig_char {
2085    } else {
2086      let msg = format!("Expected {}, got {}, inside unquote.", sig_char, p_c);
2087      out = quote!{compile_error!{ #msg }}.into();
2088    }
2089  } else {
2090    let msg = format!("Expected {}, got {:?}, inside unquote.", sig_char, tok);
2091    out = quote!{compile_error!{ #msg }}.into();
2092  }*/
2093  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            // token is now the rhs
2145            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  // We check whether it is a number or a bool, and split which one at that point
2341  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          // Check string equality
2381          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
2464/// Handle logic expressions with a nestable sublanguage
2465/// 
2466/// Basic usage: `$(logic <expression>)`.
2467/// 
2468/// Returns `true` or `false` based on evaluating standard boolean logic expressions.
2469/// Subexpressions can be created using parenthesis and nested arbitrarily.
2470/// 
2471/// | Operator | Logical Operation    |
2472/// |--------- | ---------            |
2473/// | `A & B`  | AND (conjunction)    |
2474/// | `A \| B` | OR (disjunction)     |
2475/// | `A ^ B`  | XOR (exclusive OR)   |
2476/// | `A = B`  | EQUAL (equivalence)  |
2477/// | `! A`    | NOT (negation)       |
2478/// | `true`   | TRUE literal         |
2479/// | `false`  | FALSE literal        |
2480/// 
2481/// Numeric comparisons are also supported between numeric values:
2482/// 
2483/// | Operator | Numeric operation        |
2484/// | -------- | -----------------        |
2485/// | `X > Y`  | Greater-than             |
2486/// | `X >= Y` | Greater-than or equal to |
2487/// | `X = Y`  | Equal to                 |
2488/// | `X <= Y` | Less-than or equal to    |
2489/// | `X < Y`  | Less-than                |
2490/// | `X != Y` | Not equal to             |
2491/// 
2492/// Finally, subexpressions of the form `(eq_str "a" "b")` can be used to do string equality comparisons.
2493/// 
2494/// ## Examples ##
2495/// 
2496/// ```ignore
2497/// // Logic expression returns true or false
2498/// let x1 = $(logic false | true); // x1 = true
2499/// 
2500/// // Nesting is supported
2501/// let xf = $(logic (false | (! false)) | ((true = true) & (! false))); // xf = true
2502/// 
2503/// // Numeric comparison
2504/// $(logic $N < $M)
2505/// 
2506/// // Use within an $(if) handler and containing a $(arithmetic) expression.
2507/// $(if { $(logic $(arithmetic u64u (($N * $WORDSIZE) % ((size_of u8) * 8))) = 0) } { 0 } { 1 })
2508/// ```
2509/// 
2510/// See `do_with_in_test.rs` for more examples.
2511pub 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!("Expected a path segment (ie a string literal) for the import handler; got {
2551        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(); // Skip 'include'
2558    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}
2617/// Import the contents of a file.
2618/// 
2619/// *Syntax*: `$(import <pathSegment>...)`
2620/// 
2621/// Path is specified by quoted segments; special unquoted identier `Base` is used for the crate root.
2622/// Takes into account the `file:` hint in `do-with-in!` front matter to allow relative path addressing.
2623///
2624/// Errors in the imported file will point at the import statement, rather than within the file itself.
2625/// 
2626/// See tests for more examples of file importing.
2627pub 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/*
2643 * $(fn name(_ foo, _ inner = {default}, bar = {wesf e2f}, named inner_name_2 = {,,, wefi 2we,f 2qwef}) { })
2644 *
2645 *
2646 */
2647#[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      // First we get the function's name
2683      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          // Create an argument matcher
2715          // External name and internal name
2716          // Declaration order and invocation order
2717          let mut defaults_by_declaration_position: Vec<Option<TokenStream2>> = Vec::new();
2718          let mut thunks_by_invocation_position: Vec<Option<TokenStream2>> = Vec::new();
2719          // The inner and outer names index into defaults_by_position, which is our 'root list of args'
2720          let mut inner_names: BiMap<usize, String> = BiMap::<usize, String>::new();
2721          let mut outer_names: BiMap<usize, String> = BiMap::<usize, String>::new();
2722          // Once we have all the declaration site stuff done, we populate the thunks_by_invocation_position
2723          // and then process them.
2724          // Thunks get run in an environment built up of things invoked to the left of them using the external names.
2725          // Defaults get run in an environment built up of things defined to the left of them using the internal names.
2726          // We have a list of internal/external names with assigned values
2727          // We want to allow 'lazy defaults' - that is, stuff like
2728          // $(fn save(file_base, file_extension=".bak", file_name={$(concat $file_base $file_extension)}) {...})
2729          // As long as $file_base is only used in file_name, this will error out ~ correctly when no value is specified
2730          // for file_base or file_name. Eg
2731          // $(save ()) ⇒ compile_error!{ "No such variable: file_base defined." }
2732          // $(save (file_name="backup.sav")) ⇒ success, file saved as "backup.sav"
2733          // $(save (file_base="savefile")) ⇒ success, file saved as "savefile.bak"
2734          // The order of processing is...
2735          let mut call_site_stream = t.clone().into_iter();
2736          call_site_stream.next(); // The function invocation token
2737          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            // First we parse the declaration site args to generate a parser for the use site args
2741            let mut more = true;
2742            while more {
2743              // $pi ≡ Punct("_") or Ident
2744              // $val ≡ Group or Ident or Literal
2745              // $args ≡ ($pi $pi? ("=" $val)?),*
2746              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                // We get the value and do everything else inside here too
2771                /*let second = match declaration_site_args.next() {
2772                  None => {
2773                  },
2774                  Some(...) => {
2775                  },
2776                  Some(x) => {
2777                  },
2778                };*/
2779              } else {
2780                // We stuff the first thing in the 
2781              }
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        // Consume the initial 'let'
2808        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(); // FIXME
2860  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    //error
2887    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}
2959/// Create and assign variables. Does NOT interpolate during either definition or use.
2960/// 
2961/// *Syntax*: `%(let <ident> = <value>)`
2962/// 
2963/// A variable in `do-with-in!` is an identifier with a prepended sigil.
2964/// The value assigned to a variable defined with `let` will remain unchanged before it is used.
2965/// Internally, `let` is a wrapper around [assignmentInternalHandler];
2966pub 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
2974/// Create and assign variables. DOES interpolate during both definition and use.
2975/// 
2976/// *Syntax*: `$(var <ident> = <value>)`
2977/// 
2978/// A variable in `do-with-in!` is an identifier with a prepended sigil.
2979/// Variables set with `var` can make reference to other metaprogramming variables.
2980/// Internally, `var` is a wrapper around [assignmentInternalHandler];
2981pub 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
3019/// Embeds data in one invocation of `do_with_in!` in a way that can be used in other invocations.
3020/// 
3021/// To embed an unnamed marker, call the handler with `$(marker => ...)`. An optional marker name 
3022/// can be set which can be used as a filter by `runMarkers`: `$(marker "$name" => ...)`
3023/// 
3024/// Markers evaluate to nothing when run normally; the code in the `...` is only run - and the
3025/// environment captured - when run via `runMarkers`.
3026pub 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  //while stream.peek().is_some() {
3031  //  //
3032  //}
3033  Ok((v, quote!{}))
3034}
3035
3036/// Loads data into the environment from other invocations of `do_with_in!`.
3037///      
3038/// Call as `$(runMarkers $path)` to run all markers in the file at `$path`. To run a specific named marker,
3039/// call `$(runMarkers $path => "name of marker to run")`.
3040/// 
3041/// If `$path` is empty, it will try to point to the current file (there are limitations here until some RFCs land).
3042/// 
3043/// See [`markerHandler`] for details on creating named and unnamed markers.
3044/// 
3045/// [`markerHandler`]: #method.markerHandler
3046/// 
3047/// Markers evaluate to nothing when run normally; the markers' embedded code is run, and the environment is captured,
3048/// when run via `runMarkers`.
3049/// This gives you a way to (for example) set variables or define new handlers in one part of your source file, and use
3050/// them in other invocations of `do_with_in!` within the same source file.
3051pub 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  // If we are running only a specific marker, this will have been called with $(runMarkers $path => "name of marker to run")
3054  // getCode! will have eaten the '=', but that leaves us the '>' to check on
3055  let limit = match stream.next() {
3056    None => None,
3057    Some(TokenTree2::Punct(p)) if p.as_char() == '>' => {
3058      // Limit to markers with matching name
3059      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  // The file is in `tokens`; so we go over the file to find instances of `$(marker {...})` and run all the `...`
3081  // We use c.sigil to figure out which symbol we should be looking for for $
3082  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            // Check whether the handler matches
3112            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                  // Here we check whether we have the right marker
3118                  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                          // Discard matchers with limits
3128                        },
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                          // Discard non-matching matchers
3142                        },
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
3185/// Provides tools for working with arrays.
3186/// 
3187/// *Syntax*: `$(array <q>? <command> <arguments>)`
3188/// 
3189/// An array in `do_with_in!` is a Group (delimited token stream) containing zero or more Groups, and nothing else.
3190/// The array commands simply manipulate these sequences of tokens to produce an evaluated result.
3191/// All commands that "modify" an array in fact produce a new evaluated result.
3192/// By convention, arrays are delimited by square brackets e.g. `[{100} {a b}]`.
3193/// 
3194/// ## q mode ##
3195/// 
3196/// If the `array` token is followed immediately by a `q`, the command will treat its arguments as quoted and handle them as such.
3197/// For example:
3198/// 
3199///     %(array q length %(quote [ {foo} ])); // evaluates to 1;
3200///     %(let x = { quux });
3201///     %(array ith 2 [ {1} {foo bar baz} { $x } ]); // evaluates to { quux }
3202///     %(array q ith 2 %(quote [ {1} {foo bar baz} { $x } ])); // evaluates to %(quote { $x }).
3203/// 
3204/// ## Commands ##
3205/// 
3206/// | Command     | Summary                                                                                   | Syntax |
3207/// | -------     | -------                                                                                   | ------ |
3208/// | `length`    | Return the length of the array.                                                           | `$(array length <array>)`                             |
3209/// | `ith`       | Work with array using positional arguments.                                               | `$(array ith <operation> <arguments>`                 |
3210/// | `slice`     | TODO                                                                                      |         |
3211/// | `concat`    | Concatenate the elements of two or more arrays together.                                  | `$(array concat <array1> <array2> ...)`               |
3212/// | `each`      | Passes array of argument tuples to a handler.                                             | `$(array each <handlerName> <array>)`                 |
3213/// | `map`       | Returns a new array based on applying <block> to <srcArray>                               | `$(array map <should_isolate> <name> <block> <srcArray>)` |
3214/// | `mk`        | Iterates through arguments, checks if they are valid array elements, and groups them      | `$(array mk <block1> <block2> ... )`                  |
3215/// 
3216/// Some of these commands do a lot:
3217/// 
3218/// ## `ith` ##
3219/// 
3220/// All `ith` subcommands take a zero-indexed position argument to indicate where in the array the subcommand applies.
3221/// Negative integers may be used to index from the tail of the array e.g. `-1` represents the final element, `-2` the penultimate element, and so on.
3222/// The special tokens `head` and `tail` can be used instead of integer positions 0 and -1 respectively.
3223/// 
3224/// | Subcommand  | Summary | Syntax |
3225/// | ---------   | ------- | ------ |
3226/// | `get`       | Returns the element at `<position>`.                          | `$(array ith get <position> $array);` |
3227/// | `set`       | Replace the element at `<position>` with `<newEl>`.           | `$(array ith set <position> <newEl> $array);` |
3228/// | `insert`    | Insert element `<newEl>` before the element at `<position>`.  | `$(array ith insert <position> <newEl> $array)` |
3229/// | `remove`    | Remove the element at `<position>`.                           | `$(array ith remove <position> $array)` |
3230/// 
3231/// ## `each` ##
3232/// 
3233/// Iterates through each item in <array> and runs the handler identified by <handlerName>, passing the item's sub-elements as arguments.
3234/// Useful for cases where `map` would be overkill, or for adding flexibility to `mk`-generated handlers' simple argument passing.
3235/// See `examples/mem.rs` for a demonstration of the latter pattern.
3236/// 
3237/// Example:
3238/// 
3239///  `$(array each run [ {$(let f = {3})} {$(let g = {4})} ] )` will set `$f` to 3 and `$g` to 4.
3240/// 
3241/// ## `map` ##
3242/// 
3243/// If `should_isolate` is set to `true`, the code block is kept isolated from the running environment, if `false`, variables and
3244/// handlers defined within the block will persist in the environment, allowing patterns like currying.
3245/// 
3246/// The `<name>` argument is used to set a variable representing the current element available for use within the code block `<block>`.
3247pub 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  // Now we dispatch on the array op
3262  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      // First we run all the tokens
3318      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      // Now we dispatch on the ith op
3322      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      // We need to parse the $n. It can be a positive number (indexing from the start), a negative number (indexing backwards from the end),
3331      // or the special tokens 'head' and 'tail'.
3332      pull_offset!(stream, op_anchor, offset, v);
3333      // Some of the sub_op's have different args from this point, so we have to match on the sub_op before we can continue
3334      match sub_op.as_str() {
3335        "get" => {
3336          // Next arg is an array
3337          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          // Next arg is an array element
3349          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          // Next arg is an array
3369          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          // Next arg is an array element
3381          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); // We base the offset off of the *new* size, which means that measuring from the end *can* append through using tail or -1
3392          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      // Now we dispatch on the slice op
3404      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          // Now we go through each array 'array element'-wise
3423          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      // $(array map should_isolate name {stuff} $array)
3497      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      // This is a simple thing; we just iterate through every argument,
3571      // check that it is a valid array element, and then put it in another group
3572      // There is a subtlety to whether we are in 'quoted' or not
3573      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
3631/// This function generates the default handler set.
3632///
3633/// Currently, the actually useful handlers consist of:
3634///
3635/// | Invoke as        | Defined by                | Note                                                                                                                                                                               |
3636/// |------------------|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
3637/// | if               | [ifHandler]               | Conditionally execute one of two branches, depending on the result of a test expression. Use as `$(if {test} { true branch } { false branch })`.                                   |
3638/// | let              | [letHandler]              | Create and assign a variable. Does NOT interpolate during either definition or use.                                                                                  |
3639/// | var              | [varHandler]              | Create and assign a variable. DOES interpolate during both definition and use.                                                                                     |
3640/// | concat           | [concatHandler]           | Concatenate two or more values together into a string. Calls `to_string` method on values that are not string literals.                                                            |
3641/// | arithmetic       | [arithmeticHandler]       | You have to specify the type of the number eg i8, usize, f64                                                                                                                       |
3642/// | naiveStringifier | [naiveStringifierHandler] | Return a string representation of a `do-with-in!` value. Per the name: may not cover all cases.                                                                                    |
3643/// | string_to_ident  | [string_to_identHandler]  | Turn a string into a named identifier, allowing dynamic identifier names.                                                                                                          |
3644/// | logic            | [logicHandler]            | Sublanguage: nesting with parenthesis; logic ops ⌜&⌝, ⌜\|⌝, ⌜^⌝, ⌜=⌝, unary ⌜!⌝, ⌜true⌝, ⌜false⌝; numeric comparisons with numbers ⌜>⌝, ⌜>=⌝, ⌜=⌝, ⌜<=⌝, ⌜<⌝, ⌜!=⌝                 |
3645/// | mk               | [mkHandler]               | A simple way to define new handlers at the use site                                                                                                                                |
3646/// | quote            | [quote][quote()]          | In the lisp sense; renders the argument inert                                                                                                                                      |
3647/// | unquote          | [unquote]                 | In the lisp sense; renders the argument ert                                                                                                                                        |
3648/// | run              | [run]                     | Evaluate block of code in place. Useful for pass-through arguments when building handlers, or to evaluate an unquoted array.                                                       |
3649/// | array            | [arrayHandler]            | This handler has a bunch of subcommands and options; it is where most of the functionality for dealing with the representation we use of arrays is.                                |
3650/// | import           | [importHandler]           | Basic file inclusion. Path to file is defined by a series of quoted segments, relative path can be used if `file:` hint is set in front matter.                                    |
3651/// | withSigil        | [withSigilHandler]        | Redefine which sigil to use within the scope of the handler. Sigil can be one of `$`, `%`, `#`, or `~`.                                                                            |
3652/// | marker           | [markerHandler]           | Embed data in one invocation of `do_with_in!` in a way that can be used in other invocations.                                                                                      |
3653/// | runMarkers       | [runMarkersHandler]       | Load data into the environment from other invocations of `do_with_in!`.                                                                                                            |
3654pub 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(&quote), 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  // Check for configuration first
3681  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      // For now to make testing possible
3690      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()  // we actually want to early exit here, not do: do_with_in_explicit(it.to_compile_error().into(), Configuration::<DoMarker>::default(), defaultHandlers()),
3698  }
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  //check for variables to insert
3747  //check for handlers to run
3748  //insert token
3749  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          // First we check for no interp, then interp
3772          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        // First we check for no interp, then interp
3792        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          // Check whether the handler matches
3809          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            //if let Some(handler) = v.handlers.get(
3831          }
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/*
3857fn with_maker(args: ArgList, body: Body) -> Handler {
3858  |c: Configuration, v: Variables, t: TokenStream| {
3859    // First match on the args
3860    // Then put substitutions in the body tokenstream
3861    (v, t)
3862  }
3863}
3864
3865#[proc_macro_attribute]
3866fn do_with_in_izer(args: TokenStream, body: TokenStream) -> TokenStream {
3867  let mut configuration = defaultConfiguration();
3868  // Update configuration from args
3869  let new_body = quote!(
3870    let new_args = do_with_in_explicit(t);
3871    $body
3872  }
3873  new_body
3874}
3875
3876*/
3877
3878#[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