cas_parser/parser/token/
op.rs

1//! Structs to help parse binary and unary operators.
2
3use cas_error::Error;
4use crate::{
5    parser::{error::UnexpectedToken, fmt::Latex, Parse, Parser},
6    tokenizer::TokenKind,
7};
8use std::{fmt, ops::Range};
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13/// The associativity of a binary or unary operation.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum Associativity {
16    /// The binary / unary operation is left-associative.
17    ///
18    /// For binary operations, this means `a op b op c` is evaluated as `(a op b) op c`. For unary
19    /// operations, this means `a op op` is evaluated as `(a op) op` (the operators appear to the
20    /// right of the operand).
21    Left,
22
23    /// The binary / unary operation is right-associative.
24    ///
25    /// For binary operations, this means `a op b op c` is evaluated as `a op (b op c)`. For unary
26    /// operations, this means `op op a` is evaluated as `op (op a)` (the operators appear to the
27    /// left of the operand).
28    Right,
29}
30
31/// The precedence of an operation, in order from lowest precedence (evaluated last) to highest
32/// precedence (evaluated first).
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum Precedence {
35    /// Any precedence.
36    Any,
37
38    /// Precedence of assignment (`=`, `+=`, `-=`, `*=`, `/=`, `%=`, `^=`, `&&=`, `||=`, `&=`,
39    /// `|=`, `>>=`, and `<<=`).
40    Assign,
41
42    /// Precedence of range (`..` and `..=`).
43    Range,
44
45    /// Precedence of logical or (`or`).
46    Or,
47
48    /// Precedence of logical and (`and`).
49    And,
50
51    /// Precedence of comparisons (`>`, `>=`, `<`, `<=`, `==`, `!=`, `~==`, and `~!=`).
52    Compare,
53
54    /// Precedence of bitwise or (`|`).
55    BitOr,
56
57    /// Precedence of bitwise and (`&`).
58    BitAnd,
59
60    /// Precedence of bitshifts (`<<` and `>>`).
61    Shift,
62
63    /// Precedence of addition (`+`) and subtraction (`-`), which separate terms.
64    Term,
65
66    /// Precedence of multiplication (`*`), division (`/`), and modulo (`%`), which separate
67    /// factors.
68    Factor,
69
70    /// Precedence of unary subtraction (`-`).
71    Neg,
72
73    /// Precedence of exponentiation (`^`).
74    Exp,
75
76    /// Precedence of factorial (`!`).
77    Factorial,
78
79    /// Precedence of bitwise not (`~`).
80    BitNot,
81
82    /// Precedence of logical not (`not`).
83    Not,
84}
85
86impl PartialOrd for Precedence {
87    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
88        Some(self.cmp(other))
89    }
90}
91
92impl Ord for Precedence {
93    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
94        let left = *self as u8;
95        let right = *other as u8;
96        left.cmp(&right)
97    }
98}
99
100/// The unary operation that is being performed.
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
103pub enum UnaryOpKind {
104    Not,
105    BitNot,
106    Factorial,
107    Neg,
108}
109
110impl UnaryOpKind {
111    /// Returns the precedence of the unary operation.
112    pub fn precedence(&self) -> Precedence {
113        match self {
114            Self::Not => Precedence::Not,
115            Self::BitNot => Precedence::BitNot,
116            Self::Factorial => Precedence::Factorial,
117            Self::Neg => Precedence::Neg,
118        }
119    }
120
121    /// Returns the associativity of the unary operation.
122    pub fn associativity(&self) -> Associativity {
123        match self {
124            Self::Neg | Self::BitNot | Self::Not => Associativity::Right,
125            Self::Factorial => Associativity::Left,
126        }
127    }
128}
129
130/// A unary operator that takes one operand.
131#[derive(Debug, Clone, PartialEq, Eq)]
132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
133pub struct UnaryOp {
134    /// The kind of unary operator.
135    pub kind: UnaryOpKind,
136
137    /// The region of the source code that this operator was parsed from.
138    pub span: Range<usize>,
139}
140
141impl UnaryOp {
142    /// Returns the precedence of the unary operator.
143    pub fn precedence(&self) -> Precedence {
144        self.kind.precedence()
145    }
146
147    /// Returns the associativity of the unary operator.
148    pub fn associativity(&self) -> Associativity {
149        self.kind.associativity()
150    }
151}
152
153impl<'source> Parse<'source> for UnaryOp {
154    fn std_parse(
155        input: &mut Parser<'source>,
156        _: &mut Vec<Error>
157    ) -> Result<Self, Vec<Error>> {
158        let token = input.next_token().map_err(|e| vec![e])?;
159        let kind = match token.kind {
160            TokenKind::Not => Ok(UnaryOpKind::Not),
161            TokenKind::BitNot => Ok(UnaryOpKind::BitNot),
162            TokenKind::Factorial => Ok(UnaryOpKind::Factorial),
163            TokenKind::Sub => Ok(UnaryOpKind::Neg),
164            _ => Err(vec![Error::new(
165                vec![token.span.clone()],
166                UnexpectedToken {
167                    expected: &[
168                        TokenKind::Not,
169                        TokenKind::BitNot,
170                        TokenKind::Factorial,
171                        TokenKind::Sub,
172                    ],
173                    found: token.kind,
174                },
175            )]),
176        }?;
177
178        Ok(Self {
179            kind,
180            span: token.span,
181        })
182    }
183}
184
185impl std::fmt::Display for UnaryOp {
186    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
187        match self.kind {
188            UnaryOpKind::Not => write!(f, "not"),
189            UnaryOpKind::BitNot => write!(f, "~"),
190            UnaryOpKind::Factorial => write!(f, "!"),
191            UnaryOpKind::Neg => write!(f, "-"),
192        }
193    }
194}
195
196impl Latex for UnaryOp {
197    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
198        match self.kind {
199            UnaryOpKind::Not => write!(f, "\\neg "),
200            UnaryOpKind::BitNot => write!(f, "\\sim "),
201            UnaryOpKind::Factorial => write!(f, "!"),
202            UnaryOpKind::Neg => write!(f, "-"),
203        }
204    }
205}
206
207/// The binary operation that is being performed.
208#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
210pub enum BinOpKind {
211    Exp,
212    Mul,
213    Div,
214    Mod,
215    Add,
216    Sub,
217    BitRight,
218    BitLeft,
219    BitAnd,
220    BitOr,
221    Greater,
222    GreaterEq,
223    Less,
224    LessEq,
225    Eq,
226    NotEq,
227    ApproxEq,
228    ApproxNotEq,
229    And,
230    Or,
231}
232
233impl BinOpKind {
234    /// Returns the precedence of the binary operation.
235    pub fn precedence(&self) -> Precedence {
236        match self {
237            Self::Exp => Precedence::Exp,
238            Self::Mul | Self::Div | Self::Mod => Precedence::Factor,
239            Self::Add | Self::Sub => Precedence::Term,
240            Self::BitRight | Self::BitLeft => Precedence::Shift,
241            Self::BitAnd => Precedence::BitAnd,
242            Self::BitOr => Precedence::BitOr,
243            Self::Greater | Self::GreaterEq | Self::Less | Self::LessEq
244                | Self::Eq | Self::NotEq | Self::ApproxEq | Self::ApproxNotEq => Precedence::Compare,
245            Self::And => Precedence::And,
246            Self::Or => Precedence::Or,
247        }
248    }
249
250    /// Returns the associativity of the binary operation.
251    pub fn associativity(&self) -> Associativity {
252        match self {
253            Self::Exp => Associativity::Right,
254            Self::Mul | Self::Div | Self::Mod
255                | Self::Add | Self::Sub
256                | Self::BitRight | Self::BitLeft
257                | Self::BitAnd | Self::BitOr
258                | Self::Greater | Self::GreaterEq | Self::Less | Self::LessEq
259                | Self::Eq | Self::NotEq | Self::ApproxEq | Self::ApproxNotEq
260                | Self::And | Self::Or => Associativity::Left,
261        }
262    }
263}
264
265/// A binary operator that takes two operands.
266#[derive(Debug, Clone, PartialEq, Eq)]
267#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
268pub struct BinOp {
269    /// The kind of binary operator.
270    pub kind: BinOpKind,
271
272    /// Whether this binary operator was implicitly inserted by the parser.
273    pub implicit: bool,
274
275    /// The region of the source code that this operator was parsed from.
276    pub span: Range<usize>,
277}
278
279impl BinOp {
280    /// Returns the precedence of the binary operation.
281    pub fn precedence(&self) -> Precedence {
282        self.kind.precedence()
283    }
284
285    /// Returns the associativity of the binary operation.
286    pub fn associativity(&self) -> Associativity {
287        self.kind.associativity()
288    }
289}
290
291impl<'source> Parse<'source> for BinOp {
292    fn std_parse(
293        input: &mut Parser<'source>,
294        _: &mut Vec<Error>
295    ) -> Result<Self, Vec<Error>> {
296        let token = input.next_token().map_err(|e| vec![e])?;
297        let kind = match token.kind {
298            TokenKind::Exp => Ok(BinOpKind::Exp),
299            TokenKind::Mul => Ok(BinOpKind::Mul),
300            TokenKind::Div => Ok(BinOpKind::Div),
301            TokenKind::Mod => Ok(BinOpKind::Mod),
302            TokenKind::Add => Ok(BinOpKind::Add),
303            TokenKind::Sub => Ok(BinOpKind::Sub),
304            TokenKind::BitRight => Ok(BinOpKind::BitRight),
305            TokenKind::BitLeft => Ok(BinOpKind::BitLeft),
306            TokenKind::BitAnd => Ok(BinOpKind::BitAnd),
307            TokenKind::BitOr => Ok(BinOpKind::BitOr),
308            TokenKind::Greater => Ok(BinOpKind::Greater),
309            TokenKind::GreaterEq => Ok(BinOpKind::GreaterEq),
310            TokenKind::Less => Ok(BinOpKind::Less),
311            TokenKind::LessEq => Ok(BinOpKind::LessEq),
312            TokenKind::Eq => Ok(BinOpKind::Eq),
313            TokenKind::NotEq => Ok(BinOpKind::NotEq),
314            TokenKind::ApproxEq => Ok(BinOpKind::ApproxEq),
315            TokenKind::ApproxNotEq => Ok(BinOpKind::ApproxNotEq),
316            TokenKind::And => Ok(BinOpKind::And),
317            TokenKind::Or => Ok(BinOpKind::Or),
318            _ => Err(vec![Error::new(
319                vec![token.span.clone()],
320                UnexpectedToken {
321                    expected: &[
322                        TokenKind::Exp,
323                        TokenKind::Mul,
324                        TokenKind::Div,
325                        TokenKind::Add,
326                        TokenKind::Sub,
327                    ],
328                    found: token.kind,
329                },
330            )]),
331        }?;
332
333        Ok(Self {
334            kind,
335            implicit: false,
336            span: token.span,
337        })
338    }
339}
340
341impl std::fmt::Display for BinOp {
342    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
343        if self.implicit {
344            return Ok(());
345        }
346
347        match self.kind {
348            BinOpKind::Exp => write!(f, "^"),
349            BinOpKind::Mul => write!(f, "*"),
350            BinOpKind::Div => write!(f, "/"),
351            BinOpKind::Mod => write!(f, "%"),
352            BinOpKind::Add => write!(f, "+"),
353            BinOpKind::Sub => write!(f, "-"),
354            BinOpKind::BitRight => write!(f, ">>"),
355            BinOpKind::BitLeft => write!(f, "<<"),
356            BinOpKind::BitAnd => write!(f, "&"),
357            BinOpKind::BitOr => write!(f, "|"),
358            BinOpKind::Greater => write!(f, ">"),
359            BinOpKind::GreaterEq => write!(f, ">="),
360            BinOpKind::Less => write!(f, "<"),
361            BinOpKind::LessEq => write!(f, "<="),
362            BinOpKind::Eq => write!(f, "=="),
363            BinOpKind::NotEq => write!(f, "!="),
364            BinOpKind::ApproxEq => write!(f, "~=="),
365            BinOpKind::ApproxNotEq => write!(f, "~!="),
366            BinOpKind::And => write!(f, "&&"),
367            BinOpKind::Or => write!(f, "||"),
368        }
369    }
370}
371
372impl Latex for BinOp {
373    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
374        if self.implicit {
375            return Ok(());
376        }
377
378        match self.kind {
379            BinOpKind::Exp => write!(f, "^"),
380            BinOpKind::Mul => write!(f, "\\cdot "),
381            BinOpKind::Div => write!(f, "\\div "),
382            BinOpKind::Mod => write!(f, "\\mod "),
383            BinOpKind::Add => write!(f, "+"),
384            BinOpKind::Sub => write!(f, "-"),
385            BinOpKind::BitRight => write!(f, "\\gg "),
386            BinOpKind::BitLeft => write!(f, "\\ll "),
387            BinOpKind::BitAnd => write!(f, "\\&"),
388            BinOpKind::BitOr => write!(f, "\\vert "),
389            BinOpKind::Greater => write!(f, ">"),
390            BinOpKind::GreaterEq => write!(f, "\\geq "),
391            BinOpKind::Less => write!(f, "<"),
392            BinOpKind::LessEq => write!(f, "\\leq "),
393            BinOpKind::Eq => write!(f, "="),
394            BinOpKind::NotEq => write!(f, "\\neq "),
395            BinOpKind::ApproxEq => write!(f, "\\approx "),
396            BinOpKind::ApproxNotEq => write!(f, "\\not\\approx "),
397            BinOpKind::And => write!(f, "\\wedge "),
398            BinOpKind::Or => write!(f, "\\vee "),
399        }
400    }
401}
402
403/// The kind of assignment operator.
404#[derive(Debug, Clone, Copy, PartialEq, Eq)]
405#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
406pub enum AssignOpKind {
407    Assign,
408    Add,
409    Sub,
410    Mul,
411    Div,
412    Mod,
413    Exp,
414    And,
415    Or,
416    BitAnd,
417    BitOr,
418    BitRight,
419    BitLeft,
420}
421
422impl From<AssignOpKind> for BinOpKind {
423    fn from(value: AssignOpKind) -> Self {
424        match value {
425            AssignOpKind::Assign => Self::Eq,
426            AssignOpKind::Add => Self::Add,
427            AssignOpKind::Sub => Self::Sub,
428            AssignOpKind::Mul => Self::Mul,
429            AssignOpKind::Div => Self::Div,
430            AssignOpKind::Mod => Self::Mod,
431            AssignOpKind::Exp => Self::Exp,
432            AssignOpKind::And => Self::And,
433            AssignOpKind::Or => Self::Or,
434            AssignOpKind::BitAnd => Self::BitAnd,
435            AssignOpKind::BitOr => Self::BitOr,
436            AssignOpKind::BitRight => Self::BitRight,
437            AssignOpKind::BitLeft => Self::BitLeft,
438        }
439    }
440}
441
442/// An assignment operator that takes two operands, assigning the value of the right operand to the
443/// left operand, possibly with an intermediate operation.
444#[derive(Debug, Clone, PartialEq, Eq)]
445#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
446pub struct AssignOp {
447    /// The kind of assignment operator.
448    pub kind: AssignOpKind,
449
450    /// The region of the source code that this operator was parsed from.
451    pub span: Range<usize>,
452}
453
454impl AssignOp {
455    /// Returns true if this assignment operator is the standard assignment operator (i.e. `=`).
456    pub fn is_standard(&self) -> bool {
457        matches!(self.kind, AssignOpKind::Assign)
458    }
459
460    /// Returns true if this assignment operator is a compound assignment operator.
461    pub fn is_compound(&self) -> bool {
462        !self.is_standard()
463    }
464}
465
466impl<'source> Parse<'source> for AssignOp {
467    fn std_parse(
468        input: &mut Parser<'source>,
469        _: &mut Vec<Error>
470    ) -> Result<Self, Vec<Error>> {
471        let token = input.next_token().map_err(|e| vec![e])?;
472        let kind = match token.kind {
473            TokenKind::Assign => Ok(AssignOpKind::Assign),
474            TokenKind::AddAssign => Ok(AssignOpKind::Add),
475            TokenKind::SubAssign => Ok(AssignOpKind::Sub),
476            TokenKind::MulAssign => Ok(AssignOpKind::Mul),
477            TokenKind::DivAssign => Ok(AssignOpKind::Div),
478            TokenKind::ModAssign => Ok(AssignOpKind::Mod),
479            TokenKind::ExpAssign => Ok(AssignOpKind::Exp),
480            TokenKind::AndAssign => Ok(AssignOpKind::And),
481            TokenKind::OrAssign => Ok(AssignOpKind::Or),
482            TokenKind::BitAndAssign => Ok(AssignOpKind::BitAnd),
483            TokenKind::BitOrAssign => Ok(AssignOpKind::BitOr),
484            TokenKind::BitRightAssign => Ok(AssignOpKind::BitRight),
485            TokenKind::BitLeftAssign => Ok(AssignOpKind::BitLeft),
486            _ => Err(vec![Error::new(
487                vec![token.span.clone()],
488                UnexpectedToken {
489                    expected: &[
490                        TokenKind::Assign,
491                        TokenKind::AddAssign,
492                        TokenKind::SubAssign,
493                        TokenKind::MulAssign,
494                        TokenKind::DivAssign,
495                        TokenKind::ModAssign,
496                        TokenKind::ExpAssign,
497                        TokenKind::AndAssign,
498                        TokenKind::OrAssign,
499                        TokenKind::BitAndAssign,
500                        TokenKind::BitOrAssign,
501                        TokenKind::BitRightAssign,
502                        TokenKind::BitLeftAssign,
503                    ],
504                    found: token.kind,
505                },
506            )]),
507        }?;
508
509        Ok(Self {
510            kind,
511            span: token.span,
512        })
513    }
514}
515
516impl std::fmt::Display for AssignOp {
517    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
518        match self.kind {
519            AssignOpKind::Assign => write!(f, "="),
520            AssignOpKind::Add => write!(f, "+="),
521            AssignOpKind::Sub => write!(f, "-="),
522            AssignOpKind::Mul => write!(f, "*="),
523            AssignOpKind::Div => write!(f, "/="),
524            AssignOpKind::Mod => write!(f, "%="),
525            AssignOpKind::Exp => write!(f, "^="),
526            AssignOpKind::And => write!(f, "&&="),
527            AssignOpKind::Or => write!(f, "||="),
528            AssignOpKind::BitAnd => write!(f, "&="),
529            AssignOpKind::BitOr => write!(f, "|="),
530            AssignOpKind::BitRight => write!(f, ">>="),
531            AssignOpKind::BitLeft => write!(f, "<<="),
532        }
533    }
534}
535
536impl Latex for AssignOp {
537    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
538        match self.kind {
539            AssignOpKind::Assign => write!(f, "="),
540            AssignOpKind::Add => write!(f, "+="),
541            AssignOpKind::Sub => write!(f, "-="),
542            AssignOpKind::Mul => write!(f, "*="),
543            AssignOpKind::Div => write!(f, "/="),
544            AssignOpKind::Mod => write!(f, "\\mod="),
545            AssignOpKind::Exp => write!(f, "^="),
546            AssignOpKind::And => write!(f, "\\wedge="),
547            AssignOpKind::Or => write!(f, "\\vee="),
548            AssignOpKind::BitAnd => write!(f, "\\&="),
549            AssignOpKind::BitOr => write!(f, "\\vert="),
550            AssignOpKind::BitRight => write!(f, "\\gg="),
551            AssignOpKind::BitLeft => write!(f, "\\ll="),
552        }
553    }
554}