Skip to main content

shape_ast/ast/
types.rs

1//! Type system definitions for Shape AST
2
3use super::functions::Annotation;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub enum TypeAnnotation {
8    /// Basic types: number, string, bool, row, pattern, etc.
9    Basic(String),
10    /// Vector type: T[] or Vec<T>
11    Array(Box<TypeAnnotation>),
12    /// Tuple type: [T1, T2, T3]
13    Tuple(Vec<TypeAnnotation>),
14    /// Object type: { field1: T1, field2?: T2 }
15    Object(Vec<ObjectTypeField>),
16    /// Function type: (T1, T2) => T3
17    Function {
18        params: Vec<FunctionParam>,
19        returns: Box<TypeAnnotation>,
20    },
21    /// Union type: T1 | T2 | T3 (discriminated union - value is ONE of the types)
22    Union(Vec<TypeAnnotation>),
23    /// Intersection type: T1 + T2 (structural merge - value has ALL fields from both types)
24    /// Only valid for object/interface types. Field collisions are compile-time errors.
25    Intersection(Vec<TypeAnnotation>),
26    /// Optional type: T?
27    Optional(Box<TypeAnnotation>),
28    /// Generic type: Map<K, V>
29    Generic {
30        name: String,
31        args: Vec<TypeAnnotation>,
32    },
33    /// Type reference (custom type or type alias)
34    Reference(String),
35    /// Void type
36    Void,
37    /// Any type
38    Any,
39    /// Never type
40    Never,
41    /// Null type
42    Null,
43    /// Undefined type
44    Undefined,
45    /// Trait object type: dyn Trait1 + Trait2
46    /// Represents a type-erased value that implements the given traits
47    Dyn(Vec<String>),
48}
49
50impl TypeAnnotation {
51    /// Extract a simple type name if this is a Reference or Basic type
52    ///
53    /// Returns `Some(type_name)` for:
54    /// - `TypeAnnotation::Reference(name)` - e.g., `Currency`, `MyType`
55    /// - `TypeAnnotation::Basic(name)` - e.g., `number`, `string`
56    ///
57    /// Returns `None` for complex types like arrays, tuples, functions, etc.
58    pub fn as_simple_name(&self) -> Option<&str> {
59        match self {
60            TypeAnnotation::Reference(name) => Some(name.as_str()),
61            TypeAnnotation::Basic(name) => Some(name.as_str()),
62            _ => None,
63        }
64    }
65
66    /// Convert a type annotation to its full string representation.
67    pub fn to_type_string(&self) -> String {
68        match self {
69            TypeAnnotation::Basic(name) | TypeAnnotation::Reference(name) => name.clone(),
70            TypeAnnotation::Array(inner) => format!("Array<{}>", inner.to_type_string()),
71            TypeAnnotation::Optional(inner) => format!("{}?", inner.to_type_string()),
72            TypeAnnotation::Generic { name, args } => {
73                let args_str: Vec<String> = args.iter().map(|a| a.to_type_string()).collect();
74                format!("{}<{}>", name, args_str.join(", "))
75            }
76            TypeAnnotation::Tuple(items) => {
77                let items_str: Vec<String> = items.iter().map(|t| t.to_type_string()).collect();
78                format!("[{}]", items_str.join(", "))
79            }
80            TypeAnnotation::Union(items) => {
81                let items_str: Vec<String> = items.iter().map(|t| t.to_type_string()).collect();
82                items_str.join(" | ")
83            }
84            TypeAnnotation::Void => "void".to_string(),
85            TypeAnnotation::Any => "any".to_string(),
86            TypeAnnotation::Never => "never".to_string(),
87            TypeAnnotation::Null => "null".to_string(),
88            TypeAnnotation::Undefined => "undefined".to_string(),
89            TypeAnnotation::Object(fields) => {
90                let fields_str: Vec<String> = fields
91                    .iter()
92                    .map(|f| {
93                        let opt = if f.optional { "?" } else { "" };
94                        // Include @alias in the type string so the Python extension
95                        // can use the wire name when looking up dict keys.
96                        let alias = f
97                            .annotations
98                            .iter()
99                            .find(|a| a.name == "alias")
100                            .and_then(|a| a.args.first())
101                            .and_then(|arg| match arg {
102                                super::expressions::Expr::Literal(
103                                    super::literals::Literal::String(s),
104                                    _,
105                                ) => Some(s.as_str()),
106                                _ => None,
107                            });
108                        let alias_str = alias.map(|a| format!("@\"{}\" ", a)).unwrap_or_default();
109                        format!(
110                            "{}{}{}: {}",
111                            alias_str,
112                            f.name,
113                            opt,
114                            f.type_annotation.to_type_string()
115                        )
116                    })
117                    .collect();
118                format!("{{{}}}", fields_str.join(", "))
119            }
120            _ => "any".to_string(),
121        }
122    }
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
126pub struct ObjectTypeField {
127    pub name: String,
128    pub optional: bool,
129    pub type_annotation: TypeAnnotation,
130    /// Field annotations (e.g. `@alias("wire name")`)
131    #[serde(default)]
132    pub annotations: Vec<Annotation>,
133}
134
135#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
136pub struct FunctionParam {
137    pub name: Option<String>,
138    pub optional: bool,
139    pub type_annotation: TypeAnnotation,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct TypeParam {
144    pub name: String,
145    /// Default type argument: `T = int`
146    pub default_type: Option<TypeAnnotation>,
147    /// Trait bounds: `T: Comparable + Displayable`
148    #[serde(default)]
149    pub trait_bounds: Vec<String>,
150}
151
152/// A predicate in a where clause: `T: Comparable + Display`
153#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
154pub struct WherePredicate {
155    pub type_name: String,
156    pub bounds: Vec<String>,
157}
158
159impl PartialEq for TypeParam {
160    fn eq(&self, other: &Self) -> bool {
161        self.name == other.name
162            && self.default_type == other.default_type
163            && self.trait_bounds == other.trait_bounds
164    }
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct TypeAliasDef {
169    pub name: String,
170    pub type_params: Option<Vec<TypeParam>>,
171    pub type_annotation: TypeAnnotation,
172    /// Meta parameter overrides: type Percent4 = Percent { decimals: 4 }
173    pub meta_param_overrides: Option<std::collections::HashMap<String, super::expressions::Expr>>,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct InterfaceDef {
178    pub name: String,
179    pub type_params: Option<Vec<TypeParam>>,
180    pub members: Vec<InterfaceMember>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
184pub enum InterfaceMember {
185    /// Property signature
186    Property {
187        name: String,
188        optional: bool,
189        type_annotation: TypeAnnotation,
190    },
191    /// Method signature
192    Method {
193        name: String,
194        optional: bool,
195        params: Vec<FunctionParam>,
196        return_type: TypeAnnotation,
197        /// Whether this is an async method
198        is_async: bool,
199    },
200    /// Index signature
201    IndexSignature {
202        param_name: String,
203        param_type: String, // "string" or "number"
204        return_type: TypeAnnotation,
205    },
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct EnumDef {
210    pub name: String,
211    pub type_params: Option<Vec<TypeParam>>,
212    pub members: Vec<EnumMember>,
213    /// Annotations applied to the enum (e.g., `@with_label() enum Color { ... }`)
214    #[serde(default)]
215    pub annotations: Vec<super::Annotation>,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct EnumMember {
220    pub name: String,
221    pub kind: EnumMemberKind,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
225pub enum EnumMemberKind {
226    /// Unit variant: Variant or Variant = 1
227    Unit { value: Option<EnumValue> },
228    /// Tuple variant: Variant(Type, Type)
229    Tuple(Vec<TypeAnnotation>),
230    /// Struct variant: Variant { field: Type, ... }
231    Struct(Vec<ObjectTypeField>),
232}
233
234#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
235pub enum EnumValue {
236    String(String),
237    Number(f64),
238}
239
240/// A member of a trait definition: either required (signature only) or default (with body)
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub enum TraitMember {
243    /// Required method — implementors must provide this
244    Required(InterfaceMember),
245    /// Default method — used if implementor does not override
246    Default(MethodDef),
247    /// Associated type declaration: `type Item;` or `type Item: Comparable;`
248    AssociatedType {
249        name: String,
250        bounds: Vec<TypeAnnotation>,
251    },
252}
253
254/// A concrete binding for an associated type inside an `impl` block:
255/// `type Item = number;`
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct AssociatedTypeBinding {
258    pub name: String,
259    pub concrete_type: TypeAnnotation,
260}
261
262/// Trait definition — like interface but with `trait` keyword, supporting default methods
263///
264/// ```shape
265/// trait Queryable<T> {
266///     filter(predicate: (T) => bool): Self    // required
267///     method execute() -> Result<Table<T>> {   // default
268///         return Ok(self.filter(|_| true))
269///     }
270/// }
271/// ```
272#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct TraitDef {
274    pub name: String,
275    pub type_params: Option<Vec<TypeParam>>,
276    pub members: Vec<TraitMember>,
277    /// Annotations applied to the trait (e.g., `@documented("...") trait Foo { ... }`)
278    #[serde(default)]
279    pub annotations: Vec<super::Annotation>,
280}
281
282/// Impl block — implements a trait for a type
283///
284/// ```shape
285/// impl Queryable<T> for Table<T> {
286///     method filter(predicate) { /* ... */ }
287///     method execute() { Ok(self) }
288/// }
289/// ```
290///
291/// Under the hood, compiles identically to an extend block (UFCS desugaring)
292/// plus trait validation (all required methods present with correct arities).
293#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct ImplBlock {
295    /// The trait being implemented (e.g., Queryable<T>)
296    pub trait_name: TypeName,
297    /// The type implementing the trait (e.g., Table<T>)
298    pub target_type: TypeName,
299    /// Optional named implementation selector:
300    /// `impl Display for User as JsonDisplay { ... }`
301    pub impl_name: Option<String>,
302    /// Method implementations
303    pub methods: Vec<MethodDef>,
304    /// Associated type bindings: `type Item = number;`
305    pub associated_type_bindings: Vec<AssociatedTypeBinding>,
306    /// Where clause: `where T: Display + Comparable`
307    pub where_clause: Option<Vec<WherePredicate>>,
308}
309
310/// Type extension for adding methods to existing types
311#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
312pub struct ExtendStatement {
313    /// The type being extended (e.g., "Vec")
314    pub type_name: TypeName,
315    /// Methods being added to the type
316    pub methods: Vec<MethodDef>,
317}
318
319#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
320pub struct MethodDef {
321    /// Method name
322    pub name: String,
323    /// Method parameters
324    pub params: Vec<super::functions::FunctionParameter>,
325    /// Optional when clause for conditional method definitions
326    pub when_clause: Option<Box<super::expressions::Expr>>,
327    /// Optional return type annotation
328    pub return_type: Option<TypeAnnotation>,
329    /// Method body
330    pub body: Vec<super::statements::Statement>,
331    /// Whether this is an async method
332    pub is_async: bool,
333}
334
335#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
336pub enum TypeName {
337    /// Simple type name (e.g., "Vec", "Table")
338    Simple(String),
339    /// Generic type name (e.g., "Table<Row>")
340    Generic {
341        name: String,
342        type_args: Vec<TypeAnnotation>,
343    },
344}
345
346// ============================================================================
347// Struct Type Definitions
348// ============================================================================
349
350/// Struct type definition — pure data with named fields
351///
352/// ```shape
353/// type Point { x: number, y: number }
354/// type DataVec<V, K = Timestamp> { index: Vec<K>, data: Vec<V> }
355/// ```
356#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct StructTypeDef {
358    pub name: String,
359    pub type_params: Option<Vec<TypeParam>>,
360    pub fields: Vec<StructField>,
361    /// Annotations applied to the struct (e.g., `@derive_debug type Foo { ... }`)
362    pub annotations: Vec<Annotation>,
363    /// Optional native layout metadata for `type C`.
364    #[serde(default)]
365    pub native_layout: Option<NativeLayoutBinding>,
366}
367
368/// Native layout binding metadata for `type C` declarations.
369#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
370pub struct NativeLayoutBinding {
371    /// ABI name (currently `"C"`).
372    pub abi: String,
373}
374
375/// A field in a struct type definition
376///
377/// Comptime fields are type-level constants baked at compile time.
378/// They occupy zero runtime slots (no ValueSlot in TypedObject).
379/// Access resolves to a constant push at compile time.
380///
381/// ```shape
382/// type Currency {
383///     comptime symbol: string = "$",
384///     comptime decimals: number = 2,
385///     amount: number,
386/// }
387/// ```
388#[derive(Debug, Clone, Serialize, Deserialize)]
389pub struct StructField {
390    pub annotations: Vec<Annotation>,
391    pub is_comptime: bool,
392    pub name: String,
393    pub type_annotation: TypeAnnotation,
394    pub default_value: Option<super::expressions::Expr>,
395}