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::{Span, 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, pair_span};
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::option(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<_> = pair
113                .into_inner()
114                .filter(|p| p.as_rule() == Rule::qualified_ident)
115                .map(|p| p.as_str().into())
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().into())),
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        "never" => TypeAnnotation::Never,
138        "undefined" => TypeAnnotation::Undefined,
139        other if other.contains("::") => TypeAnnotation::Reference(other.into()),
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
270fn unwrap_documented_pair<'a>(
271    pair: Pair<'a, Rule>,
272    documented_rule: Rule,
273    inner_rule: Rule,
274    context: &'static str,
275) -> Result<(Option<crate::ast::DocComment>, Pair<'a, Rule>)> {
276    if pair.as_rule() == inner_rule {
277        return Ok((None, pair));
278    }
279
280    if pair.as_rule() != documented_rule {
281        return Err(ShapeError::ParseError {
282            message: format!("expected {}", context),
283            location: Some(pair_location(&pair)),
284        });
285    }
286
287    let pair_loc = pair_location(&pair);
288    let mut inner = pair.into_inner();
289    let mut doc_comment = None;
290    let mut item = inner.next().ok_or_else(|| ShapeError::ParseError {
291        message: format!("expected {}", context),
292        location: Some(pair_loc.clone()),
293    })?;
294
295    if item.as_rule() == Rule::doc_comment {
296        doc_comment = Some(super::docs::parse_doc_comment(item));
297        item = inner.next().ok_or_else(|| ShapeError::ParseError {
298            message: format!("expected {} after doc comment", context),
299            location: Some(pair_loc.clone()),
300        })?;
301    }
302
303    if item.as_rule() != inner_rule {
304        return Err(ShapeError::ParseError {
305            message: format!("expected {}", context),
306            location: Some(pair_location(&item)),
307        });
308    }
309
310    Ok((doc_comment, item))
311}
312
313pub fn parse_type_params(pair: Pair<Rule>) -> Result<Vec<crate::ast::TypeParam>> {
314    let pair_loc = pair_location(&pair);
315    let mut params = Vec::new();
316    for param_pair in pair.into_inner() {
317        if matches!(
318            param_pair.as_rule(),
319            Rule::documented_type_param_name | Rule::type_param_name
320        ) {
321            let (doc_comment, param_pair) = unwrap_documented_pair(
322                param_pair,
323                Rule::documented_type_param_name,
324                Rule::type_param_name,
325                "type parameter",
326            )?;
327            let param_span = pair_span(&param_pair);
328            let mut param_inner = param_pair.into_inner();
329            let name_pair = param_inner.next().ok_or_else(|| ShapeError::ParseError {
330                message: "expected type parameter name".to_string(),
331                location: Some(pair_loc.clone()),
332            })?;
333            let name = name_pair.as_str().to_string();
334            let mut default_type = None;
335            let mut trait_bounds = Vec::new();
336            for remaining in param_inner {
337                match remaining.as_rule() {
338                    Rule::type_annotation => {
339                        default_type = Some(parse_type_annotation(remaining)?);
340                    }
341                    Rule::trait_bound_list => {
342                        for bound_ident in remaining.into_inner() {
343                            if bound_ident.as_rule() == Rule::qualified_ident {
344                                trait_bounds.push(bound_ident.as_str().into());
345                            }
346                        }
347                    }
348                    _ => {}
349                }
350            }
351            params.push(crate::ast::TypeParam {
352                name,
353                span: param_span,
354                doc_comment,
355                default_type,
356                trait_bounds,
357            });
358        }
359    }
360    Ok(params)
361}
362
363/// Parse a declaration-only builtin type definition.
364///
365/// Grammar:
366/// `builtin type Name<T>;`
367pub fn parse_builtin_type_decl(pair: Pair<Rule>) -> Result<crate::ast::BuiltinTypeDecl> {
368    let pair_loc = pair_location(&pair);
369    let mut name = String::new();
370    let mut name_span = crate::ast::Span::DUMMY;
371    let mut type_params = None;
372
373    for inner in pair.into_inner() {
374        match inner.as_rule() {
375            Rule::ident => {
376                if name.is_empty() {
377                    name = inner.as_str().to_string();
378                    name_span = super::pair_span(&inner);
379                }
380            }
381            Rule::type_params => {
382                type_params = Some(parse_type_params(inner)?);
383            }
384            _ => {}
385        }
386    }
387
388    if name.is_empty() {
389        return Err(ShapeError::ParseError {
390            message: "expected builtin type name".to_string(),
391            location: Some(pair_loc),
392        });
393    }
394
395    Ok(crate::ast::BuiltinTypeDecl {
396        name,
397        name_span,
398        doc_comment: None,
399        type_params,
400    })
401}
402
403/// Parse generic type with arguments
404pub fn parse_generic_type(pair: Pair<Rule>) -> Result<TypeAnnotation> {
405    let pair_loc = pair_location(&pair);
406    let mut inner = pair.into_inner();
407    let name = inner
408        .next()
409        .ok_or_else(|| ShapeError::ParseError {
410            message: "expected generic type name".to_string(),
411            location: Some(pair_loc.clone()),
412        })?
413        .as_str()
414        .to_string();
415    let mut args = Vec::new();
416    for arg in inner {
417        if arg.as_rule() == Rule::type_annotation {
418            args.push(parse_type_annotation(arg)?);
419        }
420    }
421    if name == "Matrix" {
422        return Err(ShapeError::ParseError {
423            message: "Matrix<T> has been removed; use Mat<T> instead".to_string(),
424            location: Some(pair_loc),
425        });
426    }
427    if (name == "Vec" || name == "Array") && args.len() == 1 {
428        Ok(TypeAnnotation::Array(Box::new(args.remove(0))))
429    } else {
430        Ok(TypeAnnotation::Generic { name: name.into(), args })
431    }
432}
433
434/// Parse comptime field overrides for type aliases
435///
436/// Grammar: `"{" ~ comptime_field_override ~ ("," ~ comptime_field_override)* ~ ","? ~ "}"`
437/// Where: `comptime_field_override = { ident ~ ":" ~ expression }`
438pub fn parse_comptime_field_overrides(
439    pair: Pair<Rule>,
440) -> Result<HashMap<String, crate::ast::Expr>> {
441    let mut overrides = HashMap::new();
442
443    for override_pair in pair.into_inner() {
444        if override_pair.as_rule() == Rule::comptime_field_override {
445            let mut inner = override_pair.into_inner();
446
447            let key_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
448                message: "Missing parameter name in override".to_string(),
449                location: None,
450            })?;
451            let key = key_pair.as_str().to_string();
452
453            let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
454                message: "Missing expression in parameter override".to_string(),
455                location: None,
456            })?;
457            let expr = super::expressions::parse_expression(expr_pair)?;
458
459            overrides.insert(key, expr);
460        }
461    }
462
463    Ok(overrides)
464}
465
466/// Parse struct type definition
467///
468/// Grammar: `"type" ~ ident ~ type_params? ~ "{" ~ struct_field_list? ~ "}"`
469pub fn parse_struct_type_def(pair: Pair<Rule>) -> Result<crate::ast::StructTypeDef> {
470    let pair_loc = pair_location(&pair);
471    let mut inner = pair.into_inner();
472
473    let mut annotations = Vec::new();
474    let mut type_params = None;
475    let mut fields = Vec::new();
476
477    // First child may be annotations or the struct name ident
478    let first = inner.next().ok_or_else(|| ShapeError::ParseError {
479        message: "Missing struct type name".to_string(),
480        location: Some(pair_loc.clone()),
481    })?;
482
483    let name = if first.as_rule() == Rule::annotations {
484        annotations = super::functions::parse_annotations(first)?;
485        let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
486            message: "Missing struct type name after annotations".to_string(),
487            location: Some(pair_loc.clone()),
488        })?;
489        name_pair.as_str().to_string()
490    } else {
491        first.as_str().to_string()
492    };
493
494    for part in inner {
495        match part.as_rule() {
496            Rule::type_params => {
497                type_params = Some(parse_type_params(part)?);
498            }
499            Rule::struct_field_list => {
500                for field_pair in part.into_inner() {
501                    if matches!(
502                        field_pair.as_rule(),
503                        Rule::documented_struct_field | Rule::struct_field
504                    ) {
505                        fields.push(parse_struct_field(field_pair)?);
506                    }
507                }
508            }
509            _ => {}
510        }
511    }
512
513    Ok(crate::ast::StructTypeDef {
514        name,
515        doc_comment: None,
516        type_params,
517        fields,
518        methods: Vec::new(),
519        annotations,
520        native_layout: None,
521    })
522}
523
524/// Parse native-layout type definition.
525///
526/// Grammar: `annotations? ~ "type" ~ extern_abi ~ ident ~ type_params? ~ "{" ~ struct_field_list? ~ "}"`
527pub fn parse_native_struct_type_def(pair: Pair<Rule>) -> Result<crate::ast::StructTypeDef> {
528    let pair_loc = pair_location(&pair);
529    let mut annotations = Vec::new();
530    let mut abi: Option<String> = None;
531    let mut name: Option<String> = None;
532    let mut type_params = None;
533    let mut fields = Vec::new();
534
535    for part in pair.into_inner() {
536        match part.as_rule() {
537            Rule::annotations => {
538                annotations = super::functions::parse_annotations(part)?;
539            }
540            Rule::extern_abi => {
541                abi = Some(super::functions::parse_extern_abi(part)?);
542            }
543            Rule::ident => {
544                if name.is_none() {
545                    name = Some(part.as_str().to_string());
546                }
547            }
548            Rule::type_params => {
549                type_params = Some(parse_type_params(part)?);
550            }
551            Rule::struct_field_list => {
552                for field_pair in part.into_inner() {
553                    if matches!(
554                        field_pair.as_rule(),
555                        Rule::documented_struct_field | Rule::struct_field
556                    ) {
557                        fields.push(parse_struct_field(field_pair)?);
558                    }
559                }
560            }
561            _ => {}
562        }
563    }
564
565    let abi = abi.ok_or_else(|| ShapeError::ParseError {
566        message: "native layout type declaration requires an ABI name".to_string(),
567        location: Some(pair_loc.clone()),
568    })?;
569
570    if abi.trim() != "C" {
571        return Err(ShapeError::ParseError {
572            message: format!(
573                "unsupported native ABI '{}': only C is currently supported for type layouts",
574                abi
575            ),
576            location: Some(pair_loc.clone()),
577        });
578    }
579
580    let name = name.ok_or_else(|| ShapeError::ParseError {
581        message: "Missing native layout type name".to_string(),
582        location: Some(pair_loc),
583    })?;
584
585    Ok(crate::ast::StructTypeDef {
586        name,
587        doc_comment: None,
588        type_params,
589        fields,
590        methods: Vec::new(),
591        annotations,
592        native_layout: Some(crate::ast::NativeLayoutBinding { abi }),
593    })
594}
595
596/// Parse a single struct field
597///
598/// Grammar: `annotations? ~ comptime_keyword? ~ ident ~ ":" ~ type_annotation ~ ("=" ~ expression)?`
599fn parse_struct_field(pair: Pair<Rule>) -> Result<crate::ast::StructField> {
600    let (doc_comment, pair) = unwrap_documented_pair(
601        pair,
602        Rule::documented_struct_field,
603        Rule::struct_field,
604        "struct field",
605    )?;
606    let pair_loc = pair_location(&pair);
607    let span = pair_span(&pair);
608    let mut inner = pair.into_inner();
609
610    let mut annotations = vec![];
611    let mut is_comptime = false;
612
613    // Peek at the first child — may be annotations, comptime_keyword, or ident
614    let first = inner.next().ok_or_else(|| ShapeError::ParseError {
615        message: "Missing struct field name".to_string(),
616        location: Some(pair_loc.clone()),
617    })?;
618
619    let mut current = first;
620
621    if current.as_rule() == Rule::annotations {
622        annotations = super::functions::parse_annotations(current)?;
623        current = inner.next().ok_or_else(|| ShapeError::ParseError {
624            message: "Missing struct field name after annotations".to_string(),
625            location: Some(pair_loc.clone()),
626        })?;
627    }
628
629    if current.as_rule() == Rule::comptime_keyword {
630        is_comptime = true;
631        current = inner.next().ok_or_else(|| ShapeError::ParseError {
632            message: "Missing struct field name after 'comptime'".to_string(),
633            location: Some(pair_loc.clone()),
634        })?;
635    }
636
637    let name = current.as_str().to_string();
638
639    let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
640        message: format!("Missing type annotation for struct field '{}'", name),
641        location: Some(pair_loc),
642    })?;
643    let type_annotation = parse_type_annotation(type_pair)?;
644
645    // Parse optional default value expression (for comptime fields)
646    let default_value = if let Some(expr_pair) = inner.next() {
647        Some(super::expressions::parse_expression(expr_pair)?)
648    } else {
649        None
650    };
651
652    Ok(crate::ast::StructField {
653        annotations,
654        is_comptime,
655        name,
656        span,
657        doc_comment,
658        type_annotation,
659        default_value,
660    })
661}
662
663/// Parse type alias definition
664///
665/// Grammar: `"type" ~ ident ~ type_params? ~ "=" ~ type_annotation ~ comptime_field_overrides? ~ ";"?`
666pub fn parse_type_alias_def(pair: Pair<Rule>) -> Result<crate::ast::TypeAliasDef> {
667    let mut inner = pair.into_inner();
668
669    // Parse alias name
670    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
671        message: "Missing type alias name".to_string(),
672        location: None,
673    })?;
674    let name = name_pair.as_str().to_string();
675
676    // Check for type parameters (generics), type annotation, and comptime field overrides
677    let mut type_params = None;
678    let mut type_annotation = None;
679    let mut meta_param_overrides = None;
680
681    for part in inner {
682        match part.as_rule() {
683            Rule::type_params => {
684                // Parse generic type parameters like <T, U>
685                type_params = Some(parse_type_params(part)?);
686            }
687            Rule::type_annotation => {
688                type_annotation = Some(parse_type_annotation(part)?);
689            }
690            Rule::comptime_field_overrides => {
691                meta_param_overrides = Some(parse_comptime_field_overrides(part)?);
692            }
693            _ => {}
694        }
695    }
696
697    let type_annotation = type_annotation.ok_or_else(|| ShapeError::ParseError {
698        message: "Type alias missing type annotation".to_string(),
699        location: None,
700    })?;
701
702    Ok(crate::ast::TypeAliasDef {
703        name,
704        doc_comment: None,
705        type_params,
706        type_annotation,
707        meta_param_overrides,
708    })
709}
710
711/// Parse enum definition
712///
713/// Grammar: `"enum" ~ ident ~ type_params? ~ "{" ~ enum_member_list? ~ "}"`
714pub fn parse_enum_def(pair: Pair<Rule>) -> Result<crate::ast::EnumDef> {
715    let pair_loc = pair_location(&pair);
716    let inner = pair.into_inner();
717
718    let mut annotations = Vec::new();
719    let mut name = String::new();
720    let mut type_params = None;
721    let mut members = Vec::new();
722
723    for part in inner {
724        match part.as_rule() {
725            Rule::annotations => {
726                annotations = crate::parser::functions::parse_annotations(part)?;
727            }
728            Rule::ident => {
729                if name.is_empty() {
730                    name = part.as_str().to_string();
731                }
732            }
733            Rule::type_params => {
734                type_params = Some(parse_type_params(part)?);
735            }
736            Rule::enum_member_list => {
737                for member_pair in part.into_inner() {
738                    if matches!(
739                        member_pair.as_rule(),
740                        Rule::documented_enum_member | Rule::enum_member
741                    ) {
742                        members.push(parse_enum_member(member_pair)?);
743                    }
744                }
745            }
746            Rule::documented_enum_member | Rule::enum_member => {
747                members.push(parse_enum_member(part)?);
748            }
749            _ => {}
750        }
751    }
752
753    if name.is_empty() {
754        return Err(ShapeError::ParseError {
755            message: "Missing enum name".to_string(),
756            location: Some(pair_loc),
757        });
758    }
759
760    Ok(crate::ast::EnumDef {
761        name,
762        doc_comment: None,
763        type_params,
764        members,
765        annotations,
766    })
767}
768
769fn parse_enum_member(pair: Pair<Rule>) -> Result<crate::ast::EnumMember> {
770    let (doc_comment, pair) = unwrap_documented_pair(
771        pair,
772        Rule::documented_enum_member,
773        Rule::enum_member,
774        "enum member",
775    )?;
776    let pair_loc = pair_location(&pair);
777    let span = pair_span(&pair);
778    let inner = pair
779        .into_inner()
780        .next()
781        .ok_or_else(|| ShapeError::ParseError {
782            message: "expected enum member content".to_string(),
783            location: Some(pair_loc.clone()),
784        })?;
785
786    match inner.as_rule() {
787        Rule::enum_variant_unit => {
788            let mut unit_inner = inner.into_inner();
789            let name_pair = unit_inner.next().ok_or_else(|| ShapeError::ParseError {
790                message: "expected enum variant name".to_string(),
791                location: Some(pair_loc.clone()),
792            })?;
793            let name = name_pair.as_str().to_string();
794            let value = if let Some(val_pair) = unit_inner.next() {
795                match val_pair.as_rule() {
796                    Rule::string => Some(crate::ast::EnumValue::String(parse_string_literal(
797                        val_pair.as_str(),
798                    )?)),
799                    Rule::number => {
800                        let n: f64 =
801                            val_pair
802                                .as_str()
803                                .parse()
804                                .map_err(|e| ShapeError::ParseError {
805                                    message: format!("Invalid enum value number: {}", e),
806                                    location: Some(pair_loc.clone()),
807                                })?;
808                        Some(crate::ast::EnumValue::Number(n))
809                    }
810                    _ => {
811                        return Err(ShapeError::ParseError {
812                            message: "invalid enum unit value".to_string(),
813                            location: Some(pair_loc),
814                        });
815                    }
816                }
817            } else {
818                None
819            };
820
821            Ok(crate::ast::EnumMember {
822                name,
823                kind: crate::ast::EnumMemberKind::Unit { value },
824                span,
825                doc_comment,
826            })
827        }
828        Rule::enum_variant_tuple => {
829            let mut tuple_inner = inner.into_inner();
830            let name_pair = tuple_inner.next().ok_or_else(|| ShapeError::ParseError {
831                message: "expected enum variant name".to_string(),
832                location: Some(pair_loc.clone()),
833            })?;
834            let name = name_pair.as_str().to_string();
835            let mut fields = Vec::new();
836            for type_pair in tuple_inner {
837                if type_pair.as_rule() == Rule::type_annotation {
838                    fields.push(parse_type_annotation(type_pair)?);
839                }
840            }
841            Ok(crate::ast::EnumMember {
842                name,
843                kind: crate::ast::EnumMemberKind::Tuple(fields),
844                span,
845                doc_comment,
846            })
847        }
848        Rule::enum_variant_struct => {
849            let mut struct_inner = inner.into_inner();
850            let name_pair = struct_inner.next().ok_or_else(|| ShapeError::ParseError {
851                message: "expected enum variant name".to_string(),
852                location: Some(pair_loc.clone()),
853            })?;
854            let name = name_pair.as_str().to_string();
855            let mut fields = Vec::new();
856            for part in struct_inner {
857                if part.as_rule() == Rule::object_type_member_list {
858                    for field_pair in part.into_inner() {
859                        if field_pair.as_rule() == Rule::object_type_member {
860                            fields.push(parse_object_type_member(field_pair)?);
861                        }
862                    }
863                }
864            }
865            Ok(crate::ast::EnumMember {
866                name,
867                kind: crate::ast::EnumMemberKind::Struct(fields),
868                span,
869                doc_comment,
870            })
871        }
872        _ => Err(ShapeError::ParseError {
873            message: format!("unexpected enum member rule: {:?}", inner.as_rule()),
874            location: Some(pair_loc),
875        }),
876    }
877}
878
879/// Parse interface definition
880///
881/// Grammar: `"interface" ~ ident ~ type_params? ~ "{" ~ interface_body ~ "}"`
882pub fn parse_interface_def(pair: Pair<Rule>) -> Result<crate::ast::InterfaceDef> {
883    let pair_loc = pair_location(&pair);
884    let mut inner = pair.into_inner();
885
886    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
887        message: "Missing interface name".to_string(),
888        location: Some(pair_loc.clone()),
889    })?;
890    let name = name_pair.as_str().to_string();
891
892    let mut type_params = None;
893    let mut members = Vec::new();
894
895    for part in inner {
896        match part.as_rule() {
897            Rule::type_params => {
898                type_params = Some(parse_type_params(part)?);
899            }
900            Rule::interface_body => {
901                members = parse_interface_body(part)?;
902            }
903            _ => {}
904        }
905    }
906
907    Ok(crate::ast::InterfaceDef {
908        name,
909        doc_comment: None,
910        type_params,
911        members,
912    })
913}
914
915/// Parse trait definition
916///
917/// Grammar: `annotations? ~ "trait" ~ ident ~ type_params? ~ (":" ~ type_annotation ~ ("+" ~ type_annotation)*)? ~ "{" ~ trait_body ~ "}"`
918///
919/// Traits reuse the same body syntax as interfaces (method/property signatures).
920/// Supertrait bounds use `:` syntax: `trait Foo: Bar + Baz { ... }`
921pub fn parse_trait_def(pair: Pair<Rule>) -> Result<crate::ast::TraitDef> {
922    let pair_loc = pair_location(&pair);
923    let inner = pair.into_inner();
924
925    let mut annotations = Vec::new();
926    let mut type_params = None;
927    let mut super_traits = Vec::new();
928    let mut members = Vec::new();
929    let mut name = String::new();
930
931    // First child may be annotations or ident
932    for part in inner {
933        match part.as_rule() {
934            Rule::annotations => {
935                annotations = crate::parser::functions::parse_annotations(part)?;
936            }
937            Rule::ident => {
938                if name.is_empty() {
939                    name = part.as_str().to_string();
940                }
941            }
942            Rule::type_params => {
943                type_params = Some(parse_type_params(part)?);
944            }
945            Rule::supertrait_list => {
946                for inner_part in part.into_inner() {
947                    if inner_part.as_rule() == Rule::optional_type {
948                        super_traits.push(parse_type_annotation(inner_part)?);
949                    }
950                }
951            }
952            Rule::trait_body => {
953                members = parse_trait_body(part)?;
954            }
955            _ => {}
956        }
957    }
958
959    if name.is_empty() {
960        return Err(ShapeError::ParseError {
961            message: "Missing trait name".to_string(),
962            location: Some(pair_loc),
963        });
964    }
965
966    Ok(crate::ast::TraitDef {
967        name,
968        doc_comment: None,
969        type_params,
970        super_traits,
971        members,
972        annotations,
973    })
974}
975
976fn parse_trait_body(pair: Pair<Rule>) -> Result<Vec<crate::ast::TraitMember>> {
977    let mut members = Vec::new();
978
979    for trait_member in pair.into_inner() {
980        if trait_member.as_rule() != Rule::trait_member {
981            continue;
982        }
983
984        let mut member_inner = trait_member.into_inner();
985        let mut doc_comment = None;
986        let mut inner = member_inner.next().ok_or_else(|| ShapeError::ParseError {
987            message: "expected trait member".to_string(),
988            location: None,
989        })?;
990
991        if inner.as_rule() == Rule::doc_comment {
992            doc_comment = Some(super::docs::parse_doc_comment(inner));
993            inner = member_inner.next().ok_or_else(|| ShapeError::ParseError {
994                message: "expected trait member after doc comment".to_string(),
995                location: None,
996            })?;
997        }
998
999        if inner.as_rule() == Rule::trait_member_core {
1000            inner = inner
1001                .into_inner()
1002                .next()
1003                .ok_or_else(|| ShapeError::ParseError {
1004                    message: "expected trait member".to_string(),
1005                    location: None,
1006                })?;
1007        }
1008
1009        match inner.as_rule() {
1010            Rule::associated_type_decl => {
1011                let (name, bounds, span) = parse_associated_type_decl(inner)?;
1012                members.push(crate::ast::TraitMember::AssociatedType {
1013                    name,
1014                    bounds,
1015                    span,
1016                    doc_comment,
1017                });
1018            }
1019            Rule::method_def => {
1020                let mut method = parse_method_def_shared(inner)?;
1021                method.doc_comment = doc_comment;
1022                members.push(crate::ast::TraitMember::Default(method));
1023            }
1024            Rule::interface_member | Rule::documented_interface_member => {
1025                let mut im = parse_interface_member(inner)?;
1026                if let Some(doc_comment) = doc_comment {
1027                    attach_interface_member_doc_comment(&mut im, doc_comment);
1028                }
1029                members.push(crate::ast::TraitMember::Required(im));
1030            }
1031            _ => {}
1032        }
1033    }
1034
1035    Ok(members)
1036}
1037
1038/// Parse `type Item;` or `type Item: Bound1 + Bound2;`
1039fn parse_associated_type_decl(pair: Pair<Rule>) -> Result<(String, Vec<TypeAnnotation>, Span)> {
1040    let span = pair_span(&pair);
1041    let mut inner = pair.into_inner();
1042
1043    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
1044        message: "expected associated type name".to_string(),
1045        location: None,
1046    })?;
1047    let name = name_pair.as_str().to_string();
1048
1049    let mut bounds = Vec::new();
1050    for remaining in inner {
1051        if remaining.as_rule() == Rule::trait_bound_list {
1052            for bound_ident in remaining.into_inner() {
1053                if bound_ident.as_rule() == Rule::qualified_ident {
1054                    bounds.push(TypeAnnotation::Basic(bound_ident.as_str().to_string()));
1055                }
1056            }
1057        }
1058    }
1059
1060    Ok((name, bounds, span))
1061}
1062
1063/// Shared parser for method_def rule, used by extend, impl, and trait bodies
1064pub(crate) fn parse_method_def_shared(pair: Pair<Rule>) -> Result<crate::ast::types::MethodDef> {
1065    use crate::ast::types::MethodDef;
1066
1067    // Detect optional "async" prefix from the raw text
1068    let is_async = pair.as_str().trim_start().starts_with("async");
1069    let span = pair_span(&pair);
1070
1071    let mut md_inner = pair.into_inner();
1072
1073    let name_pair = md_inner.next().ok_or_else(|| ShapeError::ParseError {
1074        message: "Missing method name".to_string(),
1075        location: None,
1076    })?;
1077    let name = name_pair.as_str().to_string();
1078
1079    let mut params = Vec::new();
1080    let mut type_params = None;
1081    let mut when_clause = None;
1082    let mut return_type = None;
1083    let mut body = Vec::new();
1084
1085    for part in md_inner {
1086        match part.as_rule() {
1087            Rule::type_params => {
1088                type_params = Some(parse_type_params(part)?);
1089            }
1090            Rule::function_params => {
1091                for param_pair in part.into_inner() {
1092                    if param_pair.as_rule() == Rule::function_param {
1093                        params.push(super::functions::parse_function_param(param_pair)?);
1094                    }
1095                }
1096            }
1097            Rule::when_clause => {
1098                if let Some(expr_pair) = part.into_inner().next() {
1099                    when_clause = Some(Box::new(crate::parser::expressions::parse_expression(
1100                        expr_pair,
1101                    )?));
1102                }
1103            }
1104            Rule::return_type => {
1105                if let Some(type_pair) = part.into_inner().next() {
1106                    return_type = Some(parse_type_annotation(type_pair)?);
1107                }
1108            }
1109            Rule::function_body => {
1110                body = super::statements::parse_statements(part.into_inner())?;
1111            }
1112            _ => {}
1113        }
1114    }
1115
1116    Ok(MethodDef {
1117        name,
1118        span,
1119        declaring_module_path: None,
1120        doc_comment: None,
1121        annotations: Vec::new(),
1122        type_params,
1123        params,
1124        when_clause,
1125        return_type,
1126        body,
1127        is_async,
1128    })
1129}
1130
1131pub(crate) fn parse_documented_method_def_shared(
1132    pair: Pair<Rule>,
1133) -> Result<crate::ast::types::MethodDef> {
1134    if pair.as_rule() == Rule::method_def {
1135        return parse_method_def_shared(pair);
1136    }
1137    assert_eq!(pair.as_rule(), Rule::documented_method_def);
1138    let inner = pair.into_inner();
1139    let mut doc_comment = None;
1140    let mut annotations = Vec::new();
1141    let mut method_pair = None;
1142
1143    for child in inner {
1144        match child.as_rule() {
1145            Rule::doc_comment => {
1146                doc_comment = Some(super::docs::parse_doc_comment(child));
1147            }
1148            Rule::annotations => {
1149                annotations = super::functions::parse_annotations(child)?;
1150            }
1151            Rule::method_def => {
1152                method_pair = Some(child);
1153            }
1154            _ => {}
1155        }
1156    }
1157
1158    let method_pair = method_pair.ok_or_else(|| ShapeError::ParseError {
1159        message: "expected method definition".to_string(),
1160        location: None,
1161    })?;
1162    let mut method = parse_method_def_shared(method_pair)?;
1163    method.doc_comment = doc_comment;
1164    method.annotations = annotations;
1165    Ok(method)
1166}
1167
1168fn parse_interface_body(pair: Pair<Rule>) -> Result<Vec<crate::ast::InterfaceMember>> {
1169    let mut members = Vec::new();
1170    for inner in pair.into_inner() {
1171        if inner.as_rule() == Rule::interface_member_list {
1172            for member in inner.into_inner() {
1173                if matches!(
1174                    member.as_rule(),
1175                    Rule::documented_interface_member | Rule::interface_member
1176                ) {
1177                    members.push(parse_interface_member(member)?);
1178                }
1179            }
1180        }
1181    }
1182    Ok(members)
1183}
1184
1185fn parse_interface_member(pair: Pair<Rule>) -> Result<crate::ast::InterfaceMember> {
1186    let (doc_comment, pair) = unwrap_documented_pair(
1187        pair,
1188        Rule::documented_interface_member,
1189        Rule::interface_member,
1190        "interface member",
1191    )?;
1192    let pair_loc = pair_location(&pair);
1193    let raw = pair.as_str();
1194    let trimmed = raw.trim_start();
1195    let span = pair_span(&pair);
1196
1197    if trimmed.starts_with('[') {
1198        return parse_interface_index_signature(pair, trimmed, doc_comment);
1199    }
1200
1201    let mut inner = pair.into_inner();
1202    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
1203        message: "expected interface member name".to_string(),
1204        location: Some(pair_loc.clone()),
1205    })?;
1206    let name = name_pair.as_str().to_string();
1207
1208    let (optional, is_method) = parse_interface_member_kind(trimmed, &name);
1209
1210    let mut params = Vec::new();
1211    let mut type_annotation = None;
1212    for part in inner {
1213        match part.as_rule() {
1214            Rule::type_param_list => {
1215                params = parse_type_param_list(part)?;
1216            }
1217            Rule::type_annotation => {
1218                type_annotation = Some(parse_type_annotation(part)?);
1219            }
1220            _ => {}
1221        }
1222    }
1223
1224    let type_annotation = type_annotation.ok_or_else(|| ShapeError::ParseError {
1225        message: format!("interface member '{}' missing type annotation", name),
1226        location: Some(pair_loc),
1227    })?;
1228
1229    if is_method {
1230        Ok(crate::ast::InterfaceMember::Method {
1231            name,
1232            optional,
1233            params,
1234            return_type: type_annotation,
1235            is_async: false,
1236            span,
1237            doc_comment,
1238        })
1239    } else {
1240        Ok(crate::ast::InterfaceMember::Property {
1241            name,
1242            optional,
1243            type_annotation,
1244            span,
1245            doc_comment,
1246        })
1247    }
1248}
1249
1250fn parse_interface_member_kind(raw: &str, name: &str) -> (bool, bool) {
1251    let trimmed = raw.trim_start();
1252    let Some(mut rest) = trimmed.strip_prefix(name) else {
1253        return (false, false);
1254    };
1255    rest = rest.trim_start();
1256    let mut optional = false;
1257    if rest.starts_with('?') {
1258        optional = true;
1259        rest = rest[1..].trim_start();
1260    }
1261    let is_method = rest.starts_with('(');
1262    (optional, is_method)
1263}
1264
1265fn parse_interface_index_signature(
1266    pair: Pair<Rule>,
1267    raw: &str,
1268    doc_comment: Option<crate::ast::DocComment>,
1269) -> Result<crate::ast::InterfaceMember> {
1270    let pair_loc = pair_location(&pair);
1271    let span = pair_span(&pair);
1272    let mut inner = pair.into_inner();
1273    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
1274        message: "expected index signature parameter name".to_string(),
1275        location: Some(pair_loc.clone()),
1276    })?;
1277    let param_name = name_pair.as_str().to_string();
1278
1279    let mut return_type = None;
1280    for part in inner {
1281        if part.as_rule() == Rule::type_annotation {
1282            return_type = Some(parse_type_annotation(part)?);
1283        }
1284    }
1285
1286    let return_type = return_type.ok_or_else(|| ShapeError::ParseError {
1287        message: "index signature missing return type".to_string(),
1288        location: Some(pair_loc.clone()),
1289    })?;
1290
1291    let param_type =
1292        parse_index_signature_param_type(raw).ok_or_else(|| ShapeError::ParseError {
1293            message: "index signature missing parameter type".to_string(),
1294            location: Some(pair_loc),
1295        })?;
1296
1297    Ok(crate::ast::InterfaceMember::IndexSignature {
1298        param_name,
1299        param_type,
1300        return_type,
1301        span,
1302        doc_comment,
1303    })
1304}
1305
1306fn attach_interface_member_doc_comment(
1307    member: &mut crate::ast::InterfaceMember,
1308    doc_comment: crate::ast::DocComment,
1309) {
1310    match member {
1311        crate::ast::InterfaceMember::Property {
1312            doc_comment: slot, ..
1313        }
1314        | crate::ast::InterfaceMember::Method {
1315            doc_comment: slot, ..
1316        }
1317        | crate::ast::InterfaceMember::IndexSignature {
1318            doc_comment: slot, ..
1319        } => *slot = Some(doc_comment),
1320    }
1321}
1322
1323fn parse_index_signature_param_type(raw: &str) -> Option<String> {
1324    let trimmed = raw.trim();
1325    let open = trimmed.find('[')?;
1326    let close = trimmed[open + 1..].find(']')? + open + 1;
1327    let inside = trimmed[open + 1..close].trim();
1328    let mut parts = inside.splitn(2, ':');
1329    parts.next()?;
1330    let param_type = parts.next()?.trim();
1331    if param_type == "string" || param_type == "number" {
1332        Some(param_type.to_string())
1333    } else {
1334        None
1335    }
1336}