Skip to main content

shape_ast/ast/
expressions.rs

1//! Core expression types for Shape AST
2
3use serde::{Deserialize, Serialize};
4
5use super::data_refs::{DataDateTimeRef, DataIndex, DataRef};
6use super::literals::{Duration, Literal};
7use super::operators::{BinaryOp, RangeKind, UnaryOp};
8use super::span::{Span, Spanned};
9use super::time::{DateTimeExpr, TimeReference, Timeframe};
10use super::types::TypeAnnotation;
11
12/// Entry in an object literal - either a field or a spread
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub enum ObjectEntry {
15    /// Regular field: key: value or key: Type = value
16    Field {
17        key: String,
18        value: Expr,
19        type_annotation: Option<TypeAnnotation>,
20    },
21    /// Spread: ...expr
22    Spread(Expr),
23}
24
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26pub enum EnumConstructorPayload {
27    Unit,
28    Tuple(Vec<Expr>),
29    Struct(Vec<(String, Expr)>),
30}
31
32#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub enum Expr {
34    /// Literal values
35    Literal(Literal, Span),
36    /// Variable/identifier reference
37    Identifier(String, Span),
38    /// Data reference: data[0], data[-1], data[1:5]
39    DataRef(DataRef, Span),
40    /// DateTime-based data reference: data[@"2024-01-15"]
41    DataDateTimeRef(DataDateTimeRef, Span),
42    /// Relative access from a reference: ref[0], ref[-1]
43    DataRelativeAccess {
44        reference: Box<Expr>,
45        index: DataIndex,
46        span: Span,
47    },
48    /// Property access: expr.property or expr?.property
49    PropertyAccess {
50        object: Box<Expr>,
51        property: String,
52        optional: bool,
53        span: Span,
54    },
55    /// Index access: expr[index] or expr[start:end]
56    IndexAccess {
57        object: Box<Expr>,
58        index: Box<Expr>,
59        end_index: Option<Box<Expr>>,
60        span: Span,
61    },
62    /// Binary operations
63    BinaryOp {
64        left: Box<Expr>,
65        op: BinaryOp,
66        right: Box<Expr>,
67        span: Span,
68    },
69    /// Fuzzy comparison with explicit tolerance: a ~= b within 0.02
70    FuzzyComparison {
71        left: Box<Expr>,
72        op: super::operators::FuzzyOp,
73        right: Box<Expr>,
74        tolerance: super::operators::FuzzyTolerance,
75        span: Span,
76    },
77    /// Unary operations
78    UnaryOp {
79        op: UnaryOp,
80        operand: Box<Expr>,
81        span: Span,
82    },
83    /// Function calls: sma(20), rsi(14), momentum(period: 10, threshold: 0.01)
84    FunctionCall {
85        name: String,
86        args: Vec<Expr>,
87        named_args: Vec<(String, Expr)>,
88        span: Span,
89    },
90    /// Qualified namespace call: module::function(args)
91    QualifiedFunctionCall {
92        namespace: String,
93        function: String,
94        args: Vec<Expr>,
95        named_args: Vec<(String, Expr)>,
96        span: Span,
97    },
98    /// Enum constructor: Enum::Variant, Enum::Variant(...), Enum::Variant { ... }
99    EnumConstructor {
100        enum_name: super::type_path::TypePath,
101        variant: String,
102        payload: EnumConstructorPayload,
103        span: Span,
104    },
105    /// Time reference: @today, @"2024-01-15"
106    TimeRef(TimeReference, Span),
107    /// DateTime expression: @"2024-01-15", @market_open, etc.
108    DateTime(DateTimeExpr, Span),
109    /// Pattern reference in expressions
110    PatternRef(String, Span),
111    /// Conditional expression: if cond then expr else expr
112    Conditional {
113        condition: Box<Expr>,
114        then_expr: Box<Expr>,
115        else_expr: Option<Box<Expr>>,
116        span: Span,
117    },
118    /// Object literal: { field1: expr1, field2: expr2, ...spread }
119    Object(Vec<ObjectEntry>, Span),
120    /// Array literal: [1, 2, 3]
121    Array(Vec<Expr>, Span),
122    /// List comprehension: [expr for var in iter if cond]
123    ListComprehension(Box<super::expr_helpers::ListComprehension>, Span),
124    /// Block expression: { let x = 10; x + 5 }
125    Block(super::expr_helpers::BlockExpr, Span),
126    /// Type assertion: expr as Type or expr as Type { param: value }
127    TypeAssertion {
128        expr: Box<Expr>,
129        type_annotation: TypeAnnotation,
130        /// Meta parameter overrides: as Percent { decimals: 4 }
131        meta_param_overrides: Option<std::collections::HashMap<String, Expr>>,
132        span: Span,
133    },
134    /// Instance check: expr instanceof Type
135    InstanceOf {
136        expr: Box<Expr>,
137        type_annotation: TypeAnnotation,
138        span: Span,
139    },
140    /// Function expression: function(x, y) { return x + y }
141    FunctionExpr {
142        params: Vec<super::functions::FunctionParameter>,
143        return_type: Option<TypeAnnotation>,
144        body: Vec<super::statements::Statement>,
145        span: Span,
146    },
147    /// Duration literal: 30d, 1h, 15m
148    Duration(Duration, Span),
149    /// Spread expression: ...expr (used in arrays and objects)
150    Spread(Box<Expr>, Span),
151
152    // ===== Expression-based Control Flow =====
153    /// If expression: if condition { expr } else { expr }
154    If(Box<super::expr_helpers::IfExpr>, Span),
155
156    /// While expression: while condition { expr }
157    While(Box<super::expr_helpers::WhileExpr>, Span),
158
159    /// For expression: for x in iter { expr }
160    For(Box<super::expr_helpers::ForExpr>, Span),
161
162    /// Loop expression: loop { expr }
163    Loop(Box<super::expr_helpers::LoopExpr>, Span),
164
165    /// Let binding expression: let x = value; expr
166    Let(Box<super::expr_helpers::LetExpr>, Span),
167
168    /// Assignment expression: x = value (returns value)
169    Assign(Box<super::expr_helpers::AssignExpr>, Span),
170
171    /// Break with optional value
172    Break(Option<Box<Expr>>, Span),
173
174    /// Continue
175    Continue(Span),
176
177    /// Return with optional value
178    Return(Option<Box<Expr>>, Span),
179
180    /// Method call: expr.method(args) or expr?.method(args)
181    MethodCall {
182        receiver: Box<Expr>,
183        method: String,
184        args: Vec<Expr>,
185        named_args: Vec<(String, Expr)>,
186        /// True when called via optional chaining: `expr?.method(args)`
187        #[serde(default)]
188        optional: bool,
189        span: Span,
190    },
191
192    /// Match expression
193    Match(Box<super::expr_helpers::MatchExpr>, Span),
194
195    /// Unit value (void)
196    Unit(Span),
197
198    /// Range expression with Rust-style syntax
199    Range {
200        start: Option<Box<Expr>>,
201        end: Option<Box<Expr>>,
202        kind: RangeKind,
203        span: Span,
204    },
205
206    /// Timeframe context expression: on(1h) { expr }
207    TimeframeContext {
208        timeframe: Timeframe,
209        expr: Box<Expr>,
210        span: Span,
211    },
212
213    /// Try operator for fallible propagation (Result/Option): expr?
214    TryOperator(Box<Expr>, Span),
215
216    /// Named implementation selector: `expr using ImplName`
217    UsingImpl {
218        expr: Box<Expr>,
219        impl_name: String,
220        span: Span,
221    },
222
223    /// Simulation call with inline parameters
224    SimulationCall {
225        name: String,
226        params: Vec<(String, Expr)>,
227        span: Span,
228    },
229
230    /// Window function expression: expr OVER (partition by ... order by ...)
231    WindowExpr(Box<super::windows::WindowExpr>, Span),
232
233    /// LINQ-style from query expression
234    /// Syntax: from var in source [clauses...] select expr
235    FromQuery(Box<super::expr_helpers::FromQueryExpr>, Span),
236
237    /// Struct literal: TypeName { field: value, ... }
238    StructLiteral {
239        type_name: super::type_path::TypePath,
240        fields: Vec<(String, Expr)>,
241        span: Span,
242    },
243
244    /// Await expression: await expr
245    Await(Box<Expr>, Span),
246
247    /// Join expression: await join all|race|any|settle { branch, ... }
248    Join(Box<super::expr_helpers::JoinExpr>, Span),
249
250    /// Annotated expression: @annotation expr
251    /// Used for expression-level annotations like `@timeout(5s) fetch()` or `@timed computation()`
252    /// Multiple annotations nest left-to-right: `@retry(3) @timeout(5s) fetch()` becomes
253    /// `Annotated { @retry(3), target: Annotated { @timeout(5s), target: fetch() } }`
254    Annotated {
255        annotation: super::functions::Annotation,
256        target: Box<Expr>,
257        span: Span,
258    },
259
260    /// Async let expression: `async let name = expr`
261    /// Spawns a task and binds a future handle to a local variable.
262    AsyncLet(Box<super::expr_helpers::AsyncLetExpr>, Span),
263
264    /// Async scope expression: `async scope { ... }`
265    /// Cancellation boundary — on scope exit, all pending tasks are cancelled in reverse order.
266    AsyncScope(Box<Expr>, Span),
267
268    /// Compile-time block expression: `comptime { stmts }`
269    /// Evaluated at compile time via the mini-VM. The result replaces this node with a literal.
270    Comptime(Vec<super::statements::Statement>, Span),
271
272    /// Compile-time for loop: `comptime for field in target.fields { ... }`
273    /// Unrolled at compile time. Each iteration is compiled with the loop variable
274    /// bound to the concrete field descriptor. Used inside comptime annotation handlers.
275    ComptimeFor(Box<super::expr_helpers::ComptimeForExpr>, Span),
276
277    /// Reference expression: `&expr` or `&mut expr`.
278    /// Creates a shared or exclusive reference to a local variable.
279    Reference {
280        expr: Box<Expr>,
281        /// True for `&mut expr` (exclusive/mutable reference).
282        is_mutable: bool,
283        span: Span,
284    },
285
286    /// Table row literal: `[a, b, c], [d, e, f]`
287    /// Used with `let t: Table<T> = [row1], [row2], ...` syntax.
288    /// Each inner Vec<Expr> is one row's positional field values.
289    TableRows(Vec<Vec<Expr>>, Span),
290}
291
292impl Expr {
293    /// Convert expression to a JSON value (for literals used in metadata)
294    pub fn to_json_value(&self) -> serde_json::Value {
295        match self {
296            Expr::Literal(lit, _) => lit.to_json_value(),
297            Expr::Array(elements, _) => {
298                serde_json::Value::Array(elements.iter().map(|e| e.to_json_value()).collect())
299            }
300            Expr::Object(entries, _) => {
301                let mut map = serde_json::Map::new();
302                for entry in entries {
303                    if let ObjectEntry::Field { key, value, .. } = entry {
304                        map.insert(key.clone(), value.to_json_value());
305                    }
306                }
307                serde_json::Value::Object(map)
308            }
309            _ => serde_json::Value::Null, // Fallback for non-literals
310        }
311    }
312}
313
314impl Spanned for Expr {
315    fn span(&self) -> Span {
316        match self {
317            Expr::Literal(_, span) => *span,
318            Expr::Identifier(_, span) => *span,
319            Expr::DataRef(_, span) => *span,
320            Expr::DataDateTimeRef(_, span) => *span,
321            Expr::DataRelativeAccess { span, .. } => *span,
322            Expr::PropertyAccess { span, .. } => *span,
323            Expr::IndexAccess { span, .. } => *span,
324            Expr::BinaryOp { span, .. } => *span,
325            Expr::FuzzyComparison { span, .. } => *span,
326            Expr::UnaryOp { span, .. } => *span,
327            Expr::FunctionCall { span, .. } => *span,
328            Expr::QualifiedFunctionCall { span, .. } => *span,
329            Expr::EnumConstructor { span, .. } => *span,
330            Expr::TimeRef(_, span) => *span,
331            Expr::DateTime(_, span) => *span,
332            Expr::PatternRef(_, span) => *span,
333            Expr::Conditional { span, .. } => *span,
334            Expr::Object(_, span) => *span,
335            Expr::Array(_, span) => *span,
336            Expr::ListComprehension(_, span) => *span,
337            Expr::Block(_, span) => *span,
338            Expr::TypeAssertion { span, .. } => *span,
339            Expr::InstanceOf { span, .. } => *span,
340            Expr::FunctionExpr { span, .. } => *span,
341            Expr::Duration(_, span) => *span,
342            Expr::Spread(_, span) => *span,
343            Expr::If(_, span) => *span,
344            Expr::While(_, span) => *span,
345            Expr::For(_, span) => *span,
346            Expr::Loop(_, span) => *span,
347            Expr::Let(_, span) => *span,
348            Expr::Assign(_, span) => *span,
349            Expr::Break(_, span) => *span,
350            Expr::Continue(span) => *span,
351            Expr::Return(_, span) => *span,
352            Expr::MethodCall { span, .. } => *span,
353            Expr::Match(_, span) => *span,
354            Expr::Unit(span) => *span,
355            Expr::Range { span, .. } => *span,
356            Expr::TimeframeContext { span, .. } => *span,
357            Expr::TryOperator(_, span) => *span,
358            Expr::UsingImpl { span, .. } => *span,
359            Expr::SimulationCall { span, .. } => *span,
360            Expr::WindowExpr(_, span) => *span,
361            Expr::FromQuery(_, span) => *span,
362            Expr::StructLiteral { span, .. } => *span,
363            Expr::Await(_, span) => *span,
364            Expr::Join(_, span) => *span,
365            Expr::Annotated { span, .. } => *span,
366            Expr::AsyncLet(_, span) => *span,
367            Expr::AsyncScope(_, span) => *span,
368            Expr::Comptime(_, span) => *span,
369            Expr::ComptimeFor(_, span) => *span,
370            Expr::Reference { span, .. } => *span,
371            Expr::TableRows(_, span) => *span,
372        }
373    }
374}