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