Skip to main content

shape_ast/ast/
types.rs

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