1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use beef::lean::Cow;
use chumsky::span::SimpleSpan;
use logos::{Lexer as RealLexer, Logos, SpannedIter};

macro_rules! tokens {
    ($($z:literal $( | $y:literal)? => $v:ident,)+) => {
        #[derive(Logos, Debug, PartialEq, Clone)]
        #[logos(skip r"[\n\s]+")]
        #[allow(dead_code)]
        pub enum Token<'strings> {
            #[regex("/[^\n/]+/", priority = 8)]
            Comment(&'strings str),
            #[regex(r"[0-9]+", |lex| lex.slice().parse().ok())]
            #[regex(r"0[xX][0-9a-fA-F]+", |lex| u64::from_str_radix(&lex.slice()[2..], 16).ok())]
            #[regex(r"0[bB][01]+", |lex| u64::from_str_radix(&lex.slice()[2..], 2).ok())]
            Int(u64),
            #[regex(r"[0-9]+\.[0-9]+", |lex| lex.slice().parse().ok())]
            Float(f64),
            #[regex(r#""([^\\"\n])*""#, callback = |lex| Cow::from(&lex.slice()[1..lex.slice().len()-1]), priority = 12)]
            #[regex(r#""[^"]*""#, callback = |lex| Cow::from(lex.slice()[1..lex.slice().len()-1].replace(r"\n", "\n")), priority = 8)]
            String(Cow<'strings, str>),
            // todo ignore alot
            #[regex(r"[^\s0-9][^\s]*", priority = 7)]
            Ident(&'strings str),

            #[token("[", chr::<'['>)]
            #[token("(", chr::<'('>)]
            #[token("{", chr::<'{'>)]
            OpeningBracket(char),
            #[token("]", chr::<']'>)]
            #[token(")", chr::<')'>)]
            #[token("}", chr::<'}'>)]
            ClosingBracket(char),

            $(#[token($z, priority = 8)] $(#[token($y, priority = 8)])? $v,)+
        }

        impl std::fmt::Display for Token<'_> {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
                match self {
                    $(Self::$v => write!(f, $z),)+
                    Self::String(s) => write!(f, "{s}"),
                    Self::Float(n) => write!(f, "{n}"),
                    Self::Int(n) => write!(f, "{n}"),
                    Self::OpeningBracket(x) | Self::ClosingBracket(x) => write!(f,"{x}"),
                    Self::Comment(_) => write!(f, ""),
                    Self::Ident(x) => write!(f, "{x}"),
                }
            }
        }
    }
}

tokens! {
    "λ" => Lamba,
    "←" => Place,
    "→" => Ret,
    "=" => Eq,
    "🐢" => Dup,
    "🐘" => Both,
    "🍴" => Fork,
    "🐈" => Flip,
    "↖" => Reverse,
    "⤵️" => Pop,
    "+" => Add,
    "×" => Mul,
    "*" => Pow,
    "√" => Sqrt,
    "≠" => Ne,
    "<" => Lt,
    "≤" | "≯" => Le,
    ">" => Gt,
    "≥" | "≮" => Ge,
    "⏪" => Shl,
    "⏩" => Shr,
    "¯" => Neg,
    "∧" => And,
    "∨" => Or,
    "⊻" => Xor,
    "÷" => Div,
    "%" => Mod,
    "🔎" => Keep,
    "🚧" => Split,
    "⬅" => First,
    "➡" => Last,
    "⏭️" => Each,
    "➡️" => Reduce,
    "↘️" => ReduceStack,

}

pub fn lex(s: &str) -> Lexer {
    Lexer {
        inner: Token::lexer(s).spanned(),
    }
}

fn chr<'src, const CHR: char>(_: &mut RealLexer<'src, Token<'src>>) -> Result<char, ()> {
    Ok(CHR)
}
pub struct Lexer<'s> {
    inner: SpannedIter<'s, Token<'s>>,
}

impl<'s> Iterator for Lexer<'s> {
    type Item = (Token<'s>, SimpleSpan<usize>);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.find_map(|(x, s)| match x.ok()? {
            Token::Comment(_) => None,
            x => Some((x, SimpleSpan::new(s.start, s.end))),
        })
    }
}

#[test]
fn lexer() {
    let mut lex = lex(r#""#);
    // while let Some(x) = lex.next() { print!("{x} "); }
    macro_rules! test {
        ($($tok:ident$(($var:literal))?)+) => {{
            $(assert_eq!(lex.next().map(|(x,_)|x), Some(Token::$tok$(($var.into()))?));)+
            assert_eq!(lex.next(), None);
        }}
    }
}