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, Subtract, Multiply, Divide, Modulo, Power, }
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, Or, }
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, Or, Xor, Not, }
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
202fn 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}