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 Expression {
79    /// If the expression consists of a single identifier, e.g. `a`
80    pub fn single_identifier(&self) -> Option<&Identifier> {
81        match &self {
82            Self::QualifiedName(qualified_name) => qualified_name.single_identifier(),
83            _ => None,
84        }
85    }
86}
87
88impl SrcReferrer for Expression {
89    fn src_ref(&self) -> crate::src_ref::SrcRef {
90        match self {
91            Self::Invalid => SrcRef(None),
92            Self::Literal(l) => l.src_ref(),
93            Self::FormatString(fs) => fs.src_ref(),
94            Self::ArrayExpression(le) => le.src_ref(),
95            Self::TupleExpression(te) => te.src_ref(),
96            Self::Call(c) => c.src_ref(),
97            Self::Body(b) => b.src_ref(),
98            Self::If(i) => i.src_ref(),
99            Self::QualifiedName(q) => q.src_ref(),
100            Self::Marker(m) => m.src_ref(),
101            Self::BinaryOp {
102                lhs: _,
103                op: _,
104                rhs: _,
105                src_ref,
106            } => src_ref.clone(),
107            Self::UnaryOp {
108                op: _,
109                rhs: _,
110                src_ref,
111            } => src_ref.clone(),
112            Self::ArrayElementAccess(_, _, src_ref) => src_ref.clone(),
113            Self::PropertyAccess(_, _, src_ref) => src_ref.clone(),
114            Self::AttributeAccess(_, _, src_ref) => src_ref.clone(),
115            Self::MethodCall(_, _, src_ref) => src_ref.clone(),
116        }
117    }
118}
119
120impl std::fmt::Display for Expression {
121    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
122        match self {
123            Self::Literal(literal) => write!(f, "{literal}"),
124            Self::FormatString(format_string) => write!(f, "{format_string}"),
125            Self::ArrayExpression(array_expression) => write!(f, "{array_expression}"),
126            Self::TupleExpression(tuple_expression) => write!(f, "{tuple_expression}"),
127            Self::BinaryOp {
128                lhs,
129                op,
130                rhs,
131                src_ref: _,
132            } => write!(f, "{lhs} {op} {rhs}"),
133            Self::UnaryOp {
134                op,
135                rhs,
136                src_ref: _,
137            } => write!(f, "{op}{rhs}"),
138            Self::ArrayElementAccess(lhs, rhs, _) => write!(f, "{lhs}[{rhs}]"),
139            Self::PropertyAccess(lhs, rhs, _) => write!(f, "{lhs}.{rhs}"),
140            Self::AttributeAccess(lhs, rhs, _) => write!(f, "{lhs}#{rhs}"),
141            Self::MethodCall(lhs, method_call, _) => write!(f, "{lhs}.{method_call}"),
142            Self::Call(call) => write!(f, "{call}"),
143            Self::Body(body) => write!(f, "{body}"),
144            Self::If(if_) => write!(f, "{if_}"),
145            Self::QualifiedName(qualified_name) => write!(f, "{qualified_name}"),
146            Self::Marker(marker) => write!(f, "{marker}"),
147            _ => unimplemented!(),
148        }
149    }
150}
151
152impl std::fmt::Debug for Expression {
153    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
154        match self {
155            Self::Literal(literal) => write!(f, "{literal}"),
156            Self::FormatString(format_string) => write!(f, "{format_string:?}"),
157            Self::ArrayExpression(array_expression) => write!(f, "{array_expression:?}"),
158            Self::TupleExpression(tuple_expression) => write!(f, "{tuple_expression:?}"),
159            Self::BinaryOp {
160                lhs,
161                op,
162                rhs,
163                src_ref: _,
164            } => write!(f, "{lhs:?} {op} {rhs:?}"),
165            Self::UnaryOp {
166                op,
167                rhs,
168                src_ref: _,
169            } => write!(f, "{op}{rhs:?}"),
170            Self::ArrayElementAccess(lhs, rhs, _) => write!(f, "{lhs:?}[{rhs:?}]"),
171            Self::PropertyAccess(lhs, rhs, _) => write!(f, "{lhs:?}.{rhs:?}"),
172            Self::AttributeAccess(lhs, rhs, _) => write!(f, "{lhs:?}#{rhs:?}"),
173            Self::MethodCall(lhs, method_call, _) => write!(f, "{lhs:?}.{method_call:?}"),
174            Self::Call(call) => write!(f, "{call:?}"),
175            Self::Body(body) => write!(f, "{body:?}"),
176            Self::If(if_) => write!(f, "{if_:?}"),
177            Self::QualifiedName(qualified_name) => write!(f, "{qualified_name:?}"),
178            Self::Marker(marker) => write!(f, "{marker:?}"),
179            _ => unimplemented!(),
180        }
181    }
182}
183
184impl TreeDisplay for Value {
185    fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
186        write!(f, "{:depth$}Value: {value}", "", value = self)
187    }
188}
189
190impl TreeDisplay for Expression {
191    fn tree_print(&self, f: &mut std::fmt::Formatter, mut depth: TreeState) -> std::fmt::Result {
192        match self {
193            Expression::Literal(literal) => literal.tree_print(f, depth),
194            Expression::FormatString(format_string) => format_string.tree_print(f, depth),
195            Expression::ArrayExpression(array_expression) => array_expression.tree_print(f, depth),
196            Expression::TupleExpression(tuple_expression) => tuple_expression.tree_print(f, depth),
197            Expression::BinaryOp {
198                lhs,
199                op,
200                rhs,
201                src_ref: _,
202            } => {
203                writeln!(f, "{:depth$}BinaryOp '{op}':", "")?;
204                depth.indent();
205                lhs.tree_print(f, depth)?;
206                rhs.tree_print(f, depth)
207            }
208            Expression::UnaryOp {
209                op,
210                rhs,
211                src_ref: _,
212            } => {
213                writeln!(f, "{:depth$}UnaryOp '{op}':", "")?;
214                depth.indent();
215                rhs.tree_print(f, depth)
216            }
217            Expression::ArrayElementAccess(lhs, rhs, _) => {
218                writeln!(f, "{:depth$}ArrayElementAccess:", "")?;
219                depth.indent();
220                lhs.tree_print(f, depth)?;
221                rhs.tree_print(f, depth)
222            }
223            Expression::PropertyAccess(lhs, rhs, _) => {
224                writeln!(f, "{:depth$}FieldAccess:", "")?;
225                depth.indent();
226                lhs.tree_print(f, depth)?;
227                rhs.tree_print(f, depth)
228            }
229            Expression::AttributeAccess(lhs, rhs, _) => {
230                writeln!(f, "{:depth$}AttributeAccess:", "")?;
231                depth.indent();
232                lhs.tree_print(f, depth)?;
233                rhs.tree_print(f, depth)
234            }
235            Expression::MethodCall(lhs, method_call, _) => {
236                writeln!(f, "{:depth$}MethodCall:", "")?;
237                depth.indent();
238                lhs.tree_print(f, depth)?;
239                method_call.tree_print(f, depth)
240            }
241            Expression::Call(call) => call.tree_print(f, depth),
242            Expression::Body(body) => body.tree_print(f, depth),
243            Expression::If(if_) => if_.tree_print(f, depth),
244            Expression::QualifiedName(qualified_name) => qualified_name.tree_print(f, depth),
245            Expression::Marker(marker) => marker.tree_print(f, depth),
246            Expression::Invalid => write!(f, "{}", crate::invalid!(EXPRESSION)),
247        }
248    }
249}
250
251impl AsRef<Self> for Expression {
252    fn as_ref(&self) -> &Self {
253        self
254    }
255}
256
257impl PartialEq for Expression {
258    fn eq(&self, other: &Self) -> bool {
259        match (self, other) {
260            (Self::Literal(l0), Self::Literal(r0)) => l0 == r0,
261            (Self::FormatString(l0), Self::FormatString(r0)) => l0 == r0,
262            (Self::ArrayExpression(l0), Self::ArrayExpression(r0)) => l0 == r0,
263            (Self::TupleExpression(l0), Self::TupleExpression(r0)) => l0 == r0,
264            (Self::QualifiedName(l0), Self::QualifiedName(r0)) => l0 == r0,
265            (
266                Self::BinaryOp {
267                    lhs: l_lhs,
268                    op: l_op,
269                    rhs: l_rhs,
270                    src_ref: l_src_ref,
271                },
272                Self::BinaryOp {
273                    lhs: r_lhs,
274                    op: r_op,
275                    rhs: r_rhs,
276                    src_ref: r_src_ref,
277                },
278            ) => l_lhs == r_lhs && l_op == r_op && l_rhs == r_rhs && l_src_ref == r_src_ref,
279            (
280                Self::UnaryOp {
281                    op: l_op,
282                    rhs: l_rhs,
283                    src_ref: l_src_ref,
284                },
285                Self::UnaryOp {
286                    op: r_op,
287                    rhs: r_rhs,
288                    src_ref: r_src_ref,
289                },
290            ) => l_op == r_op && l_rhs == r_rhs && l_src_ref == r_src_ref,
291            (Self::ArrayElementAccess(l0, l1, l2), Self::ArrayElementAccess(r0, r1, r2)) => {
292                l0 == r0 && l1 == r1 && l2 == r2
293            }
294            _ => unreachable!("PartialEq implemented for const expressions only"),
295        }
296    }
297}