Skip to main content

shape_ast/parser/
types.rs

1//! Type annotation parsing for Shape
2//!
3//! This module handles parsing of type annotations including:
4//! - Basic types (number, string, boolean, etc.)
5//! - Complex types (arrays, objects, tuples, functions)
6//! - Generic types and union types
7//! - Optional types
8
9use crate::ast::TypeAnnotation;
10use crate::error::{Result, ShapeError};
11use crate::parser::string_literals::parse_string_literal;
12use pest::iterators::Pair;
13use std::collections::HashMap;
14
15use super::{Rule, pair_location};
16
17/// Parse a type annotation
18pub fn parse_type_annotation(pair: Pair<Rule>) -> Result<TypeAnnotation> {
19    let pair_loc = pair_location(&pair);
20
21    match pair.as_rule() {
22        Rule::type_annotation => {
23            let loc = pair_loc.clone();
24            let mut inner = pair.into_inner();
25            let type_part = inner.next().ok_or_else(|| ShapeError::ParseError {
26                message: "expected type annotation content".to_string(),
27                location: Some(loc.clone()),
28            })?;
29            parse_type_annotation(type_part)
30        }
31        Rule::union_type => {
32            let mut types = Vec::new();
33            for inner in pair.into_inner() {
34                types.push(parse_type_annotation(inner)?);
35            }
36            if types.len() == 1 {
37                Ok(types.remove(0))
38            } else {
39                Ok(TypeAnnotation::Union(types))
40            }
41        }
42        Rule::intersection_type => {
43            let mut types = Vec::new();
44            for inner in pair.into_inner() {
45                types.push(parse_type_annotation(inner)?);
46            }
47            if types.len() == 1 {
48                Ok(types.remove(0))
49            } else {
50                Ok(TypeAnnotation::Intersection(types))
51            }
52        }
53        Rule::optional_type => {
54            let inner = pair
55                .clone()
56                .into_inner()
57                .next()
58                .ok_or_else(|| ShapeError::ParseError {
59                    message: "expected type in optional type annotation".to_string(),
60                    location: Some(pair_loc),
61                })?;
62            let mut ty = parse_type_annotation(inner)?;
63            if pair.as_str().trim_end().ends_with('?') {
64                ty = TypeAnnotation::Optional(Box::new(ty));
65            }
66            Ok(ty)
67        }
68        Rule::primary_type => {
69            let inner = pair
70                .clone()
71                .into_inner()
72                .next()
73                .ok_or_else(|| ShapeError::ParseError {
74                    message: "expected type in primary type annotation".to_string(),
75                    location: Some(pair_loc),
76                })?;
77            let mut ty = parse_type_annotation(inner)?;
78            let mut remaining = pair.as_str().trim();
79            while remaining.ends_with("[]") {
80                ty = TypeAnnotation::Array(Box::new(ty));
81                remaining = &remaining[..remaining.len() - 2];
82            }
83            Ok(ty)
84        }
85        Rule::non_array_type => {
86            let mut inner = pair.clone().into_inner();
87            let inner_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
88                message: "expected type in non-array type annotation".to_string(),
89                location: Some(pair_loc),
90            })?;
91            if pair.as_str().trim_start().starts_with("Vec<")
92                && inner_pair.as_rule() == Rule::type_annotation
93            {
94                let inner_ty = parse_type_annotation(inner_pair)?;
95                return Ok(TypeAnnotation::Array(Box::new(inner_ty)));
96            }
97            parse_type_annotation(inner_pair)
98        }
99        Rule::basic_type => parse_basic_type(pair.as_str()),
100        Rule::tuple_type => {
101            let mut members = Vec::new();
102            for inner in pair.into_inner() {
103                if inner.as_rule() == Rule::type_annotation {
104                    members.push(parse_type_annotation(inner)?);
105                }
106            }
107            Ok(TypeAnnotation::Tuple(members))
108        }
109        Rule::object_type => parse_object_type(pair),
110        Rule::function_type => parse_function_type(pair),
111        Rule::dyn_type => {
112            let trait_names: Vec<String> = pair
113                .into_inner()
114                .filter(|p| p.as_rule() == Rule::ident)
115                .map(|p| p.as_str().to_string())
116                .collect();
117            Ok(TypeAnnotation::Dyn(trait_names))
118        }
119        Rule::unit_type => Ok(TypeAnnotation::Basic("()".to_string())),
120        Rule::generic_type => parse_generic_type(pair),
121        Rule::type_param => {
122            let param = parse_type_param(pair)?;
123            Ok(param.type_annotation)
124        }
125        Rule::ident => Ok(TypeAnnotation::Reference(pair.as_str().to_string())),
126        _ => Err(ShapeError::ParseError {
127            message: format!("invalid type annotation: {:?}", pair.as_rule()),
128            location: Some(pair_loc),
129        }),
130    }
131}
132
133/// Parse basic types (primitives and special types)
134pub fn parse_basic_type(name: &str) -> Result<TypeAnnotation> {
135    Ok(match name {
136        "void" => TypeAnnotation::Void,
137        "any" => TypeAnnotation::Any,
138        "never" => TypeAnnotation::Never,
139        "undefined" => TypeAnnotation::Undefined,
140        other => TypeAnnotation::Basic(other.to_string()),
141    })
142}
143
144/// Parse object type with fields
145pub fn parse_object_type(pair: Pair<Rule>) -> Result<TypeAnnotation> {
146    let mut fields = Vec::new();
147    for inner in pair.into_inner() {
148        if inner.as_rule() == Rule::object_type_member_list {
149            for member in inner.into_inner() {
150                if member.as_rule() == Rule::object_type_member {
151                    fields.push(parse_object_type_member(member)?);
152                }
153            }
154        }
155    }
156    Ok(TypeAnnotation::Object(fields))
157}
158
159/// Parse a single object type member (field)
160pub fn parse_object_type_member(pair: Pair<Rule>) -> Result<crate::ast::ObjectTypeField> {
161    let pair_loc = pair_location(&pair);
162    let mut inner = pair.clone().into_inner();
163    let mut annotations = Vec::new();
164
165    let first = inner.next().ok_or_else(|| ShapeError::ParseError {
166        message: "expected field name in object type member".to_string(),
167        location: Some(pair_loc.clone()),
168    })?;
169
170    let name_pair = if first.as_rule() == Rule::annotations {
171        annotations = super::functions::parse_annotations(first)?;
172        inner.next().ok_or_else(|| ShapeError::ParseError {
173            message: "expected field name after annotations in object type member".to_string(),
174            location: Some(pair_loc.clone()),
175        })?
176    } else {
177        first
178    };
179    let name = name_pair.as_str().to_string();
180
181    let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
182        message: format!("expected type annotation for field '{}'", name),
183        location: Some(pair_loc),
184    })?;
185    let type_annotation = parse_type_annotation(type_pair)?;
186
187    let before_colon = pair.as_str().split(':').next().unwrap_or("");
188    let optional = before_colon.contains('?');
189
190    Ok(crate::ast::ObjectTypeField {
191        name,
192        optional,
193        type_annotation,
194        annotations,
195    })
196}
197
198/// Parse function type signature
199pub fn parse_function_type(pair: Pair<Rule>) -> Result<TypeAnnotation> {
200    let mut params = Vec::new();
201    let mut return_type = None;
202
203    for inner in pair.into_inner() {
204        match inner.as_rule() {
205            Rule::type_param_list => {
206                params = parse_type_param_list(inner)?;
207            }
208            Rule::type_annotation => {
209                return_type = Some(parse_type_annotation(inner)?);
210            }
211            _ => {}
212        }
213    }
214
215    let returns = return_type.ok_or_else(|| ShapeError::ParseError {
216        message: "Function type missing return type".to_string(),
217        location: None,
218    })?;
219
220    Ok(TypeAnnotation::Function {
221        params,
222        returns: Box::new(returns),
223    })
224}
225
226/// Parse list of type parameters
227pub fn parse_type_param_list(pair: Pair<Rule>) -> Result<Vec<crate::ast::FunctionParam>> {
228    let mut params = Vec::new();
229    for inner in pair.into_inner() {
230        if inner.as_rule() == Rule::type_param {
231            params.push(parse_type_param(inner)?);
232        }
233    }
234    Ok(params)
235}
236
237/// Parse a single type parameter
238pub fn parse_type_param(pair: Pair<Rule>) -> Result<crate::ast::FunctionParam> {
239    let pair_loc = pair_location(&pair);
240    let mut inner = pair.clone().into_inner();
241    let first = inner.next().ok_or_else(|| ShapeError::ParseError {
242        message: "expected type parameter content".to_string(),
243        location: Some(pair_loc.clone()),
244    })?;
245
246    if first.as_rule() == Rule::ident {
247        let name = first.as_str().to_string();
248        let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
249            message: format!("type parameter '{}' missing type annotation", name),
250            location: Some(pair_loc),
251        })?;
252        let type_annotation = parse_type_annotation(type_pair)?;
253        let before_colon = pair.as_str().split(':').next().unwrap_or("");
254        let optional = before_colon.contains('?');
255        Ok(crate::ast::FunctionParam {
256            name: Some(name),
257            optional,
258            type_annotation,
259        })
260    } else {
261        let type_annotation = parse_type_annotation(first)?;
262        Ok(crate::ast::FunctionParam {
263            name: None,
264            optional: false,
265            type_annotation,
266        })
267    }
268}
269
270pub fn parse_type_params(pair: Pair<Rule>) -> Result<Vec<crate::ast::TypeParam>> {
271    let pair_loc = pair_location(&pair);
272    let mut params = Vec::new();
273    for param_pair in pair.into_inner() {
274        if param_pair.as_rule() == Rule::type_param_name {
275            let mut param_inner = param_pair.into_inner();
276            let name_pair = param_inner.next().ok_or_else(|| ShapeError::ParseError {
277                message: "expected type parameter name".to_string(),
278                location: Some(pair_loc.clone()),
279            })?;
280            let name = name_pair.as_str().to_string();
281            let mut default_type = None;
282            let mut trait_bounds = Vec::new();
283            for remaining in param_inner {
284                match remaining.as_rule() {
285                    Rule::type_annotation => {
286                        default_type = Some(parse_type_annotation(remaining)?);
287                    }
288                    Rule::trait_bound_list => {
289                        for bound_ident in remaining.into_inner() {
290                            if bound_ident.as_rule() == Rule::ident {
291                                trait_bounds.push(bound_ident.as_str().to_string());
292                            }
293                        }
294                    }
295                    _ => {}
296                }
297            }
298            params.push(crate::ast::TypeParam {
299                name,
300                default_type,
301                trait_bounds,
302            });
303        }
304    }
305    Ok(params)
306}
307
308/// Parse a declaration-only builtin type definition.
309///
310/// Grammar:
311/// `builtin type Name<T>;`
312pub fn parse_builtin_type_decl(pair: Pair<Rule>) -> Result<crate::ast::BuiltinTypeDecl> {
313    let pair_loc = pair_location(&pair);
314    let mut name = String::new();
315    let mut name_span = crate::ast::Span::DUMMY;
316    let mut type_params = None;
317
318    for inner in pair.into_inner() {
319        match inner.as_rule() {
320            Rule::ident => {
321                if name.is_empty() {
322                    name = inner.as_str().to_string();
323                    name_span = super::pair_span(&inner);
324                }
325            }
326            Rule::type_params => {
327                type_params = Some(parse_type_params(inner)?);
328            }
329            _ => {}
330        }
331    }
332
333    if name.is_empty() {
334        return Err(ShapeError::ParseError {
335            message: "expected builtin type name".to_string(),
336            location: Some(pair_loc),
337        });
338    }
339
340    Ok(crate::ast::BuiltinTypeDecl {
341        name,
342        name_span,
343        type_params,
344    })
345}
346
347/// Parse generic type with arguments
348pub fn parse_generic_type(pair: Pair<Rule>) -> Result<TypeAnnotation> {
349    let pair_loc = pair_location(&pair);
350    let mut inner = pair.into_inner();
351    let name = inner
352        .next()
353        .ok_or_else(|| ShapeError::ParseError {
354            message: "expected generic type name".to_string(),
355            location: Some(pair_loc.clone()),
356        })?
357        .as_str()
358        .to_string();
359    let mut args = Vec::new();
360    for arg in inner {
361        if arg.as_rule() == Rule::type_annotation {
362            args.push(parse_type_annotation(arg)?);
363        }
364    }
365    if name == "Matrix" {
366        return Err(ShapeError::ParseError {
367            message: "Matrix<T> has been removed; use Mat<T> instead".to_string(),
368            location: Some(pair_loc),
369        });
370    }
371    if (name == "Vec" || name == "Array") && args.len() == 1 {
372        Ok(TypeAnnotation::Array(Box::new(args.remove(0))))
373    } else {
374        Ok(TypeAnnotation::Generic { name, args })
375    }
376}
377
378/// Parse comptime field overrides for type aliases
379///
380/// Grammar: `"{" ~ comptime_field_override ~ ("," ~ comptime_field_override)* ~ ","? ~ "}"`
381/// Where: `comptime_field_override = { ident ~ ":" ~ expression }`
382pub fn parse_comptime_field_overrides(
383    pair: Pair<Rule>,
384) -> Result<HashMap<String, crate::ast::Expr>> {
385    let mut overrides = HashMap::new();
386
387    for override_pair in pair.into_inner() {
388        if override_pair.as_rule() == Rule::comptime_field_override {
389            let mut inner = override_pair.into_inner();
390
391            let key_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
392                message: "Missing parameter name in override".to_string(),
393                location: None,
394            })?;
395            let key = key_pair.as_str().to_string();
396
397            let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
398                message: "Missing expression in parameter override".to_string(),
399                location: None,
400            })?;
401            let expr = super::expressions::parse_expression(expr_pair)?;
402
403            overrides.insert(key, expr);
404        }
405    }
406
407    Ok(overrides)
408}
409
410/// Parse struct type definition
411///
412/// Grammar: `"type" ~ ident ~ type_params? ~ "{" ~ struct_field_list? ~ "}"`
413pub fn parse_struct_type_def(pair: Pair<Rule>) -> Result<crate::ast::StructTypeDef> {
414    let pair_loc = pair_location(&pair);
415    let mut inner = pair.into_inner();
416
417    let mut annotations = Vec::new();
418    let mut type_params = None;
419    let mut fields = Vec::new();
420
421    // First child may be annotations or the struct name ident
422    let first = inner.next().ok_or_else(|| ShapeError::ParseError {
423        message: "Missing struct type name".to_string(),
424        location: Some(pair_loc.clone()),
425    })?;
426
427    let name = if first.as_rule() == Rule::annotations {
428        annotations = super::functions::parse_annotations(first)?;
429        let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
430            message: "Missing struct type name after annotations".to_string(),
431            location: Some(pair_loc.clone()),
432        })?;
433        name_pair.as_str().to_string()
434    } else {
435        first.as_str().to_string()
436    };
437
438    for part in inner {
439        match part.as_rule() {
440            Rule::type_params => {
441                type_params = Some(parse_type_params(part)?);
442            }
443            Rule::struct_field_list => {
444                for field_pair in part.into_inner() {
445                    if field_pair.as_rule() == Rule::struct_field {
446                        fields.push(parse_struct_field(field_pair)?);
447                    }
448                }
449            }
450            _ => {}
451        }
452    }
453
454    Ok(crate::ast::StructTypeDef {
455        name,
456        type_params,
457        fields,
458        annotations,
459        native_layout: None,
460    })
461}
462
463/// Parse native-layout type definition.
464///
465/// Grammar: `annotations? ~ "type" ~ extern_abi ~ ident ~ type_params? ~ "{" ~ struct_field_list? ~ "}"`
466pub fn parse_native_struct_type_def(pair: Pair<Rule>) -> Result<crate::ast::StructTypeDef> {
467    let pair_loc = pair_location(&pair);
468    let mut annotations = Vec::new();
469    let mut abi: Option<String> = None;
470    let mut name: Option<String> = None;
471    let mut type_params = None;
472    let mut fields = Vec::new();
473
474    for part in pair.into_inner() {
475        match part.as_rule() {
476            Rule::annotations => {
477                annotations = super::functions::parse_annotations(part)?;
478            }
479            Rule::extern_abi => {
480                abi = Some(super::functions::parse_extern_abi(part)?);
481            }
482            Rule::ident => {
483                if name.is_none() {
484                    name = Some(part.as_str().to_string());
485                }
486            }
487            Rule::type_params => {
488                type_params = Some(parse_type_params(part)?);
489            }
490            Rule::struct_field_list => {
491                for field_pair in part.into_inner() {
492                    if field_pair.as_rule() == Rule::struct_field {
493                        fields.push(parse_struct_field(field_pair)?);
494                    }
495                }
496            }
497            _ => {}
498        }
499    }
500
501    let abi = abi.ok_or_else(|| ShapeError::ParseError {
502        message: "native layout type declaration requires an ABI name".to_string(),
503        location: Some(pair_loc.clone()),
504    })?;
505
506    if abi.trim() != "C" {
507        return Err(ShapeError::ParseError {
508            message: format!(
509                "unsupported native ABI '{}': only C is currently supported for type layouts",
510                abi
511            ),
512            location: Some(pair_loc.clone()),
513        });
514    }
515
516    let name = name.ok_or_else(|| ShapeError::ParseError {
517        message: "Missing native layout type name".to_string(),
518        location: Some(pair_loc),
519    })?;
520
521    Ok(crate::ast::StructTypeDef {
522        name,
523        type_params,
524        fields,
525        annotations,
526        native_layout: Some(crate::ast::NativeLayoutBinding { abi }),
527    })
528}
529
530/// Parse a single struct field
531///
532/// Grammar: `annotations? ~ comptime_keyword? ~ ident ~ ":" ~ type_annotation ~ ("=" ~ expression)?`
533fn parse_struct_field(pair: Pair<Rule>) -> Result<crate::ast::StructField> {
534    let pair_loc = pair_location(&pair);
535    let mut inner = pair.into_inner();
536
537    let mut annotations = vec![];
538    let mut is_comptime = false;
539
540    // Peek at the first child — may be annotations, comptime_keyword, or ident
541    let first = inner.next().ok_or_else(|| ShapeError::ParseError {
542        message: "Missing struct field name".to_string(),
543        location: Some(pair_loc.clone()),
544    })?;
545
546    let mut current = first;
547
548    if current.as_rule() == Rule::annotations {
549        annotations = super::functions::parse_annotations(current)?;
550        current = inner.next().ok_or_else(|| ShapeError::ParseError {
551            message: "Missing struct field name after annotations".to_string(),
552            location: Some(pair_loc.clone()),
553        })?;
554    }
555
556    if current.as_rule() == Rule::comptime_keyword {
557        is_comptime = true;
558        current = inner.next().ok_or_else(|| ShapeError::ParseError {
559            message: "Missing struct field name after 'comptime'".to_string(),
560            location: Some(pair_loc.clone()),
561        })?;
562    }
563
564    let name = current.as_str().to_string();
565
566    let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
567        message: format!("Missing type annotation for struct field '{}'", name),
568        location: Some(pair_loc),
569    })?;
570    let type_annotation = parse_type_annotation(type_pair)?;
571
572    // Parse optional default value expression (for comptime fields)
573    let default_value = if let Some(expr_pair) = inner.next() {
574        Some(super::expressions::parse_expression(expr_pair)?)
575    } else {
576        None
577    };
578
579    Ok(crate::ast::StructField {
580        annotations,
581        is_comptime,
582        name,
583        type_annotation,
584        default_value,
585    })
586}
587
588/// Parse type alias definition
589///
590/// Grammar: `"type" ~ ident ~ type_params? ~ "=" ~ type_annotation ~ comptime_field_overrides? ~ ";"?`
591pub fn parse_type_alias_def(pair: Pair<Rule>) -> Result<crate::ast::TypeAliasDef> {
592    let mut inner = pair.into_inner();
593
594    // Parse alias name
595    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
596        message: "Missing type alias name".to_string(),
597        location: None,
598    })?;
599    let name = name_pair.as_str().to_string();
600
601    // Check for type parameters (generics), type annotation, and comptime field overrides
602    let mut type_params = None;
603    let mut type_annotation = None;
604    let mut meta_param_overrides = None;
605
606    for part in inner {
607        match part.as_rule() {
608            Rule::type_params => {
609                // Parse generic type parameters like <T, U>
610                type_params = Some(parse_type_params(part)?);
611            }
612            Rule::type_annotation => {
613                type_annotation = Some(parse_type_annotation(part)?);
614            }
615            Rule::comptime_field_overrides => {
616                meta_param_overrides = Some(parse_comptime_field_overrides(part)?);
617            }
618            _ => {}
619        }
620    }
621
622    let type_annotation = type_annotation.ok_or_else(|| ShapeError::ParseError {
623        message: "Type alias missing type annotation".to_string(),
624        location: None,
625    })?;
626
627    Ok(crate::ast::TypeAliasDef {
628        name,
629        type_params,
630        type_annotation,
631        meta_param_overrides,
632    })
633}
634
635/// Parse enum definition
636///
637/// Grammar: `"enum" ~ ident ~ type_params? ~ "{" ~ enum_member_list? ~ "}"`
638pub fn parse_enum_def(pair: Pair<Rule>) -> Result<crate::ast::EnumDef> {
639    let pair_loc = pair_location(&pair);
640    let mut inner = pair.into_inner();
641
642    let mut annotations = Vec::new();
643    let mut name = String::new();
644    let mut type_params = None;
645    let mut members = Vec::new();
646
647    for part in inner {
648        match part.as_rule() {
649            Rule::annotations => {
650                annotations = crate::parser::functions::parse_annotations(part)?;
651            }
652            Rule::ident => {
653                if name.is_empty() {
654                    name = part.as_str().to_string();
655                }
656            }
657            Rule::type_params => {
658                type_params = Some(parse_type_params(part)?);
659            }
660            Rule::enum_member_list => {
661                for member_pair in part.into_inner() {
662                    if member_pair.as_rule() == Rule::enum_member {
663                        members.push(parse_enum_member(member_pair)?);
664                    }
665                }
666            }
667            Rule::enum_member => {
668                members.push(parse_enum_member(part)?);
669            }
670            _ => {}
671        }
672    }
673
674    if name.is_empty() {
675        return Err(ShapeError::ParseError {
676            message: "Missing enum name".to_string(),
677            location: Some(pair_loc),
678        });
679    }
680
681    Ok(crate::ast::EnumDef {
682        name,
683        type_params,
684        members,
685        annotations,
686    })
687}
688
689fn parse_enum_member(pair: Pair<Rule>) -> Result<crate::ast::EnumMember> {
690    let pair_loc = pair_location(&pair);
691    let inner = pair
692        .into_inner()
693        .next()
694        .ok_or_else(|| ShapeError::ParseError {
695            message: "expected enum member content".to_string(),
696            location: Some(pair_loc.clone()),
697        })?;
698
699    match inner.as_rule() {
700        Rule::enum_variant_unit => {
701            let mut unit_inner = inner.into_inner();
702            let name_pair = unit_inner.next().ok_or_else(|| ShapeError::ParseError {
703                message: "expected enum variant name".to_string(),
704                location: Some(pair_loc.clone()),
705            })?;
706            let name = name_pair.as_str().to_string();
707            let value = if let Some(val_pair) = unit_inner.next() {
708                match val_pair.as_rule() {
709                    Rule::string => Some(crate::ast::EnumValue::String(parse_string_literal(
710                        val_pair.as_str(),
711                    )?)),
712                    Rule::number => {
713                        let n: f64 =
714                            val_pair
715                                .as_str()
716                                .parse()
717                                .map_err(|e| ShapeError::ParseError {
718                                    message: format!("Invalid enum value number: {}", e),
719                                    location: Some(pair_loc.clone()),
720                                })?;
721                        Some(crate::ast::EnumValue::Number(n))
722                    }
723                    _ => {
724                        return Err(ShapeError::ParseError {
725                            message: "invalid enum unit value".to_string(),
726                            location: Some(pair_loc),
727                        });
728                    }
729                }
730            } else {
731                None
732            };
733
734            Ok(crate::ast::EnumMember {
735                name,
736                kind: crate::ast::EnumMemberKind::Unit { value },
737            })
738        }
739        Rule::enum_variant_tuple => {
740            let mut tuple_inner = inner.into_inner();
741            let name_pair = tuple_inner.next().ok_or_else(|| ShapeError::ParseError {
742                message: "expected enum variant name".to_string(),
743                location: Some(pair_loc.clone()),
744            })?;
745            let name = name_pair.as_str().to_string();
746            let mut fields = Vec::new();
747            for type_pair in tuple_inner {
748                if type_pair.as_rule() == Rule::type_annotation {
749                    fields.push(parse_type_annotation(type_pair)?);
750                }
751            }
752            Ok(crate::ast::EnumMember {
753                name,
754                kind: crate::ast::EnumMemberKind::Tuple(fields),
755            })
756        }
757        Rule::enum_variant_struct => {
758            let mut struct_inner = inner.into_inner();
759            let name_pair = struct_inner.next().ok_or_else(|| ShapeError::ParseError {
760                message: "expected enum variant name".to_string(),
761                location: Some(pair_loc.clone()),
762            })?;
763            let name = name_pair.as_str().to_string();
764            let mut fields = Vec::new();
765            for part in struct_inner {
766                if part.as_rule() == Rule::object_type_member_list {
767                    for field_pair in part.into_inner() {
768                        if field_pair.as_rule() == Rule::object_type_member {
769                            fields.push(parse_object_type_member(field_pair)?);
770                        }
771                    }
772                }
773            }
774            Ok(crate::ast::EnumMember {
775                name,
776                kind: crate::ast::EnumMemberKind::Struct(fields),
777            })
778        }
779        _ => Err(ShapeError::ParseError {
780            message: format!("unexpected enum member rule: {:?}", inner.as_rule()),
781            location: Some(pair_loc),
782        }),
783    }
784}
785
786/// Parse interface definition
787///
788/// Grammar: `"interface" ~ ident ~ type_params? ~ "{" ~ interface_body ~ "}"`
789pub fn parse_interface_def(pair: Pair<Rule>) -> Result<crate::ast::InterfaceDef> {
790    let pair_loc = pair_location(&pair);
791    let mut inner = pair.into_inner();
792
793    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
794        message: "Missing interface name".to_string(),
795        location: Some(pair_loc.clone()),
796    })?;
797    let name = name_pair.as_str().to_string();
798
799    let mut type_params = None;
800    let mut members = Vec::new();
801
802    for part in inner {
803        match part.as_rule() {
804            Rule::type_params => {
805                type_params = Some(parse_type_params(part)?);
806            }
807            Rule::interface_body => {
808                members = parse_interface_body(part)?;
809            }
810            _ => {}
811        }
812    }
813
814    Ok(crate::ast::InterfaceDef {
815        name,
816        type_params,
817        members,
818    })
819}
820
821/// Parse trait definition
822///
823/// Grammar: `"trait" ~ ident ~ type_params? ~ "{" ~ trait_body ~ "}"`
824///
825/// Traits reuse the same body syntax as interfaces (method/property signatures).
826pub fn parse_trait_def(pair: Pair<Rule>) -> Result<crate::ast::TraitDef> {
827    let pair_loc = pair_location(&pair);
828    let inner = pair.into_inner();
829
830    let mut annotations = Vec::new();
831    let mut type_params = None;
832    let mut members = Vec::new();
833    let mut name = String::new();
834
835    // First child may be annotations or ident
836    for part in inner {
837        match part.as_rule() {
838            Rule::annotations => {
839                annotations = crate::parser::functions::parse_annotations(part)?;
840            }
841            Rule::ident => {
842                if name.is_empty() {
843                    name = part.as_str().to_string();
844                }
845            }
846            Rule::type_params => {
847                type_params = Some(parse_type_params(part)?);
848            }
849            Rule::trait_body => {
850                members = parse_trait_body(part)?;
851            }
852            _ => {}
853        }
854    }
855
856    if name.is_empty() {
857        return Err(ShapeError::ParseError {
858            message: "Missing trait name".to_string(),
859            location: Some(pair_loc),
860        });
861    }
862
863    Ok(crate::ast::TraitDef {
864        name,
865        type_params,
866        members,
867        annotations,
868    })
869}
870
871fn parse_trait_body(pair: Pair<Rule>) -> Result<Vec<crate::ast::TraitMember>> {
872    let mut members = Vec::new();
873
874    for trait_member in pair.into_inner() {
875        if trait_member.as_rule() != Rule::trait_member {
876            continue;
877        }
878
879        // Each trait_member is a method_def (default), interface_member (required),
880        // or associated_type_decl
881        for inner in trait_member.into_inner() {
882            match inner.as_rule() {
883                Rule::associated_type_decl => {
884                    let (name, bounds) = parse_associated_type_decl(inner)?;
885                    members.push(crate::ast::TraitMember::AssociatedType { name, bounds });
886                }
887                Rule::method_def => {
888                    let method = parse_method_def_shared(inner)?;
889                    members.push(crate::ast::TraitMember::Default(method));
890                }
891                Rule::interface_member => {
892                    let im = parse_interface_member(inner)?;
893                    members.push(crate::ast::TraitMember::Required(im));
894                }
895                _ => {} // skip separators etc.
896            }
897        }
898    }
899
900    Ok(members)
901}
902
903/// Parse `type Item;` or `type Item: Bound1 + Bound2;`
904fn parse_associated_type_decl(pair: Pair<Rule>) -> Result<(String, Vec<TypeAnnotation>)> {
905    let mut inner = pair.into_inner();
906
907    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
908        message: "expected associated type name".to_string(),
909        location: None,
910    })?;
911    let name = name_pair.as_str().to_string();
912
913    let mut bounds = Vec::new();
914    for remaining in inner {
915        if remaining.as_rule() == Rule::trait_bound_list {
916            for bound_ident in remaining.into_inner() {
917                if bound_ident.as_rule() == Rule::ident {
918                    bounds.push(TypeAnnotation::Basic(bound_ident.as_str().to_string()));
919                }
920            }
921        }
922    }
923
924    Ok((name, bounds))
925}
926
927/// Shared parser for method_def rule, used by extend, impl, and trait bodies
928pub(crate) fn parse_method_def_shared(pair: Pair<Rule>) -> Result<crate::ast::types::MethodDef> {
929    use crate::ast::types::MethodDef;
930
931    // Detect optional "async" prefix from the raw text
932    let is_async = pair.as_str().trim_start().starts_with("async");
933
934    let mut md_inner = pair.into_inner();
935
936    let name_pair = md_inner.next().ok_or_else(|| ShapeError::ParseError {
937        message: "Missing method name".to_string(),
938        location: None,
939    })?;
940    let name = name_pair.as_str().to_string();
941
942    let mut params = Vec::new();
943    let mut when_clause = None;
944    let mut return_type = None;
945    let mut body = Vec::new();
946
947    for part in md_inner {
948        match part.as_rule() {
949            Rule::function_params => {
950                for param_pair in part.into_inner() {
951                    if param_pair.as_rule() == Rule::function_param {
952                        params.push(super::functions::parse_function_param(param_pair)?);
953                    }
954                }
955            }
956            Rule::when_clause => {
957                if let Some(expr_pair) = part.into_inner().next() {
958                    when_clause = Some(Box::new(crate::parser::expressions::parse_expression(
959                        expr_pair,
960                    )?));
961                }
962            }
963            Rule::return_type => {
964                if let Some(type_pair) = part.into_inner().next() {
965                    return_type = Some(parse_type_annotation(type_pair)?);
966                }
967            }
968            Rule::function_body => {
969                body = super::statements::parse_statements(part.into_inner())?;
970            }
971            _ => {}
972        }
973    }
974
975    Ok(MethodDef {
976        name,
977        params,
978        when_clause,
979        return_type,
980        body,
981        is_async,
982    })
983}
984
985fn parse_interface_body(pair: Pair<Rule>) -> Result<Vec<crate::ast::InterfaceMember>> {
986    let mut members = Vec::new();
987    for inner in pair.into_inner() {
988        if inner.as_rule() == Rule::interface_member_list {
989            for member in inner.into_inner() {
990                if member.as_rule() == Rule::interface_member {
991                    members.push(parse_interface_member(member)?);
992                }
993            }
994        }
995    }
996    Ok(members)
997}
998
999fn parse_interface_member(pair: Pair<Rule>) -> Result<crate::ast::InterfaceMember> {
1000    let pair_loc = pair_location(&pair);
1001    let raw = pair.as_str();
1002    let trimmed = raw.trim_start();
1003
1004    if trimmed.starts_with('[') {
1005        return parse_interface_index_signature(pair, trimmed);
1006    }
1007
1008    let mut inner = pair.into_inner();
1009    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
1010        message: "expected interface member name".to_string(),
1011        location: Some(pair_loc.clone()),
1012    })?;
1013    let name = name_pair.as_str().to_string();
1014
1015    let (optional, is_method) = parse_interface_member_kind(trimmed, &name);
1016
1017    let mut params = Vec::new();
1018    let mut type_annotation = None;
1019    for part in inner {
1020        match part.as_rule() {
1021            Rule::type_param_list => {
1022                params = parse_type_param_list(part)?;
1023            }
1024            Rule::type_annotation => {
1025                type_annotation = Some(parse_type_annotation(part)?);
1026            }
1027            _ => {}
1028        }
1029    }
1030
1031    let type_annotation = type_annotation.ok_or_else(|| ShapeError::ParseError {
1032        message: format!("interface member '{}' missing type annotation", name),
1033        location: Some(pair_loc),
1034    })?;
1035
1036    if is_method {
1037        Ok(crate::ast::InterfaceMember::Method {
1038            name,
1039            optional,
1040            params,
1041            return_type: type_annotation,
1042            is_async: false,
1043        })
1044    } else {
1045        Ok(crate::ast::InterfaceMember::Property {
1046            name,
1047            optional,
1048            type_annotation,
1049        })
1050    }
1051}
1052
1053fn parse_interface_member_kind(raw: &str, name: &str) -> (bool, bool) {
1054    let trimmed = raw.trim_start();
1055    let Some(mut rest) = trimmed.strip_prefix(name) else {
1056        return (false, false);
1057    };
1058    rest = rest.trim_start();
1059    let mut optional = false;
1060    if rest.starts_with('?') {
1061        optional = true;
1062        rest = rest[1..].trim_start();
1063    }
1064    let is_method = rest.starts_with('(');
1065    (optional, is_method)
1066}
1067
1068fn parse_interface_index_signature(
1069    pair: Pair<Rule>,
1070    raw: &str,
1071) -> Result<crate::ast::InterfaceMember> {
1072    let pair_loc = pair_location(&pair);
1073    let mut inner = pair.into_inner();
1074    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
1075        message: "expected index signature parameter name".to_string(),
1076        location: Some(pair_loc.clone()),
1077    })?;
1078    let param_name = name_pair.as_str().to_string();
1079
1080    let mut return_type = None;
1081    for part in inner {
1082        if part.as_rule() == Rule::type_annotation {
1083            return_type = Some(parse_type_annotation(part)?);
1084        }
1085    }
1086
1087    let return_type = return_type.ok_or_else(|| ShapeError::ParseError {
1088        message: "index signature missing return type".to_string(),
1089        location: Some(pair_loc.clone()),
1090    })?;
1091
1092    let param_type =
1093        parse_index_signature_param_type(raw).ok_or_else(|| ShapeError::ParseError {
1094            message: "index signature missing parameter type".to_string(),
1095            location: Some(pair_loc),
1096        })?;
1097
1098    Ok(crate::ast::InterfaceMember::IndexSignature {
1099        param_name,
1100        param_type,
1101        return_type,
1102    })
1103}
1104
1105fn parse_index_signature_param_type(raw: &str) -> Option<String> {
1106    let trimmed = raw.trim();
1107    let open = trimmed.find('[')?;
1108    let close = trimmed[open + 1..].find(']')? + open + 1;
1109    let inside = trimmed[open + 1..close].trim();
1110    let mut parts = inside.splitn(2, ':');
1111    parts.next()?;
1112    let param_type = parts.next()?.trim();
1113    if param_type == "string" || param_type == "number" {
1114        Some(param_type.to_string())
1115    } else {
1116        None
1117    }
1118}