1use crate::ast::{Block, Expr, Generics, Ident, Param, TypeExpr, Visibility, WhereClause};
14use crate::lexer::Token;
15use crate::parser::{ParseError, ParseResult, Parser};
16use crate::span::Span;
17
18use super::ast::*;
19use super::lexer::{AlterSourceMarker, ForcedOperation, PluralityTokenStream};
20
21pub trait PluralityParser {
27 fn parse_plurality_item(&mut self) -> ParseResult<PluralityItem>;
29 fn parse_alter_def(&mut self, visibility: Visibility) -> ParseResult<AlterDef>;
30 fn parse_headspace_def(&mut self, visibility: Visibility) -> ParseResult<HeadspaceDef>;
31 fn parse_reality_def(&mut self, visibility: Visibility) -> ParseResult<RealityDef>;
32 fn parse_cocon_channel(&mut self) -> ParseResult<CoConChannel>;
33 fn parse_trigger_handler(&mut self) -> ParseResult<TriggerHandler>;
34
35 fn parse_plurality_expr(&mut self) -> ParseResult<PluralityExpr>;
37 fn parse_alter_block(&mut self) -> ParseResult<AlterBlock>;
38 fn parse_switch_expr(&mut self) -> ParseResult<SwitchExpr>;
39 fn parse_split_expr(&mut self) -> ParseResult<SplitExpr>;
40
41 fn parse_alter_sourced_type(&mut self) -> ParseResult<AlterSourcedType>;
43
44 fn parse_alter_expr(&mut self) -> ParseResult<AlterExpr>;
46 fn parse_alter_source(&mut self) -> ParseResult<Option<AlterSource>>;
47 fn try_parse_alter_source_marker(&mut self) -> Option<AlterSourceMarker>;
48}
49
50impl<'a> PluralityParser for Parser<'a> {
51 fn parse_plurality_item(&mut self) -> ParseResult<PluralityItem> {
57 let visibility = self.parse_visibility()?;
58
59 match self.current_token() {
60 Some(Token::Alter) => Ok(PluralityItem::Alter(self.parse_alter_def(visibility)?)),
61 Some(Token::Headspace) => Ok(PluralityItem::Headspace(
62 self.parse_headspace_def(visibility)?,
63 )),
64 Some(Token::Reality) => Ok(PluralityItem::Reality(self.parse_reality_def(visibility)?)),
65 Some(Token::CoCon) => Ok(PluralityItem::CoConChannel(self.parse_cocon_channel()?)),
66 Some(Token::On) => Ok(PluralityItem::TriggerHandler(self.parse_trigger_handler()?)),
67 Some(t) => Err(ParseError::UnexpectedToken {
68 expected: "plurality item (alter, headspace, reality, cocon, or trigger handler)"
69 .to_string(),
70 found: t.clone(),
71 span: self.current_span(),
72 }),
73 None => Err(ParseError::UnexpectedEof),
74 }
75 }
76
77 fn parse_alter_def(&mut self, visibility: Visibility) -> ParseResult<AlterDef> {
90 let start = self.current_span();
91
92 self.expect(Token::Alter)?;
94
95 let name = self.parse_ident()?;
97
98 let category = if self.consume_if(&Token::Colon) {
100 let cat_ident = self.parse_ident()?;
101 AlterCategory::from_ident(&cat_ident)
102 } else {
103 AlterCategory::Custom
104 };
105
106 let generics = self.parse_generics_opt()?;
108
109 let where_clause = self.parse_where_clause_opt()?;
111
112 self.expect(Token::LBrace)?;
114 let body = self.parse_alter_body()?;
115 self.expect(Token::RBrace)?;
116
117 let end = self.current_span();
118
119 Ok(AlterDef {
120 visibility,
121 attrs: Vec::new(),
122 name,
123 category,
124 generics,
125 where_clause,
126 body,
127 span: start.merge(end),
128 })
129 }
130
131 fn parse_headspace_def(&mut self, visibility: Visibility) -> ParseResult<HeadspaceDef> {
140 let start = self.current_span();
141
142 self.expect(Token::Headspace)?;
143 let name = self.parse_ident()?;
144
145 self.expect(Token::LBrace)?;
146
147 let mut locations = Vec::new();
148 let mut methods = Vec::new();
149
150 while !self.check(&Token::RBrace) && !self.is_eof() {
151 self.skip_comments();
152
153 if self.check(&Token::Location) {
154 locations.push(self.parse_location_def()?);
155 } else if self.check(&Token::Fn) || self.check(&Token::Async) {
156 methods.push(self.parse_alter_method()?);
157 } else if self.check(&Token::RBrace) {
158 break;
159 } else {
160 return Err(ParseError::UnexpectedToken {
161 expected: "location or method".to_string(),
162 found: self.current_token().cloned().unwrap_or(Token::RBrace),
163 span: self.current_span(),
164 });
165 }
166 }
167
168 self.expect(Token::RBrace)?;
169 let end = self.current_span();
170
171 Ok(HeadspaceDef {
172 visibility,
173 name,
174 locations,
175 methods,
176 span: start.merge(end),
177 })
178 }
179
180 fn parse_reality_def(&mut self, visibility: Visibility) -> ParseResult<RealityDef> {
190 let start = self.current_span();
191
192 self.expect(Token::Reality)?;
193 self.expect_ident("entity")?;
194 let name = self.parse_ident()?;
195
196 self.expect(Token::LBrace)?;
197
198 let mut layers = Vec::new();
199 let mut transforms = Vec::new();
200
201 while !self.check(&Token::RBrace) && !self.is_eof() {
202 self.skip_comments();
203
204 if self.check(&Token::Layer) {
205 layers.push(self.parse_reality_layer()?);
206 } else if self.check_ident("transform") {
207 transforms.push(self.parse_reality_transform()?);
208 } else if self.check(&Token::RBrace) {
209 break;
210 } else {
211 return Err(ParseError::UnexpectedToken {
212 expected: "layer or transform".to_string(),
213 found: self.current_token().cloned().unwrap_or(Token::RBrace),
214 span: self.current_span(),
215 });
216 }
217 }
218
219 self.expect(Token::RBrace)?;
220 let end = self.current_span();
221
222 Ok(RealityDef {
223 visibility,
224 name,
225 layers,
226 transforms,
227 span: start.merge(end),
228 })
229 }
230
231 fn parse_cocon_channel(&mut self) -> ParseResult<CoConChannel> {
239 let start = self.current_span();
240
241 self.expect(Token::CoCon)?;
242 self.expect(Token::Lt)?;
243
244 let mut participants = Vec::new();
246 participants.push(self.parse_ident()?);
247 while self.consume_if(&Token::Comma) {
248 if self.check(&Token::Gt) {
249 break;
250 }
251 participants.push(self.parse_ident()?);
252 }
253 self.expect_gt()?;
254
255 let name = self.parse_ident()?;
256 let body = self.parse_block()?;
257 let end = self.current_span();
258
259 Ok(CoConChannel {
260 participants,
261 name,
262 body,
263 span: start.merge(end),
264 })
265 }
266
267 fn parse_trigger_handler(&mut self) -> ParseResult<TriggerHandler> {
275 let start = self.current_span();
276
277 self.expect(Token::On)?;
278 self.expect(Token::Trigger)?;
279
280 let pattern = self.parse_trigger_pattern()?;
282
283 let guard = if self.consume_if(&Token::Where) {
285 Some(self.parse_expr()?)
286 } else {
287 None
288 };
289
290 let body = self.parse_block()?;
292 let end = self.current_span();
293
294 Ok(TriggerHandler {
295 pattern,
296 guard,
297 body,
298 span: start.merge(end),
299 })
300 }
301
302 fn parse_plurality_expr(&mut self) -> ParseResult<PluralityExpr> {
308 match self.current_token() {
309 Some(Token::Alter) => Ok(PluralityExpr::AlterBlock(self.parse_alter_block()?)),
310 Some(Token::Switch) => Ok(PluralityExpr::Switch(self.parse_switch_expr()?)),
311 Some(Token::Split) => Ok(PluralityExpr::Split(self.parse_split_expr()?)),
312 Some(t) => Err(ParseError::UnexpectedToken {
313 expected: "plurality expression (alter, switch, or split)".to_string(),
314 found: t.clone(),
315 span: self.current_span(),
316 }),
317 None => Err(ParseError::UnexpectedEof),
318 }
319 }
320
321 fn parse_alter_block(&mut self) -> ParseResult<AlterBlock> {
329 let start = self.current_span();
330
331 self.expect(Token::Alter)?;
332 let alter = self.parse_alter_expr()?;
333 let body = self.parse_block()?;
334 let end = self.current_span();
335
336 Ok(AlterBlock {
337 alter,
338 body,
339 span: start.merge(end),
340 })
341 }
342
343 fn parse_switch_expr(&mut self) -> ParseResult<SwitchExpr> {
354 let start = self.current_span();
355
356 self.expect(Token::Switch)?;
357
358 let forced = self.consume_if(&Token::Bang);
360
361 self.expect(Token::To)?;
362 let target = self.parse_alter_expr()?;
363
364 let config = if self.check(&Token::LBrace) {
366 self.parse_switch_config()?
367 } else {
368 SwitchConfig::default()
369 };
370
371 let end = self.current_span();
372
373 Ok(SwitchExpr {
374 forced,
375 target,
376 config,
377 span: start.merge(end),
378 })
379 }
380
381 fn parse_split_expr(&mut self) -> ParseResult<SplitExpr> {
391 let start = self.current_span();
392
393 self.expect(Token::Split)?;
394 self.expect(Token::Bang)?; self.expect(Token::From)?;
396
397 let parent = self.parse_alter_expr()?;
398 let config = self.parse_split_config()?;
399 let end = self.current_span();
400
401 Ok(SplitExpr {
402 parent,
403 config,
404 span: start.merge(end),
405 })
406 }
407
408 fn parse_alter_sourced_type(&mut self) -> ParseResult<AlterSourcedType> {
421 let start = self.current_span();
422 let inner = self.parse_type()?;
423
424 if let Some(marker) = self.try_parse_alter_source_marker() {
426 let end = self.current_span();
427 let alter_source = match marker {
428 AlterSourceMarker::Fronting => AlterSource::Fronting,
429 AlterSourceMarker::CoCon => AlterSource::CoConscious(None),
430 AlterSourceMarker::Dormant => AlterSource::Dormant(None),
431 AlterSourceMarker::Blended => AlterSource::Blended(Vec::new()),
432 };
433
434 Ok(AlterSourcedType {
435 inner,
436 alter_source,
437 span: start.merge(end),
438 })
439 } else {
440 let end = self.current_span();
442 Ok(AlterSourcedType {
443 inner,
444 alter_source: AlterSource::Fronting,
445 span: start.merge(end),
446 })
447 }
448 }
449
450 fn parse_alter_expr(&mut self) -> ParseResult<AlterExpr> {
456 match self.current_token() {
457 Some(Token::Ident(_)) => {
458 let ident = self.parse_ident()?;
459
460 if self.check(&Token::MiddleDot) {
462 self.advance();
463 let method = self.parse_ident()?;
464 if self.check(&Token::LParen) {
465 self.advance(); let mut args = Vec::new();
468 while !self.check(&Token::RParen) && !self.is_eof() {
469 args.push(self.parse_expr()?);
470 if !self.consume_if(&Token::Comma) {
471 break;
472 }
473 }
474 self.expect(Token::RParen)?;
475
476 let receiver_path = crate::ast::TypePath {
478 segments: vec![crate::ast::PathSegment {
479 ident: ident.clone(),
480 generics: None,
481 }],
482 };
483 let call_expr = Expr::MethodCall {
484 receiver: Box::new(Expr::Path(receiver_path)),
485 method,
486 type_args: None,
487 args,
488 };
489 return Ok(AlterExpr::CurrentFronter(Box::new(call_expr)));
490 }
491 let combined_path = crate::ast::TypePath {
493 segments: vec![crate::ast::PathSegment {
494 ident: Ident {
495 name: format!("{}.{}", ident.name, method.name),
496 evidentiality: None,
497 affect: None,
498 span: ident.span.merge(method.span),
499 },
500 generics: None,
501 }],
502 };
503 return Ok(AlterExpr::Expr(Box::new(Expr::Path(combined_path))));
504 }
505
506 Ok(AlterExpr::Named(ident))
507 }
508 Some(_) => {
509 let expr = self.parse_expr()?;
511 Ok(AlterExpr::Expr(Box::new(expr)))
512 }
513 None => Err(ParseError::UnexpectedEof),
514 }
515 }
516
517 fn parse_alter_source(&mut self) -> ParseResult<Option<AlterSource>> {
519 if !self.check(&Token::At) {
520 return Ok(None);
521 }
522
523 self.advance(); match self.current_token() {
526 Some(Token::Bang) => {
527 self.advance();
528 Ok(Some(AlterSource::Fronting))
529 }
530 Some(Token::Tilde) => {
531 self.advance();
532 Ok(Some(AlterSource::CoConscious(None)))
533 }
534 Some(Token::Question) => {
535 self.advance();
536 Ok(Some(AlterSource::Dormant(None)))
537 }
538 Some(Token::Interrobang) => {
539 self.advance();
540 Ok(Some(AlterSource::Blended(Vec::new())))
541 }
542 Some(Token::Ident(_)) => {
543 let ident = self.parse_ident()?;
544 match ident.name.as_str() {
545 "Fronting" => Ok(Some(AlterSource::Fronting)),
546 "CoCon" => Ok(Some(AlterSource::CoConscious(None))),
547 "Dormant" => Ok(Some(AlterSource::Dormant(None))),
548 "Blended" => Ok(Some(AlterSource::Blended(Vec::new()))),
549 _ => Ok(Some(AlterSource::Named(ident))),
550 }
551 }
552 _ => Ok(None),
553 }
554 }
555
556 fn try_parse_alter_source_marker(&mut self) -> Option<AlterSourceMarker> {
558 if !self.check(&Token::At) {
559 return None;
560 }
561
562 let next = self.peek_next()?;
564 let marker = match next {
565 Token::Bang => Some(AlterSourceMarker::Fronting),
566 Token::Tilde => Some(AlterSourceMarker::CoCon),
567 Token::Question => Some(AlterSourceMarker::Dormant),
568 Token::Interrobang => Some(AlterSourceMarker::Blended),
569 _ => None,
570 };
571
572 if marker.is_some() {
573 self.advance(); self.advance(); }
576
577 marker
578 }
579}
580
581impl<'a> Parser<'a> {
586 fn check_ident(&self, name: &str) -> bool {
588 matches!(self.current_token(), Some(Token::Ident(s)) if s == name)
589 }
590
591 fn expect_ident(&mut self, name: &str) -> ParseResult<Span> {
593 match self.current_token() {
594 Some(Token::Ident(s)) if s == name => {
595 let span = self.current_span();
596 self.advance();
597 Ok(span)
598 }
599 Some(t) => Err(ParseError::UnexpectedToken {
600 expected: format!("identifier '{}'", name),
601 found: t.clone(),
602 span: self.current_span(),
603 }),
604 None => Err(ParseError::UnexpectedEof),
605 }
606 }
607
608 fn parse_alter_body(&mut self) -> ParseResult<AlterBody> {
610 let mut body = AlterBody {
611 archetype: None,
612 preferred_reality: None,
613 abilities: Vec::new(),
614 triggers: Vec::new(),
615 anima: None,
616 states: None,
617 special: Vec::new(),
618 methods: Vec::new(),
619 types: Vec::new(),
620 };
621
622 while !self.check(&Token::RBrace) && !self.is_eof() {
623 self.skip_comments();
624
625 match self.current_token() {
626 Some(Token::Anima) => {
628 self.advance();
629 self.expect(Token::Colon)?;
630 body.anima = Some(self.parse_anima_config()?);
631 self.consume_if(&Token::Comma);
632 }
633 Some(Token::States) => {
634 self.advance();
635 self.expect(Token::Colon)?;
636 body.states = Some(self.parse_alter_state_machine()?);
637 self.consume_if(&Token::Comma);
638 }
639 Some(Token::Ident(s)) => match s.as_str() {
641 "archetype" => {
642 self.advance();
643 self.expect(Token::Colon)?;
644 body.archetype = Some(self.parse_expr()?);
645 self.consume_if(&Token::Comma);
646 }
647 "preferred_reality" => {
648 self.advance();
649 self.expect(Token::Colon)?;
650 body.preferred_reality = Some(self.parse_expr()?);
651 self.consume_if(&Token::Comma);
652 }
653 "abilities" => {
654 self.advance();
655 self.expect(Token::Colon)?;
656 body.abilities = self.parse_bracketed_expr_list()?;
657 self.consume_if(&Token::Comma);
658 }
659 "triggers" => {
660 self.advance();
661 self.expect(Token::Colon)?;
662 body.triggers = self.parse_bracketed_expr_list()?;
663 self.consume_if(&Token::Comma);
664 }
665 _ => {
666 return Err(ParseError::UnexpectedToken {
668 expected: "alter body field".to_string(),
669 found: Token::Ident(s.clone()),
670 span: self.current_span(),
671 });
672 }
673 },
674 Some(Token::Fn) | Some(Token::Async) => {
675 body.methods.push(self.parse_alter_method()?);
676 }
677 Some(Token::Type) => {
678 body.types.push(self.parse_alter_type_alias()?);
679 }
680 Some(Token::RBrace) => break,
681 Some(t) => {
682 return Err(ParseError::UnexpectedToken {
683 expected: "alter body field or method".to_string(),
684 found: t.clone(),
685 span: self.current_span(),
686 });
687 }
688 None => return Err(ParseError::UnexpectedEof),
689 }
690 }
691
692 Ok(body)
693 }
694
695 fn parse_anima_config(&mut self) -> ParseResult<AnimaConfig> {
697 self.expect(Token::LBrace)?;
698
699 let mut config = AnimaConfig {
700 base_arousal: None,
701 base_dominance: None,
702 expressiveness: None,
703 susceptibility: None,
704 extra: Vec::new(),
705 };
706
707 while !self.check(&Token::RBrace) && !self.is_eof() {
708 self.skip_comments();
709
710 let field_name = self.parse_ident()?;
711 self.expect(Token::Colon)?;
712 let value = self.parse_expr()?;
713
714 match field_name.name.as_str() {
715 "base_arousal" => config.base_arousal = Some(value),
716 "base_dominance" => config.base_dominance = Some(value),
717 "expressiveness" => config.expressiveness = Some(value),
718 "susceptibility" => config.susceptibility = Some(value),
719 _ => config.extra.push((field_name, value)),
720 }
721
722 self.consume_if(&Token::Comma);
723 }
724
725 self.expect(Token::RBrace)?;
726 Ok(config)
727 }
728
729 fn parse_alter_state_machine(&mut self) -> ParseResult<AlterStateMachine> {
731 self.expect(Token::LBrace)?;
732
733 let mut transitions = Vec::new();
734
735 while !self.check(&Token::RBrace) && !self.is_eof() {
736 self.skip_comments();
737 transitions.push(self.parse_alter_transition()?);
738 self.consume_if(&Token::Comma);
739 }
740
741 self.expect(Token::RBrace)?;
742 Ok(AlterStateMachine { transitions })
743 }
744
745 fn parse_alter_transition(&mut self) -> ParseResult<AlterTransition> {
748 let from_ident = self.parse_ident()?;
749 let from = AlterState::from_ident(&from_ident);
750
751 self.expect(Token::Arrow)?;
752
753 let to_ident = self.parse_ident()?;
754 let to = AlterState::from_ident(&to_ident);
755
756 self.expect(Token::Colon)?;
757 self.expect(Token::On)?;
758
759 let on = self.parse_expr()?;
760
761 let guard = if self.check(&Token::Where) {
763 self.advance();
764 Some(self.parse_expr()?)
765 } else {
766 None
767 };
768
769 let action = if self.check(&Token::LBrace) {
771 Some(self.parse_block()?)
772 } else {
773 None
774 };
775
776 Ok(AlterTransition {
777 from,
778 to,
779 on,
780 guard,
781 action,
782 })
783 }
784
785 fn parse_alter_method(&mut self) -> ParseResult<AlterMethod> {
787 let visibility = self.parse_visibility()?;
788 let is_async = self.consume_if(&Token::Async);
789 self.expect(Token::Fn)?;
790 let name = self.parse_ident()?;
791
792 self.expect(Token::LParen)?;
793 let params = self.parse_params()?;
794 self.expect(Token::RParen)?;
795
796 let return_type = if self.consume_if(&Token::Arrow) {
797 Some(self.parse_type()?)
798 } else {
799 None
800 };
801
802 let body = if self.check(&Token::LBrace) {
803 Some(self.parse_block()?)
804 } else {
805 self.consume_if(&Token::Semi);
806 None
807 };
808
809 Ok(AlterMethod {
810 visibility,
811 is_async,
812 name,
813 params,
814 return_type,
815 body,
816 })
817 }
818
819 fn parse_alter_type_alias(&mut self) -> ParseResult<AlterTypeAlias> {
821 let visibility = self.parse_visibility()?;
822 self.expect(Token::Type)?;
823 let name = self.parse_ident()?;
824 self.expect(Token::Eq)?;
825 let ty = self.parse_type()?;
826 self.consume_if(&Token::Semi);
827
828 Ok(AlterTypeAlias {
829 visibility,
830 name,
831 ty,
832 })
833 }
834
835 fn parse_location_def(&mut self) -> ParseResult<LocationDef> {
837 self.expect(Token::Location)?;
838 let name = self.parse_ident()?;
839 self.expect(Token::Colon)?;
840 let location_type = self.parse_ident()?;
841
842 self.expect(Token::LBrace)?;
843
844 let mut fields = Vec::new();
845 let mut connections = Vec::new();
846 let mut hazards = Vec::new();
847
848 while !self.check(&Token::RBrace) && !self.is_eof() {
849 self.skip_comments();
850
851 let field_name = self.parse_ident()?;
852 self.expect(Token::Colon)?;
853
854 match field_name.name.as_str() {
855 "connections" => {
856 self.expect(Token::LBracket)?;
858 while !self.check(&Token::RBracket) {
859 connections.push(self.parse_stream_def()?);
860 self.consume_if(&Token::Comma);
861 }
862 self.expect(Token::RBracket)?;
863 }
864 "hazards" => {
865 hazards = self.parse_bracketed_expr_list()?;
866 }
867 _ => {
868 let value = self.parse_expr()?;
869 fields.push((field_name, value));
870 }
871 }
872
873 self.consume_if(&Token::Comma);
874 }
875
876 self.expect(Token::RBrace)?;
877
878 Ok(LocationDef {
879 name,
880 location_type,
881 fields,
882 connections,
883 hazards,
884 })
885 }
886
887 fn parse_stream_def(&mut self) -> ParseResult<StreamDef> {
890 let target = self.parse_ident()?;
892
893 let mut bidirectional = false;
894 let mut locked = false;
895 let mut content = None;
896
897 if self.consume_if(&Token::Comma) {
899 while !self.check(&Token::RParen)
900 && !self.check(&Token::RBracket)
901 && !self.check(&Token::Comma)
902 && !self.is_eof()
903 {
904 let opt_name = self.parse_ident()?;
905 self.expect(Token::Colon)?;
906
907 match opt_name.name.as_str() {
908 "bidirectional" => {
909 bidirectional = self.consume_if(&Token::True);
910 if !bidirectional {
911 self.consume_if(&Token::False);
912 }
913 }
914 "locked" => {
915 locked = self.consume_if(&Token::True);
916 if !locked {
917 self.consume_if(&Token::False);
918 }
919 }
920 "content" => {
921 content = Some(self.parse_expr()?);
922 }
923 _ => {}
924 }
925
926 if !self.consume_if(&Token::Comma) {
927 break;
928 }
929 }
930 }
931
932 Ok(StreamDef {
933 target,
934 content,
935 bidirectional,
936 locked,
937 })
938 }
939
940 fn parse_reality_layer(&mut self) -> ParseResult<RealityLayer> {
942 self.expect(Token::Layer)?;
943 let name = self.parse_ident()?;
944
945 self.expect(Token::LBrace)?;
946
947 let mut fields = Vec::new();
948
949 while !self.check(&Token::RBrace) && !self.is_eof() {
950 self.skip_comments();
951
952 let field_name = self.parse_ident()?;
953 self.expect(Token::Colon)?;
954 let value = self.parse_expr()?;
955 fields.push((field_name, value));
956
957 self.consume_if(&Token::Comma);
958 }
959
960 self.expect(Token::RBrace)?;
961
962 Ok(RealityLayer { name, fields })
963 }
964
965 fn parse_reality_transform(&mut self) -> ParseResult<RealityTransform> {
967 self.expect_ident("transform")?;
968 let from = self.parse_ident()?;
969 self.expect(Token::Arrow)?;
970 let to = self.parse_ident()?;
971 self.expect(Token::Colon)?;
972 self.expect(Token::On)?;
973 let condition = self.parse_expr()?;
974 self.consume_if(&Token::Comma);
975
976 Ok(RealityTransform {
977 from,
978 to,
979 condition,
980 })
981 }
982
983 fn parse_switch_config(&mut self) -> ParseResult<SwitchConfig> {
985 self.expect(Token::LBrace)?;
986
987 let mut config = SwitchConfig {
988 reason: None,
989 urgency: None,
990 requires: None,
991 then_block: None,
992 else_block: None,
993 emergency_block: None,
994 bypass_deliberation: false,
995 };
996
997 while !self.check(&Token::RBrace) && !self.is_eof() {
998 self.skip_comments();
999
1000 let field_name = self.parse_ident()?;
1001 self.expect(Token::Colon)?;
1002
1003 match field_name.name.as_str() {
1004 "reason" => config.reason = Some(self.parse_expr()?),
1005 "urgency" => config.urgency = Some(self.parse_expr()?),
1006 "requires" => config.requires = Some(self.parse_expr()?),
1007 "then" => config.then_block = Some(self.parse_block()?),
1008 "else" => config.else_block = Some(self.parse_block()?),
1009 "emergency" => config.emergency_block = Some(self.parse_block()?),
1010 "bypass_deliberation" => {
1011 config.bypass_deliberation = self.consume_if(&Token::True);
1012 if !config.bypass_deliberation {
1013 self.consume_if(&Token::False);
1014 }
1015 }
1016 _ => {
1017 let _ = self.parse_expr()?;
1019 }
1020 }
1021
1022 self.consume_if(&Token::Comma);
1023 }
1024
1025 self.expect(Token::RBrace)?;
1026 Ok(config)
1027 }
1028
1029 fn parse_split_config(&mut self) -> ParseResult<SplitConfig> {
1031 self.expect(Token::LBrace)?;
1032
1033 let mut config = SplitConfig {
1034 purpose: None,
1035 memories: None,
1036 traits: None,
1037 extra: Vec::new(),
1038 };
1039
1040 while !self.check(&Token::RBrace) && !self.is_eof() {
1041 self.skip_comments();
1042
1043 let field_name = self.parse_ident()?;
1044 self.expect(Token::Colon)?;
1045 let value = self.parse_expr()?;
1046
1047 match field_name.name.as_str() {
1048 "purpose" => config.purpose = Some(value),
1049 "memories" => config.memories = Some(value),
1050 "traits" => config.traits = Some(value),
1051 _ => config.extra.push((field_name, value)),
1052 }
1053
1054 self.consume_if(&Token::Comma);
1055 }
1056
1057 self.expect(Token::RBrace)?;
1058 Ok(config)
1059 }
1060
1061 fn parse_trigger_pattern(&mut self) -> ParseResult<TriggerPattern> {
1063 let trigger_type = self.parse_ident()?;
1064
1065 let mut fields = Vec::new();
1066
1067 if self.consume_if(&Token::LBrace) {
1068 while !self.check(&Token::RBrace) && !self.is_eof() {
1069 let field_name = self.parse_ident()?;
1070 self.expect(Token::Colon)?;
1071 let binding = self.parse_ident()?;
1072 fields.push((field_name, binding));
1073
1074 if !self.consume_if(&Token::Comma) {
1075 break;
1076 }
1077 }
1078 self.expect(Token::RBrace)?;
1079 }
1080
1081 Ok(TriggerPattern {
1082 trigger_type,
1083 fields,
1084 })
1085 }
1086
1087 fn parse_bracketed_expr_list(&mut self) -> ParseResult<Vec<Expr>> {
1089 self.expect(Token::LBracket)?;
1090
1091 let mut exprs = Vec::new();
1092
1093 while !self.check(&Token::RBracket) && !self.is_eof() {
1094 exprs.push(self.parse_expr()?);
1095 if !self.consume_if(&Token::Comma) {
1096 break;
1097 }
1098 }
1099
1100 self.expect(Token::RBracket)?;
1101 Ok(exprs)
1102 }
1103}
1104
1105impl Default for SwitchConfig {
1110 fn default() -> Self {
1111 Self {
1112 reason: None,
1113 urgency: None,
1114 requires: None,
1115 then_block: None,
1116 else_block: None,
1117 emergency_block: None,
1118 bypass_deliberation: false,
1119 }
1120 }
1121}
1122
1123#[cfg(test)]
1128mod tests {
1129 use super::*;
1130
1131 fn parse_plurality(source: &str) -> ParseResult<PluralityItem> {
1132 let mut parser = Parser::new(source);
1133 parser.parse_plurality_item()
1134 }
1135
1136 #[test]
1137 fn test_parse_alter_def_basic() {
1138 let source = r#"
1139 alter Abaddon: Council {
1140 archetype: Goetia::Abaddon,
1141 }
1142 "#;
1143 let result = parse_plurality(source);
1144 assert!(result.is_ok());
1145 if let Ok(PluralityItem::Alter(def)) = result {
1146 assert_eq!(def.name.name, "Abaddon");
1147 assert_eq!(def.category, AlterCategory::Council);
1148 }
1149 }
1150
1151 #[test]
1152 fn test_parse_switch_expr() {
1153 let source = r#"
1154 alter test {
1155 switch to Beleth {
1156 reason: SwitchReason::Combat,
1157 urgency: 0.8,
1158 }
1159 }
1160 "#;
1161 }
1163}