microcad_lang/syntax/expression/
mod.rs

1// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! µcad syntax elements related to expressions
5
6mod array_expression;
7mod marker;
8mod range_expression;
9mod tuple_expression;
10
11pub use array_expression::*;
12pub use marker::*;
13pub use range_expression::*;
14pub use tuple_expression::*;
15
16use crate::{src_ref::*, syntax::*, value::*};
17
18/// List of expressions.
19pub type ListExpression = Vec<Expression>;
20
21/// Any expression.
22#[derive(Clone, Default)]
23pub enum Expression {
24    /// Something went wrong (and an error will be reported)
25    #[default]
26    Invalid,
27    /// An integer, float, color or bool literal: 1, 1.0, #00FF00, false
28    Literal(Literal),
29    /// A string that contains format expressions: "value = {a}"
30    FormatString(FormatString),
31    /// A list: [a, b, c]
32    ArrayExpression(ArrayExpression),
33    /// A tuple: (a, b, c)
34    TupleExpression(TupleExpression),
35    /// A body: `{}`.
36    Body(Body),
37    /// An if statement: `if {} else {}`.
38    If(Box<IfStatement>),
39    /// A call: `ops::subtract()`.
40    Call(Call),
41    /// A qualified name: `foo::bar`.
42    QualifiedName(QualifiedName),
43    /// A marker expression: `@input`.
44    Marker(Marker),
45    /// A binary operation: `a + b`
46    BinaryOp {
47        /// Left-hand side
48        lhs: Box<Expression>,
49        /// Operator  ('+', '-', '/', '*', '<', '>', '≤', '≥', '&', '|')
50        op: String,
51        /// Right -hand side
52        rhs: Box<Expression>,
53        /// Source code reference
54        src_ref: SrcRef,
55    },
56    /// A unary operation: !a
57    UnaryOp {
58        /// Operator ('+', '-', '!')
59        op: String,
60        /// Right -hand side
61        rhs: Box<Expression>,
62        /// Source code reference
63        src_ref: SrcRef,
64    },
65    /// Access an element of a list (`a[0]`) or a tuple (`a.0` or `a.b`)
66    ArrayElementAccess(Box<Expression>, Box<Expression>, SrcRef),
67    /// Access an element of a tuple: `a.b`.
68    PropertyAccess(Box<Expression>, Identifier, SrcRef),
69
70    /// Access an attribute of a model: `a#b`.
71    AttributeAccess(Box<Expression>, Identifier, SrcRef),
72
73    /// Call to a method: `[2,3].len()`
74    /// First expression must evaluate to a value
75    MethodCall(Box<Expression>, MethodCall, SrcRef),
76}
77
78impl SingleIdentifier for Expression {
79    /// If the expression includes just one identifier, e.g. `a` or `a * (a + 2)`
80    fn single_identifier(&self) -> Option<&Identifier> {
81        match &self {
82            Expression::Invalid
83            | Expression::Literal(..)
84            | Expression::FormatString(..)
85            | Expression::Marker(..)
86            | Expression::PropertyAccess(..)
87            | Expression::AttributeAccess(..)
88            | Expression::MethodCall(..)
89            | Expression::ArrayExpression(..)
90            | Expression::TupleExpression(..)
91            | Expression::Body(..)
92            | Expression::If(..)
93            | Expression::Call(..) => None,
94
95            Expression::QualifiedName(qualified_name) => qualified_name.single_identifier(),
96            Expression::BinaryOp {
97                lhs,
98                op: _,
99                rhs,
100                src_ref: _,
101            } => {
102                let l = lhs.single_identifier();
103                let r = rhs.single_identifier();
104                if l == r || r.is_none() {
105                    l
106                } else if l.is_none() {
107                    r
108                } else {
109                    None
110                }
111            }
112            Expression::UnaryOp {
113                op: _,
114                rhs,
115                src_ref: _,
116            } => rhs.single_identifier(),
117            Expression::ArrayElementAccess(expression, ..) => expression.single_identifier(),
118        }
119    }
120}
121
122impl SrcReferrer for Expression {
123    fn src_ref(&self) -> crate::src_ref::SrcRef {
124        match self {
125            Self::Invalid => SrcRef(None),
126            Self::Literal(l) => l.src_ref(),
127            Self::FormatString(fs) => fs.src_ref(),
128            Self::ArrayExpression(le) => le.src_ref(),
129            Self::TupleExpression(te) => te.src_ref(),
130            Self::Call(c) => c.src_ref(),
131            Self::Body(b) => b.src_ref(),
132            Self::If(i) => i.src_ref(),
133            Self::QualifiedName(q) => q.src_ref(),
134            Self::Marker(m) => m.src_ref(),
135            Self::BinaryOp {
136                lhs: _,
137                op: _,
138                rhs: _,
139                src_ref,
140            } => src_ref.clone(),
141            Self::UnaryOp {
142                op: _,
143                rhs: _,
144                src_ref,
145            } => src_ref.clone(),
146            Self::ArrayElementAccess(_, _, src_ref) => src_ref.clone(),
147            Self::PropertyAccess(_, _, src_ref) => src_ref.clone(),
148            Self::AttributeAccess(_, _, src_ref) => src_ref.clone(),
149            Self::MethodCall(_, _, src_ref) => src_ref.clone(),
150        }
151    }
152}
153
154impl std::fmt::Display for Expression {
155    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
156        match self {
157            Self::Literal(literal) => write!(f, "{literal}"),
158            Self::FormatString(format_string) => write!(f, "{format_string}"),
159            Self::ArrayExpression(array_expression) => write!(f, "{array_expression}"),
160            Self::TupleExpression(tuple_expression) => write!(f, "{tuple_expression}"),
161            Self::BinaryOp {
162                lhs,
163                op,
164                rhs,
165                src_ref: _,
166            } => write!(f, "{lhs} {op} {rhs}"),
167            Self::UnaryOp {
168                op,
169                rhs,
170                src_ref: _,
171            } => write!(f, "{op}{rhs}"),
172            Self::ArrayElementAccess(lhs, rhs, _) => write!(f, "{lhs}[{rhs}]"),
173            Self::PropertyAccess(lhs, rhs, _) => write!(f, "{lhs}.{rhs}"),
174            Self::AttributeAccess(lhs, rhs, _) => write!(f, "{lhs}#{rhs}"),
175            Self::MethodCall(lhs, method_call, _) => write!(f, "{lhs}.{method_call}"),
176            Self::Call(call) => write!(f, "{call}"),
177            Self::Body(body) => write!(f, "{body}"),
178            Self::If(if_) => write!(f, "{if_}"),
179            Self::QualifiedName(qualified_name) => write!(f, "{qualified_name}"),
180            Self::Marker(marker) => write!(f, "{marker}"),
181            _ => unimplemented!(),
182        }
183    }
184}
185
186impl std::fmt::Debug for Expression {
187    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
188        match self {
189            Self::Literal(literal) => write!(f, "{literal}"),
190            Self::FormatString(format_string) => write!(f, "{format_string:?}"),
191            Self::ArrayExpression(array_expression) => write!(f, "{array_expression:?}"),
192            Self::TupleExpression(tuple_expression) => write!(f, "{tuple_expression:?}"),
193            Self::BinaryOp {
194                lhs,
195                op,
196                rhs,
197                src_ref: _,
198            } => write!(f, "{lhs:?} {op} {rhs:?}"),
199            Self::UnaryOp {
200                op,
201                rhs,
202                src_ref: _,
203            } => write!(f, "{op}{rhs:?}"),
204            Self::ArrayElementAccess(lhs, rhs, _) => write!(f, "{lhs:?}[{rhs:?}]"),
205            Self::PropertyAccess(lhs, rhs, _) => write!(f, "{lhs:?}.{rhs:?}"),
206            Self::AttributeAccess(lhs, rhs, _) => write!(f, "{lhs:?}#{rhs:?}"),
207            Self::MethodCall(lhs, method_call, _) => write!(f, "{lhs:?}.{method_call:?}"),
208            Self::Call(call) => write!(f, "{call:?}"),
209            Self::Body(body) => write!(f, "{body:?}"),
210            Self::If(if_) => write!(f, "{if_:?}"),
211            Self::QualifiedName(qualified_name) => write!(f, "{qualified_name:?}"),
212            Self::Marker(marker) => write!(f, "{marker:?}"),
213            _ => unimplemented!(),
214        }
215    }
216}
217
218impl TreeDisplay for Value {
219    fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
220        write!(f, "{:depth$}Value: {value}", "", value = self)
221    }
222}
223
224impl TreeDisplay for Expression {
225    fn tree_print(&self, f: &mut std::fmt::Formatter, mut depth: TreeState) -> std::fmt::Result {
226        match self {
227            Expression::Literal(literal) => literal.tree_print(f, depth),
228            Expression::FormatString(format_string) => format_string.tree_print(f, depth),
229            Expression::ArrayExpression(array_expression) => array_expression.tree_print(f, depth),
230            Expression::TupleExpression(tuple_expression) => tuple_expression.tree_print(f, depth),
231            Expression::BinaryOp {
232                lhs,
233                op,
234                rhs,
235                src_ref: _,
236            } => {
237                writeln!(f, "{:depth$}BinaryOp '{op}':", "")?;
238                depth.indent();
239                lhs.tree_print(f, depth)?;
240                rhs.tree_print(f, depth)
241            }
242            Expression::UnaryOp {
243                op,
244                rhs,
245                src_ref: _,
246            } => {
247                writeln!(f, "{:depth$}UnaryOp '{op}':", "")?;
248                depth.indent();
249                rhs.tree_print(f, depth)
250            }
251            Expression::ArrayElementAccess(lhs, rhs, _) => {
252                writeln!(f, "{:depth$}ArrayElementAccess:", "")?;
253                depth.indent();
254                lhs.tree_print(f, depth)?;
255                rhs.tree_print(f, depth)
256            }
257            Expression::PropertyAccess(lhs, rhs, _) => {
258                writeln!(f, "{:depth$}FieldAccess:", "")?;
259                depth.indent();
260                lhs.tree_print(f, depth)?;
261                rhs.tree_print(f, depth)
262            }
263            Expression::AttributeAccess(lhs, rhs, _) => {
264                writeln!(f, "{:depth$}AttributeAccess:", "")?;
265                depth.indent();
266                lhs.tree_print(f, depth)?;
267                rhs.tree_print(f, depth)
268            }
269            Expression::MethodCall(lhs, method_call, _) => {
270                writeln!(f, "{:depth$}MethodCall:", "")?;
271                depth.indent();
272                lhs.tree_print(f, depth)?;
273                method_call.tree_print(f, depth)
274            }
275            Expression::Call(call) => call.tree_print(f, depth),
276            Expression::Body(body) => body.tree_print(f, depth),
277            Expression::If(if_) => if_.tree_print(f, depth),
278            Expression::QualifiedName(qualified_name) => qualified_name.tree_print(f, depth),
279            Expression::Marker(marker) => marker.tree_print(f, depth),
280            Expression::Invalid => write!(f, "{}", crate::invalid!(EXPRESSION)),
281        }
282    }
283}
284
285impl AsRef<Self> for Expression {
286    fn as_ref(&self) -> &Self {
287        self
288    }
289}
290
291impl PartialEq for Expression {
292    fn eq(&self, other: &Self) -> bool {
293        match (self, other) {
294            (Self::Literal(l0), Self::Literal(r0)) => l0 == r0,
295            (Self::FormatString(l0), Self::FormatString(r0)) => l0 == r0,
296            (Self::ArrayExpression(l0), Self::ArrayExpression(r0)) => l0 == r0,
297            (Self::TupleExpression(l0), Self::TupleExpression(r0)) => l0 == r0,
298            (Self::QualifiedName(l0), Self::QualifiedName(r0)) => l0 == r0,
299            (
300                Self::BinaryOp {
301                    lhs: l_lhs,
302                    op: l_op,
303                    rhs: l_rhs,
304                    src_ref: l_src_ref,
305                },
306                Self::BinaryOp {
307                    lhs: r_lhs,
308                    op: r_op,
309                    rhs: r_rhs,
310                    src_ref: r_src_ref,
311                },
312            ) => l_lhs == r_lhs && l_op == r_op && l_rhs == r_rhs && l_src_ref == r_src_ref,
313            (
314                Self::UnaryOp {
315                    op: l_op,
316                    rhs: l_rhs,
317                    src_ref: l_src_ref,
318                },
319                Self::UnaryOp {
320                    op: r_op,
321                    rhs: r_rhs,
322                    src_ref: r_src_ref,
323                },
324            ) => l_op == r_op && l_rhs == r_rhs && l_src_ref == r_src_ref,
325            (Self::ArrayElementAccess(l0, l1, l2), Self::ArrayElementAccess(r0, r1, r2)) => {
326                l0 == r0 && l1 == r1 && l2 == r2
327            }
328            _ => unreachable!("PartialEq implemented for const expressions only"),
329        }
330    }
331}