arithmetic_parser/ast/
expr.rs

1//! `Expr` and tightly related types.
2
3use core::fmt;
4
5use super::{Block, FnDefinition, ObjectExpr};
6use crate::{
7    alloc::{Box, Vec},
8    grammars::Grammar,
9    ops::{BinaryOp, UnaryOp},
10    spans::Spanned,
11};
12
13/// Arithmetic expression with an abstract types for type annotations and literals.
14#[derive(Debug)]
15#[non_exhaustive]
16pub enum Expr<'a, T: Grammar> {
17    /// Variable use, e.g., `x`.
18    Variable,
19    /// Literal (semantic depends on `T`).
20    Literal(T::Lit),
21    /// Function definition, e.g., `|x, y| { x + y }`.
22    FnDefinition(FnDefinition<'a, T>),
23    /// Type cast, e.g., `x as Bool`.
24    TypeCast {
25        /// Value being cast, e.g., `x` in `x as Bool`.
26        value: Box<SpannedExpr<'a, T>>,
27        /// Type annotation for the case, e.g., `Bool` in `x as Bool`.
28        ty: Spanned<'a, T::Type<'a>>,
29    },
30    /// Function call, e.g., `foo(x, y)` or `|x| { x + 5 }(3)`.
31    Function {
32        /// Function value. In the simplest case, this is a variable, but may also be another
33        /// kind of expression, such as `|x| { x + 5 }` in `|x| { x + 5 }(3)`.
34        name: Box<SpannedExpr<'a, T>>,
35        /// Function arguments.
36        args: Vec<SpannedExpr<'a, T>>,
37    },
38    /// Field access, e.g., `foo.bar`.
39    FieldAccess {
40        /// Name of the called method, e.g. `bar` in `foo.bar`.
41        name: Box<SpannedExpr<'a, T>>,
42        /// Receiver of the call, e.g., `foo` in `foo.bar(x, 5)`.
43        receiver: Box<SpannedExpr<'a, T>>,
44    },
45    /// Method call, e.g., `foo.bar(x, 5)`.
46    Method {
47        /// Name of the called method, e.g. `bar` in `foo.bar(x, 5)`.
48        name: Box<SpannedExpr<'a, T>>,
49        /// Receiver of the call, e.g., `foo` in `foo.bar(x, 5)`.
50        receiver: Box<SpannedExpr<'a, T>>,
51        /// Separator between the receiver and the called method, e.g., `.` in `foo.bar(x, 5)`.
52        separator: Spanned<'a>,
53        /// Arguments; e.g., `x, 5` in `foo.bar(x, 5)`.
54        args: Vec<SpannedExpr<'a, T>>,
55    },
56    /// Unary operation, e.g., `-x`.
57    Unary {
58        /// Operator.
59        op: Spanned<'a, UnaryOp>,
60        /// Inner expression.
61        inner: Box<SpannedExpr<'a, T>>,
62    },
63    /// Binary operation, e.g., `x + 1`.
64    Binary {
65        /// LHS of the operation.
66        lhs: Box<SpannedExpr<'a, T>>,
67        /// Operator.
68        op: Spanned<'a, BinaryOp>,
69        /// RHS of the operation.
70        rhs: Box<SpannedExpr<'a, T>>,
71    },
72    /// Tuple expression, e.g., `(x, y + z)`.
73    Tuple(Vec<SpannedExpr<'a, T>>),
74    /// Block expression, e.g., `{ x = 3; x + y }`.
75    Block(Block<'a, T>),
76    /// Object expression, e.g., `#{ x, y: x + 2 }`.
77    Object(ObjectExpr<'a, T>),
78}
79
80impl<'a, T: Grammar> Expr<'a, T> {
81    /// Returns LHS of the binary expression. If this is not a binary expression, returns `None`.
82    pub fn binary_lhs(&self) -> Option<&SpannedExpr<'a, T>> {
83        match self {
84            Expr::Binary { ref lhs, .. } => Some(lhs),
85            _ => None,
86        }
87    }
88
89    /// Returns RHS of the binary expression. If this is not a binary expression, returns `None`.
90    pub fn binary_rhs(&self) -> Option<&SpannedExpr<'a, T>> {
91        match self {
92            Expr::Binary { ref rhs, .. } => Some(rhs),
93            _ => None,
94        }
95    }
96
97    /// Returns the type of this expression.
98    pub fn ty(&self) -> ExprType {
99        match self {
100            Self::Variable => ExprType::Variable,
101            Self::Literal(_) => ExprType::Literal,
102            Self::FnDefinition(_) => ExprType::FnDefinition,
103            Self::TypeCast { .. } => ExprType::Cast,
104            Self::Tuple(_) => ExprType::Tuple,
105            Self::Object(_) => ExprType::Object,
106            Self::Block(_) => ExprType::Block,
107            Self::Function { .. } => ExprType::Function,
108            Self::FieldAccess { .. } => ExprType::FieldAccess,
109            Self::Method { .. } => ExprType::Method,
110            Self::Unary { .. } => ExprType::Unary,
111            Self::Binary { .. } => ExprType::Binary,
112        }
113    }
114}
115
116impl<T: Grammar> Clone for Expr<'_, T> {
117    fn clone(&self) -> Self {
118        match self {
119            Self::Variable => Self::Variable,
120            Self::Literal(lit) => Self::Literal(lit.clone()),
121            Self::FnDefinition(function) => Self::FnDefinition(function.clone()),
122            Self::TypeCast { value, ty } => Self::TypeCast {
123                value: value.clone(),
124                ty: ty.clone(),
125            },
126            Self::Tuple(tuple) => Self::Tuple(tuple.clone()),
127            Self::Object(statements) => Self::Object(statements.clone()),
128            Self::Block(block) => Self::Block(block.clone()),
129            Self::Function { name, args } => Self::Function {
130                name: name.clone(),
131                args: args.clone(),
132            },
133            Self::FieldAccess { name, receiver } => Self::FieldAccess {
134                name: name.clone(),
135                receiver: receiver.clone(),
136            },
137            Self::Method {
138                name,
139                receiver,
140                separator,
141                args,
142            } => Self::Method {
143                name: name.clone(),
144                receiver: receiver.clone(),
145                separator: *separator,
146                args: args.clone(),
147            },
148            Self::Unary { op, inner } => Self::Unary {
149                op: *op,
150                inner: inner.clone(),
151            },
152            Self::Binary { op, lhs, rhs } => Self::Binary {
153                op: *op,
154                lhs: lhs.clone(),
155                rhs: rhs.clone(),
156            },
157        }
158    }
159}
160
161impl<'a, T> PartialEq for Expr<'a, T>
162where
163    T: Grammar,
164    T::Lit: PartialEq,
165    T::Type<'a>: PartialEq,
166{
167    fn eq(&self, other: &Self) -> bool {
168        match (self, other) {
169            (Self::Variable, Self::Variable) => true,
170            (Self::Literal(this), Self::Literal(that)) => this == that,
171            (Self::FnDefinition(this), Self::FnDefinition(that)) => this == that,
172
173            (
174                Self::TypeCast { value, ty },
175                Self::TypeCast {
176                    value: other_value,
177                    ty: other_ty,
178                },
179            ) => value == other_value && ty == other_ty,
180
181            (Self::Tuple(this), Self::Tuple(that)) => this == that,
182            (Self::Object(this), Self::Object(that)) => this == that,
183            (Self::Block(this), Self::Block(that)) => this == that,
184
185            (
186                Self::Function { name, args },
187                Self::Function {
188                    name: that_name,
189                    args: that_args,
190                },
191            ) => name == that_name && args == that_args,
192
193            (
194                Self::FieldAccess { name, receiver },
195                Self::FieldAccess {
196                    name: that_name,
197                    receiver: that_receiver,
198                },
199            ) => name == that_name && receiver == that_receiver,
200
201            (
202                Self::Method {
203                    name,
204                    receiver,
205                    separator,
206                    args,
207                },
208                Self::Method {
209                    name: that_name,
210                    receiver: that_receiver,
211                    separator: that_separator,
212                    args: that_args,
213                },
214            ) => {
215                name == that_name
216                    && receiver == that_receiver
217                    && args == that_args
218                    && separator == that_separator
219            }
220
221            (
222                Self::Unary { op, inner },
223                Self::Unary {
224                    op: that_op,
225                    inner: that_inner,
226                },
227            ) => op == that_op && inner == that_inner,
228
229            (
230                Self::Binary { lhs, op, rhs },
231                Self::Binary {
232                    lhs: that_lhs,
233                    op: that_op,
234                    rhs: that_rhs,
235                },
236            ) => op == that_op && lhs == that_lhs && rhs == that_rhs,
237
238            _ => false,
239        }
240    }
241}
242
243/// `Expr` with the associated type and code span.
244pub type SpannedExpr<'a, T> = Spanned<'a, Expr<'a, T>>;
245
246/// Type of an `Expr`.
247#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
248#[non_exhaustive]
249pub enum ExprType {
250    /// Variable use, e.g., `x`.
251    Variable,
252    /// Literal (semantic depends on the grammar).
253    Literal,
254    /// Function definition, e.g., `|x, y| { x + y }`.
255    FnDefinition,
256    /// Cast, e.g., `x as Bool`.
257    Cast,
258    /// Function call, e.g., `foo(x, y)` or `|x| { x + 5 }(3)`.
259    Function,
260    /// Field access, e.g., `foo.bar`.
261    FieldAccess,
262    /// Method call, e.g., `foo.bar(x, 5)`.
263    Method,
264    /// Unary operation, e.g., `-x`.
265    Unary,
266    /// Binary operation, e.g., `x + 1`.
267    Binary,
268    /// Tuple expression, e.g., `(x, y + z)`.
269    Tuple,
270    /// Object expression, e.g., `#{ x = 1; y = x + 2; }`.
271    Object,
272    /// Block expression, e.g., `{ x = 3; x + y }`.
273    Block,
274}
275
276impl fmt::Display for ExprType {
277    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
278        formatter.write_str(match self {
279            Self::Variable => "variable",
280            Self::Literal => "literal",
281            Self::FnDefinition => "function definition",
282            Self::Cast => "type cast",
283            Self::Function => "function call",
284            Self::FieldAccess => "field access",
285            Self::Method => "method call",
286            Self::Unary => "unary operation",
287            Self::Binary => "binary operation",
288            Self::Tuple => "tuple",
289            Self::Object => "object",
290            Self::Block => "block",
291        })
292    }
293}