macroscript/
stdlib.rs

1/*!
2Contains the standard library for macroscript.
3
4If you want to see the documentation for all macros at once, see [`DocumentationHelper`].
5
6*/
7
8
9#![allow(
10    clippy::cast_sign_loss,
11    clippy::float_cmp,
12    clippy::cast_possible_truncation,
13    clippy::cast_possible_wrap
14)]
15
16use itertools::Itertools;
17use std::{
18    collections::HashMap,
19    str::FromStr,
20    hash::{Hasher, BuildHasher}
21};
22use rand_pcg::Pcg32;
23use rand::{Rng, SeedableRng};
24use seahash::SeaHasher;
25use regex::Regex;
26
27use crate::{execution::{Macro, MacroError, MacroErrorKind}, parsing::unescape, TextMacro};
28
29macro_rules! count {
30    ($tt: tt $($tts: tt)*) => {
31        1 + count!($($tts)*)
32    };
33    () => {0}
34}
35
36macro_rules! builtin_macros {
37    ($($(#[$attr: meta])* macro $id: ident as $name: literal {$inner: item})*) => {$(
38        #[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Hash)]
39        #[doc = concat!("See the documentation on [`DocumentationHelper`] for documentation on this struct.")]
40        pub struct $id;
41        
42        impl Macro for $id {
43            $inner
44        }
45    )*
46
47        /// Item purely for documentation purposes of the standard library.
48        /// Dynamically made for easier browsing.
49        /**
50# Core macros
51Even without the standard library, there are a few core macros that are always included. They are as follows:
52
53## `try`
54Executes some escaped macroscript, and returns a boolean value and output.
55
56- If the inner script errors, then the boolean is `false` and the output is the error message.
57- If the inner script succeeds, then the boolean is `true` and the output is the result of the inner script.
58
59This is reminiscent of Lua's `pcall` function.
60
61### Examples
62```
63# use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
64[try/\[add\/5\/5\]] -> true/10
65[try/\[shl\/5\/100\]] -> false/shift amount of 100 is too large
66# "#)}
67```
68
69## `load`
70Loads a variable's value and returns it. Errors if the variable doesn't exist.
71
72### Examples
73```
74# use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
75[load/x] -> error: variable "x" does not currently exist
76[store/x/5][load/x] -> 5
77# "#)}
78```
79
80## `store`
81Stores a value into a variable and returns nothing.
82
83The variable table is global to the `apply_macros` function.
84
85### Example
86```
87# use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
88[store/x/5] -> <no output>
89# "#)}
90```
91
92## `drop`
93Deletes a variable.
94
95### Example
96```
97# use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
98[store/x/5][drop/x][load/x] -> error: variable "x" does not currently exist
99# "#)}
100```
101
102## `get`
103Gets the value of a variable, storing a supplied default and returning it if the variable doesn't exist.
104
105### Example
106```
107# use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
108[get/x/5],[load/x] -> 5,5
109# "#)}
110```
111
112## `is_stored`
113Returns whether a variable currently exists.
114
115### Examples
116```
117# use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
118[is_stored/x] -> false
119[store/x/5][is_stored/x] -> true
120# "#)}
121```
122         */
123        /// ---
124        /// # Standard library
125        ///
126        /// These macros need to be included using [`crate::add_stdlib`].
127        ///
128        $(
129        /// ---
130        ///
131        #[doc = concat!("# [`", $name, "`](struct@", stringify!($id), ")")]
132        $(#[$attr])*
133        ///
134        )*
135        pub enum DocumentationHelper {}
136
137        /// Adds the standard library's builtin macros to a map of macro names.
138        pub fn add(macros: &mut HashMap<String, Box<dyn Macro>, impl BuildHasher>) {
139            $(
140                macros.insert($name.into(), Box::new($id));
141            )*
142        }
143    }
144}
145
146macro_rules! get_args {
147    ($name: literal, $arguments: ident; $($ids: ident),+) => {{
148        let mut args = $arguments.iter();
149        let c = count!($($ids)*);
150        get_args!{_recur $name args; c $($ids)* | }
151    }};
152    (_recur $name: literal $args: ident; $amount: ident $id: ident $($ids: ident)* | $($leftover: ident)*) => {
153        let Some($id) = $args.next() else {
154              return Err(MacroError::new(
155                  $name.into(),
156                  MacroErrorKind::not_enough_args($amount, count!($($leftover)*))
157              ));
158          };
159        get_args!{ _recur $name $args; $amount $($ids)* | $($leftover)* $id }
160    };
161    (_recur $name: literal $args: ident; $amount: ident | $($leftover: ident)*) => {
162        ($($leftover,)*)
163    }
164}
165
166macro_rules! convert_to_number {
167    ($name: literal; at $idx: expr => $arg: expr) => {
168        convert_to_number!($name; <f64> at $idx => $arg)
169    };
170    ($name: literal; <$ty: ty> at $idx: expr => $arg: expr) => {{
171        let arg = $arg;
172        <$ty>::from_str(arg).map_err(|_| {
173            MacroError::new(
174                $name.into(),
175                MacroErrorKind::user(
176                    format!("could not convert argument {} \"{arg}\" to {}", $idx, stringify!($ty))
177                   )
178            )
179        })?
180    }}
181}
182
183fn truthy(string: impl AsRef<str>) -> bool {
184    match string.as_ref() {
185        "true" | "True" => true,
186        v if f64::from_str(v).is_ok_and(|v| v > 0. && !v.is_nan()) => true,
187        _ => false
188    }
189}
190
191builtin_macros! {
192    /// Comment. Returns nothing.
193    /// ### Example
194    /// ```
195    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
196    /// [/comment!] -> <no output>
197    /// # "#)}
198    /// ```
199    macro Comment as "" {
200        fn apply(&self, _arguments: Vec<&str>) -> Result<String, MacroError> {
201            Ok(String::new())
202        }        
203    }
204
205    /// Reverses the given inputs.
206    /// ### Example
207    /// ```
208    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
209    /// [reverse/one/tw\/o/thr\\ee] -> thr\\ee/tw\/o/one
210    /// # "#)}
211    /// ```
212    macro Reverse as "reverse" {
213        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
214            Ok(
215                arguments
216                .into_iter()
217                .rev()
218                .join("/")
219            )
220        }
221    }
222
223    /// Addition. Takes 0 or more numeric arguments and returns their sum.
224    /// ### Examples
225    /// ```
226    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"    
227    /// [add/3/2/3/5/3] -> 16
228    /// [add/5] -> 5
229    /// [add] -> 0
230    /// [add/a/b] -> error: could not convert argument 1 "a" to f64
231    /// # "#)}
232    /// ```
233    macro Add as "add" {
234        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
235            arguments
236                .iter()
237                .enumerate()
238                .map(|(idx, arg)| {
239                    Ok(convert_to_number!("add"; at idx+1 => arg))
240                })
241                .process_results(|iter| iter.sum())
242                .map(|sum: f64| sum.to_string())
243        }
244    }
245
246    /// Multiplicaton. Takes 0 or more numeric arguments and returns their product.
247    /// ### Examples
248    /// ```
249    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
250    /// [multiply/1/2/3/4/5] -> 120
251    /// [multiply/5] -> 5
252    /// [multiply] -> 1
253    /// # "#)}
254    /// ```
255    macro Multiply as "multiply" {
256        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
257            arguments
258                .iter()
259                .enumerate()
260                .map(|(idx, arg)| {
261                    Ok(convert_to_number!("multiply"; at idx+1 => arg))
262                })
263                .process_results(|iter| iter.product())
264                .map(|product: f64| product.to_string())
265        }
266    }
267
268    /// Unescapes its input.
269    /// ### Examples
270    /// ```
271    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
272    /// [unescape/among\/us] -> among/us
273    /// [unescape/[if/true/\[add\/1\/1\]/\[add\/2\/1\]]] -> 2
274    /// # "#)}
275    /// ```
276    macro Unescape as "unescape" {
277        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
278               let (first_arg, ) = get_args!("unescape", arguments; first_arg);
279            Ok(unescape(first_arg).to_string())
280        }
281    }
282
283    /// Basic alternation. Chooses between all even arguments with the condition of the odd ones,
284    ///  with the last as a base case.
285    /// ### Examples
286    /// ```
287    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
288    /// [if/true/a/true/b/c] -> a
289    /// [if/false/a/true/b/c] -> b
290    /// [if/false/a/false/b/c] -> c
291    /// [if/false/a/false/b] -> error: all conditions exhausted
292    /// [if/c] -> c
293    /// # "#)}
294    /// ```
295    macro If as "if" {
296        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
297            let mut chunks = arguments.chunks_exact(2);
298            // Technically refutable pattern
299            while let Some([condition, value]) = chunks.next() {
300                if truthy(condition) {
301                    return Ok((*value).to_string());
302                }
303            }
304            if let [end] = chunks.remainder() {
305                Ok((*end).to_string())
306            } else {
307                Err(MacroError {
308                    name: "if".into(),
309                    error_type: MacroErrorKind::User {
310                        message: "all conditions exhausted".into()
311                    }
312                })
313            }
314        }
315    }
316
317    /// Returns whether a string is "truthy", i.e. whether it converts to true or false.
318    /// Truthy strings have to be either "True", "true", or a number greater than 0.
319    /// ### Examples
320    /// ```
321    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
322    /// [truthy/1] -> true
323    /// [truthy/0] -> false
324    /// [truthy/ture] -> false
325    /// [truthy/among us] -> false
326    /// [truthy/True/true] -> true/true
327    /// # "#)}
328    /// ```
329    macro Truthy as "truthy" {
330        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
331               Ok(arguments.into_iter().map(truthy).join("/"))
332          }        
333    }
334
335    /// Returns whether a string can be converted to a number.
336    /// ### Examples
337    /// ```
338    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
339    /// [is_number/1] -> true
340    /// [is_number/abc/2] -> false/true
341    /// # "#)}
342    /// ```
343    macro IsNumber as "is_number" {
344        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
345                Ok(arguments.into_iter().map(|v| f64::from_str(v).is_ok()).join("/"))
346        }
347    }
348
349    /// Raises a number to the power of another.
350    /// ### Examples
351    /// ```
352    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
353    /// [pow/7/2] -> 49
354    /// # "#)}
355    /// ``` 
356    macro Pow as "pow" {
357        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
358               let (base, exp) = get_args!("pow", arguments; base, exp);
359               let base = convert_to_number!("pow"; at 1 => base);
360               let exp = convert_to_number!("pow"; at 2 => exp);
361            Ok(base.powf(exp).to_string())
362        }
363    }
364
365    /// Subtracts a number from another.
366    /// ### Examples
367    /// ```
368    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
369    /// [subtract/7/2] -> 5
370    /// [subtract/3/5] -> -2
371    /// # "#)}
372    /// ``` 
373    macro Sub as "subtract" {
374        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
375               let (lhs, rhs) = get_args!("subtract", arguments; a, b);
376               let lhs = convert_to_number!("subtract"; at 1 => lhs);
377               let rhs = convert_to_number!("subtract"; at 2 => rhs);
378            Ok((lhs - rhs).to_string())
379        }
380    }
381    
382    /// Divides a number by another.
383    /// ### Examples
384    /// ```
385    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
386    /// [divide/5/2] -> 2.5 
387    /// [divide/3/5] -> 0.6
388    /// [divide/1/0] -> inf
389    /// [divide/-1/0] -> -inf
390    /// [divide/0/0] -> NaN
391    /// # "#)}
392    /// ``` 
393    macro Div as "divide" {
394        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
395               let (lhs, rhs) = get_args!("divide", arguments; a, b);
396               let lhs = convert_to_number!("divide"; at 1 => lhs);
397               let rhs = convert_to_number!("divide"; at 2 => rhs);
398            Ok((lhs / rhs).to_string())
399        }
400    }
401    
402    /// Takes the modulus of one number with respect to another.
403    /// ### Examples
404    /// ```
405    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
406    /// [mod/5/2] -> 1
407    /// [mod/-3/5] -> 2
408    /// # "#)}
409    /// ``` 
410    macro Modulus as "mod" {
411        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
412               let (lhs, rhs) = get_args!("mod", arguments; a, b);
413               let lhs = convert_to_number!("mod"; at 1 => lhs);
414               let rhs = convert_to_number!("mod"; at 2 => rhs);
415            Ok(lhs.rem_euclid(rhs).to_string())
416        }
417    }
418
419    
420    /// Takes the logarithm of a number. The base is optional, and defaults to [`std::f64::consts::E`].
421    /// ### Examples
422    /// ```
423    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
424    /// [log/5] -> 1.6094379124341003
425    /// [log/16/2] -> 4
426    /// # "#)}
427    /// ``` 
428    macro Log as "log" {
429        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
430               let (value, ) = get_args!("log", arguments; value);
431               let value = convert_to_number!("log"; at 1 => value);
432               let base = if let Some(base) = arguments.get(1) {
433                   convert_to_number!("log"; at 2 => base)
434               } else {
435                   std::f64::consts::E
436               };
437            Ok(value.log(base).to_string())
438        }
439    }
440
441    /// Gets a random number on the range [0, 1).
442    /// A seed can optionally be supplied.
443    /// ### Examples
444    /// ```
445    /// # /*
446    /// [rand] -> ?
447    /// # */
448    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
449    /// [rand/among us] -> 0.22694492387911513
450    /// # "#)}
451    /// ``` 
452    macro Rand as "rand" {
453        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
454               let value: f64 = if let Some(seed) = arguments.first() {
455                   let mut hasher = SeaHasher::new();
456                   hasher.write(seed.as_bytes());
457                let mut rand = Pcg32::seed_from_u64(hasher.finish());
458                rand.gen()
459               } else {
460                   rand::random()
461               };
462               Ok(value.to_string())
463        }
464    }
465
466    /// Hashes many values, returning 64-bit integers.
467    /// ### Examples
468    /// ```
469    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
470    /// [hash/rain world/brain rot] -> -4983183619591677382/-1860790453662518022
471    /// # "#)}
472    /// ```
473    macro Hash as "hash" {
474        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
475           Ok(
476                arguments.iter().map(|value| {
477                    let mut hasher = SeaHasher::new();
478                    hasher.write(value.as_bytes());
479                    hasher.finish() as i64
480               }).join("/")
481            )
482        }
483    }
484
485    /// Replaces all matches of a regular expression with a pattern.
486    /// Both the pattern and replacement are unescaped.
487    /// ### Examples
488    /// ```
489    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
490    /// [replace/vaporeon/(\[aeiou\])/$1$1] -> vaapooreeoon
491    /// [replace/porygon/\[o/e] -> error: unclosed character class
492    /// # "#)}
493    /// ```
494    macro Replace as "replace" {
495        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
496               let (haystack, pattern, replacement) = get_args!("hash", arguments; a, b, c);
497            let pattern = unescape(pattern);
498            let replacement = unescape(replacement);
499               let regex = Regex::new(&pattern).map_err(|err| {
500                let disp = match err {
501                    regex::Error::Syntax(err) => {
502                        let err_string = err.to_string();
503                        let last_line = err_string.lines().last().unwrap();
504                        last_line[7..].to_string()
505                    },
506                    regex::Error::CompiledTooBig(limit) =>
507                        format!("compiled regex exceeds size limit of {limit} bytes"),
508                    _ => err.to_string()
509                };
510                MacroError::new("replace".into(), MacroErrorKind::user(disp))
511            })?;
512               let res = regex.replace_all(haystack, replacement);
513               Ok(res.into_owned())
514        }
515    }
516
517    /// Converts the input to an integer, with an optional base to convert from.
518    /// ### Examples
519    /// ```
520    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
521    /// [int/54.2] -> 54
522    /// [int/-101/2] -> -5
523    /// [int/E621/16] -> 58913
524    /// # "#)}
525    /// ```
526    macro Int as "int" {
527        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
528               let (value, ) = get_args!("int", arguments; value);
529               if let Some(base) = arguments.get(1) {
530                let base = convert_to_number!("int"; <u32> at 2 => base);
531                if !(2 ..= 36).contains(&base) {
532                    return Err(MacroError::new("int".into(), MacroErrorKind::user(
533                        format!("invalid base {base} (must be between 2 and 36, inclusive)")
534                    )));
535                }
536                 i64::from_str_radix(value, base)
537                     .map(|v| v.to_string())
538                     .map_err(|_| MacroError::new("int".into(), MacroErrorKind::user(
539                         format!("failed to convert {value} to a number with base {base}")
540                     )))
541             } else {
542                     let value = convert_to_number!("int"; at 1 => value) as i64;
543                   Ok(value.to_string())
544               }
545        }
546    }
547
548    /// Converts the input to a hexadecimal integer.
549    /// ### Examples
550    /// ```
551    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
552    /// [hex/16] -> 10
553    /// [hex/255/5] -> FF/5
554    /// # "#)}
555    /// ```
556    macro Hex as "hex" {
557        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
558            arguments.iter().enumerate()
559                .map(|(idx, value)|
560                    Ok(format!("{:X}", convert_to_number!("hex"; <i64> at idx + 1 => value)))
561                ).process_results(|mut iter| iter.join("/"))
562        }
563    }
564
565    
566    /// Converts the input to a binary integer.
567    /// ### Examples
568    /// ```
569    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
570    /// [bin/5] -> 101
571    /// [bin/7/8] -> 111/1000
572    /// # "#)}
573    /// ```
574    macro Bin as "bin" {
575        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
576            arguments.iter().enumerate()
577                .map(|(idx, value)|
578                    Ok(format!("{:b}", convert_to_number!("bin"; <i64> at idx + 1 => value)))
579                ).process_results(|mut iter| iter.join("/"))
580        }
581    }
582
583    
584    /// Converts the input to an octal integer.
585    /// ### Examples
586    /// ```
587    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
588    /// [oct/59] -> 73
589    /// [oct/1777/755] -> 3361/1363
590    /// # "#)}
591    /// ```
592    macro Oct as "oct" {
593        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
594            arguments.iter().enumerate()
595                .map(|(idx, value)|
596                    Ok(format!("{:o}", convert_to_number!("oct"; <i64> at idx + 1 => value)))
597                ).process_results(|mut iter| iter.join("/"))
598        }
599    }
600
601    /// Converts a unicode codepoint to a character.
602    /// Note that this will error for invalid codepoints!
603    /// ### Examples
604    /// ```
605    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
606    /// [chr/55296] -> error: invalid codepoint at argument 1
607    /// [chr/65] -> A
608    /// [chr/65/109/111/110/103/32/85/115] -> Among Us
609    /// # "#)}
610    /// ```
611    macro Chr as "chr" {
612        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
613            arguments
614                .iter().enumerate()
615                .map(|(idx, chr)| {
616                    let ord = convert_to_number!("chr"; <u32> at idx + 1 => *chr);
617                    char::from_u32(ord).ok_or_else(|| MacroError::new("chr".into(), MacroErrorKind::user(
618                        format!("invalid codepoint at argument {}", idx + 1)
619                    )))
620                }).collect()
621        }
622    }
623
624    /// Converts characters into their unicode codepoints.
625    /// ### Examples
626    /// ```
627    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
628    /// [ord/] -> <no output>
629    /// [ord/A] -> 65
630    /// [ord/Among Us] -> 65/109/111/110/103/32/85/115
631    /// # "#)}
632    /// ```
633    macro Ord as "ord" {
634        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
635               let (value, ) = get_args!("ord", arguments; value);
636               Ok(value.chars()
637                   .map(|c| (c as u32).to_string())
638                   .join("/"))
639        }
640    }
641
642    /// Gets the length of the inputs.
643    /// ### Examples
644    /// ```
645    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
646    /// [len/] -> 0
647    /// [len/abc] -> 3
648    /// [len/abc/de] -> 3/2
649    /// # "#)}
650    /// ```
651    macro Length as "len" {
652        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
653               Ok(arguments.into_iter().map(|c| c.chars().count().to_string()).join("/"))
654        }
655    }
656
657    /// Splits the first input delimited by the second,
658    /// then returns the section at the third argument.
659    /// ### Example
660    /// ```
661    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
662    /// [split/a,b,c/,/1] -> b
663    /// # "#)}
664    /// ```
665    macro Split as "split" {
666        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
667               let (haystack, delimiter, index) = get_args!("split", arguments; a, b, c);
668            let index = convert_to_number!("split"; <usize> at 1 => index);
669               haystack.split(&**delimiter).nth(index)
670                .map(ToString::to_string)
671                   .ok_or_else(|| MacroError::new(
672                       "split".into(), MacroErrorKind::user(
673                           format!("index {index} is out of bounds")
674                       )
675                   ))
676        }        
677    }
678
679    /// Selects one of the arguments based on an index on the first.
680    /// If the index is `#`, returns the number of arguments, minus 1 for the `#`.
681    /// ### Examples
682    /// ```
683    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
684    /// [select/1/a/b/c] -> a
685    /// [select/#/one/two/three] -> 3
686    /// [select/0/it works, but why would you do this?] -> 0
687    /// [select/5/a/b] -> error: index 5 is out of bounds
688    /// [select/-1/nope, this isn't python] -> error: could not convert argument 1 "-1" to usize
689    /// # "#)}
690    /// ```
691    macro Select as "select" {
692        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
693               let (index, ) = get_args!("select", arguments; a);
694               if *index == "#" {
695                   return Ok((arguments.len() - 1).to_string());
696               }
697            let index = convert_to_number!("select"; <usize> at 1 => index);
698            arguments.get(index)
699                .map(ToString::to_string)
700                .ok_or_else(|| MacroError::new(
701                       "select".into(), MacroErrorKind::user(
702                           format!("index {index} is out of bounds")
703                       )
704                   ))
705        }        
706    }
707
708    /// Returns whether many strings are equal.
709    /// ### Examples
710    /// ```
711    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
712    /// [equal/one/one] -> true
713    /// [equal/one/two/three] -> false
714    /// [equal/1/1] -> true
715    /// [equal/1/1.0] -> false
716    /// # "#)}
717    /// ```
718    macro Equal as "equal" {
719        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
720            Ok(arguments.windows(2).all(|w| *w[0] == *w[1]).to_string()) // ** to convert &Cow<str> to str
721        }
722    }
723
724    /// Returns whether a number is equal to another.
725    /// ### Examples
726    /// ```
727    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
728    /// [#equal/1/1.0] -> true
729    /// [#equal/0.3/[add/0.1/0.2]] -> false
730    /// [#equal/nan/nan] -> false
731    /// # "#)}
732    /// ```
733    macro NumEqual as "#equal" {
734        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
735               let (lhs, rhs) = get_args!("#equal", arguments; a, b);
736            let lhs = convert_to_number!("#equal"; at 1 => lhs);
737            let rhs = convert_to_number!("#equal"; at 2 => rhs);
738            Ok((lhs == rhs).to_string())
739        }
740    }
741
742    /// Returns whether a number is greater than another.
743    /// ### Examples
744    /// ```
745    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
746    /// [greater/1/1] -> false
747    /// [greater/0.2/0.1] -> true
748    /// [greater/nan/nan] -> false
749    /// # "#)}
750    /// ```
751    macro Greater as "greater" {
752        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
753               let (lhs, rhs) = get_args!("greater", arguments; a, b);
754            let lhs = convert_to_number!("greater"; at 1 => lhs);
755            let rhs = convert_to_number!("greater"; at 2 => rhs);
756            Ok((lhs > rhs).to_string())
757        }
758    }
759
760    /// Returns whether a number is less than another.
761    /// ### Examples
762    /// ```
763    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
764    /// [less/1/1] -> false
765    /// [less/0.1/0.2] -> true
766    /// [less/nan/nan] -> false
767    /// # "#)}
768    /// ```
769    macro Less as "less" {
770        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
771               let (lhs, rhs) = get_args!("less", arguments; a, b);
772            let lhs = convert_to_number!("less"; at 1 => lhs);
773            let rhs = convert_to_number!("less"; at 2 => rhs);
774            Ok((lhs < rhs).to_string())
775        }
776    }
777
778    /// Negates many boolean inputs.
779    /// ### Examples
780    /// ```
781    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
782    /// [not/1.0] -> false
783    /// [not/true/false/3.0/-5.9] -> false/true/false/true
784    /// # "#)}
785    /// ```
786    macro Not as "not" {
787        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
788            Ok(
789                arguments.iter()
790                    .map(truthy)
791                    .map(|v| !v)
792                    .map(|v| v.to_string())
793                    .join("/")
794            )
795        }
796    }
797
798    /// Takes the logical AND of an arbitrary number of boolean inputs.
799    /// ### Examples
800    /// ```
801    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
802    /// [and/true/true] -> true
803    /// [and/false/true/true] -> false
804    /// # "#)}
805    /// ```
806    macro And as "and" {
807        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
808            Ok(
809                arguments.iter()
810                    .map(truthy)
811                    .reduce(|a, b| a && b)
812                    .unwrap_or(false)
813                    .to_string()
814            )
815        }
816    }
817
818    /// Takes the logical OR of an arbitrary number of boolean inputs.
819    /// ### Example
820    /// ```
821    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
822    /// [or/false/true] -> true
823    /// [or/false/true/true] -> true
824    /// # "#)}
825    /// ```
826    macro Or as "or" {
827        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
828            Ok(
829                arguments.iter()
830                    .map(truthy)
831                    .reduce(|a, b| a || b)
832                    .unwrap_or(false)
833                    .to_string()
834            )
835        }
836    }
837
838
839    /// Takes the logical XOR of an arbitrary number of boolean inputs.
840    /// ### Examples
841    /// ```
842    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
843    /// [xor/false/true] -> true
844    /// [xor/false/true/true] -> false
845    /// # "#)}
846    /// ```
847    macro Xor as "xor" {
848        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
849            Ok(
850                arguments.iter()
851                    .map(truthy)
852                    .reduce(|a, b| a ^ b)
853                    .unwrap_or(false)
854                    .to_string()
855            )
856        }
857    }
858
859    /// Takes the bitwise NOT of many 64-bit signed integer inputs.
860    /// ### Example
861    /// ```
862    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
863    /// [#not/0] -> -1 (0b00...0 -> 0b11...1)
864    /// [#not/5/-4] -> -6/3
865    /// # "#)}
866    /// ```
867    macro BitNot as "#not" {
868        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
869            arguments.iter().enumerate()
870                .map(|(idx, value)|
871                    Ok(!convert_to_number!("abs"; <i64> at idx + 1 => value))
872                ).process_results(|mut iter| iter.join("/"))
873        }        
874    }
875
876    /// Takes the bitwise AND of many 64-bit signed integer inputs.
877    /// ### Examples
878    /// ```
879    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
880    /// [#and/11/5] -> 1 (0b1011 & 0b0101)
881    /// [#and/8/13/7] -> 0 (0b1000 & 0b1101 & 0b0111)
882    /// # "#)}
883    /// ```
884    macro BitAnd as "#and" {
885        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
886            arguments.iter().enumerate()
887                .map(|(idx, value)| Ok(convert_to_number!("#and"; <i64> at idx + 1 => value)))
888                .process_results(|iter| iter.reduce(|a, b| a & b).unwrap_or(0).to_string())
889        }        
890    }
891    
892    /// Takes the bitwise OR of many 64-bit signed integer inputs.
893    /// ### Examples
894    /// ```
895    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
896    /// [#or/5/3] -> 7 (0b0101 | 0b0011)
897    /// [#or/9/5/2] -> 15 (0b1001 | 0b0101 | 0b0010)
898    /// # "#)}
899    /// ```
900    macro BitOr as "#or" {
901        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
902            arguments.iter().enumerate()
903                .map(|(idx, value)| Ok(convert_to_number!("#or"; <i64> at idx + 1 => value)))
904                .process_results(|iter| iter.reduce(|a, b| a | b).unwrap_or(0).to_string())
905        }        
906    }
907
908    
909    /// Takes the bitwise XOR of two 64-bit signed integer inputs.
910    /// ### Examples
911    /// ```
912    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
913    /// [#xor/5/3] -> 6 (0b0101 ^ 0b0011)
914    /// [#xor/8/11/5] -> 6 (0b1000 ^ 0b1011 ^ 0b0101)
915    /// # "#)}
916    /// ```
917    macro BitXor as "#xor" {
918        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
919            arguments.iter().enumerate()
920                .map(|(idx, value)| Ok(convert_to_number!("#xor"; <i64> at idx + 1 => value)))
921                .process_results(|iter| iter.reduce(|a, b| a ^ b).unwrap_or(0).to_string())
922        }        
923    }
924
925    /// Shifts the first argument's bits to the left by the second argument.
926    /// The second argument may not be greater than 63.
927    /// ### Examples
928    /// ```
929    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
930    /// [shl/5/2] -> 20 (0b101 -> 0b10100)
931    /// [shl/-9223372036854775808/1] -> 0 (0b100...0 -> 0b00...0)
932    /// # "#)}
933    /// ```
934    macro ShiftLeft as "shl" {
935        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
936            let (lhs, rhs) = get_args!("shl", arguments; a, b);
937            let lhs = convert_to_number!("shl"; <i64> at 1 => lhs) as u64;
938            let rhs = convert_to_number!("shl"; <u32> at 2 => rhs);
939            lhs.checked_shl(rhs)
940                .map(|v| (v as i64).to_string())
941                .ok_or_else(|| MacroError::new(
942                    "shl".into(),
943                    MacroErrorKind::user(format!("shift amount of {rhs} is too large"))
944                ))
945        }
946    }
947
948    
949    /// Shifts the first argument's bits to the right by the second argument.
950    /// The second argument may not be greater than 63.
951    /// ### Example
952    /// ```
953    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
954    /// [shr/-9223372036854775808/1] -> 4611686018427387904 (0b100...0 -> 0b0100...0)
955    /// # "#)}
956    /// ```
957    macro ShiftRight as "shr" {
958        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
959            let (lhs, rhs) = get_args!("shr", arguments; a, b);
960            let lhs = convert_to_number!("shr"; <i64> at 1 => lhs) as u64;
961            let rhs = convert_to_number!("shr"; <u32> at 2 => rhs);
962            lhs.checked_shr(rhs)
963                .map(|v| (v as i64).to_string())
964                .ok_or_else(|| MacroError::new(
965                    "shr".into(),
966                    MacroErrorKind::user(format!("shift amount of {rhs} is too large"))
967                ))
968        }
969    }
970
971    
972    /// Shifts the first argument's bits to the right by the second argument, keeping the sign bit.
973    /// The second argument may not be greater than 63.
974    /// ### Example
975    /// ```
976    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
977    /// [#shr/-9223372036854775808/1] -> -4611686018427387904 (0b100...0 -> 0b1100...0)
978    /// # "#)}
979    /// ```
980    macro ArithmeticShiftRight as "#shr" {
981        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
982            let (lhs, rhs) = get_args!("#shr", arguments; a, b);
983            let lhs = convert_to_number!("#shr"; <i64> at 1 => lhs);
984            let rhs = convert_to_number!("#shr"; <u32> at 2 => rhs);
985            lhs.checked_shr(rhs)
986                .map(|v| v.to_string())
987                .ok_or_else(|| MacroError::new(
988                    "#shr".into(),
989                    MacroErrorKind::user(format!("shift amount of {rhs} is too large"))
990                ))
991        }
992    }
993
994    /// Gets the absolute value of many numbers.
995    /// ### Examples
996    /// ```
997    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
998    /// [abs/-5] -> 5
999    /// [abs/NaN/-inf] -> NaN/inf
1000    /// # "#)}
1001    /// ```
1002    macro Abs as "abs" {
1003        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1004            arguments.iter().enumerate()
1005                .map(|(idx, value)|
1006                    Ok(convert_to_number!("abs"; at idx + 1 => value).abs().to_string())
1007                ).process_results(|mut iter| iter.join("/"))
1008        }    
1009    }
1010    
1011    /// Gets the sine of many numbers.
1012    /// ### Example
1013    /// ```
1014    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1015    /// [int/[sin/3.14159]] -> 0
1016    /// # "#)}
1017    /// ```
1018    macro Sine as "sin" {
1019        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1020            arguments.iter().enumerate()
1021                .map(|(idx, value)|
1022                    Ok(convert_to_number!("sin"; at idx + 1 => value).sin().to_string())
1023                ).process_results(|mut iter| iter.join("/"))
1024        }    
1025    }
1026
1027    /// Gets the cosine of many numbers.
1028    /// ### Example
1029    /// ```
1030    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1031    /// [int/[add/-0.01/[cos/3.14159]]] -> -1
1032    /// # "#)}
1033    /// ```
1034    macro Cosine as "cos" {
1035        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1036            arguments.iter().enumerate()
1037                .map(|(idx, value)|
1038                    Ok(convert_to_number!("cos"; at idx + 1 => value).cos().to_string())
1039                ).process_results(|mut iter| iter.join("/"))
1040        }    
1041    }
1042    
1043    /// Gets the tangent of many numbers.
1044    /// ### Example
1045    /// ```
1046    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1047    /// [int/[multiply/2/[tan/1]]] -> 3
1048    /// # "#)}
1049    /// ```
1050    macro Tangent as "tan" {
1051        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1052            arguments.iter().enumerate()
1053                .map(|(idx, value)|
1054                    Ok(convert_to_number!("tan"; at idx + 1 => value).tan().to_string())
1055                ).process_results(|mut iter| iter.join("/"))
1056        }
1057    }
1058
1059    
1060    /// Gets the inverse sine of many numbers.
1061    /// ### Example
1062    /// ```
1063    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1064    /// [asin/0/1] -> 0/1.5707963267948966
1065    /// # "#)}
1066    /// ```
1067    macro InvSine as "asin" {
1068        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1069            arguments.iter().enumerate()
1070                .map(|(idx, value)|
1071                    Ok(convert_to_number!("asin"; at idx + 1 => value).asin().to_string())
1072                ).process_results(|mut iter| iter.join("/"))
1073        }    
1074    }
1075
1076    /// Gets the inverse cosine of many numbers.
1077    /// ### Example
1078    /// ```
1079    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1080    /// [acos/1/0] -> 0/1.5707963267948966
1081    /// # "#)}
1082    /// ```
1083    macro InvCosine as "acos" {
1084        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1085            arguments.iter().enumerate()
1086                .map(|(idx, value)|
1087                    Ok(convert_to_number!("sin"; at idx + 1 => value).acos().to_string())
1088                ).process_results(|mut iter| iter.join("/"))
1089        }    
1090    }
1091    
1092    /// Gets the inverse tangent of a number.
1093    /// ### Example
1094    /// ```
1095    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1096    /// [int/[atan/1.5708]] -> 1
1097    /// # "#)}
1098    /// ```
1099    macro InvTangent as "atan" {
1100        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1101            arguments.iter().enumerate()
1102                .map(|(idx, value)|
1103                    Ok(convert_to_number!("atan"; at idx + 1 => value).atan().to_string())
1104                ).process_results(|mut iter| iter.join("/"))
1105        }
1106    }
1107
1108    /// Immediately raises an error. The error message is unescaped.
1109    /// ### Example
1110    /// ```
1111    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1112    /// [error/oh no!] -> error: oh no!
1113    /// # "#)}
1114    /// ```
1115    macro Error as "error" {
1116        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1117            Err(MacroError::new("error".into(), MacroErrorKind::user(
1118                arguments.first().map_or(String::from("no reason given"), ToString::to_string)
1119            )))
1120        }        
1121    }
1122
1123    /// Raises an error if the first argument is not truthy.
1124    /// ### Examples
1125    /// ```
1126    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1127    /// [assert/1/all good] -> <no output>
1128    /// [assert/false/yikes] -> error: yikes
1129    /// # "#)}
1130    /// ```
1131    macro Assert as "assert" {
1132        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1133               let (condition, ) = get_args!("assert", arguments; a);
1134            if truthy(condition) {
1135                Ok(String::new())
1136            } else {
1137                Err(MacroError::new("assert".into(), MacroErrorKind::user(
1138                    arguments.get(1).map_or(String::from("no reason given"), ToString::to_string)
1139                )))
1140            }
1141        }
1142    }
1143
1144    /// Slices a string.
1145    /// The first argument is the start, the next is the end, and optionally, the last is the step size.
1146    /// This works similarly to Python's string slicing rules (and is in fact carried over from it).
1147    /// ### Examples
1148    /// ```
1149    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1150    /// [slice/abcdefg/1/4] -> bcd
1151    /// [slice/abcde/1/] -> bcde
1152    /// [slice/1,2,30,45///2] -> 123,5
1153    /// [slice/kcab///-1] -> back
1154    /// # "#)}
1155    /// ```
1156    macro Slice as "slice" {
1157        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1158               let (haystack, start, end) = get_args!("slice", arguments; a, b, c);
1159            let start = (!start.is_empty())
1160                .then(|| Ok(convert_to_number!("slice"; <usize> at 2 => start)))
1161                .transpose()?;
1162            let end = (!end.is_empty())
1163                .then(|| Ok(convert_to_number!("slice"; <usize> at 3 => end)))
1164                .transpose()?;
1165            let step = arguments.get(3)
1166                    .map(|v| Ok(convert_to_number!("slice"; <isize> at 4 => v)))
1167                    .transpose()?
1168                    .unwrap_or(1);
1169            if step == 0 {
1170                return Err(MacroError::new("slice".into(), MacroErrorKind::user(
1171                    "cannot have a step length of 0"
1172                )))
1173            }
1174            let Some(slice) = (match (start, end) {
1175                (None, None) => Some(&haystack[..]),
1176                (Some(s), None) => haystack.char_indices().nth(s).and_then(|(s, _)| haystack.get(s..)),
1177                (None, Some(e)) => haystack.char_indices().nth(e).and_then(|(e, _)| haystack.get(..e)),
1178                (Some(s), Some(e)) => haystack.char_indices().nth(s)
1179                    .and_then(|(s, _)| Some((s, haystack.char_indices().nth(e)?)))
1180                    .and_then(|(s, (e, _))| haystack.get(s..e))
1181            }) else {
1182                return Err(MacroError::new("slice".into(), MacroErrorKind::user(
1183                    format!(
1184                        "part of range \"{}..{}\" is out of bounds for string of length {}",
1185                        start.map(|v| v.to_string()).unwrap_or_default(),
1186                        end.map(|v| v.to_string()).unwrap_or_default(),
1187                        haystack.chars().count()
1188                    )
1189                )))
1190            };
1191            if step == 1 {
1192                // Fast path
1193                Ok(slice.to_string())
1194            } else {
1195                // Slow path
1196                Ok(
1197                    if step < 0 {
1198                        slice.chars().rev().step_by((-step) as usize).collect()
1199                    } else {
1200                        slice.chars().step_by(step as usize).collect()
1201                    }
1202                )
1203            }
1204         }
1205     }
1206
1207    /// Returns the start location of the second argument in the first.
1208    /// Returns -1 if it couldn't be found.
1209    /// ### Examples
1210    /// ```
1211    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1212    /// [find/homeowner/meow] -> 2
1213    /// [find/clubstep monster/end] -> -1
1214    /// # "#)}
1215    /// ```
1216     macro Find as "find" {
1217        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1218              let (haystack, needle) = get_args!("find", arguments; a, b);
1219            
1220            Ok(haystack.find(&**needle).map_or(-1, |v| {
1221                haystack[..v].chars().count() as isize
1222            }).to_string())
1223        }
1224    }
1225
1226    /// Returns the number of disjoint occurrences of the second argument in the first.
1227    /// Returns 0 if none were found.
1228    /// ### Examples
1229    /// ```
1230    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1231    /// [count/Pacific Ocean/c] -> 3
1232    /// [count/hellololo/lol] -> 1
1233    /// # "#)}
1234    /// ```
1235    macro Count as "count" {
1236        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1237              let (haystack, needle) = get_args!("count", arguments; a, b);
1238            Ok(haystack.matches(&**needle).count().to_string())
1239        }
1240    }
1241
1242    /// Joins all arguments with the unescaped first argument.
1243    /// ### Examples
1244    /// ```
1245    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1246    /// [join/:/red/left/sleep] -> red:left:sleep
1247    /// [join/\/\//dou/ble] -> dou//ble
1248    /// # "#)}
1249    /// ```
1250    macro Join as "join" {
1251        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1252              let (delimiter, ) = get_args!("join", arguments; a);
1253              Ok(arguments.iter().skip(1).join(&unescape(delimiter)))
1254        }        
1255    }
1256
1257    /// Escapes the first argument.
1258    ///
1259    /// ### Example
1260    /// ```
1261    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1262    /// [escape/add/5/3] -> add\/5\/3
1263    /// # "#)}
1264    /// ```
1265    macro Escape as "escape" {
1266        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1267              let raw = arguments.join("/");
1268              Ok(raw.replace('\\', r"\\").replace('/', r"\/").replace('[', r"\[").replace(']', r"\]"))
1269        }
1270    }
1271
1272    /// Repeats the first argument N times, where N is the second argument, optionally joined by the third argument.
1273    /// ### Examples
1274    /// ```
1275    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1276    /// [repeat/5/5/:] -> 5:5:5:5:5
1277    /// [store/x/0][unescape/[repeat/\[store\/x\/\[add\/\[load\/x\]\/1\]\]\[load\/x\]/5]] -> 12345
1278    /// # "#)}
1279    /// ```
1280    macro Repeat as "repeat" {
1281        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1282              let (target, count) = get_args!("repeat", arguments; a, b);
1283            let count = convert_to_number!("repeat"; <usize> at 2 => count);
1284            Ok(std::iter::repeat(target).take(count).join(arguments.get(2).map_or("", |v| &**v)))
1285        }
1286    }
1287
1288    /// Turns the input into lowercase.
1289    /// ### Examples
1290    /// ```
1291    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1292    /// [lower/VVVVVV/GO PLAY IT] -> vvvvvv/go play it
1293    /// [lower/ὈΔΥΣΣΕΎΣ] -> ὀδυσσεύς
1294    /// # "#)}
1295    /// ```
1296    macro Lower as "lower" {
1297        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1298            Ok(arguments.into_iter().map(str::to_lowercase).join("/"))
1299        }
1300    }
1301
1302    /// Turns the input into uppercase.
1303    /// ### Examples
1304    /// ```
1305    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1306    /// [upper/vvvvvv/go play it] -> VVVVVV/GO PLAY IT
1307    /// [upper/tschüß] -> TSCHÜSS
1308    /// # "#)}
1309    /// ```
1310    macro Upper as "upper" {
1311        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1312            Ok(arguments.into_iter().map(str::to_uppercase).join("/"))
1313        }
1314    }
1315
1316    /// Maps an escaped text macro over all of the inputs, returning the results as outputs.
1317    /// # Example
1318    /// ```
1319    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1320    /// [map/\[multiply\/$1\/2\]/1/2/3] -> 2/4/6
1321    /// # "#)}
1322    /// ```
1323    macro Map as "map" {
1324        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1325            if arguments.len() == 1 { return Ok(String::new()) }
1326            let (mac, ) = get_args!("map", arguments; a);
1327            let mac = TextMacro::new(unescape(mac));
1328            arguments
1329                .iter()
1330                .skip(1)
1331                .map(|v| mac.apply(vec![v]))
1332                .process_results(|mut v| v.join("/"))
1333        }
1334    }
1335
1336    /// Performs a fold with an escaped text macro over all of the inputs, taking the first as a base case.
1337    /// # Example
1338    /// ```
1339    /// # use macroscript::test::test_output; fn main() -> Result<(), Box<dyn std::error::Error>> { test_output(r#"
1340    /// [fold/\[add\/$1\/$2\]/0/1/2/3] -> 6
1341    /// # "#)}
1342    /// ```
1343    macro Fold as "fold" {
1344        fn apply(&self, arguments: Vec<&str>) -> Result<String, MacroError> {
1345            let (mac, base) = get_args!("map", arguments; a, b);
1346            let mac = TextMacro::new(unescape(mac));
1347            arguments
1348                .iter()
1349                .skip(2)
1350                .try_fold((*base).to_string(), |a, b| mac.apply(vec![&a, *b]))
1351        }
1352    }
1353}