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    /// A call: `ops::subtract()`.
38    Call(Call),
39    /// A qualified name: `foo::bar`.
40    QualifiedName(QualifiedName),
41    /// A marker expression: `@input`.
42    Marker(Marker),
43    /// A binary operation: `a + b`
44    BinaryOp {
45        /// Left-hand side
46        lhs: Box<Expression>,
47        /// Operator  ('+', '-', '/', '*', '<', '>', '≤', '≥', '&', '|')
48        op: String,
49        /// Right -hand side
50        rhs: Box<Expression>,
51        /// Source code reference
52        src_ref: SrcRef,
53    },
54    /// A unary operation: !a
55    UnaryOp {
56        /// Operator ('+', '-', '!')
57        op: String,
58        /// Right -hand side
59        rhs: Box<Expression>,
60        /// Source code reference
61        src_ref: SrcRef,
62    },
63    /// Access an element of a list (`a[0]`) or a tuple (`a.0` or `a.b`)
64    ArrayElementAccess(Box<Expression>, Box<Expression>, SrcRef),
65    /// Access an element of a tuple: `a.b`.
66    PropertyAccess(Box<Expression>, Identifier, SrcRef),
67
68    /// Access an attribute of a model: `a#b`.
69    AttributeAccess(Box<Expression>, Identifier, SrcRef),
70
71    /// Call to a method: `[2,3].len()`
72    /// First expression must evaluate to a value
73    MethodCall(Box<Expression>, MethodCall, SrcRef),
74}
75
76impl Expression {
77    /// If the expression consists of a single identifier, e.g. `a`
78    pub fn single_identifier(&self) -> Option<&Identifier> {
79        match &self {
80            Self::QualifiedName(qualified_name) => qualified_name.single_identifier(),
81            _ => None,
82        }
83    }
84}
85
86impl SrcReferrer for Expression {
87    fn src_ref(&self) -> crate::src_ref::SrcRef {
88        match self {
89            Self::Invalid => SrcRef(None),
90            Self::Literal(l) => l.src_ref(),
91            Self::FormatString(fs) => fs.src_ref(),
92            Self::ArrayExpression(le) => le.src_ref(),
93            Self::TupleExpression(te) => te.src_ref(),
94            Self::Call(c) => c.src_ref(),
95            Self::Body(b) => b.src_ref(),
96            Self::QualifiedName(q) => q.src_ref(),
97            Self::Marker(m) => m.src_ref(),
98            Self::BinaryOp {
99                lhs: _,
100                op: _,
101                rhs: _,
102                src_ref,
103            } => src_ref.clone(),
104            Self::UnaryOp {
105                op: _,
106                rhs: _,
107                src_ref,
108            } => src_ref.clone(),
109            Self::ArrayElementAccess(_, _, src_ref) => src_ref.clone(),
110            Self::PropertyAccess(_, _, src_ref) => src_ref.clone(),
111            Self::AttributeAccess(_, _, src_ref) => src_ref.clone(),
112            Self::MethodCall(_, _, src_ref) => src_ref.clone(),
113        }
114    }
115}
116
117impl std::fmt::Display for Expression {
118    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
119        match self {
120            Self::Literal(literal) => write!(f, "{literal}"),
121            Self::FormatString(format_string) => write!(f, "{format_string}"),
122            Self::ArrayExpression(array_expression) => write!(f, "{array_expression}"),
123            Self::TupleExpression(tuple_expression) => write!(f, "{tuple_expression}"),
124            Self::BinaryOp {
125                lhs,
126                op,
127                rhs,
128                src_ref: _,
129            } => write!(f, "{lhs} {op} {rhs}"),
130            Self::UnaryOp {
131                op,
132                rhs,
133                src_ref: _,
134            } => write!(f, "{op}{rhs}"),
135            Self::ArrayElementAccess(lhs, rhs, _) => write!(f, "{lhs}[{rhs}]"),
136            Self::PropertyAccess(lhs, rhs, _) => write!(f, "{lhs}.{rhs}"),
137            Self::AttributeAccess(lhs, rhs, _) => write!(f, "{lhs}#{rhs}"),
138            Self::MethodCall(lhs, method_call, _) => write!(f, "{lhs}.{method_call}"),
139            Self::Call(call) => write!(f, "{call}"),
140            Self::Body(body) => write!(f, "{body}"),
141            Self::QualifiedName(qualified_name) => write!(f, "{qualified_name}"),
142            Self::Marker(marker) => write!(f, "{marker}"),
143            _ => unimplemented!(),
144        }
145    }
146}
147
148impl std::fmt::Debug for Expression {
149    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
150        match self {
151            Self::Literal(literal) => write!(f, "{literal}"),
152            Self::FormatString(format_string) => write!(f, "{format_string:?}"),
153            Self::ArrayExpression(array_expression) => write!(f, "{array_expression:?}"),
154            Self::TupleExpression(tuple_expression) => write!(f, "{tuple_expression:?}"),
155            Self::BinaryOp {
156                lhs,
157                op,
158                rhs,
159                src_ref: _,
160            } => write!(f, "{lhs:?} {op} {rhs:?}"),
161            Self::UnaryOp {
162                op,
163                rhs,
164                src_ref: _,
165            } => write!(f, "{op}{rhs:?}"),
166            Self::ArrayElementAccess(lhs, rhs, _) => write!(f, "{lhs:?}[{rhs:?}]"),
167            Self::PropertyAccess(lhs, rhs, _) => write!(f, "{lhs:?}.{rhs:?}"),
168            Self::AttributeAccess(lhs, rhs, _) => write!(f, "{lhs:?}#{rhs:?}"),
169            Self::MethodCall(lhs, method_call, _) => write!(f, "{lhs:?}.{method_call:?}"),
170            Self::Call(call) => write!(f, "{call:?}"),
171            Self::Body(body) => write!(f, "{body:?}"),
172            Self::QualifiedName(qualified_name) => write!(f, "{qualified_name:?}"),
173            Self::Marker(marker) => write!(f, "{marker:?}"),
174            _ => unimplemented!(),
175        }
176    }
177}
178
179impl TreeDisplay for Value {
180    fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
181        write!(f, "{:depth$}Value: {value}", "", value = self)
182    }
183}
184
185impl TreeDisplay for Expression {
186    fn tree_print(&self, f: &mut std::fmt::Formatter, mut depth: TreeState) -> std::fmt::Result {
187        match self {
188            Expression::Literal(literal) => literal.tree_print(f, depth),
189            Expression::FormatString(format_string) => format_string.tree_print(f, depth),
190            Expression::ArrayExpression(array_expression) => array_expression.tree_print(f, depth),
191            Expression::TupleExpression(tuple_expression) => tuple_expression.tree_print(f, depth),
192            Expression::BinaryOp {
193                lhs,
194                op,
195                rhs,
196                src_ref: _,
197            } => {
198                writeln!(f, "{:depth$}BinaryOp '{op}':", "")?;
199                depth.indent();
200                lhs.tree_print(f, depth)?;
201                rhs.tree_print(f, depth)
202            }
203            Expression::UnaryOp {
204                op,
205                rhs,
206                src_ref: _,
207            } => {
208                writeln!(f, "{:depth$}UnaryOp '{op}':", "")?;
209                depth.indent();
210                rhs.tree_print(f, depth)
211            }
212            Expression::ArrayElementAccess(lhs, rhs, _) => {
213                writeln!(f, "{:depth$}ArrayElementAccess:", "")?;
214                depth.indent();
215                lhs.tree_print(f, depth)?;
216                rhs.tree_print(f, depth)
217            }
218            Expression::PropertyAccess(lhs, rhs, _) => {
219                writeln!(f, "{:depth$}FieldAccess:", "")?;
220                depth.indent();
221                lhs.tree_print(f, depth)?;
222                rhs.tree_print(f, depth)
223            }
224            Expression::AttributeAccess(lhs, rhs, _) => {
225                writeln!(f, "{:depth$}AttributeAccess:", "")?;
226                depth.indent();
227                lhs.tree_print(f, depth)?;
228                rhs.tree_print(f, depth)
229            }
230            Expression::MethodCall(lhs, method_call, _) => {
231                writeln!(f, "{:depth$}MethodCall:", "")?;
232                depth.indent();
233                lhs.tree_print(f, depth)?;
234                method_call.tree_print(f, depth)
235            }
236            Expression::Call(call) => call.tree_print(f, depth),
237            Expression::Body(body) => body.tree_print(f, depth),
238            Expression::QualifiedName(qualified_name) => qualified_name.tree_print(f, depth),
239            Expression::Marker(marker) => marker.tree_print(f, depth),
240            Expression::Invalid => write!(f, "{}", crate::invalid!(EXPRESSION)),
241        }
242    }
243}
244
245impl AsRef<Self> for Expression {
246    fn as_ref(&self) -> &Self {
247        self
248    }
249}
250
251impl PartialEq for Expression {
252    fn eq(&self, other: &Self) -> bool {
253        match (self, other) {
254            (Self::Literal(l0), Self::Literal(r0)) => l0 == r0,
255            (Self::FormatString(l0), Self::FormatString(r0)) => l0 == r0,
256            (Self::ArrayExpression(l0), Self::ArrayExpression(r0)) => l0 == r0,
257            (Self::TupleExpression(l0), Self::TupleExpression(r0)) => l0 == r0,
258            (Self::QualifiedName(l0), Self::QualifiedName(r0)) => l0 == r0,
259            (
260                Self::BinaryOp {
261                    lhs: l_lhs,
262                    op: l_op,
263                    rhs: l_rhs,
264                    src_ref: l_src_ref,
265                },
266                Self::BinaryOp {
267                    lhs: r_lhs,
268                    op: r_op,
269                    rhs: r_rhs,
270                    src_ref: r_src_ref,
271                },
272            ) => l_lhs == r_lhs && l_op == r_op && l_rhs == r_rhs && l_src_ref == r_src_ref,
273            (
274                Self::UnaryOp {
275                    op: l_op,
276                    rhs: l_rhs,
277                    src_ref: l_src_ref,
278                },
279                Self::UnaryOp {
280                    op: r_op,
281                    rhs: r_rhs,
282                    src_ref: r_src_ref,
283                },
284            ) => l_op == r_op && l_rhs == r_rhs && l_src_ref == r_src_ref,
285            (Self::ArrayElementAccess(l0, l1, l2), Self::ArrayElementAccess(r0, r1, r2)) => {
286                l0 == r0 && l1 == r1 && l2 == r2
287            }
288            _ => unreachable!("PartialEq implemented for const expressions only"),
289        }
290    }
291}