badlang_parser/
lib.rs

1#![feature(let_chains)]
2#![feature(if_let_guard)]
3#![feature(map_try_insert)]
4#![forbid(unsafe_code)]
5#![deny(clippy::pedantic)]
6#![deny(clippy::nursery)]
7#![forbid(clippy::enum_glob_use)]
8#![forbid(clippy::unwrap_used)]
9// #![allow(clippy::too_many_lines)]
10// #![allow(clippy::cognitive_complexity)]
11// #![allow(clippy::cast_precision_loss)]
12// #![allow(clippy::cast_possible_truncation)]
13// #![allow(clippy::cast_sign_loss)]
14// #![allow(clippy::cast_possible_wrap)]
15
16use std::{
17    collections::HashMap,
18    path::PathBuf,
19    time::{Duration, Instant},
20};
21
22use colored::Colorize;
23#[cfg(feature = "silly")]
24use geocoding::Reverse;
25use itertools::Itertools;
26use savefile_derive::Savefile;
27use strum::EnumCount;
28use strum_macros::EnumCount as EnumCountMacro;
29
30pub fn report_error(string: &str) -> ! {
31    panic!("{}: {string}", "ERROR".bold().red());
32}
33
34pub fn report_warning(string: &str) {
35    eprintln!("{}: {string}", "WARNING".bold().yellow());
36}
37
38#[derive(Clone, Debug, PartialEq, Savefile)]
39pub enum StackValue {
40    Integer(i64),
41    Float(f64),
42    String(String),
43    Bool(bool),
44}
45
46impl std::fmt::Display for StackValue {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        match self {
49            Self::Integer(int) => write!(f, "{int}"),
50            Self::Float(float) => write!(f, "{float:.2}"),
51            Self::String(string) => write!(f, "{string}"),
52            Self::Bool(boolean) => write!(f, "{boolean}"),
53        }
54    }
55}
56
57impl std::ops::Add for StackValue {
58    type Output = Self;
59
60    fn add(self, other: Self) -> Self {
61        match self {
62            Self::String(string) => Self::String(string + other.to_string().as_str()),
63            Self::Integer(int) => match other {
64                Self::Integer(int2) => Self::Integer(int + int2),
65                Self::Float(float) => Self::Float(int as f64 + float),
66                Self::String(string) => Self::String(int.to_string() + string.as_str()),
67                Self::Bool(boolean) => Self::String(int.to_string() + boolean.to_string().as_str()),
68            },
69            Self::Float(float) => match other {
70                Self::Integer(int) => Self::Float(float + int as f64),
71                Self::Float(float2) => Self::Float(float + float2),
72                Self::String(string) => Self::String(self.to_string() + string.as_str()),
73                Self::Bool(boolean) => Self::String(self.to_string() + boolean.to_string().as_str()),
74            },
75            Self::Bool(boolean) => match other {
76                Self::Bool(boolean2) => Self::Integer(i64::from(boolean) + i64::from(boolean2)),
77                Self::String(string) => Self::String(boolean.to_string() + string.as_str()),
78                Self::Float(_) => Self::String(boolean.to_string() + other.to_string().as_str()),
79                Self::Integer(int) => Self::String(boolean.to_string() + int.to_string().as_str()),
80            },
81        }
82    }
83}
84
85impl std::ops::Sub for StackValue {
86    type Output = anyhow::Result<Self>;
87
88    fn sub(self, other: Self) -> Self::Output {
89        Ok(match self {
90            Self::String(ref string) => match other {
91                Self::Integer(int) => {
92                    if int < 0 {
93                        Self::String(string.to_string() + " ".repeat((-int) as usize).as_str())
94                    } else if int as usize > string.len() {
95                        anyhow::bail!("Tried to subtract int from string where the int is bigger than the strings length");
96                    } else {
97                        Self::String(string[..string.len() - int as usize].to_string())
98                    }
99                }
100                Self::Float(float) => {
101                    let int = float.round() as i64;
102                    if int as usize > string.len() {
103                        anyhow::bail!("Tried to subtract float from string where the float is bigger than the strings length");
104                    }
105                    (self - Self::Integer(int))?
106                }
107
108                Self::Bool(bool) => {
109                    let int = i64::from(bool);
110                    if int as usize > string.len() {
111                        anyhow::bail!("Tried to subtract bool from string where the bool is bigger than the strings length");
112                    }
113                    Self::String(string[..string.len() - int as usize].to_string())
114                }
115                Self::String(string2) => Self::String(string.replace(string2.as_str(), "")),
116            },
117            Self::Integer(int) => match other {
118                Self::Integer(int2) => Self::Integer(int - int2),
119                Self::Float(float) => Self::Float(int as f64 - float),
120                Self::String(string) => Self::String(int.to_string() + " - " + string.as_str()),
121                Self::Bool(boolean) => Self::Integer(int - i64::from(boolean)),
122            },
123            Self::Float(float) => match other {
124                Self::Integer(int) => Self::Float(float - int as f64),
125                Self::Float(float2) => Self::Float(float - float2),
126                Self::String(string) => Self::String(self.to_string() + " - " + string.as_str()),
127                Self::Bool(boolean) => Self::Float(float - f64::from(boolean)),
128            },
129            Self::Bool(boolean) => match other {
130                Self::Bool(boolean2) => Self::Integer(i64::from(boolean) - i64::from(boolean2)),
131                Self::String(string) => Self::String(boolean.to_string() + " - " + string.as_str()),
132                Self::Float(float) => Self::Float(f64::from(boolean) - float),
133                Self::Integer(int) => Self::Integer(i64::from(boolean) - int),
134            },
135        })
136    }
137}
138
139impl std::ops::Mul for StackValue {
140    type Output = Self;
141
142    fn mul(self, other: Self) -> Self {
143        match self {
144            Self::String(string) => match other {
145                Self::Integer(int) => {
146                    let temp = string.repeat(int.unsigned_abs() as usize);
147                    Self::String(if int < 0 { temp.chars().rev().collect() } else { temp })
148                }
149                Self::Float(float) => {
150                    let temp = string.repeat(float.abs().floor() as usize) + &string[0..(string.len() as f64 * float.abs().fract()).round() as usize];
151                    Self::String(if float < 0.0 { temp.chars().rev().collect() } else { temp })
152                }
153                Self::Bool(boolean) => Self::String(if boolean { string } else { String::new() }),
154                Self::String(string2) => Self::String(string2.chars().interleave(string.chars()).collect()),
155            },
156            Self::Integer(int) => match other {
157                Self::Integer(int2) => Self::Integer(int * int2),
158                Self::Float(float) => Self::Float(int as f64 * float),
159                Self::String(_) => other * self,
160                Self::Bool(boolean) => Self::Integer(int * i64::from(boolean)),
161            },
162            Self::Float(float) => match other {
163                Self::Integer(int) => Self::Float(float * int as f64),
164                Self::Float(float2) => Self::Float(float * float2),
165                Self::String(_) => other * self,
166                Self::Bool(boolean) => Self::Float(float * f64::from(boolean)),
167            },
168            Self::Bool(boolean) => match other {
169                Self::Bool(boolean2) => Self::Integer(i64::from(boolean && boolean2)),
170                _ => other * self,
171            },
172        }
173    }
174}
175
176impl std::ops::Div for StackValue {
177    type Output = anyhow::Result<either::Either<Self, Vec<Self>>>;
178
179    fn div(self, other: Self) -> Self::Output {
180        Ok(either::Either::Left(match self {
181            Self::String(string) => match other {
182                Self::Integer(int) => Self::String(string) * Self::Float(1.0 / int as f64),
183                Self::Float(float) => Self::String(string) * Self::Float(1.0 / float),
184                Self::Bool(boolean) => Self::String(if boolean { String::new() } else { string }),
185                Self::String(string2) => return Ok(either::Either::Right(string.split(string2.as_str()).map(str::to_string).map(Self::String).collect::<Vec<_>>())),
186            },
187            Self::Integer(int) => match other {
188                Self::Integer(int2) => {
189                    if int2 == 0 {
190                        anyhow::bail!("Tried to divide by 0");
191                    }
192                    Self::Float(int as f64 / int2 as f64)
193                }
194                Self::Float(float) => {
195                    if float == 0.0 {
196                        anyhow::bail!("Tried to divide by 0")
197                    }
198                    Self::Float(int as f64 / float)
199                }
200                Self::String(string) => Self::String(int.to_string() + " / " + string.as_str()),
201                Self::Bool(boolean) => {
202                    if !boolean {
203                        anyhow::bail!("Tried to divide by false")
204                    }
205                    self
206                }
207            },
208            Self::Float(float) => match other {
209                Self::Integer(int) => {
210                    if int == 0 {
211                        anyhow::bail!("Tried to divide by 0")
212                    }
213                    Self::Float(float / int as f64)
214                }
215                Self::Float(float2) => {
216                    if float2 == 0.0 {
217                        anyhow::bail!("Tried to divide by 0");
218                    }
219                    Self::Float(float / float2)
220                }
221                Self::String(string) => Self::String(float.to_string() + " / " + string.as_str()),
222                Self::Bool(boolean) => {
223                    if !boolean {
224                        anyhow::bail!("Tried to divide by false")
225                    }
226                    self
227                }
228            },
229            Self::Bool(boolean) => match other {
230                Self::Bool(boolean2) => {
231                    if !boolean2 {
232                        anyhow::bail!("Tried to divide by false")
233                    }
234                    self
235                }
236                Self::String(string) => Self::String(boolean.to_string() + " / " + string.as_str()),
237                Self::Float(float) => {
238                    if float == 0.0 {
239                        anyhow::bail!("Tried to divide by 0")
240                    }
241                    Self::Float(f64::from(boolean) / float)
242                }
243                Self::Integer(int) => {
244                    if int == 0 {
245                        anyhow::bail!("Tried to divide by 0")
246                    }
247                    Self::Float(f64::from(boolean) / int as f64)
248                }
249            },
250        }))
251    }
252}
253
254impl StackValue {
255    // I pulled 639.4 out of my ass 👍
256    const EPSILON: f64 = 639.4 * std::f64::EPSILON;
257
258    pub fn loose_equal(&self, other: &Self) -> bool {
259        match self {
260            Self::String(string) => string == &other.to_string(),
261            Self::Integer(int) => match other {
262                Self::Integer(int2) => int == int2,
263                Self::Float(float) => int == &(float.round() as i64),
264                Self::Bool(boolean) => *int == i64::from(*boolean),
265                Self::String(_) => other.loose_equal(self),
266            },
267            Self::Float(float) => match other {
268                Self::Float(float2) => float == float2,
269                Self::Bool(boolean) => float.round() == f64::from(*boolean),
270                _ => other.loose_equal(self),
271            },
272            Self::Bool(boolean) => match other {
273                Self::Bool(boolean2) => boolean == boolean2,
274                _ => other.loose_equal(self),
275            },
276        }
277    }
278
279    pub fn strict_equal(&self, other: &Self) -> bool {
280        match self {
281            Self::String(string) => matches!(other, Self::String(string2) if string == string2),
282            Self::Integer(int) => match other {
283                Self::Integer(int2) => int == int2,
284                Self::Float(float) => ((*int as f64) - float).abs() < Self::EPSILON,
285                Self::Bool(boolean) => int == &i64::from(*boolean),
286                Self::String(_) => other.strict_equal(self),
287            },
288            Self::Float(float) => match other {
289                Self::Float(float2) => (float - float2).abs() < Self::EPSILON,
290                Self::Bool(_) => false,
291                _ => other.strict_equal(self),
292            },
293            Self::Bool(boolean) => match other {
294                Self::Bool(boolean2) => boolean == boolean2,
295                _ => other.strict_equal(self),
296            },
297        }
298    }
299    // strict_strict_equal is just the derived PartialEq
300}
301
302impl std::ops::Shr for StackValue {
303    type Output = anyhow::Result<Self>;
304
305    fn shr(self, other: Self) -> Self::Output {
306        Ok(match self {
307            Self::String(_) => match other {
308                Self::String(string2) => match string2.parse() {
309                    Ok(int) => (self >> Self::Integer(int))?,
310                    Err(_) => anyhow::bail!("Couldn't parse string as number"),
311                },
312                _ => {
313                    (self - other)? // The behavior I intended is basically
314                                    // the same as the subtraction
315                }
316            },
317            Self::Integer(int) => match other {
318                Self::Integer(int2) => Self::Integer(if int2 < 0 { int << (-int2) } else { int >> int2 }),
319                Self::Float(float) => Self::Float(int as f64 * 0.5_f64.powf(float)),
320                Self::String(string) => match string.parse::<i64>() {
321                    Ok(int2) => (self >> Self::Integer(int2))?,
322                    Err(_) => anyhow::bail!("Couldn't parse string as number"),
323                },
324                Self::Bool(boolean) => Self::Integer(int >> i64::from(boolean)),
325            },
326            Self::Float(float) => match other {
327                Self::Integer(_) => (Self::Integer(i64::from_le_bytes(float.to_bits().to_le_bytes())) >> other)?,
328                Self::Float(float2) => Self::Float(float * 0.5_f64.powf(float2)),
329                Self::String(string) => match string.parse::<i64>() {
330                    Ok(int) => (self >> Self::Integer(int))?,
331                    Err(_) => anyhow::bail!("Couldn't parse string as number"),
332                },
333                Self::Bool(boolean) => Self::Float(if boolean { float / 2.0 } else { float }),
334            },
335            Self::Bool(boolean) => (Self::Integer(i64::from(boolean)) >> other)?,
336        })
337    }
338}
339
340impl std::ops::Shl for StackValue {
341    type Output = anyhow::Result<Self>;
342
343    fn shl(self, other: Self) -> Self::Output {
344        Ok(match self {
345            Self::Integer(int) => match other {
346                Self::Integer(int2) => (self >> Self::Integer(-int2))?,
347                Self::Float(float) => Self::Float(int as f64 * 2_f64.powf(float)),
348                Self::String(string) => match string.parse::<i64>() {
349                    Ok(int2) => (self << Self::Integer(int2))?,
350                    Err(_) => anyhow::bail!("Couldn't parse string as number"),
351                },
352                Self::Bool(boolean) => Self::Integer(int << i64::from(boolean)),
353            },
354            Self::Float(float) => match other {
355                Self::Integer(_) => (Self::Integer(i64::from_le_bytes(float.to_bits().to_le_bytes())) << other)?,
356                Self::Float(float2) => Self::Float(float * 2.0_f64.powf(float2)),
357                Self::String(string) => match string.parse::<i64>() {
358                    Ok(int) => (self << Self::Integer(int))?,
359                    Err(_) => anyhow::bail!("Couldn't parse string as number"),
360                },
361                Self::Bool(boolean) => Self::Float(if boolean { float * 2.0 } else { float }),
362            },
363            Self::String(_) => self + other,
364            Self::Bool(boolean) => (Self::Integer(i64::from(boolean)) << other)?,
365        })
366    }
367}
368
369impl std::ops::BitOr for StackValue {
370    type Output = Self;
371
372    fn bitor(self, other: Self) -> Self::Output {
373        use itertools::EitherOrBoth as E;
374        match self {
375            Self::Integer(int) => match other {
376                Self::Integer(int2) => Self::Integer(int | int2),
377                Self::Float(float) => Self::Integer(int | i64::from_le_bytes(float.to_le_bytes())),
378                Self::String(_) => Self::String(format!("{int:064b}")) | other,
379                Self::Bool(boolean) => Self::Bool((int.abs() > 0) || boolean),
380            },
381            Self::Float(float) => match other {
382                Self::Integer(_) => other | self,
383                Self::Float(float2) => Self::Integer(i64::from_be_bytes(float.to_be_bytes()) | i64::from_ne_bytes(float2.to_ne_bytes())),
384                Self::String(_) => Self::String(format!("{:064b}", i64::from_le_bytes(float.to_le_bytes()))) | other,
385                Self::Bool(boolean) => Self::Bool((float.abs() > 0.0) || boolean),
386            },
387            Self::String(ref string) => match other {
388                Self::String(string2) => Self::String(
389                    string
390                        .chars()
391                        .zip_longest(string2.chars())
392                        .map(|v| match v {
393                            E::Both(a, b) => a.max(b),
394                            E::Left(a) => a,
395                            E::Right(b) => b,
396                        })
397                        .collect(),
398                ),
399                Self::Bool(boolean) => Self::Bool(!string.is_empty() || boolean),
400                _ => other | self,
401            },
402            Self::Bool(boolean) => match other {
403                Self::Bool(boolean2) => Self::Bool(boolean || boolean2),
404                _ => other | self,
405            },
406        }
407    }
408}
409
410impl std::ops::BitAnd for StackValue {
411    type Output = Self;
412
413    fn bitand(self, other: Self) -> Self::Output {
414        use itertools::EitherOrBoth as E;
415        match self {
416            Self::Integer(int) => match other {
417                Self::Integer(int2) => Self::Integer(int & int2),
418                Self::Float(float) => Self::Integer(int & i64::from_le_bytes(float.to_le_bytes())),
419                Self::String(_) => Self::String(format!("{int:064b}")) & other,
420                Self::Bool(boolean) => Self::Bool((int.abs() > 0) && boolean),
421            },
422            Self::Float(float) => match other {
423                Self::Integer(_) => other & self,
424                Self::Float(float2) => Self::Integer(i64::from_be_bytes(float.to_be_bytes()) & i64::from_ne_bytes(float2.to_ne_bytes())),
425                Self::String(_) => Self::String(format!("{:064b}", i64::from_le_bytes(float.to_le_bytes()))) & other,
426                Self::Bool(boolean) => Self::Bool((float.abs() > 0.0) && boolean),
427            },
428            Self::String(ref string) => match other {
429                Self::String(string2) => Self::String(
430                    string
431                        .chars()
432                        .zip_longest(string2.chars())
433                        .map(|v| match v {
434                            E::Both(a, b) => {
435                                if a == b {
436                                    a
437                                } else {
438                                    ' '
439                                }
440                            }
441                            _ => ' ',
442                        })
443                        .collect(),
444                ),
445                Self::Bool(boolean) => Self::Bool(!string.is_empty() && boolean),
446                _ => other & self,
447            },
448            Self::Bool(boolean) => match other {
449                Self::Bool(boolean2) => Self::Bool(boolean && boolean2),
450                _ => other & self,
451            },
452        }
453    }
454}
455
456impl std::ops::BitXor for StackValue {
457    type Output = Self;
458
459    fn bitxor(self, other: Self) -> Self::Output {
460        use itertools::EitherOrBoth as E;
461        match self {
462            Self::Integer(int) => match other {
463                Self::Integer(int2) => Self::Integer(int ^ int2),
464                Self::Float(float) => Self::Integer(int ^ i64::from_le_bytes(float.to_le_bytes())),
465                Self::String(_) => Self::String(format!("{int:064b}")) ^ other,
466                Self::Bool(boolean) => Self::Bool((int.abs() > 0) != boolean),
467            },
468            Self::Float(float) => match other {
469                Self::Integer(_) => other ^ self,
470                Self::Float(float2) => Self::Integer(i64::from_be_bytes(float.to_be_bytes()) ^ i64::from_ne_bytes(float2.to_ne_bytes())),
471                Self::String(_) => Self::String(format!("{:064b}", i64::from_le_bytes(float.to_le_bytes()))) ^ other,
472                Self::Bool(boolean) => Self::Bool((float.abs() > 0.0) != boolean),
473            },
474            Self::String(ref string) => match other {
475                Self::String(string2) => Self::String(
476                    string
477                        .chars()
478                        .zip_longest(string2.chars())
479                        .map(|v| match v {
480                            E::Both(a, b) => {
481                                if a == ' ' {
482                                    b
483                                } else if b == ' ' {
484                                    a
485                                } else {
486                                    ' '
487                                }
488                            }
489                            E::Left(c) | E::Right(c) => c,
490                        })
491                        .collect(),
492                ),
493                Self::Bool(boolean) => Self::Bool(!string.is_empty() != boolean),
494                _ => other ^ self,
495            },
496            Self::Bool(boolean) => match other {
497                Self::Bool(boolean2) => Self::Bool(boolean != boolean2),
498                _ => other ^ self,
499            },
500        }
501    }
502}
503
504impl std::ops::Not for StackValue {
505    type Output = Self;
506
507    fn not(self) -> Self::Output {
508        match self {
509            Self::Integer(int) => Self::Integer(!int),
510            Self::Float(float) => Self::Integer(!i64::from_be_bytes(float.to_be_bytes())),
511            Self::String(string) => Self::String(
512                string
513                    .chars()
514                    .map(|c| (c.to_ascii_lowercase(), c.is_uppercase()))
515                    .map(|(c, b)| {
516                        (
517                            match c {
518                                'a'..='z' => (((c as u8 - b'a' + 13) % 26) + b'a') as char,
519                                _ => c,
520                            },
521                            b,
522                        )
523                    })
524                    .map(|(c, b)| if b { c.to_ascii_uppercase() } else { c })
525                    .collect(),
526            ),
527            Self::Bool(boolean) => Self::Bool(!boolean),
528        }
529    }
530}
531
532impl std::cmp::PartialOrd for StackValue {
533    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
534        match self {
535            Self::String(string) => string.partial_cmp(&other.to_string()),
536            Self::Integer(int) => match other {
537                Self::Integer(int2) => int.partial_cmp(int2),
538                Self::Float(float) => ((*int) as f64).partial_cmp(float),
539                Self::Bool(boolean) => int.partial_cmp(&i64::from(*boolean)),
540                Self::String(string) => int.to_string().partial_cmp(string),
541            },
542            Self::Float(float) => match other {
543                Self::Float(float2) => float.partial_cmp(float2),
544                Self::Integer(int) => float.partial_cmp(&(*int as f64)),
545                Self::Bool(boolean) => float.partial_cmp(&(f64::from(*boolean))),
546                Self::String(string) => float.to_string().partial_cmp(string),
547            },
548            Self::Bool(boolean) => match other {
549                Self::Bool(boolean2) => boolean.partial_cmp(boolean2),
550                Self::Integer(int) => i64::from(*boolean).partial_cmp(int),
551                Self::Float(float) => f64::from(*boolean).partial_cmp(float),
552                Self::String(string) => boolean.to_string().partial_cmp(string),
553            },
554        }
555    }
556}
557
558#[derive(EnumCountMacro, Clone, PartialEq, Debug, Savefile)]
559pub enum Token {
560    /// Just a fucking n̶u̶m̶b̶e̶r̶ value✨
561    StackValue(StackValue),
562    /// Addition. Often used to add numbers.
563    Add,
564    /// Subtraction. Nothin' more, Nothin' less.
565    Subtract,
566    /// Multiplication. Very similar to multiplication.
567    Multiply,
568    /// Division. Quoted in famous works such as "Math".
569    Divide,
570    /// Used to duplicate things, much like mitosis. a -- a a
571    Dup,
572    /// Drops the thing, much like I drop depth charges at 55°16'06.9"S
573    /// 13°06'37.3"W (for legal reasons, this is a joke). a --
574    Drop,
575    /// Swaps the two things, much like the process of nurses swapping
576    /// babies in hospitals. a b -- b a
577    Swap,
578    /// Lets the thing jump over. No good jokes here. a b -- a b a
579    Over,
580    /// Rotates three things, much like my testicles. a b c -- b c a
581    Rot,
582    /// Prints da thang, no matter what it is (least racist keyword). a --
583    Print,
584    /// Very similar to print, but with that sweet ln
585    Println,
586    /// if-condition, often used by white people. The u32 is an offset to
587    /// jump to.
588    If(usize),
589    /// elif is like an elif,
590    Elif(usize),
591    /// else-condition exists but is non-existent in tokens because
592    Else(usize),
593    /// fi also exists, but non-existent in tokens because
594    /// `MrBeast!` is a mixture between fi and elif:
595    /// Once it is reached, one of the if/(el)ifs has already executed,
596    /// meaning it will jump to fi.
597    MrBeast(usize),
598    /// Equality, much like the thing globally not yet reached.
599    Eq,
600    /// Strict equality, similar to javascripts strict equality thing.
601    Seq,
602    /// Even stricter equality, stricter than javascripts triple equal.
603    Sseq,
604    /// Inequality,
605    Ineq,
606    /// Strict inequality, similar to javascripts strict inequality thing.
607    Sineq,
608    /// Even stricter inequality, stricter than javascripts double inequal.
609    Ssineq,
610    /// Greater-than,
611    Gt,
612    /// Less-than,
613    Lt,
614    /// Greater-than or equal,
615    Ge,
616    /// Greater-than or strict equal,
617    Gse,
618    /// Greater-than or stricterer equal,
619    Gsse,
620    /// Less-than or equal,
621    Le,
622    /// Less-than or strict equal,
623    Lse,
624    /// Less-than or strict strict equal,
625    Lsse,
626    /// Shift right,
627    Shr,
628    /// Shift left,
629    Shl,
630    /// Or, both bool and integer
631    Or,
632    /// And, both bool and integer
633    And,
634    /// Not, both bool and integer
635    Not,
636    /// Xor, both bool and integer
637    Xor,
638    /// Does absolutely nothing, much like this programming language.
639    Dummy,
640}
641
642impl Token {
643    pub fn name(&self) -> &'static str {
644        match self {
645            Token::StackValue(StackValue::Integer(_)) => "integer literals",
646            Token::StackValue(StackValue::String(_)) => "string literals",
647            Token::StackValue(StackValue::Float(_)) => "float literals",
648            Token::StackValue(StackValue::Bool(_)) => "boolean literals",
649            Token::Add => "addition (+)",
650            Token::Subtract => "subtraction (-)",
651            Token::Multiply => "multiplication (*)",
652            Token::Divide => "division (/)",
653            Token::Dup => "the `dup` keyword",
654            Token::Drop => "the `drop` keyword",
655            Token::Swap => "the `swap` keyword",
656            Token::Over => "the `over` keyword",
657            Token::Rot => "the `rot` keyword",
658            Token::Print => "the `print` function",
659            Token::Println => "the `println` function",
660            Token::If(_) => "the `if` and `fi` keywords",
661            Token::Elif(_) => "the `elif` keyword",
662            Token::Else(_) => "the `else` keyword",
663            Token::MrBeast(_) => "the `MrBeast!` keyword",
664            Token::Eq => "simple equals (=)",
665            Token::Seq => "strict equals (==)",
666            Token::Sseq => "stricter equals (===)",
667            Token::Ineq => "simple unequals (!=)",
668            Token::Sineq => "strict unequals (!==)",
669            Token::Ssineq => "stricter unequals (!===)",
670            Token::Gt => "greater than (>)",
671            Token::Lt => "less than (<)",
672            Token::Ge => "greater than or equal (=>)",
673            Token::Gse => "greater than or strict equal (==>)",
674            Token::Gsse => "greater than or stricter equal (===>)",
675            Token::Le => "less than or equal (<=)",
676            Token::Lse => "less than or strict equal (<==)",
677            Token::Lsse => "less than or stricter equal (<===)",
678            Token::Shr => "shift right (>>)",
679            Token::Shl => "shift left (<<)",
680            Token::Or => "the `or` keyword",
681            Token::And => "the `and` keyword",
682            Token::Not => "the `not` keyword",
683            Token::Xor => "the `xor` keyword",
684            Token::Dummy => "unreachable",
685        }
686    }
687}
688
689pub fn parse_file(path: &PathBuf) -> anyhow::Result<Vec<Token>> {
690    let contents = match std::fs::read_to_string(path) {
691        Ok(string) => string,
692        Err(err) => {
693            report_error(format!("File could not be read because {err}").as_str());
694        }
695    };
696    parse_string(contents)
697}
698
699pub fn parse_string(mut contents: String) -> anyhow::Result<Vec<Token>> {
700    contents += " "; // This prevents a parser bug where the parser ignores the last token if it
701                     // isn't followed by whitespace. No fix for this is planned.
702
703    let mut tokens = Vec::new();
704    let mut if_statements: Vec<usize> = Vec::with_capacity(4); // People are gonna wanna nest at least four times.
705    let mut elif_statements: HashMap<usize, usize> = HashMap::new();
706    let mut mr_beast_statements: HashMap<usize, Vec<usize>> = HashMap::new();
707    let mut else_statements: Vec<usize> = Vec::with_capacity(3);
708    let mut is_commenting = false;
709    let mut is_stringing = false;
710
711    let mut word = String::new();
712    let mut index = 0;
713
714    let mut chars = contents.chars();
715    while let Some(chr) = chars.next() {
716        if chr == '\'' && !is_commenting {
717            if is_stringing {
718                tokens.push(Token::StackValue(StackValue::String(word)));
719                word = String::new();
720                index += 1;
721            }
722            is_stringing = !is_stringing;
723            continue;
724        }
725        if is_stringing {
726            if chr == '\\' {
727                word.push(match chars.next() {
728                    Some('n') => '\n',
729                    Some('r') => '\r',
730                    Some('t') => '\t',
731                    Some('\\') => '\\',
732                    Some('0') => '\0',
733                    Some('\'') => '\'',
734                    Some(x) => anyhow::bail!(format!("Unexpected escape character '{x}'")),
735                    None => anyhow::bail!("Expected escape character, found end of file"),
736                });
737            } else {
738                word.push(chr);
739            }
740            continue;
741        }
742        if !chr.is_whitespace() {
743            word.push(chr);
744            continue;
745        }
746        if chr.is_whitespace() && word.is_empty() {
747            continue;
748        }
749        if !is_commenting {
750            static_assertions::const_assert_eq!(Token::COUNT, 37);
751            let token = match word.as_str() {
752                "+" => Token::Add,
753                "-" => Token::Subtract,
754                "*" => Token::Multiply,
755                "/" => Token::Divide,
756                "=" => Token::Eq,
757                "==" => Token::Seq,
758                "===" => Token::Sseq,
759                "!=" => Token::Ineq,
760                "!==" => Token::Sineq,
761                "!===" => Token::Ssineq,
762                ">" => Token::Gt,
763                "<" => Token::Lt,
764                "=>" => Token::Ge,
765                "==>" => Token::Gse,
766                "===>" => Token::Gsse,
767                "<=" => Token::Le,
768                "<==" => Token::Lse,
769                "<===" => Token::Lsse,
770                ">>" => Token::Shr,
771                "<<" => Token::Shl,
772                "or" => Token::Or,
773                "and" => Token::And,
774                "not" => Token::Not,
775                "xor" => Token::Xor,
776                "if" => {
777                    if_statements.push(index);
778                    Token::If(usize::MAX)
779                }
780                "elif" => {
781                    let Some(if_index) = if_statements.last() else {
782                        anyhow::bail!("Found 'elif' without 'if'");
783                    };
784                    if elif_statements.try_insert(*if_index, index).is_err() {
785                        anyhow::bail!("Found two 'elif's next to eachother without 'MrBeast' between them")
786                    }
787                    Token::Elif(usize::MAX)
788                }
789                "MrBeast!" => {
790                    let Some(if_index) = if_statements.last() else {
791                        anyhow::bail!("Found 'MrBeast' closing an if-statement that doesn't exist");
792                    };
793
794                    if let Some(mr_beasts) = mr_beast_statements.get_mut(if_index) {
795                        mr_beasts.push(index);
796                        if let Some(elif_index) = elif_statements.remove(if_index)
797                            && let Some(Token::Elif(jump_addr)) = tokens.get_mut(elif_index)
798                        {
799                            *jump_addr = index + 1;
800                        } else {
801                            anyhow::bail!("This is embarrassing");
802                        }
803                    } else {
804                        mr_beast_statements.insert(*if_index, vec![index]);
805                        if let Some(Token::If(jump_addr)) = tokens.get_mut(*if_index) {
806                            *jump_addr = index + 1;
807                        } else {
808                            anyhow::bail!("This is embarrassing");
809                        }
810                    }
811                    Token::MrBeast(usize::MAX)
812                }
813                "else" => {
814                    let Some(if_index) = if_statements.last() else {
815                        anyhow::bail!("Found 'else' without match 'if'");
816                    };
817                    if let Some(elif_index) = elif_statements.remove(if_index) {
818                        if let Some(Token::Elif(jump_addr)) = tokens.get_mut(elif_index) {
819                            *jump_addr = index + 1;
820                        } else {
821                            anyhow::bail!("This is embarrassing");
822                        }
823                    } else if let Some(Token::If(jump_addr)) = tokens.get_mut(*if_index) {
824                        *jump_addr = index + 1;
825                    } else {
826                        anyhow::bail!("This is embarrassing");
827                    }
828
829                    else_statements.push(index);
830                    Token::Else(usize::MAX)
831                }
832                "fi" => {
833                    let Some(if_index) = if_statements.pop() else {
834                        anyhow::bail!("Found 'fi' closing an if-statement that doesn't exist");
835                    };
836                    if let Some(mr_beasts) = mr_beast_statements.remove(&if_index) {
837                        for mr_beast_index in mr_beasts {
838                            if let Some(Token::MrBeast(jump_addr)) = tokens.get_mut(mr_beast_index) {
839                                *jump_addr = index;
840                            }
841                        }
842                    } else if let Some(Token::If(jump_addr)) = tokens.get_mut(if_index) {
843                        if *jump_addr == usize::MAX {
844                            *jump_addr = index;
845                        }
846                    } else {
847                        anyhow::bail!("This is embarrassing");
848                    }
849
850                    if let Some(else_index) = else_statements.pop() {
851                        let Some(Token::Else(else_statement)) = tokens.get_mut(else_index) else {
852                            anyhow::bail!("This is embarrassing");
853                        };
854                        *else_statement = index;
855                    }
856                    Token::Dummy
857                }
858
859                "dup" => Token::Dup,
860                "drop" => Token::Drop,
861                "swap" => Token::Swap,
862                "over" => Token::Over,
863                "rot" => Token::Rot,
864                "print" => Token::Print,
865                "println" => Token::Println,
866                "comment" => {
867                    is_commenting = true;
868                    Token::Dummy // This will just chill in the tokens
869                }
870                x if let Ok(int) = x.parse::<i64>() => Token::StackValue(StackValue::Integer(int)),
871                x if let Ok(float) = x.parse::<f64>() => Token::StackValue(StackValue::Float(float)),
872                x if let Ok(boolean) = x.parse::<bool>() => Token::StackValue(StackValue::Bool(boolean)),
873                x if x.len() == 3 && x.chars().next().is_some_and(|c| c == '"') && x.chars().last().is_some_and(|c| c == '"') => {
874                    Token::StackValue(StackValue::Integer(x[1..x.len() - 1].chars().next().expect("This should work") as i64))
875                }
876                unrecognized => {
877                    anyhow::bail!(format!("Unrecognized token {unrecognized}",));
878                }
879            };
880            tokens.push(token);
881        }
882        if word == "no_comment" {
883            is_commenting = false;
884        }
885        word.clear();
886        index += 1;
887    }
888    if !if_statements.is_empty() {
889        anyhow::bail!("Unclosed if-statement");
890    }
891    if !else_statements.is_empty() {
892        anyhow::bail!("This shouldn't happen: Dangling else-statement");
893    }
894    if !mr_beast_statements.is_empty() {
895        anyhow::bail!("This shouldn't happen: Dangling MrBeast-statements");
896    }
897    if is_commenting {
898        anyhow::bail!("Unclosed comment");
899    }
900
901    Ok(tokens)
902}
903
904pub fn execute_tokens<T: std::io::Write>(tokens: &[Token], #[cfg(feature = "silly")] out_of_free_runs: bool, writable: &mut T, time_limit: Option<Duration>) -> anyhow::Result<Vec<StackValue>> {
905    #[cfg(feature = "silly")]
906    if out_of_free_runs {
907        let local_ip = local_ip_address::local_ip().expect("I'm so done").to_string();
908        let info = geolocation::find(local_ip.as_str()).expect("What");
909        let (longitude, latitude) = (info.longitude.parse::<f64>().unwrap_or(180.0), info.latitude.parse::<f64>().unwrap_or(0.0));
910        let openstreetmap = geocoding::Openstreetmap::new();
911        let location = openstreetmap.reverse(&geocoding::Point::new(-longitude, 180.0 - latitude));
912        println!(
913            "Connecting to our servers in {}, our datacenter that is nearest to you!",
914            location.unwrap_or_else(|_| Some("Antarctica".to_string())).unwrap_or_else(|| "Antarctica".to_string())
915        );
916        std::thread::sleep(std::time::Duration::from_secs(1));
917    }
918
919    let mut stack: Vec<StackValue> = Vec::new();
920    let mut i: usize = 0;
921
922    let start = Instant::now();
923    while let Some(token) = tokens.get(i) {
924        #[cfg(feature = "silly")]
925        if out_of_free_runs {
926            std::thread::sleep(std::time::Duration::from_millis(300));
927        }
928        if let Some(limit) = time_limit
929            && start - Instant::now() > limit
930        {
931            anyhow::bail!("Exceeded time limit!");
932        }
933        static_assertions::const_assert_eq!(Token::COUNT, 37);
934        // println!("{token:?}, {i}");
935        match token {
936            Token::Dummy => {}
937            Token::StackValue(x) => stack.push(x.clone()),
938            Token::Add => {
939                if let Some(a) = stack.pop()
940                    && let Some(b) = stack.pop()
941                {
942                    stack.push(b + a);
943                } else {
944                    anyhow::bail!("The stack must contain at least two elements for an addition to be made");
945                }
946            }
947            Token::Subtract => {
948                if let Some(a) = stack.pop()
949                    && let Some(b) = stack.pop()
950                {
951                    stack.push((b - a)?);
952                } else {
953                    anyhow::bail!("The stack must contain at least two elements for a subtraction to be made");
954                }
955            }
956            Token::Multiply => {
957                if let Some(a) = stack.pop()
958                    && let Some(b) = stack.pop()
959                {
960                    stack.push(a * b);
961                } else {
962                    anyhow::bail!("The stack must contain at least two elements for a multiplication to be made");
963                }
964            }
965            Token::Divide => {
966                if let Some(a) = stack.pop()
967                    && let Some(b) = stack.pop()
968                {
969                    match (b / a)? {
970                        either::Either::Left(sv) => stack.push(sv),
971                        either::Either::Right(svs) => stack.extend(svs),
972                    }
973                } else {
974                    anyhow::bail!("The stack must contain at least two elements for a division to be made");
975                }
976            }
977            Token::Eq => {
978                if let Some(a) = stack.pop()
979                    && let Some(b) = stack.pop()
980                {
981                    stack.push(StackValue::Bool(a.loose_equal(&b)));
982                } else {
983                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
984                }
985            }
986            Token::Ineq => {
987                if let Some(a) = stack.pop()
988                    && let Some(b) = stack.pop()
989                {
990                    stack.push(StackValue::Bool(!a.loose_equal(&b)));
991                } else {
992                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
993                }
994            }
995            Token::Seq => {
996                if let Some(a) = stack.pop()
997                    && let Some(b) = stack.pop()
998                {
999                    stack.push(StackValue::Bool(a.strict_equal(&b)));
1000                } else {
1001                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1002                }
1003            }
1004            Token::Sineq => {
1005                if let Some(a) = stack.pop()
1006                    && let Some(b) = stack.pop()
1007                {
1008                    stack.push(StackValue::Bool(!a.loose_equal(&b)));
1009                } else {
1010                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1011                }
1012            }
1013            Token::Sseq => {
1014                if let Some(a) = stack.pop()
1015                    && let Some(b) = stack.pop()
1016                {
1017                    stack.push(StackValue::Bool(a == b))
1018                } else {
1019                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1020                }
1021            }
1022            Token::Ssineq => {
1023                if let Some(a) = stack.pop()
1024                    && let Some(b) = stack.pop()
1025                {
1026                    stack.push(StackValue::Bool(a != b))
1027                } else {
1028                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1029                }
1030            }
1031            Token::Gt => {
1032                if let Some(a) = stack.pop()
1033                    && let Some(b) = stack.pop()
1034                {
1035                    stack.push(StackValue::Bool(b > a));
1036                } else {
1037                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1038                }
1039            }
1040            Token::Lt => {
1041                if let Some(a) = stack.pop()
1042                    && let Some(b) = stack.pop()
1043                {
1044                    stack.push(StackValue::Bool(b < a));
1045                } else {
1046                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1047                }
1048            }
1049            Token::Ge => {
1050                if let Some(a) = stack.pop()
1051                    && let Some(b) = stack.pop()
1052                {
1053                    stack.push(StackValue::Bool(b > a || b.loose_equal(&a)));
1054                } else {
1055                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1056                }
1057            }
1058            Token::Le => {
1059                if let Some(a) = stack.pop()
1060                    && let Some(b) = stack.pop()
1061                {
1062                    stack.push(StackValue::Bool(b < a || b.loose_equal(&a)));
1063                } else {
1064                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1065                }
1066            }
1067            Token::Gse => {
1068                if let Some(a) = stack.pop()
1069                    && let Some(b) = stack.pop()
1070                {
1071                    stack.push(StackValue::Bool(b > a || b.strict_equal(&a)));
1072                } else {
1073                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1074                }
1075            }
1076            Token::Lse => {
1077                if let Some(a) = stack.pop()
1078                    && let Some(b) = stack.pop()
1079                {
1080                    stack.push(StackValue::Bool(b < a || b.strict_equal(&a)));
1081                } else {
1082                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1083                }
1084            }
1085            Token::Gsse => {
1086                if let Some(a) = stack.pop()
1087                    && let Some(b) = stack.pop()
1088                {
1089                    stack.push(StackValue::Bool(b > a || b == a));
1090                } else {
1091                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1092                }
1093            }
1094            Token::Lsse => {
1095                if let Some(a) = stack.pop()
1096                    && let Some(b) = stack.pop()
1097                {
1098                    stack.push(StackValue::Bool(b < a || b == a));
1099                } else {
1100                    anyhow::bail!("The stack must contain at least two elements for them to be compared");
1101                }
1102            }
1103            Token::Shr => {
1104                if let Some(a) = stack.pop()
1105                    && let Some(b) = stack.pop()
1106                {
1107                    stack.push((b >> a)?);
1108                } else {
1109                    anyhow::bail!("The stack must contain at least two elements for them to be manipulated");
1110                }
1111            }
1112            Token::Shl => {
1113                if let Some(a) = stack.pop()
1114                    && let Some(b) = stack.pop()
1115                {
1116                    stack.push((b << a)?);
1117                } else {
1118                    anyhow::bail!("The stack must contain at least two elements for them to be manipulated");
1119                }
1120            }
1121            Token::Or => {
1122                if let Some(a) = stack.pop()
1123                    && let Some(b) = stack.pop()
1124                {
1125                    stack.push(b | a);
1126                } else {
1127                    anyhow::bail!("The stack must contain at least two elements for them to be manipulated");
1128                }
1129            }
1130            Token::And => {
1131                if let Some(a) = stack.pop()
1132                    && let Some(b) = stack.pop()
1133                {
1134                    stack.push(b & a);
1135                } else {
1136                    anyhow::bail!("The stack must contain at least two elements for them to be manipulated");
1137                }
1138            }
1139            Token::Not => {
1140                if let Some(a) = stack.pop() {
1141                    stack.push(!a);
1142                } else {
1143                    anyhow::bail!("The stack must contain at least one element for it to be negated");
1144                }
1145            }
1146            Token::Xor => {
1147                if let Some(a) = stack.pop()
1148                    && let Some(b) = stack.pop()
1149                {
1150                    stack.push(b ^ a);
1151                } else {
1152                    anyhow::bail!("The stack must contain at least two elements for them to be manipulated");
1153                }
1154            }
1155            Token::Dup => {
1156                if let Some(a) = stack.last() {
1157                    stack.push(a.clone());
1158                } else {
1159                    anyhow::bail!("The stack must contain at least one element for it to be duplicated");
1160                }
1161            }
1162            Token::Drop => {
1163                if stack.is_empty() {
1164                    anyhow::bail!("The stack must contain at least one element for it to be dropped");
1165                }
1166                let _ = stack.pop();
1167            }
1168            Token::Swap => {
1169                if let Some(a) = stack.pop()
1170                    && let Some(b) = stack.pop()
1171                {
1172                    stack.push(a);
1173                    stack.push(b);
1174                } else {
1175                    anyhow::bail!("The stack must contain at least two elements for them to be swapped");
1176                }
1177            }
1178            Token::Over => {
1179                if let Some(a) = stack.pop()
1180                    && let Some(b) = stack.pop()
1181                {
1182                    stack.push(b.clone());
1183                    stack.push(a);
1184                    stack.push(b);
1185                } else {
1186                    anyhow::bail!("The stack must contain at least two elements for them to be overed");
1187                }
1188            }
1189            Token::Rot => {
1190                if let Some(a) = stack.pop()
1191                    && let Some(b) = stack.pop()
1192                    && let Some(c) = stack.pop()
1193                {
1194                    stack.push(b);
1195                    stack.push(a);
1196                    stack.push(c);
1197                } else {
1198                    anyhow::bail!("The stack must contain at least three elements for them to be roted");
1199                }
1200            }
1201            Token::Print => {
1202                if let Some(a) = stack.pop() {
1203                    if let Err(err) = write!(writable, "{a}") {
1204                        anyhow::bail!("Couldn't write to writable because {err}");
1205                    };
1206                } else {
1207                    anyhow::bail!("The stack must contain at least one element for it to be printed");
1208                }
1209            }
1210            Token::Println => {
1211                if let Some(a) = stack.pop() {
1212                    if let Err(err) = writeln!(writable, "{a}") {
1213                        anyhow::bail!("Couldn't write to writable because {err}");
1214                    }
1215                } else {
1216                    anyhow::bail!("The stack must contain at least one element for it to be printed");
1217                }
1218            }
1219            Token::If(jump_addr) | Token::Elif(jump_addr) => {
1220                if let Some(StackValue::Bool(boolean)) = stack.pop() {
1221                    if !boolean {
1222                        i = *jump_addr;
1223                        continue;
1224                    }
1225                } else {
1226                    anyhow::bail!("If needs one boolean to be on the stack");
1227                }
1228            }
1229            Token::MrBeast(jump_addr) | Token::Else(jump_addr) => {
1230                i = *jump_addr;
1231                continue;
1232            } // token => todo!("Not yet impld {token:?}"),
1233        }
1234        i += 1;
1235    }
1236    Ok(stack)
1237}