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<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
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 => TypeAnnotation::Basic(other.to_string()),
140 })
141}
142
143pub 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
158pub 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
197pub 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
225pub 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
236pub 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(¶m_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
362pub 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
402pub 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
433pub 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
465pub 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 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
523pub 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
595fn 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 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 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
662pub fn parse_type_alias_def(pair: Pair<Rule>) -> Result<crate::ast::TypeAliasDef> {
666 let mut inner = pair.into_inner();
667
668 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 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 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
710pub 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
878pub 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
914pub 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 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
1027fn 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
1052pub(crate) fn parse_method_def_shared(pair: Pair<Rule>) -> Result<crate::ast::types::MethodDef> {
1054 use crate::ast::types::MethodDef;
1055
1056 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}