Skip to main content

shape_ast/ast/
patterns.rs

1//! Pattern matching and destructuring types for Shape AST
2
3use serde::{Deserialize, Serialize};
4
5use super::literals::Literal;
6use super::span::Span;
7use super::types::TypeAnnotation;
8
9/// Pattern for pattern matching
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub enum Pattern {
12    /// Match a specific identifier and bind it
13    Identifier(String),
14    /// Match by type and bind identifier when the runtime value conforms
15    Typed {
16        name: String,
17        type_annotation: TypeAnnotation,
18    },
19    /// Match a literal value
20    Literal(Literal),
21    /// Match an array pattern
22    Array(Vec<Pattern>),
23    /// Match an object pattern
24    Object(Vec<(String, Pattern)>),
25    /// Match anything (underscore)
26    Wildcard,
27    /// Match a constructor pattern
28    Constructor {
29        enum_name: Option<super::type_path::TypePath>,
30        variant: String,
31        fields: PatternConstructorFields,
32    },
33}
34
35/// Fields bound in a constructor pattern
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub enum PatternConstructorFields {
38    Unit,
39    Tuple(Vec<Pattern>),
40    Struct(Vec<(String, Pattern)>),
41}
42
43impl std::fmt::Display for Pattern {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        match self {
46            Pattern::Identifier(name) => write!(f, "{}", name),
47            Pattern::Typed {
48                name,
49                type_annotation,
50            } => write!(f, "{}: {:?}", name, type_annotation),
51            Pattern::Wildcard => write!(f, "_"),
52            Pattern::Literal(lit) => write!(f, "{}", lit),
53            Pattern::Array(pats) => {
54                write!(f, "[")?;
55                for (i, p) in pats.iter().enumerate() {
56                    if i > 0 {
57                        write!(f, ", ")?;
58                    }
59                    write!(f, "{}", p)?;
60                }
61                write!(f, "]")
62            }
63            Pattern::Object(fields) => {
64                write!(f, "{{ ")?;
65                for (i, (key, pat)) in fields.iter().enumerate() {
66                    if i > 0 {
67                        write!(f, ", ")?;
68                    }
69                    write!(f, "{}: {}", key, pat)?;
70                }
71                write!(f, " }}")
72            }
73            Pattern::Constructor {
74                enum_name,
75                variant,
76                fields,
77            } => {
78                if let Some(e) = enum_name {
79                    write!(f, "{}::{}", e, variant)?;
80                } else {
81                    write!(f, "{}", variant)?;
82                }
83                match fields {
84                    PatternConstructorFields::Unit => Ok(()),
85                    PatternConstructorFields::Tuple(pats) => {
86                        write!(f, "(")?;
87                        for (i, p) in pats.iter().enumerate() {
88                            if i > 0 {
89                                write!(f, ", ")?;
90                            }
91                            write!(f, "{}", p)?;
92                        }
93                        write!(f, ")")
94                    }
95                    PatternConstructorFields::Struct(fields) => {
96                        write!(f, " {{ ")?;
97                        for (i, (key, pat)) in fields.iter().enumerate() {
98                            if i > 0 {
99                                write!(f, ", ")?;
100                            }
101                            write!(f, "{}: {}", key, pat)?;
102                        }
103                        write!(f, " }}")
104                    }
105                }
106            }
107        }
108    }
109}
110
111impl Pattern {
112    /// Get the simple identifier name if this is a simple pattern
113    pub fn as_simple_name(&self) -> Option<&str> {
114        match self {
115            Pattern::Identifier(name) => Some(name),
116            Pattern::Typed { name, .. } => Some(name),
117            _ => None,
118        }
119    }
120}
121
122/// Pattern for destructuring assignments
123#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
124pub enum DestructurePattern {
125    /// Simple identifier pattern: let x = ...
126    Identifier(String, Span),
127
128    /// Array destructuring: let [a, b, c] = ...
129    Array(Vec<DestructurePattern>),
130
131    /// Object destructuring: let {x, y} = ...
132    Object(Vec<ObjectPatternField>),
133
134    /// Rest pattern: let [a, ...rest] = ... or let {x, ...rest} = ...
135    Rest(Box<DestructurePattern>),
136
137    /// Decomposition pattern: let a: A, b: B = intersection_value
138    /// Extracts component types from an intersection type (A + B).
139    /// Each binding specifies a name and type annotation for the component.
140    Decomposition(Vec<DecompositionBinding>),
141}
142
143/// A single binding in a decomposition pattern
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145pub struct DecompositionBinding {
146    /// The variable name to bind
147    pub name: String,
148    /// The type annotation (component type to extract)
149    pub type_annotation: TypeAnnotation,
150    /// Source span for error reporting
151    pub span: Span,
152}
153
154/// Field in object destructuring pattern
155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
156pub struct ObjectPatternField {
157    pub key: String,
158    pub pattern: DestructurePattern, // For {x: y} where y is the local name
159}
160
161impl DestructurePattern {
162    /// Get the identifier name if this is a simple identifier pattern
163    pub fn as_identifier(&self) -> Option<&str> {
164        match self {
165            DestructurePattern::Identifier(name, _) => Some(name),
166            _ => None,
167        }
168    }
169
170    /// Get the identifier span if this is a simple identifier pattern
171    pub fn as_identifier_span(&self) -> Option<Span> {
172        match self {
173            DestructurePattern::Identifier(_, span) => Some(*span),
174            _ => None,
175        }
176    }
177
178    /// Get all identifier names in this pattern
179    pub fn get_identifiers(&self) -> Vec<String> {
180        self.get_bindings()
181            .into_iter()
182            .map(|(name, _)| name)
183            .collect()
184    }
185
186    /// Get all identifier names and their source spans in this pattern.
187    ///
188    /// This is the canonical way to extract bound variables from any pattern
189    /// shape. Both the compiler and LSP should use this method to avoid
190    /// divergence in how pattern bindings are discovered.
191    pub fn get_bindings(&self) -> Vec<(String, Span)> {
192        match self {
193            DestructurePattern::Identifier(name, span) => vec![(name.clone(), *span)],
194            DestructurePattern::Array(patterns) => {
195                patterns.iter().flat_map(|p| p.get_bindings()).collect()
196            }
197            DestructurePattern::Object(fields) => fields
198                .iter()
199                .flat_map(|f| f.pattern.get_bindings())
200                .collect(),
201            DestructurePattern::Rest(pattern) => pattern.get_bindings(),
202            DestructurePattern::Decomposition(bindings) => {
203                bindings.iter().map(|b| (b.name.clone(), b.span)).collect()
204            }
205        }
206    }
207}
208
209// REMOVED: PatternDef and related types for pattern block syntax
210// Use annotated functions instead
211
212/// Sweep parameter for optimization
213/// Used in backtest config to specify parameter ranges for optimization
214#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
215pub enum SweepParam {
216    /// Range sweep: [min..max] or [min..max, step: step]
217    Range {
218        min: Box<super::expressions::Expr>,
219        max: Box<super::expressions::Expr>,
220        step: Option<Box<super::expressions::Expr>>,
221    },
222    /// Discrete values: [v1, v2, v3, ...]
223    Discrete(Vec<super::expressions::Expr>),
224}