1use 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#[derive(Debug)]
15#[non_exhaustive]
16pub enum Expr<'a, T: Grammar> {
17 Variable,
19 Literal(T::Lit),
21 FnDefinition(FnDefinition<'a, T>),
23 TypeCast {
25 value: Box<SpannedExpr<'a, T>>,
27 ty: Spanned<'a, T::Type<'a>>,
29 },
30 Function {
32 name: Box<SpannedExpr<'a, T>>,
35 args: Vec<SpannedExpr<'a, T>>,
37 },
38 FieldAccess {
40 name: Box<SpannedExpr<'a, T>>,
42 receiver: Box<SpannedExpr<'a, T>>,
44 },
45 Method {
47 name: Box<SpannedExpr<'a, T>>,
49 receiver: Box<SpannedExpr<'a, T>>,
51 separator: Spanned<'a>,
53 args: Vec<SpannedExpr<'a, T>>,
55 },
56 Unary {
58 op: Spanned<'a, UnaryOp>,
60 inner: Box<SpannedExpr<'a, T>>,
62 },
63 Binary {
65 lhs: Box<SpannedExpr<'a, T>>,
67 op: Spanned<'a, BinaryOp>,
69 rhs: Box<SpannedExpr<'a, T>>,
71 },
72 Tuple(Vec<SpannedExpr<'a, T>>),
74 Block(Block<'a, T>),
76 Object(ObjectExpr<'a, T>),
78}
79
80impl<'a, T: Grammar> Expr<'a, T> {
81 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 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 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
243pub type SpannedExpr<'a, T> = Spanned<'a, Expr<'a, T>>;
245
246#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
248#[non_exhaustive]
249pub enum ExprType {
250 Variable,
252 Literal,
254 FnDefinition,
256 Cast,
258 Function,
260 FieldAccess,
262 Method,
264 Unary,
266 Binary,
268 Tuple,
270 Object,
272 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}