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