datex_core/ast/
expressions.rs

1use crate::ast::resolved_variable::{ResolvedVariable, VariableId};
2use crate::ast::spanned::Spanned;
3use crate::ast::type_expressions::TypeExpression;
4use crate::global::operators::BinaryOperator;
5use crate::global::operators::ComparisonOperator;
6use crate::global::operators::assignment::AssignmentOperator;
7use crate::global::operators::{ArithmeticUnaryOperator, UnaryOperator};
8use crate::references::reference::ReferenceMutability;
9use crate::stdlib::vec::Vec;
10use crate::values::core_value::CoreValue;
11pub use crate::values::core_values::callable::CallableKind;
12use crate::values::core_values::decimal::Decimal;
13use crate::values::core_values::decimal::typed_decimal::TypedDecimal;
14use crate::values::core_values::endpoint::Endpoint;
15use crate::values::core_values::integer::Integer;
16use crate::values::core_values::integer::typed_integer::TypedInteger;
17use crate::values::core_values::r#type::Type;
18use crate::values::pointer::PointerAddress;
19use crate::values::value::Value;
20use crate::values::value_container::ValueContainer;
21use core::fmt::Display;
22use core::ops::{Neg, Range};
23
24#[derive(Clone, Debug)]
25/// An expression in the AST
26pub struct DatexExpression {
27    pub data: DatexExpressionData,
28    pub span: Range<usize>,
29    pub ty: Option<Type>,
30}
31impl Default for DatexExpression {
32    fn default() -> Self {
33        DatexExpression {
34            data: DatexExpressionData::Statements(Statements {
35                statements: Vec::new(),
36                is_terminated: false,
37                unbounded: None,
38            }),
39            span: 0..0,
40            ty: None,
41        }
42    }
43}
44impl DatexExpression {
45    pub fn new(data: DatexExpressionData, span: Range<usize>) -> Self {
46        DatexExpression {
47            data,
48            span,
49            ty: None,
50        }
51    }
52}
53
54// PartialEquality for DatexExpression ignores the span (allows for easier testing)
55impl PartialEq for DatexExpression {
56    fn eq(&self, other: &Self) -> bool {
57        self.data == other.data
58    }
59}
60
61#[derive(Clone, Debug, PartialEq)]
62/// The different kinds of type expressions in the AST
63#[derive(Default)]
64pub enum DatexExpressionData {
65    /// This is a marker for recovery from parse errors.
66    /// We should never use this manually.
67    #[default]
68    Noop,
69
70    Recover,
71    NativeImplementationIndicator,
72
73    /// null
74    Null,
75    /// Boolean (true or false)
76    Boolean(bool),
77    /// Text, e.g "Hello, world!"
78    Text(String),
79    /// Decimal, e.g 123.456789123456
80    Decimal(Decimal),
81
82    /// Typed Decimal, e.g. 123.456i8
83    TypedDecimal(TypedDecimal),
84
85    /// Integer, e.g 123456789123456789
86    Integer(Integer),
87
88    /// Typed Integer, e.g. 123i8
89    TypedInteger(TypedInteger),
90
91    /// Identifier (variable / core type usage)
92    Identifier(String),
93
94    /// Endpoint, e.g. @test_a or @test_b
95    Endpoint(Endpoint),
96    /// List, e.g  `[1, 2, 3, "text"]`
97    List(List),
98    /// Map, e.g {"xy": 2, (3): 4, xy: "xy"}
99    Map(Map),
100    /// One or more statements, e.g (1; 2; 3)
101    Statements(Statements),
102    /// reference access, e.g. &<ABCDEF>
103    GetReference(PointerAddress),
104
105    /// Conditional expression, e.g. if (true) { 1 } else { 2 }
106    Conditional(Conditional),
107
108    // TODO #611: Give information on type kind (nominal & structural)
109    /// Variable declaration, e.g. const x = 1, const mut x = 1, or var y = 2. VariableId is always set to 0 by the ast parser.
110    VariableDeclaration(VariableDeclaration),
111    /// Variable assignment, e.g. x = 42 or y += 1
112    VariableAssignment(VariableAssignment),
113    /// Variable access - only generated by the precompiler, not by the parser
114    VariableAccess(VariableAccess),
115
116    // TODO #612: Shall we avoid hoisting for type aliases?
117    // This would remove the ability to have recursive type
118    // definitions.
119    /// Type declaration, e.g. type MyType = { x: 42, y: "John" };
120    TypeDeclaration(TypeDeclaration),
121
122    /// Type expression, e.g. type(1 | 2)
123    TypeExpression(TypeExpression),
124
125    /// callable (function/procedure) declaration, e.g. function my_function() -> type ( ... )
126    CallableDeclaration(CallableDeclaration),
127
128    // TODO #613 combine
129    /// Reference, e.g. &x or &mut x
130    CreateRef(CreateRef),
131
132    /// Deref
133    Deref(Deref),
134
135    /// Slot, e.g. #1, #endpoint
136    Slot(Slot),
137
138    /// Slot assignment
139    SlotAssignment(SlotAssignment),
140
141    /// Pointer address $<identifier>
142    PointerAddress(PointerAddress),
143
144    /// Binary operation, e.g. x + y
145    BinaryOperation(BinaryOperation),
146
147    /// Comparison operation, e.g. x < y
148    ComparisonOperation(ComparisonOperation),
149
150    /// Deref assignment, e.g. *x = y, **x += y
151    DerefAssignment(DerefAssignment),
152
153    /// Property assignment, e.g. obj.property = value
154    PropertyAssignment(PropertyAssignment),
155
156    /// Unary operation, e.g. -x, !x
157    UnaryOperation(UnaryOperation),
158
159    /// Apply a value to another value, e.g. function call or type cast
160    Apply(Apply),
161
162    /// Apply a property access to an argument
163    PropertyAccess(PropertyAccess),
164
165    /// Generic instantiation, e.g. MyType<u8>
166    GenericInstantiation(GenericInstantiation),
167
168    /// The '?' placeholder expression
169    Placeholder,
170
171    /// Remote execution, e.g. @example :: 41 + 1
172    RemoteExecution(RemoteExecution),
173
174    /// Variant access, e.g. integer/u8
175    VariantAccess(VariantAccess),
176}
177
178impl Spanned for DatexExpressionData {
179    type Output = DatexExpression;
180
181    fn with_span<T: Into<Range<usize>>>(self, span: T) -> Self::Output {
182        DatexExpression {
183            data: self,
184            span: span.into(),
185            ty: None,
186        }
187    }
188
189    fn with_default_span(self) -> Self::Output {
190        DatexExpression {
191            data: self,
192            span: (0..0),
193            ty: None,
194        }
195    }
196}
197
198// directly convert DatexExpression to a ValueContainer
199impl TryFrom<&DatexExpressionData> for ValueContainer {
200    type Error = ();
201
202    fn try_from(expr: &DatexExpressionData) -> Result<Self, Self::Error> {
203        Ok(match expr {
204            DatexExpressionData::UnaryOperation(UnaryOperation {
205                operator,
206                expression,
207            }) => {
208                let value = ValueContainer::try_from(&expression.data)?;
209                match value {
210                    ValueContainer::Value(Value {
211                        inner: CoreValue::Integer(_) | CoreValue::Decimal(_),
212                        ..
213                    }) => match operator {
214                        UnaryOperator::Arithmetic(
215                            ArithmeticUnaryOperator::Plus,
216                        ) => value,
217                        UnaryOperator::Arithmetic(
218                            ArithmeticUnaryOperator::Minus,
219                        ) => value.neg().map_err(|_| ())?,
220                        _ => Err(())?,
221                    },
222                    _ => Err(())?,
223                }
224            }
225            DatexExpressionData::Null => ValueContainer::Value(Value::null()),
226            DatexExpressionData::Boolean(b) => ValueContainer::from(*b),
227            DatexExpressionData::Text(s) => ValueContainer::from(s.clone()),
228            DatexExpressionData::Decimal(d) => ValueContainer::from(d.clone()),
229            DatexExpressionData::Integer(i) => ValueContainer::from(i.clone()),
230            DatexExpressionData::TypedInteger(i) => {
231                ValueContainer::from(i.clone())
232            }
233            DatexExpressionData::TypedDecimal(d) => {
234                ValueContainer::from(d.clone())
235            }
236            DatexExpressionData::Endpoint(e) => ValueContainer::from(e.clone()),
237            DatexExpressionData::List(list) => {
238                let entries = list
239                    .items
240                    .iter()
241                    .map(|e| ValueContainer::try_from(&e.data))
242                    .collect::<Result<Vec<ValueContainer>, ()>>()?;
243                ValueContainer::from(
244                    datex_core::values::core_values::list::List::from(entries),
245                )
246            }
247            DatexExpressionData::Map(pairs) => {
248                let entries = pairs
249                    .entries
250                    .iter()
251                    .map(|(k, v)| {
252                        let key = ValueContainer::try_from(&k.data)?;
253                        let value = ValueContainer::try_from(&v.data)?;
254                        Ok((key, value))
255                    })
256                    .collect::<Result<Vec<(ValueContainer, ValueContainer)>, ()>>()?;
257                ValueContainer::from(
258                    crate::values::core_values::map::Map::from(entries),
259                )
260            }
261            _ => Err(())?,
262        })
263    }
264}
265
266#[derive(Clone, Debug, PartialEq)]
267pub struct BinaryOperation {
268    pub operator: BinaryOperator,
269    pub left: Box<DatexExpression>,
270    pub right: Box<DatexExpression>,
271    pub ty: Option<Type>,
272}
273
274#[derive(Clone, Debug, PartialEq)]
275pub struct ComparisonOperation {
276    pub operator: ComparisonOperator,
277    pub left: Box<DatexExpression>,
278    pub right: Box<DatexExpression>,
279}
280
281#[derive(Clone, Debug, PartialEq)]
282pub struct DerefAssignment {
283    pub operator: AssignmentOperator,
284    pub deref_expression: Box<DatexExpression>,
285    pub assigned_expression: Box<DatexExpression>,
286}
287
288#[derive(Clone, Debug, PartialEq)]
289pub struct PropertyAssignment {
290    pub operator: AssignmentOperator,
291    pub base: Box<DatexExpression>,
292    pub property: Box<DatexExpression>,
293    pub assigned_expression: Box<DatexExpression>,
294}
295
296#[derive(Clone, Debug, PartialEq)]
297pub struct Conditional {
298    pub condition: Box<DatexExpression>,
299    pub then_branch: Box<DatexExpression>,
300    pub else_branch: Option<Box<DatexExpression>>,
301}
302
303#[derive(Clone, Debug, PartialEq)]
304pub enum TypeDeclarationKind {
305    Nominal,
306    Structural,
307}
308impl Display for TypeDeclarationKind {
309    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
310        match self {
311            TypeDeclarationKind::Nominal => core::write!(f, "type"),
312            TypeDeclarationKind::Structural => core::write!(f, "typealias"),
313        }
314    }
315}
316impl TypeDeclarationKind {
317    pub fn is_nominal(&self) -> bool {
318        matches!(self, TypeDeclarationKind::Nominal)
319    }
320    pub fn is_structural(&self) -> bool {
321        matches!(self, TypeDeclarationKind::Structural)
322    }
323}
324
325#[derive(Clone, Debug, PartialEq)]
326pub struct TypeDeclaration {
327    pub id: Option<VariableId>,
328    pub name: String, // TODO #614: separate variant from name
329    pub definition: TypeExpression,
330    pub hoisted: bool,
331    pub kind: TypeDeclarationKind,
332}
333
334#[derive(Clone, Debug, PartialEq)]
335pub struct UnaryOperation {
336    pub operator: UnaryOperator,
337    pub expression: Box<DatexExpression>,
338}
339
340#[derive(Clone, Debug, PartialEq)]
341pub struct Apply {
342    pub base: Box<DatexExpression>,
343    pub arguments: Vec<DatexExpression>,
344}
345
346#[derive(Clone, Debug, PartialEq)]
347pub struct PropertyAccess {
348    pub base: Box<DatexExpression>,
349    pub property: Box<DatexExpression>,
350}
351
352#[derive(Clone, Debug, PartialEq)]
353pub struct GenericInstantiation {
354    pub base: Box<DatexExpression>,
355    pub generic_arguments: Vec<TypeExpression>,
356}
357
358#[derive(Clone, Debug, PartialEq)]
359pub struct RemoteExecution {
360    pub left: Box<DatexExpression>,
361    pub right: Box<DatexExpression>,
362}
363
364#[derive(Clone, Debug, PartialEq)]
365pub struct UnboundedStatement {
366    pub is_first: bool,
367    pub is_last: bool,
368}
369
370#[derive(Clone, Debug, PartialEq)]
371pub struct Statements {
372    pub statements: Vec<DatexExpression>,
373    pub is_terminated: bool,
374    pub unbounded: Option<UnboundedStatement>,
375}
376impl Statements {
377    pub fn empty() -> Self {
378        Statements {
379            statements: Vec::new(),
380            is_terminated: true,
381            unbounded: None,
382        }
383    }
384    pub fn new_terminated(statements: Vec<DatexExpression>) -> Self {
385        Statements {
386            statements,
387            is_terminated: true,
388            unbounded: None,
389        }
390    }
391    pub fn new_unterminated(statements: Vec<DatexExpression>) -> Self {
392        Statements {
393            statements,
394            is_terminated: false,
395            unbounded: None,
396        }
397    }
398}
399
400#[derive(Clone, Debug, PartialEq)]
401pub struct VariableDeclaration {
402    pub id: Option<VariableId>,
403    pub kind: VariableKind,
404    pub name: String,
405    pub type_annotation: Option<TypeExpression>,
406    pub init_expression: Box<DatexExpression>,
407}
408
409#[derive(Clone, Debug, PartialEq)]
410pub struct VariableAssignment {
411    pub id: Option<VariableId>,
412    pub name: String,
413    pub operator: AssignmentOperator,
414    pub expression: Box<DatexExpression>,
415}
416
417#[derive(Clone, Debug, PartialEq)]
418pub struct VariableAccess {
419    pub id: VariableId,
420    pub name: String,
421}
422
423#[derive(Clone, Debug, PartialEq)]
424pub struct CallableDeclaration {
425    pub name: Option<String>,
426    pub kind: CallableKind,
427    pub parameters: Vec<(String, TypeExpression)>,
428    pub rest_parameter: Option<(String, TypeExpression)>,
429    pub return_type: Option<TypeExpression>,
430    pub yeet_type: Option<TypeExpression>,
431    pub body: Box<DatexExpression>,
432}
433
434#[derive(Clone, Debug, PartialEq)]
435pub struct List {
436    pub items: Vec<DatexExpression>,
437}
438
439impl List {
440    pub fn new(items: Vec<DatexExpression>) -> Self {
441        List { items }
442    }
443}
444
445#[derive(Clone, Debug, PartialEq)]
446pub struct Map {
447    pub entries: Vec<(DatexExpression, DatexExpression)>,
448}
449
450impl Map {
451    pub fn new(entries: Vec<(DatexExpression, DatexExpression)>) -> Self {
452        Map { entries }
453    }
454}
455
456#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
457pub enum VariableKind {
458    Const,
459    Var,
460}
461
462impl Display for VariableKind {
463    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
464        match self {
465            VariableKind::Const => core::write!(f, "const"),
466            VariableKind::Var => core::write!(f, "var"),
467        }
468    }
469}
470
471#[derive(Clone, Debug, PartialEq)]
472pub enum Slot {
473    Addressed(u32),
474    Named(String),
475}
476impl Display for Slot {
477    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
478        core::write!(f, "#")?;
479        match self {
480            Slot::Addressed(addr) => core::write!(f, "{}", addr),
481            Slot::Named(name) => core::write!(f, "{}", name),
482        }
483    }
484}
485
486#[derive(Clone, Debug, PartialEq)]
487pub struct SlotAssignment {
488    pub slot: Slot,
489    pub expression: Box<DatexExpression>,
490}
491
492#[derive(Clone, Debug, PartialEq)]
493pub struct VariantAccess {
494    pub name: String,
495    pub variant: String,
496    pub base: ResolvedVariable,
497}
498
499#[derive(Clone, Debug, PartialEq)]
500pub struct Deref {
501    pub expression: Box<DatexExpression>,
502}
503
504#[derive(Clone, Debug, PartialEq)]
505pub struct CreateRef {
506    pub mutability: ReferenceMutability,
507    pub expression: Box<DatexExpression>,
508}