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, Debug, Default)]
23pub enum Expression {
24    /// Something went wrong (and an error will be reported)
25    #[default]
26    Invalid,
27    /// A processed value.
28    Value(Value),
29    /// An integer, float, color or bool literal: 1, 1.0, #00FF00, false
30    Literal(Literal),
31    /// A string that contains format expressions: "value = {a}"
32    FormatString(FormatString),
33    /// A list: [a, b, c]
34    ArrayExpression(ArrayExpression),
35    /// A tuple: (a, b, c)
36    TupleExpression(TupleExpression),
37    /// A body: `{}`.
38    Body(Body),
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 SrcReferrer for Expression {
79    fn src_ref(&self) -> crate::src_ref::SrcRef {
80        match self {
81            Self::Invalid => SrcRef(None),
82            Self::Value(_) => SrcRef(None),
83            Self::Literal(l) => l.src_ref(),
84            Self::FormatString(fs) => fs.src_ref(),
85            Self::ArrayExpression(le) => le.src_ref(),
86            Self::TupleExpression(te) => te.src_ref(),
87            Self::Call(c) => c.src_ref(),
88            Self::Body(b) => b.src_ref(),
89            Self::QualifiedName(q) => q.src_ref(),
90            Self::Marker(m) => m.src_ref(),
91            Self::BinaryOp {
92                lhs: _,
93                op: _,
94                rhs: _,
95                src_ref,
96            } => src_ref.clone(),
97            Self::UnaryOp {
98                op: _,
99                rhs: _,
100                src_ref,
101            } => src_ref.clone(),
102            Self::ArrayElementAccess(_, _, src_ref) => src_ref.clone(),
103            Self::PropertyAccess(_, _, src_ref) => src_ref.clone(),
104            Self::AttributeAccess(_, _, src_ref) => src_ref.clone(),
105            Self::MethodCall(_, _, src_ref) => src_ref.clone(),
106        }
107    }
108}
109
110impl std::fmt::Display for Expression {
111    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112        match self {
113            Self::Value(value) => write!(f, "{value}"),
114            Self::Literal(literal) => write!(f, "{literal}"),
115            Self::FormatString(format_string) => write!(f, "{format_string}"),
116            Self::ArrayExpression(array_expression) => write!(f, "{array_expression}"),
117            Self::TupleExpression(tuple_expression) => write!(f, "{tuple_expression}"),
118            Self::BinaryOp {
119                lhs,
120                op,
121                rhs,
122                src_ref: _,
123            } => write!(f, "{lhs} {op} {rhs}"),
124            Self::UnaryOp {
125                op,
126                rhs,
127                src_ref: _,
128            } => write!(f, "{op}{rhs}"),
129            Self::ArrayElementAccess(lhs, rhs, _) => write!(f, "{lhs}[{rhs}]"),
130            Self::PropertyAccess(lhs, rhs, _) => write!(f, "{lhs}.{rhs}"),
131            Self::AttributeAccess(lhs, rhs, _) => write!(f, "{lhs}#{rhs}"),
132            Self::MethodCall(lhs, method_call, _) => write!(f, "{lhs}.{method_call}"),
133            Self::Call(call) => write!(f, "{call}"),
134            Self::Body(body) => write!(f, "{body}"),
135            Self::QualifiedName(qualified_name) => write!(f, "{qualified_name}"),
136            Self::Marker(marker) => write!(f, "{marker}"),
137            _ => unimplemented!(),
138        }
139    }
140}
141
142impl TreeDisplay for Value {
143    fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
144        write!(f, "{:depth$}Value: {value}", "", value = self)
145    }
146}
147
148impl TreeDisplay for Expression {
149    fn tree_print(&self, f: &mut std::fmt::Formatter, mut depth: TreeState) -> std::fmt::Result {
150        match self {
151            Expression::Value(value) => value.tree_print(f, depth),
152            Expression::Literal(literal) => literal.tree_print(f, depth),
153            Expression::FormatString(format_string) => format_string.tree_print(f, depth),
154            Expression::ArrayExpression(array_expression) => array_expression.tree_print(f, depth),
155            Expression::TupleExpression(tuple_expression) => tuple_expression.tree_print(f, depth),
156            Expression::BinaryOp {
157                lhs,
158                op,
159                rhs,
160                src_ref: _,
161            } => {
162                writeln!(f, "{:depth$}BinaryOp '{op}':", "")?;
163                depth.indent();
164                lhs.tree_print(f, depth)?;
165                rhs.tree_print(f, depth)
166            }
167            Expression::UnaryOp {
168                op,
169                rhs,
170                src_ref: _,
171            } => {
172                writeln!(f, "{:depth$}UnaryOp '{op}':", "")?;
173                depth.indent();
174                rhs.tree_print(f, depth)
175            }
176            Expression::ArrayElementAccess(lhs, rhs, _) => {
177                writeln!(f, "{:depth$}ArrayElementAccess:", "")?;
178                depth.indent();
179                lhs.tree_print(f, depth)?;
180                rhs.tree_print(f, depth)
181            }
182            Expression::PropertyAccess(lhs, rhs, _) => {
183                writeln!(f, "{:depth$}FieldAccess:", "")?;
184                depth.indent();
185                lhs.tree_print(f, depth)?;
186                rhs.tree_print(f, depth)
187            }
188            Expression::AttributeAccess(lhs, rhs, _) => {
189                writeln!(f, "{:depth$}AttributeAccess:", "")?;
190                depth.indent();
191                lhs.tree_print(f, depth)?;
192                rhs.tree_print(f, depth)
193            }
194            Expression::MethodCall(lhs, method_call, _) => {
195                writeln!(f, "{:depth$}MethodCall:", "")?;
196                depth.indent();
197                lhs.tree_print(f, depth)?;
198                method_call.tree_print(f, depth)
199            }
200            Expression::Call(call) => call.tree_print(f, depth),
201            Expression::Body(body) => body.tree_print(f, depth),
202            Expression::QualifiedName(qualified_name) => qualified_name.tree_print(f, depth),
203            Expression::Marker(marker) => marker.tree_print(f, depth),
204            Expression::Invalid => write!(f, "{}", crate::invalid!(EXPRESSION)),
205        }
206    }
207}
208
209impl Expression {
210    /// If the expression consists of a single identifier, e.g. `a`
211    pub fn single_identifier(&self) -> Option<&Identifier> {
212        match &self {
213            Self::QualifiedName(qualified_name) => qualified_name.single_identifier(),
214            _ => None,
215        }
216    }
217}