boolean_logic/
tokenizer.rs

1use std::{
2    fmt::{self, Display, Write},
3    ops::Deref,
4};
5
6use logos::Logos;
7
8#[derive(Logos, Debug, PartialEq, Clone)]
9pub enum Token {
10    #[regex("[a-zA-Z]+", |lex| lex.slice().chars().next().unwrap())]
11    Ident(char),
12    #[token("(")]
13    OpenParen,
14    #[token(")")]
15    CloseParen,
16    #[token("[")]
17    OpenBracket,
18    #[token("]")]
19    CloseBracket,
20    #[token("{")]
21    OpenCurlyBrace,
22    #[token("}")]
23    CloseCurlyBrace,
24    #[token("not", |_| '¬')]
25    #[token("!", |_| '¬')]
26    #[token("¬", |_| '¬')]
27    #[token("∼", |_| '¬')]
28    #[token("~", |_| '¬')]
29    Not(char),
30    #[token("->", |_| '→')]
31    #[token("=>", |_| '→')]
32    #[token("⇒", |_| '→')]
33    #[token("→", |_| '→')]
34    #[token("⊃", |_| '→')]
35    Implication(char),
36    #[token("<->", |_| '↔')]
37    #[token("<=>", |_| '↔')]
38    #[token("⇔", |_| '↔')]
39    #[token("↔", |_| '↔')]
40    #[token("iff", |_| '↔')]
41    #[token("xnor", |_| '↔')]
42    Biconditional(char),
43    #[token("and", |_| '∧')]
44    #[token("&", |_| '∧')]
45    #[token("&&", |_| '∧')]
46    #[token("∧", |_| '∧')]
47    And(char),
48    #[token("or", |_| '∨')]
49    #[token("|", |_| '∨')]
50    #[token("||", |_| '∨')]
51    #[token("∨", |_| '∨')]
52    Or(char),
53    #[token("xor", |_| '⊕')]
54    #[token("⊕", |_| '⊕')]
55    XOr(char),
56    #[token("=", |_| '≡')]
57    #[token("==", |_| '≡')]
58    #[token("eq", |_| '≡')]
59    #[token("≡", |_| '≡')]
60    Equals(char),
61    #[token("!=", |_| '≠')]
62    #[token("≠", |_| '≠')]
63    NotEquals(char),
64    #[token("0")]
65    #[token("false")]
66    #[token("False")]
67    False,
68    #[token("1")]
69    #[token("true")]
70    #[token("True")]
71    True,
72}
73
74impl Into<bool> for Token {
75    fn into(self) -> bool{
76        if let Token::True = self {
77            return  true;
78        }
79        false
80    }
81}
82
83impl From<bool> for Token {
84    fn from(value: bool) -> Self {
85        if value {
86            return Token::True;
87        }
88        Token::False
89    }
90}
91
92#[derive(Debug)]
93pub struct Tokens {
94    tokens: Vec<Token>,
95}
96
97impl Tokens {
98    pub fn from_text(text: &str) -> Self {
99        Self {
100            tokens: Token::lexer(text).filter_map(|result| result.ok()).collect(),
101        }
102    }
103    
104    pub fn enclose(&mut self, left: Token,right: Token) {
105        self.tokens.insert(0, left);
106        self.tokens.push(right);
107    }
108}
109
110impl Deref for Tokens {
111    type Target = [Token];
112    fn deref(&self) -> &Self::Target {
113        &self.tokens
114    }
115}
116
117impl Display for Tokens {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        for token in self.tokens.iter() {
120            match token {
121                Token::Ident(c) => f.write_char(*c),
122                Token::OpenParen => f.write_char('('),
123                Token::CloseParen => f.write_char(')'),
124                Token::OpenBracket => f.write_char('['),
125                Token::CloseBracket => f.write_char(']'),
126                Token::OpenCurlyBrace => f.write_char('{'),
127                Token::CloseCurlyBrace => f.write_char('}'),
128                Token::Not(symb) |
129                Token::Implication(symb) |
130                Token::Biconditional(symb) |
131                Token::And(symb) |
132                Token::Or(symb) |
133                Token::XOr(symb) | 
134                Token::Equals(symb) | 
135                Token::NotEquals(symb) => f.write_str(&format!(" {} ",symb.to_string())),
136                Token::False => f.write_char('0'),
137                Token::True => f.write_char('1'),
138            }?
139        }
140        Ok(())
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn implication() {
150        let s = "a -> b";
151        assert_eq!(
152            Tokens::from_text(s).tokens,
153            vec![Token::Ident('a'), Token::Implication('→'), Token::Ident('b')]
154        );
155    }
156
157    #[test]
158    fn equals() {
159        let s = "a == b";
160        assert_eq!(
161            Tokens::from_text(s).tokens,
162            vec![Token::Ident('a'), Token::Equals('≡'), Token::Ident('b')]
163        );
164    }
165
166    #[test]
167    fn not_equals() {
168        let s = "a != b";
169        assert_eq!(
170            Tokens::from_text(s).tokens,
171            vec![Token::Ident('a'), Token::NotEquals('≠'), Token::Ident('b')]
172        );
173    }
174
175    #[test]
176    fn not() {
177        let s = "(not a)";
178        let tokens = Tokens::from_text(s).tokens;
179        assert_eq!(
180            tokens,
181            vec![Token::OpenParen,Token::Not('¬'), Token::Ident('a'),Token::CloseParen]
182        );
183    }
184
185    #[test]
186    fn and() {
187        let symbols = ["and", "&", "&&", "∧"];
188        for s in symbols {
189            let expr = format!("a {} b",s);
190            let tokens = Tokens::from_text(&expr).tokens;
191            assert_eq!(
192                tokens,
193                vec![Token::Ident('a'),Token::And('∧'), Token::Ident('b')]
194            );
195        }
196    }
197
198    #[test]
199    fn or() {
200        let symbols = ["or", "|", "||", "∨"];
201        for s in symbols {
202            let expr = format!("a {} b",s);
203            let tokens = Tokens::from_text(&expr).tokens;
204            assert_eq!(
205                tokens,
206                vec![Token::Ident('a'),Token::Or('∨'), Token::Ident('b')]
207            );
208        }
209    }
210}