1use std::{
17 cell::{Ref, RefCell},
18 collections::{BTreeSet, HashMap, HashSet},
19 fmt::{Display, Formatter}
20};
21
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Serialize};
24
25#[cfg(doc)]
26use crate::{Evaluator, Function, RollingRecord};
27
28#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub struct RollRange
36{
37 pub dest: RollingRecordIndex,
39
40 pub start: AddressingMode,
42
43 pub end: AddressingMode
45}
46
47impl Display for RollRange
48{
49 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
50 {
51 write!(f, "{} <- roll range {}:{}", self.dest, self.start, self.end)
52 }
53}
54
55#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58pub struct RollStandardDice
59{
60 pub dest: RollingRecordIndex,
62
63 pub count: AddressingMode,
65
66 pub faces: AddressingMode
68}
69
70impl Display for RollStandardDice
71{
72 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
73 {
74 write!(
75 f,
76 "{} <- roll standard dice {}D{}",
77 self.dest, self.count, self.faces
78 )
79 }
80}
81
82#[derive(Debug, Clone, Hash, PartialEq, Eq)]
84#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
85pub struct RollCustomDice
86{
87 pub dest: RollingRecordIndex,
89
90 pub count: AddressingMode,
92
93 pub faces: Vec<i32>
95}
96
97impl RollCustomDice
98{
99 pub fn distinct_faces(&self) -> usize
104 {
105 self.faces.iter().collect::<HashSet<_>>().len()
106 }
107}
108
109impl Display for RollCustomDice
110{
111 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
112 {
113 write!(f, "{} <- roll custom dice {}D[", self.dest, self.count)?;
114 let mut first = true;
115 for face in &self.faces
116 {
117 if !first
118 {
119 write!(f, ", ")?;
120 }
121 write!(f, "{}", face)?;
122 first = false;
123 }
124 write!(f, "]")
125 }
126}
127
128#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
134#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
135pub struct DropLowest
136{
137 pub dest: RollingRecordIndex,
139
140 pub count: AddressingMode
142}
143
144impl Display for DropLowest
145{
146 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
147 {
148 write!(
149 f,
150 "{} <- drop lowest {} from {}",
151 self.dest, self.count, self.dest
152 )
153 }
154}
155
156#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
162#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
163pub struct DropHighest
164{
165 pub dest: RollingRecordIndex,
167
168 pub count: AddressingMode
170}
171
172impl Display for DropHighest
173{
174 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
175 {
176 write!(
177 f,
178 "{} <- drop highest {} from {}",
179 self.dest, self.count, self.dest
180 )
181 }
182}
183
184#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
188#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
189pub struct SumRollingRecord
190{
191 pub dest: RegisterIndex,
193
194 pub src: RollingRecordIndex
196}
197
198impl Display for SumRollingRecord
199{
200 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
201 {
202 write!(f, "{} <- sum rolling record {}", self.dest, self.src)
203 }
204}
205
206#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
209pub struct Add
210{
211 pub dest: RegisterIndex,
213
214 pub op1: AddressingMode,
216
217 pub op2: AddressingMode
219}
220
221impl Display for Add
222{
223 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
224 {
225 write!(f, "{} <- {} + {}", self.dest, self.op1, self.op2)
226 }
227}
228
229#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232pub struct Sub
233{
234 pub dest: RegisterIndex,
236
237 pub op1: AddressingMode,
239
240 pub op2: AddressingMode
242}
243
244impl Display for Sub
245{
246 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
247 {
248 write!(f, "{} <- {} - {}", self.dest, self.op1, self.op2)
249 }
250}
251
252#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
254#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
255pub struct Mul
256{
257 pub dest: RegisterIndex,
259
260 pub op1: AddressingMode,
262
263 pub op2: AddressingMode
265}
266
267impl Display for Mul
268{
269 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
270 {
271 write!(f, "{} <- {} * {}", self.dest, self.op1, self.op2)
272 }
273}
274
275#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
278#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
279pub struct Div
280{
281 pub dest: RegisterIndex,
283
284 pub op1: AddressingMode,
286
287 pub op2: AddressingMode
289}
290
291impl Display for Div
292{
293 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
294 {
295 write!(f, "{} <- {} / {}", self.dest, self.op1, self.op2)
296 }
297}
298
299#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
302#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
303pub struct Mod
304{
305 pub dest: RegisterIndex,
307
308 pub op1: AddressingMode,
310
311 pub op2: AddressingMode
313}
314
315impl Display for Mod
316{
317 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
318 {
319 write!(f, "{} <- {} % {}", self.dest, self.op1, self.op2)
320 }
321}
322
323#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
326#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
327pub struct Exp
328{
329 pub dest: RegisterIndex,
331
332 pub op1: AddressingMode,
334
335 pub op2: AddressingMode
337}
338
339impl Display for Exp
340{
341 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
342 {
343 write!(f, "{} <- {} ^ {}", self.dest, self.op1, self.op2)
344 }
345}
346
347#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
349#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
350pub struct Neg
351{
352 pub dest: RegisterIndex,
354
355 pub op: AddressingMode
357}
358
359impl Display for Neg
360{
361 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
362 {
363 write!(f, "{} <- -{}", self.dest, self.op)
364 }
365}
366
367#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
369#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
370pub struct Return
371{
372 pub src: AddressingMode
374}
375
376impl Display for Return
377{
378 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
379 {
380 write!(f, "return {}", self.src)
381 }
382}
383
384#[derive(Debug, Clone, Hash, PartialEq, Eq)]
386#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
387pub enum Instruction
388{
389 RollRange(RollRange),
390 RollStandardDice(RollStandardDice),
391 RollCustomDice(RollCustomDice),
392 DropLowest(DropLowest),
393 DropHighest(DropHighest),
394 SumRollingRecord(SumRollingRecord),
395 Add(Add),
396 Sub(Sub),
397 Mul(Mul),
398 Div(Div),
399 Mod(Mod),
400 Exp(Exp),
401 Neg(Neg),
402 Return(Return)
403}
404
405impl Instruction
406{
407 pub fn destination(&self) -> Option<AddressingMode>
412 {
413 match self
414 {
415 Self::RollRange(inst) => Some(inst.dest.into()),
416 Self::RollStandardDice(inst) => Some(inst.dest.into()),
417 Self::RollCustomDice(inst) => Some(inst.dest.into()),
418 Self::DropLowest(inst) => Some(inst.dest.into()),
419 Self::DropHighest(inst) => Some(inst.dest.into()),
420 Self::SumRollingRecord(inst) => Some(inst.dest.into()),
421 Self::Add(inst) => Some(inst.dest.into()),
422 Self::Sub(inst) => Some(inst.dest.into()),
423 Self::Mul(inst) => Some(inst.dest.into()),
424 Self::Div(inst) => Some(inst.dest.into()),
425 Self::Mod(inst) => Some(inst.dest.into()),
426 Self::Exp(inst) => Some(inst.dest.into()),
427 Self::Neg(inst) => Some(inst.dest.into()),
428 Self::Return(_) => None
429 }
430 }
431
432 pub fn sources(&self) -> Vec<AddressingMode>
437 {
438 match self
439 {
440 Self::RollRange(inst) => vec![inst.start, inst.end],
441 Self::RollStandardDice(inst) => vec![inst.count, inst.faces],
442 Self::RollCustomDice(inst) => vec![inst.count],
443 Self::DropLowest(inst) => vec![inst.dest.into(), inst.count],
444 Self::DropHighest(inst) => vec![inst.dest.into(), inst.count],
445 Self::SumRollingRecord(inst) => vec![inst.src.into()],
446 Self::Add(inst) => vec![inst.op1, inst.op2],
447 Self::Sub(inst) => vec![inst.op1, inst.op2],
448 Self::Mul(inst) => vec![inst.op1, inst.op2],
449 Self::Div(inst) => vec![inst.op1, inst.op2],
450 Self::Mod(inst) => vec![inst.op1, inst.op2],
451 Self::Exp(inst) => vec![inst.op1, inst.op2],
452 Self::Neg(inst) => vec![inst.op],
453 Self::Return(inst) => vec![inst.src]
454 }
455 }
456
457 #[inline]
467 pub const fn roll_range(
468 dest: RollingRecordIndex,
469 start: AddressingMode,
470 end: AddressingMode
471 ) -> Self
472 {
473 Self::RollRange(RollRange { dest, start, end })
474 }
475
476 #[inline]
486 pub const fn roll_standard_dice(
487 dest: RollingRecordIndex,
488 count: AddressingMode,
489 faces: AddressingMode
490 ) -> Self
491 {
492 Self::RollStandardDice(RollStandardDice { dest, count, faces })
493 }
494
495 #[inline]
505 pub const fn roll_custom_dice(
506 dest: RollingRecordIndex,
507 count: AddressingMode,
508 faces: Vec<i32>
509 ) -> Self
510 {
511 Self::RollCustomDice(RollCustomDice { dest, count, faces })
512 }
513
514 #[inline]
523 pub const fn drop_lowest(
524 dest: RollingRecordIndex,
525 count: AddressingMode
526 ) -> Self
527 {
528 Self::DropLowest(DropLowest { dest, count })
529 }
530
531 #[inline]
540 pub const fn drop_highest(
541 dest: RollingRecordIndex,
542 count: AddressingMode
543 ) -> Self
544 {
545 Self::DropHighest(DropHighest { dest, count })
546 }
547
548 #[inline]
557 pub const fn sum_rolling_record(
558 dest: RegisterIndex,
559 src: RollingRecordIndex
560 ) -> Self
561 {
562 Self::SumRollingRecord(SumRollingRecord { dest, src })
563 }
564
565 #[inline]
575 pub const fn add(
576 dest: RegisterIndex,
577 op1: AddressingMode,
578 op2: AddressingMode
579 ) -> Self
580 {
581 Self::Add(Add { dest, op1, op2 })
582 }
583
584 #[inline]
594 pub const fn sub(
595 dest: RegisterIndex,
596 op1: AddressingMode,
597 op2: AddressingMode
598 ) -> Self
599 {
600 Self::Sub(Sub { dest, op1, op2 })
601 }
602
603 #[inline]
613 pub const fn mul(
614 dest: RegisterIndex,
615 op1: AddressingMode,
616 op2: AddressingMode
617 ) -> Self
618 {
619 Self::Mul(Mul { dest, op1, op2 })
620 }
621
622 #[inline]
632 pub const fn div(
633 dest: RegisterIndex,
634 op1: AddressingMode,
635 op2: AddressingMode
636 ) -> Self
637 {
638 Self::Div(Div { dest, op1, op2 })
639 }
640
641 #[inline]
651 pub const fn r#mod(
652 dest: RegisterIndex,
653 op1: AddressingMode,
654 op2: AddressingMode
655 ) -> Self
656 {
657 Self::Mod(Mod { dest, op1, op2 })
658 }
659
660 #[inline]
670 pub const fn exp(
671 dest: RegisterIndex,
672 op1: AddressingMode,
673 op2: AddressingMode
674 ) -> Self
675 {
676 Self::Exp(Exp { dest, op1, op2 })
677 }
678
679 #[inline]
688 pub const fn neg(dest: RegisterIndex, op: AddressingMode) -> Self
689 {
690 Self::Neg(Neg { dest, op })
691 }
692
693 #[inline]
701 pub const fn r#return(src: AddressingMode) -> Self
702 {
703 Self::Return(Return { src })
704 }
705}
706
707impl Display for Instruction
708{
709 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
710 {
711 match self
712 {
713 Self::RollRange(inst) => write!(f, "{}", inst),
714 Self::RollStandardDice(inst) => write!(f, "{}", inst),
715 Self::RollCustomDice(inst) => write!(f, "{}", inst),
716 Self::DropLowest(inst) => write!(f, "{}", inst),
717 Self::DropHighest(inst) => write!(f, "{}", inst),
718 Self::SumRollingRecord(inst) => write!(f, "{}", inst),
719 Self::Add(inst) => write!(f, "{}", inst),
720 Self::Sub(inst) => write!(f, "{}", inst),
721 Self::Mul(inst) => write!(f, "{}", inst),
722 Self::Div(inst) => write!(f, "{}", inst),
723 Self::Mod(inst) => write!(f, "{}", inst),
724 Self::Exp(inst) => write!(f, "{}", inst),
725 Self::Neg(inst) => write!(f, "{}", inst),
726 Self::Return(inst) => write!(f, "{}", inst)
727 }
728 }
729}
730
731impl From<RollRange> for Instruction
732{
733 fn from(inst: RollRange) -> Self { Self::RollRange(inst) }
734}
735
736impl From<RollStandardDice> for Instruction
737{
738 fn from(inst: RollStandardDice) -> Self { Self::RollStandardDice(inst) }
739}
740
741impl From<RollCustomDice> for Instruction
742{
743 fn from(inst: RollCustomDice) -> Self { Self::RollCustomDice(inst) }
744}
745
746impl From<DropLowest> for Instruction
747{
748 fn from(inst: DropLowest) -> Self { Self::DropLowest(inst) }
749}
750
751impl From<DropHighest> for Instruction
752{
753 fn from(inst: DropHighest) -> Self { Self::DropHighest(inst) }
754}
755
756impl From<SumRollingRecord> for Instruction
757{
758 fn from(inst: SumRollingRecord) -> Self { Self::SumRollingRecord(inst) }
759}
760
761impl From<Add> for Instruction
762{
763 fn from(inst: Add) -> Self { Self::Add(inst) }
764}
765
766impl From<Sub> for Instruction
767{
768 fn from(inst: Sub) -> Self { Self::Sub(inst) }
769}
770
771impl From<Mul> for Instruction
772{
773 fn from(inst: Mul) -> Self { Self::Mul(inst) }
774}
775
776impl From<Div> for Instruction
777{
778 fn from(inst: Div) -> Self { Self::Div(inst) }
779}
780
781impl From<Mod> for Instruction
782{
783 fn from(inst: Mod) -> Self { Self::Mod(inst) }
784}
785
786impl From<Exp> for Instruction
787{
788 fn from(inst: Exp) -> Self { Self::Exp(inst) }
789}
790
791impl From<Neg> for Instruction
792{
793 fn from(inst: Neg) -> Self { Self::Neg(inst) }
794}
795
796impl From<Return> for Instruction
797{
798 fn from(inst: Return) -> Self { Self::Return(inst) }
799}
800
801impl TryFrom<Instruction> for RollRange
802{
803 type Error = ();
804
805 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
806 {
807 match inst
808 {
809 Instruction::RollRange(inst) => Ok(inst),
810 _ => Err(())
811 }
812 }
813}
814
815impl TryFrom<Instruction> for RollStandardDice
816{
817 type Error = ();
818
819 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
820 {
821 match inst
822 {
823 Instruction::RollStandardDice(inst) => Ok(inst),
824 _ => Err(())
825 }
826 }
827}
828
829impl TryFrom<Instruction> for RollCustomDice
830{
831 type Error = ();
832
833 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
834 {
835 match inst
836 {
837 Instruction::RollCustomDice(inst) => Ok(inst),
838 _ => Err(())
839 }
840 }
841}
842
843impl TryFrom<Instruction> for DropLowest
844{
845 type Error = ();
846
847 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
848 {
849 match inst
850 {
851 Instruction::DropLowest(inst) => Ok(inst),
852 _ => Err(())
853 }
854 }
855}
856
857impl TryFrom<Instruction> for DropHighest
858{
859 type Error = ();
860
861 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
862 {
863 match inst
864 {
865 Instruction::DropHighest(inst) => Ok(inst),
866 _ => Err(())
867 }
868 }
869}
870
871impl TryFrom<Instruction> for SumRollingRecord
872{
873 type Error = ();
874
875 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
876 {
877 match inst
878 {
879 Instruction::SumRollingRecord(inst) => Ok(inst),
880 _ => Err(())
881 }
882 }
883}
884
885impl TryFrom<Instruction> for Add
886{
887 type Error = ();
888
889 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
890 {
891 match inst
892 {
893 Instruction::Add(inst) => Ok(inst),
894 _ => Err(())
895 }
896 }
897}
898
899impl TryFrom<Instruction> for Sub
900{
901 type Error = ();
902
903 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
904 {
905 match inst
906 {
907 Instruction::Sub(inst) => Ok(inst),
908 _ => Err(())
909 }
910 }
911}
912
913impl TryFrom<Instruction> for Mul
914{
915 type Error = ();
916
917 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
918 {
919 match inst
920 {
921 Instruction::Mul(inst) => Ok(inst),
922 _ => Err(())
923 }
924 }
925}
926
927impl TryFrom<Instruction> for Div
928{
929 type Error = ();
930
931 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
932 {
933 match inst
934 {
935 Instruction::Div(inst) => Ok(inst),
936 _ => Err(())
937 }
938 }
939}
940
941impl TryFrom<Instruction> for Mod
942{
943 type Error = ();
944
945 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
946 {
947 match inst
948 {
949 Instruction::Mod(inst) => Ok(inst),
950 _ => Err(())
951 }
952 }
953}
954
955impl TryFrom<Instruction> for Exp
956{
957 type Error = ();
958
959 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
960 {
961 match inst
962 {
963 Instruction::Exp(inst) => Ok(inst),
964 _ => Err(())
965 }
966 }
967}
968
969impl TryFrom<Instruction> for Neg
970{
971 type Error = ();
972
973 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
974 {
975 match inst
976 {
977 Instruction::Neg(inst) => Ok(inst),
978 _ => Err(())
979 }
980 }
981}
982
983impl TryFrom<Instruction> for Return
984{
985 type Error = ();
986
987 fn try_from(inst: Instruction) -> Result<Self, Self::Error>
988 {
989 match inst
990 {
991 Instruction::Return(inst) => Ok(inst),
992 _ => Err(())
993 }
994 }
995}
996
997#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1006#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1007pub enum AddressingMode
1008{
1009 Immediate(Immediate),
1011
1012 Register(RegisterIndex),
1014
1015 RollingRecord(RollingRecordIndex)
1017}
1018
1019impl Display for AddressingMode
1020{
1021 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
1022 {
1023 match self
1024 {
1025 Self::Immediate(imm) => write!(f, "{}", imm),
1026 Self::Register(reg) => write!(f, "{}", reg),
1027 Self::RollingRecord(rec) => write!(f, "{}", rec)
1028 }
1029 }
1030}
1031
1032#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1034#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1035pub struct Immediate(pub i32);
1036
1037impl Display for Immediate
1038{
1039 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
1040 {
1041 write!(f, "{}", self.0)
1042 }
1043}
1044
1045impl std::ops::Add for Immediate
1046{
1047 type Output = Self;
1048
1049 fn add(self, rhs: Self) -> Self::Output { Self(self.0 + rhs.0) }
1050}
1051
1052impl std::ops::Sub for Immediate
1053{
1054 type Output = Self;
1055
1056 fn sub(self, rhs: Self) -> Self::Output { Self(self.0 - rhs.0) }
1057}
1058
1059impl std::ops::Mul for Immediate
1060{
1061 type Output = Self;
1062
1063 fn mul(self, rhs: Self) -> Self::Output { Self(self.0 * rhs.0) }
1064}
1065
1066impl std::ops::Div for Immediate
1067{
1068 type Output = Self;
1069
1070 fn div(self, rhs: Self) -> Self::Output { Self(self.0 / rhs.0) }
1071}
1072
1073impl std::ops::Rem for Immediate
1074{
1075 type Output = Self;
1076
1077 fn rem(self, rhs: Self) -> Self::Output { Self(self.0 % rhs.0) }
1078}
1079
1080impl std::ops::Neg for Immediate
1081{
1082 type Output = Self;
1083
1084 fn neg(self) -> Self::Output { Self(-self.0) }
1085}
1086
1087impl From<usize> for Immediate
1088{
1089 fn from(immediate: usize) -> Self { Self(immediate as i32) }
1090}
1091
1092impl From<Immediate> for i32
1093{
1094 fn from(immediate: Immediate) -> Self { immediate.0 }
1095}
1096
1097impl From<Immediate> for AddressingMode
1098{
1099 fn from(immediate: Immediate) -> Self { Self::Immediate(immediate) }
1100}
1101
1102#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1104#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1105pub struct RegisterIndex(pub usize);
1106
1107impl Display for RegisterIndex
1108{
1109 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
1110 {
1111 write!(f, "@{}", self.0)
1112 }
1113}
1114
1115impl From<usize> for RegisterIndex
1116{
1117 fn from(reg: usize) -> Self { Self(reg) }
1118}
1119
1120impl From<RegisterIndex> for usize
1121{
1122 fn from(reg: RegisterIndex) -> Self { reg.0 }
1123}
1124
1125impl From<RegisterIndex> for AddressingMode
1126{
1127 fn from(reg: RegisterIndex) -> Self { Self::Register(reg) }
1128}
1129
1130#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1133pub struct RollingRecordIndex(pub usize);
1134
1135impl Display for RollingRecordIndex
1136{
1137 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
1138 {
1139 write!(f, "⚅{}", self.0)
1140 }
1141}
1142
1143impl From<usize> for RollingRecordIndex
1144{
1145 fn from(rec: usize) -> Self { Self(rec) }
1146}
1147
1148impl From<RollingRecordIndex> for usize
1149{
1150 fn from(rec: RollingRecordIndex) -> Self { rec.0 }
1151}
1152
1153impl From<RollingRecordIndex> for AddressingMode
1154{
1155 fn from(rec: RollingRecordIndex) -> Self { Self::RollingRecord(rec) }
1156}
1157
1158impl TryFrom<AddressingMode> for Immediate
1159{
1160 type Error = ();
1161
1162 fn try_from(value: AddressingMode) -> Result<Self, Self::Error>
1163 {
1164 match value
1165 {
1166 AddressingMode::Immediate(imm) => Ok(imm),
1167 _ => Err(())
1168 }
1169 }
1170}
1171
1172impl TryFrom<AddressingMode> for RegisterIndex
1173{
1174 type Error = ();
1175
1176 fn try_from(value: AddressingMode) -> Result<Self, Self::Error>
1177 {
1178 match value
1179 {
1180 AddressingMode::Register(reg) => Ok(reg),
1181 _ => Err(())
1182 }
1183 }
1184}
1185
1186impl TryFrom<AddressingMode> for RollingRecordIndex
1187{
1188 type Error = ();
1189
1190 fn try_from(value: AddressingMode) -> Result<Self, Self::Error>
1191 {
1192 match value
1193 {
1194 AddressingMode::RollingRecord(rec) => Ok(rec),
1195 _ => Err(())
1196 }
1197 }
1198}
1199
1200#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1205pub struct ProgramCounter(pub usize);
1206
1207impl Display for ProgramCounter
1208{
1209 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
1210 {
1211 write!(f, "*{}", self.0)
1212 }
1213}
1214
1215impl From<usize> for ProgramCounter
1216{
1217 fn from(pc: usize) -> Self { Self(pc) }
1218}
1219
1220impl From<ProgramCounter> for usize
1221{
1222 fn from(pc: ProgramCounter) -> Self { pc.0 }
1223}
1224
1225pub trait CanAllocate
1228{
1229 fn allocate(&mut self) -> Self;
1234}
1235
1236impl CanAllocate for RegisterIndex
1237{
1238 fn allocate(&mut self) -> Self
1239 {
1240 let register = *self;
1241 self.0 += 1;
1242 register
1243 }
1244}
1245
1246impl CanAllocate for RollingRecordIndex
1247{
1248 fn allocate(&mut self) -> Self
1249 {
1250 let record = *self;
1251 self.0 += 1;
1252 record
1253 }
1254}
1255
1256impl CanAllocate for ProgramCounter
1257{
1258 fn allocate(&mut self) -> Self
1259 {
1260 let pc = *self;
1261 self.0 += 1;
1262 pc
1263 }
1264}
1265
1266pub trait InstructionVisitor<E>
1276{
1277 fn visit_roll_range(&mut self, inst: &RollRange) -> Result<(), E>;
1285
1286 fn visit_roll_standard_dice(
1294 &mut self,
1295 inst: &RollStandardDice
1296 ) -> Result<(), E>;
1297
1298 fn visit_roll_custom_dice(
1306 &mut self,
1307 inst: &RollCustomDice
1308 ) -> Result<(), E>;
1309
1310 fn visit_drop_lowest(&mut self, inst: &DropLowest) -> Result<(), E>;
1318
1319 fn visit_drop_highest(&mut self, inst: &DropHighest) -> Result<(), E>;
1327
1328 fn visit_sum_rolling_record(
1336 &mut self,
1337 inst: &SumRollingRecord
1338 ) -> Result<(), E>;
1339
1340 fn visit_add(&mut self, inst: &Add) -> Result<(), E>;
1348
1349 fn visit_sub(&mut self, inst: &Sub) -> Result<(), E>;
1357
1358 fn visit_mul(&mut self, inst: &Mul) -> Result<(), E>;
1366
1367 fn visit_div(&mut self, inst: &Div) -> Result<(), E>;
1375
1376 fn visit_mod(&mut self, inst: &Mod) -> Result<(), E>;
1384
1385 fn visit_exp(&mut self, inst: &Exp) -> Result<(), E>;
1393
1394 fn visit_neg(&mut self, inst: &Neg) -> Result<(), E>;
1402
1403 fn visit_return(&mut self, inst: &Return) -> Result<(), E>;
1411}
1412
1413pub trait CanVisitInstructions<V, E>
1419where
1420 V: InstructionVisitor<E>
1421{
1422 fn visit(&self, visitor: &mut V) -> Result<(), E>;
1430}
1431
1432impl<V, E> CanVisitInstructions<V, E> for Instruction
1433where
1434 V: InstructionVisitor<E>
1435{
1436 fn visit(&self, visitor: &mut V) -> Result<(), E>
1437 {
1438 match self
1439 {
1440 Instruction::RollRange(inst) => visitor.visit_roll_range(inst),
1441 Instruction::RollStandardDice(inst) =>
1442 {
1443 visitor.visit_roll_standard_dice(inst)
1444 },
1445 Instruction::RollCustomDice(inst) =>
1446 {
1447 visitor.visit_roll_custom_dice(inst)
1448 },
1449 Instruction::DropLowest(inst) => visitor.visit_drop_lowest(inst),
1450 Instruction::DropHighest(inst) => visitor.visit_drop_highest(inst),
1451 Instruction::SumRollingRecord(inst) =>
1452 {
1453 visitor.visit_sum_rolling_record(inst)
1454 },
1455 Instruction::Add(inst) => visitor.visit_add(inst),
1456 Instruction::Sub(inst) => visitor.visit_sub(inst),
1457 Instruction::Mul(inst) => visitor.visit_mul(inst),
1458 Instruction::Div(inst) => visitor.visit_div(inst),
1459 Instruction::Mod(inst) => visitor.visit_mod(inst),
1460 Instruction::Exp(inst) => visitor.visit_exp(inst),
1461 Instruction::Neg(inst) => visitor.visit_neg(inst),
1462 Instruction::Return(inst) => visitor.visit_return(inst)
1463 }
1464 }
1465}
1466
1467#[derive(Debug, Clone, PartialEq, Eq)]
1473pub struct DependencyAnalyzer<'inst>
1474{
1475 instructions: &'inst [Instruction],
1477
1478 pc: ProgramCounter,
1481
1482 writers: HashMap<AddressingMode, BTreeSet<ProgramCounter>>,
1486
1487 readers: HashMap<AddressingMode, BTreeSet<ProgramCounter>>,
1489
1490 transitive_dependencies:
1493 RefCell<Option<HashMap<AddressingMode, BTreeSet<ProgramCounter>>>>,
1494
1495 transitive_dependents:
1498 RefCell<Option<HashMap<AddressingMode, BTreeSet<ProgramCounter>>>>
1499}
1500
1501impl<'inst> DependencyAnalyzer<'inst>
1502{
1503 pub fn analyze(instructions: &'inst [Instruction]) -> Self
1512 {
1513 let mut analyzer = Self {
1514 instructions,
1515 pc: ProgramCounter::default(),
1516 writers: HashMap::new(),
1517 readers: HashMap::new(),
1518 transitive_dependencies: RefCell::default(),
1519 transitive_dependents: RefCell::default()
1520 };
1521 for instruction in analyzer.instructions
1523 {
1524 instruction.visit(&mut analyzer).unwrap();
1525 analyzer.pc.allocate();
1526 }
1527 analyzer
1528 }
1529
1530 pub fn instructions(&self) -> &'inst [Instruction] { self.instructions }
1535
1536 pub fn writers(&self)
1542 -> &HashMap<AddressingMode, BTreeSet<ProgramCounter>>
1543 {
1544 &self.writers
1545 }
1546
1547 pub fn readers(&self)
1553 -> &HashMap<AddressingMode, BTreeSet<ProgramCounter>>
1554 {
1555 &self.readers
1556 }
1557
1558 pub fn transitive_dependencies(
1564 &self
1565 ) -> Ref<'_, HashMap<AddressingMode, BTreeSet<ProgramCounter>>>
1566 {
1567 if self.transitive_dependencies.borrow().is_some()
1569 {
1570 return Ref::map(self.transitive_dependencies.borrow(), |x| {
1571 x.as_ref().unwrap()
1572 })
1573 }
1574 let mut transitive_dependencies =
1575 HashMap::<AddressingMode, BTreeSet<ProgramCounter>>::new();
1576 for (dest, writers) in &self.writers
1580 {
1581 let mut all_dependencies = BTreeSet::new();
1582 let mut to_visit = writers.clone();
1583 while let Some(pc) = to_visit.pop_first()
1584 {
1585 if all_dependencies.insert(pc)
1586 {
1587 let dependency = &self.instructions[pc.0];
1591 dependency.sources().iter().for_each(|src| {
1592 if let Some(writers) = self.writers.get(src)
1593 {
1594 to_visit.extend(writers.iter().clone());
1598 }
1599 });
1600 }
1601 }
1602 transitive_dependencies.insert(*dest, all_dependencies);
1603 }
1604 *self.transitive_dependencies.borrow_mut() =
1605 Some(transitive_dependencies);
1606 Ref::map(self.transitive_dependencies.borrow(), |x| {
1607 x.as_ref().unwrap()
1608 })
1609 }
1610
1611 pub fn transitive_dependents(
1617 &self
1618 ) -> Ref<'_, HashMap<AddressingMode, BTreeSet<ProgramCounter>>>
1619 {
1620 if self.transitive_dependents.borrow().is_some()
1622 {
1623 return Ref::map(self.transitive_dependents.borrow(), |x| {
1624 x.as_ref().unwrap()
1625 })
1626 }
1627 let mut transitive_dependents =
1628 HashMap::<AddressingMode, BTreeSet<ProgramCounter>>::new();
1629 for (dest, readers) in &self.readers
1630 {
1631 let mut all_dependents = BTreeSet::new();
1632 let mut to_visit = readers.clone();
1633 while let Some(pc) = to_visit.pop_first()
1634 {
1635 if all_dependents.insert(pc)
1636 {
1637 let dependency = &self.instructions[pc.0];
1641 if let Some(dest) = dependency.destination()
1642 {
1643 if let Some(readers) = self.readers.get(&dest)
1644 {
1645 to_visit.extend(readers.iter().clone());
1649 }
1650 }
1651 }
1652 }
1653 transitive_dependents.insert(*dest, all_dependents);
1654 }
1655 *self.transitive_dependents.borrow_mut() = Some(transitive_dependents);
1656 Ref::map(self.transitive_dependents.borrow(), |x| x.as_ref().unwrap())
1657 }
1658}
1659
1660impl InstructionVisitor<()> for DependencyAnalyzer<'_>
1661{
1662 fn visit_roll_range(&mut self, inst: &RollRange) -> Result<(), ()>
1663 {
1664 self.writers
1665 .entry(inst.dest.into())
1666 .or_default()
1667 .insert(self.pc);
1668 self.readers.entry(inst.start).or_default().insert(self.pc);
1669 self.readers.entry(inst.end).or_default().insert(self.pc);
1670 Ok(())
1671 }
1672
1673 fn visit_roll_standard_dice(
1674 &mut self,
1675 inst: &RollStandardDice
1676 ) -> Result<(), ()>
1677 {
1678 self.writers
1679 .entry(inst.dest.into())
1680 .or_default()
1681 .insert(self.pc);
1682 self.readers.entry(inst.count).or_default().insert(self.pc);
1683 self.readers.entry(inst.faces).or_default().insert(self.pc);
1684 Ok(())
1685 }
1686
1687 fn visit_roll_custom_dice(
1688 &mut self,
1689 inst: &RollCustomDice
1690 ) -> Result<(), ()>
1691 {
1692 self.writers
1693 .entry(inst.dest.into())
1694 .or_default()
1695 .insert(self.pc);
1696 self.readers.entry(inst.count).or_default().insert(self.pc);
1697 Ok(())
1698 }
1699
1700 fn visit_drop_lowest(&mut self, inst: &DropLowest) -> Result<(), ()>
1701 {
1702 self.writers
1703 .entry(inst.dest.into())
1704 .or_default()
1705 .insert(self.pc);
1706 self.readers
1707 .entry(inst.dest.into())
1708 .or_default()
1709 .insert(self.pc);
1710 self.readers.entry(inst.count).or_default().insert(self.pc);
1711 Ok(())
1712 }
1713
1714 fn visit_drop_highest(&mut self, inst: &DropHighest) -> Result<(), ()>
1715 {
1716 self.writers
1717 .entry(inst.dest.into())
1718 .or_default()
1719 .insert(self.pc);
1720 self.readers
1721 .entry(inst.dest.into())
1722 .or_default()
1723 .insert(self.pc);
1724 self.readers.entry(inst.count).or_default().insert(self.pc);
1725 Ok(())
1726 }
1727
1728 fn visit_sum_rolling_record(
1729 &mut self,
1730 inst: &SumRollingRecord
1731 ) -> Result<(), ()>
1732 {
1733 self.writers
1734 .entry(inst.dest.into())
1735 .or_default()
1736 .insert(self.pc);
1737 self.readers
1738 .entry(inst.src.into())
1739 .or_default()
1740 .insert(self.pc);
1741 Ok(())
1742 }
1743
1744 fn visit_add(&mut self, inst: &Add) -> Result<(), ()>
1745 {
1746 self.writers
1747 .entry(inst.dest.into())
1748 .or_default()
1749 .insert(self.pc);
1750 self.readers.entry(inst.op1).or_default().insert(self.pc);
1751 self.readers.entry(inst.op2).or_default().insert(self.pc);
1752 Ok(())
1753 }
1754
1755 fn visit_sub(&mut self, inst: &Sub) -> Result<(), ()>
1756 {
1757 self.writers
1758 .entry(inst.dest.into())
1759 .or_default()
1760 .insert(self.pc);
1761 self.readers.entry(inst.op1).or_default().insert(self.pc);
1762 self.readers.entry(inst.op2).or_default().insert(self.pc);
1763 Ok(())
1764 }
1765
1766 fn visit_mul(&mut self, inst: &Mul) -> Result<(), ()>
1767 {
1768 self.writers
1769 .entry(inst.dest.into())
1770 .or_default()
1771 .insert(self.pc);
1772 self.readers.entry(inst.op1).or_default().insert(self.pc);
1773 self.readers.entry(inst.op2).or_default().insert(self.pc);
1774 Ok(())
1775 }
1776
1777 fn visit_div(&mut self, inst: &Div) -> Result<(), ()>
1778 {
1779 self.writers
1780 .entry(inst.dest.into())
1781 .or_default()
1782 .insert(self.pc);
1783 self.readers.entry(inst.op1).or_default().insert(self.pc);
1784 self.readers.entry(inst.op2).or_default().insert(self.pc);
1785 Ok(())
1786 }
1787
1788 fn visit_mod(&mut self, inst: &Mod) -> Result<(), ()>
1789 {
1790 self.writers
1791 .entry(inst.dest.into())
1792 .or_default()
1793 .insert(self.pc);
1794 self.readers.entry(inst.op1).or_default().insert(self.pc);
1795 self.readers.entry(inst.op2).or_default().insert(self.pc);
1796 Ok(())
1797 }
1798
1799 fn visit_exp(&mut self, inst: &Exp) -> Result<(), ()>
1800 {
1801 self.writers
1802 .entry(inst.dest.into())
1803 .or_default()
1804 .insert(self.pc);
1805 self.readers.entry(inst.op1).or_default().insert(self.pc);
1806 self.readers.entry(inst.op2).or_default().insert(self.pc);
1807 Ok(())
1808 }
1809
1810 fn visit_neg(&mut self, inst: &Neg) -> Result<(), ()>
1811 {
1812 self.writers
1813 .entry(inst.dest.into())
1814 .or_default()
1815 .insert(self.pc);
1816 self.readers.entry(inst.op).or_default().insert(self.pc);
1817 Ok(())
1818 }
1819
1820 fn visit_return(&mut self, inst: &Return) -> Result<(), ()>
1821 {
1822 self.readers.entry(inst.src).or_default().insert(self.pc);
1823 Ok(())
1824 }
1825}
1826
1827#[cfg(test)]
1832mod test
1833{
1834 use std::collections::BTreeSet;
1835
1836 use pretty_assertions::assert_eq;
1837
1838 use crate::{
1839 AddressingMode, DependencyAnalyzer, Function, Immediate, Instruction,
1840 ProgramCounter, RegisterIndex
1841 };
1842
1843 fn function() -> Function
1849 {
1850 Function {
1860 parameters: vec!["x".to_string()],
1861 externals: Vec::new(),
1862 register_count: 6,
1863 rolling_record_count: 0,
1864 instructions: vec![
1865 Instruction::add(
1866 1.into(),
1867 Immediate(1).into(),
1868 RegisterIndex(0).into()
1869 ),
1870 Instruction::add(
1871 2.into(),
1872 RegisterIndex(1).into(),
1873 Immediate(1).into()
1874 ),
1875 Instruction::add(
1876 3.into(),
1877 RegisterIndex(2).into(),
1878 RegisterIndex(0).into()
1879 ),
1880 Instruction::add(
1881 4.into(),
1882 RegisterIndex(3).into(),
1883 Immediate(1).into()
1884 ),
1885 Instruction::add(
1886 5.into(),
1887 RegisterIndex(4).into(),
1888 RegisterIndex(0).into()
1889 ),
1890 Instruction::r#return(RegisterIndex(5).into()),
1891 ]
1892 }
1893 }
1894
1895 #[test]
1897 fn test_analyze_writers()
1898 {
1899 let function = function();
1900 let analyzer = DependencyAnalyzer::analyze(&function.instructions);
1901 assert_eq!(
1902 analyzer.writers(),
1903 &[
1904 (
1905 AddressingMode::Register(RegisterIndex(1)),
1906 BTreeSet::from([ProgramCounter(0)])
1907 ),
1908 (
1909 AddressingMode::Register(RegisterIndex(2)),
1910 BTreeSet::from([ProgramCounter(1)])
1911 ),
1912 (
1913 AddressingMode::Register(RegisterIndex(3)),
1914 BTreeSet::from([ProgramCounter(2)])
1915 ),
1916 (
1917 AddressingMode::Register(RegisterIndex(4)),
1918 BTreeSet::from([ProgramCounter(3)])
1919 ),
1920 (
1921 AddressingMode::Register(RegisterIndex(5)),
1922 BTreeSet::from([ProgramCounter(4)])
1923 )
1924 ]
1925 .into()
1926 );
1927 }
1928
1929 #[test]
1931 fn test_analyze_readers()
1932 {
1933 let function = function();
1934 let analyzer = DependencyAnalyzer::analyze(&function.instructions);
1935 assert_eq!(
1936 analyzer.readers(),
1937 &[
1938 (
1939 AddressingMode::Immediate(Immediate(1)),
1940 BTreeSet::from([
1941 ProgramCounter(0),
1942 ProgramCounter(1),
1943 ProgramCounter(3)
1944 ])
1945 ),
1946 (
1947 AddressingMode::Register(RegisterIndex(0)),
1948 BTreeSet::from([
1949 ProgramCounter(0),
1950 ProgramCounter(2),
1951 ProgramCounter(4)
1952 ])
1953 ),
1954 (
1955 AddressingMode::Register(RegisterIndex(1)),
1956 BTreeSet::from([ProgramCounter(1)])
1957 ),
1958 (
1959 AddressingMode::Register(RegisterIndex(2)),
1960 BTreeSet::from([ProgramCounter(2)])
1961 ),
1962 (
1963 AddressingMode::Register(RegisterIndex(3)),
1964 BTreeSet::from([ProgramCounter(3)])
1965 ),
1966 (
1967 AddressingMode::Register(RegisterIndex(4)),
1968 BTreeSet::from([ProgramCounter(4)])
1969 ),
1970 (
1971 AddressingMode::Register(RegisterIndex(5)),
1972 BTreeSet::from([ProgramCounter(5)])
1973 ),
1974 ]
1975 .into()
1976 );
1977 }
1978
1979 #[test]
1982 fn test_dependencies()
1983 {
1984 let function = function();
1985 let analyzer = DependencyAnalyzer::analyze(&function.instructions);
1986 let dependencies = analyzer.transitive_dependencies();
1987 assert_eq!(
1988 *dependencies,
1989 [
1990 (
1991 AddressingMode::Register(RegisterIndex(1)),
1992 BTreeSet::from([ProgramCounter(0)])
1993 ),
1994 (
1995 AddressingMode::Register(RegisterIndex(2)),
1996 BTreeSet::from([ProgramCounter(0), ProgramCounter(1)])
1997 ),
1998 (
1999 AddressingMode::Register(RegisterIndex(3)),
2000 BTreeSet::from([
2001 ProgramCounter(0),
2002 ProgramCounter(1),
2003 ProgramCounter(2)
2004 ])
2005 ),
2006 (
2007 AddressingMode::Register(RegisterIndex(4)),
2008 BTreeSet::from([
2009 ProgramCounter(0),
2010 ProgramCounter(1),
2011 ProgramCounter(2),
2012 ProgramCounter(3)
2013 ])
2014 ),
2015 (
2016 AddressingMode::Register(RegisterIndex(5)),
2017 BTreeSet::from([
2018 ProgramCounter(0),
2019 ProgramCounter(1),
2020 ProgramCounter(2),
2021 ProgramCounter(3),
2022 ProgramCounter(4)
2023 ])
2024 )
2025 ]
2026 .into()
2027 );
2028 }
2029
2030 #[test]
2033 fn test_dependents()
2034 {
2035 let function = function();
2036 let analyzer = DependencyAnalyzer::analyze(&function.instructions);
2037 let dependents = analyzer.transitive_dependents();
2038 assert_eq!(
2039 *dependents,
2040 [
2041 (
2042 AddressingMode::Immediate(Immediate(1)),
2043 BTreeSet::from([
2044 ProgramCounter(0),
2045 ProgramCounter(1),
2046 ProgramCounter(2),
2047 ProgramCounter(3),
2048 ProgramCounter(4),
2049 ProgramCounter(5)
2050 ])
2051 ),
2052 (
2053 AddressingMode::Register(RegisterIndex(0)),
2054 BTreeSet::from([
2055 ProgramCounter(0),
2056 ProgramCounter(1),
2057 ProgramCounter(2),
2058 ProgramCounter(3),
2059 ProgramCounter(4),
2060 ProgramCounter(5)
2061 ])
2062 ),
2063 (
2064 AddressingMode::Register(RegisterIndex(1)),
2065 BTreeSet::from([
2066 ProgramCounter(1),
2067 ProgramCounter(2),
2068 ProgramCounter(3),
2069 ProgramCounter(4),
2070 ProgramCounter(5)
2071 ])
2072 ),
2073 (
2074 AddressingMode::Register(RegisterIndex(2)),
2075 BTreeSet::from([
2076 ProgramCounter(2),
2077 ProgramCounter(3),
2078 ProgramCounter(4),
2079 ProgramCounter(5)
2080 ])
2081 ),
2082 (
2083 AddressingMode::Register(RegisterIndex(3)),
2084 BTreeSet::from([
2085 ProgramCounter(3),
2086 ProgramCounter(4),
2087 ProgramCounter(5)
2088 ])
2089 ),
2090 (
2091 AddressingMode::Register(RegisterIndex(4)),
2092 BTreeSet::from([ProgramCounter(4), ProgramCounter(5)])
2093 ),
2094 (
2095 AddressingMode::Register(RegisterIndex(5)),
2096 BTreeSet::from([ProgramCounter(5)])
2097 )
2098 ]
2099 .into()
2100 );
2101 }
2102}