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