datex_core/ast/
binary_operation.rs

1use crate::ast::DatexExpression;
2use crate::ast::DatexParserTrait;
3use crate::ast::lexer::Token;
4use crate::ast::utils::is_identifier;
5use crate::ast::utils::operation;
6use crate::global::instruction_codes::InstructionCode;
7use crate::global::protocol_structures::instructions::Instruction;
8use chumsky::prelude::*;
9use std::fmt::Display;
10
11#[derive(Clone, Debug, PartialEq, Copy)]
12pub enum BinaryOperator {
13    Arithmetic(ArithmeticOperator),
14    Logical(LogicalOperator),
15    Bitwise(BitwiseOperator),
16    VariantAccess,
17}
18impl From<ArithmeticOperator> for BinaryOperator {
19    fn from(op: ArithmeticOperator) -> Self {
20        BinaryOperator::Arithmetic(op)
21    }
22}
23impl From<LogicalOperator> for BinaryOperator {
24    fn from(op: LogicalOperator) -> Self {
25        BinaryOperator::Logical(op)
26    }
27}
28impl From<BitwiseOperator> for BinaryOperator {
29    fn from(op: BitwiseOperator) -> Self {
30        BinaryOperator::Bitwise(op)
31    }
32}
33
34#[derive(Clone, Debug, PartialEq, Copy)]
35pub enum ArithmeticOperator {
36    Add,      // +
37    Subtract, // -
38    Multiply, // *
39    Divide,   // /
40    Modulo,   // %
41    Power,    // ^
42}
43impl Display for ArithmeticOperator {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        write!(
46            f,
47            "{}",
48            match self {
49                ArithmeticOperator::Add => "+",
50                ArithmeticOperator::Subtract => "-",
51                ArithmeticOperator::Multiply => "*",
52                ArithmeticOperator::Divide => "/",
53                ArithmeticOperator::Modulo => "%",
54                ArithmeticOperator::Power => "^",
55            }
56        )
57    }
58}
59impl From<&ArithmeticOperator> for InstructionCode {
60    fn from(op: &ArithmeticOperator) -> Self {
61        match op {
62            ArithmeticOperator::Add => InstructionCode::ADD,
63            ArithmeticOperator::Subtract => InstructionCode::SUBTRACT,
64            ArithmeticOperator::Multiply => InstructionCode::MULTIPLY,
65            ArithmeticOperator::Divide => InstructionCode::DIVIDE,
66            ArithmeticOperator::Modulo => InstructionCode::MODULO,
67            ArithmeticOperator::Power => InstructionCode::POWER,
68        }
69    }
70}
71
72#[derive(Clone, Debug, PartialEq, Copy)]
73pub enum LogicalOperator {
74    And, // and
75    Or,  // or
76}
77
78impl From<&LogicalOperator> for InstructionCode {
79    fn from(op: &LogicalOperator) -> Self {
80        match op {
81            LogicalOperator::And => InstructionCode::AND,
82            LogicalOperator::Or => InstructionCode::OR,
83        }
84    }
85}
86
87impl Display for LogicalOperator {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        write!(
90            f,
91            "{}",
92            match self {
93                LogicalOperator::And => "and",
94                LogicalOperator::Or => "or",
95            }
96        )
97    }
98}
99
100#[derive(Clone, Debug, PartialEq, Copy)]
101pub enum BitwiseOperator {
102    And, // &
103    Or,  // |
104    Xor, // ^
105    Not, // ~
106}
107
108impl From<&BitwiseOperator> for InstructionCode {
109    fn from(op: &BitwiseOperator) -> Self {
110        match op {
111            BitwiseOperator::And => InstructionCode::AND,
112            BitwiseOperator::Or => InstructionCode::OR,
113            BitwiseOperator::Not => InstructionCode::NOT,
114            _ => {
115                todo!(
116                    "Bitwise operator {:?} not implemented for InstructionCode",
117                    op
118                )
119            }
120        }
121    }
122}
123
124impl Display for BitwiseOperator {
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        write!(
127            f,
128            "{}",
129            match self {
130                BitwiseOperator::And => "&",
131                BitwiseOperator::Or => "|",
132                BitwiseOperator::Xor => "^",
133                BitwiseOperator::Not => "~",
134            }
135        )
136    }
137}
138
139impl Display for BinaryOperator {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        write!(
142            f,
143            "{}",
144            match self {
145                BinaryOperator::Arithmetic(op) => op.to_string(),
146                BinaryOperator::Logical(op) => op.to_string(),
147                BinaryOperator::Bitwise(op) => op.to_string(),
148                BinaryOperator::VariantAccess => "/".to_string(),
149            }
150        )
151    }
152}
153
154fn binary_op(
155    op: BinaryOperator,
156) -> impl Fn(Box<DatexExpression>, Box<DatexExpression>) -> DatexExpression + Clone
157{
158    move |lhs, rhs| DatexExpression::BinaryOperation(op, lhs, rhs, None)
159}
160
161fn product<'a>(chain: impl DatexParserTrait<'a>) -> impl DatexParserTrait<'a> {
162    chain
163        .clone()
164        .foldl(
165            choice((
166                operation(Token::Star).to(ArithmeticOperator::Multiply),
167                operation(Token::Slash).to(ArithmeticOperator::Divide),
168            ))
169            .then(chain)
170            .repeated(),
171            |lhs, (op, rhs)| {
172                let effective_op = if matches!(op, ArithmeticOperator::Divide)
173                    && is_identifier(&lhs)
174                    && is_identifier(&rhs)
175                {
176                    BinaryOperator::VariantAccess
177                } else {
178                    op.into()
179                };
180
181                binary_op(effective_op)(Box::new(lhs), Box::new(rhs))
182            },
183        )
184        .boxed()
185}
186
187fn sum<'a>(product: impl DatexParserTrait<'a>) -> impl DatexParserTrait<'a> {
188    product
189        .clone()
190        .foldl(
191            choice((
192                operation(Token::Plus).to(ArithmeticOperator::Add),
193                operation(Token::Minus).to(ArithmeticOperator::Subtract),
194            ))
195            .then(product)
196            .repeated(),
197            |lhs, (op, rhs)| binary_op(op.into())(Box::new(lhs), Box::new(rhs)),
198        )
199        .boxed()
200}
201
202/// FIXME #354: Rethink syntax for bitwise operations, due to colission with type system syntax
203fn bitwise_and<'a>(
204    sum: impl DatexParserTrait<'a>,
205) -> impl DatexParserTrait<'a> {
206    sum.clone()
207        .foldl(
208            operation(Token::Ampersand)
209                .to(binary_op(BitwiseOperator::And.into()))
210                .then(sum.clone())
211                .repeated(),
212            |lhs, (op, rhs)| op(Box::new(lhs), Box::new(rhs)),
213        )
214        .boxed()
215}
216
217fn bitwise_or<'a>(
218    intersection: impl DatexParserTrait<'a>,
219) -> impl DatexParserTrait<'a> {
220    intersection
221        .clone()
222        .foldl(
223            operation(Token::Pipe)
224                .to(binary_op(BitwiseOperator::Or.into()))
225                .then(intersection.clone())
226                .repeated(),
227            |lhs, (op, rhs)| op(Box::new(lhs), Box::new(rhs)),
228        )
229        .boxed()
230}
231
232pub fn binary_operation<'a>(
233    chain: impl DatexParserTrait<'a>,
234) -> impl DatexParserTrait<'a> {
235    bitwise_or(bitwise_and(sum(product(chain))))
236}
237
238impl From<&BinaryOperator> for InstructionCode {
239    fn from(op: &BinaryOperator) -> Self {
240        match op {
241            BinaryOperator::Arithmetic(op) => InstructionCode::from(op),
242            BinaryOperator::Logical(op) => InstructionCode::from(op),
243            BinaryOperator::Bitwise(op) => InstructionCode::from(op),
244            BinaryOperator::VariantAccess => {
245                todo!("#355 VariantAccess not implemented for InstructionCode")
246            }
247            operator => todo!(
248                "Binary operator {:?} not implemented for InstructionCode",
249                operator
250            ),
251        }
252    }
253}
254
255impl From<BinaryOperator> for InstructionCode {
256    fn from(op: BinaryOperator) -> Self {
257        InstructionCode::from(&op)
258    }
259}
260
261impl From<&InstructionCode> for BinaryOperator {
262    fn from(code: &InstructionCode) -> Self {
263        match code {
264            InstructionCode::ADD => {
265                BinaryOperator::Arithmetic(ArithmeticOperator::Add)
266            }
267            InstructionCode::SUBTRACT => {
268                BinaryOperator::Arithmetic(ArithmeticOperator::Subtract)
269            }
270            InstructionCode::MULTIPLY => {
271                BinaryOperator::Arithmetic(ArithmeticOperator::Multiply)
272            }
273            InstructionCode::DIVIDE => {
274                BinaryOperator::Arithmetic(ArithmeticOperator::Divide)
275            }
276            InstructionCode::MODULO => {
277                BinaryOperator::Arithmetic(ArithmeticOperator::Modulo)
278            }
279            InstructionCode::POWER => {
280                BinaryOperator::Arithmetic(ArithmeticOperator::Power)
281            }
282            InstructionCode::AND => {
283                BinaryOperator::Logical(LogicalOperator::And)
284            }
285            InstructionCode::OR => BinaryOperator::Logical(LogicalOperator::Or),
286            InstructionCode::UNION => {
287                BinaryOperator::Bitwise(BitwiseOperator::And)
288            }
289            _ => todo!("#154 Binary operator for {:?} not implemented", code),
290        }
291    }
292}
293
294impl From<InstructionCode> for BinaryOperator {
295    fn from(code: InstructionCode) -> Self {
296        BinaryOperator::from(&code)
297    }
298}
299
300impl From<&Instruction> for BinaryOperator {
301    fn from(instruction: &Instruction) -> Self {
302        match instruction {
303            Instruction::Add => {
304                BinaryOperator::Arithmetic(ArithmeticOperator::Add)
305            }
306            Instruction::Subtract => {
307                BinaryOperator::Arithmetic(ArithmeticOperator::Subtract)
308            }
309            Instruction::Multiply => {
310                BinaryOperator::Arithmetic(ArithmeticOperator::Multiply)
311            }
312            Instruction::Divide => {
313                BinaryOperator::Arithmetic(ArithmeticOperator::Divide)
314            }
315            _ => {
316                todo!(
317                    "#155 Binary operator for instruction {:?} not implemented",
318                    instruction
319                );
320            }
321        }
322    }
323}
324
325impl From<Instruction> for BinaryOperator {
326    fn from(instruction: Instruction) -> Self {
327        BinaryOperator::from(&instruction)
328    }
329}