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 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 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
400pub 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
440pub 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
471pub 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
503pub 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 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
561pub 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
633fn 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 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 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
700pub fn parse_type_alias_def(pair: Pair<Rule>) -> Result<crate::ast::TypeAliasDef> {
704 let mut inner = pair.into_inner();
705
706 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 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 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
748pub 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
916pub 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 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
1043fn 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
1068pub(crate) fn parse_method_def_shared(pair: Pair<Rule>) -> Result<crate::ast::types::MethodDef> {
1070 use crate::ast::types::MethodDef;
1071
1072 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 let return_type = type_annotation.unwrap_or_else(|| {
1218 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 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 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}