1use std::{fmt, str::FromStr};
2use thiserror::Error;
3
4pub type CellAddress = usize;
5pub type CellValue = i64;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum Operand {
9 Number(CellValue), ValueInCell(CellAddress), ValueOfValueInCell(CellAddress), }
13
14#[derive(Error, Debug, PartialEq, Eq)]
15#[error("Operand {0} is not a valid operand")]
16pub struct InvalidOperandError(String);
17
18#[derive(Error, Debug, PartialEq, Eq)]
19pub enum OperandParseError {
20 #[error("Operand {0} is not a valid operand for keyword `{1}`")]
21 InvalidOperand(String, String),
22 #[error("Expected operand for keyword `{0}`, found nothing")]
23 OperandNotFound(String),
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub enum CellOperand {
28 AddressOfCell(CellAddress), AddressOfCellInCell(CellAddress), }
31
32#[derive(Error, Debug, PartialEq, Eq)]
33pub enum ExpandError {
34 #[error("Value `{0}` in cell `{1}` could not be converted to a tape index.")]
35 ConvertError(CellValue, CellAddress),
36 #[error("Tried reading from cell with address `{0}`, which was never set.")]
37 ValueNotSet(CellAddress),
38}
39
40impl Operand {
41 pub fn expand<'a>(
42 &'a self,
43 tape: &'a [Option<CellValue>],
44 ) -> Result<&'a CellValue, ExpandError> {
45 use Operand::*;
46 match self {
47 Number(v) => Ok(v),
48 ValueInCell(cell) => Ok(tape
49 .get(*cell)
50 .and_then(|val| val.as_ref())
51 .ok_or(ExpandError::ValueNotSet(*cell))?),
52 ValueOfValueInCell(cell) => tape
53 .get(
54 CellAddress::try_from(
55 tape.get(*cell)
56 .ok_or(ExpandError::ValueNotSet(*cell))?
57 .ok_or(ExpandError::ValueNotSet(*cell))?,
58 )
59 .map_err(|_| {
60 ExpandError::ConvertError(
61 tape.get(*cell).expect("Would've failed before").unwrap(),
62 *cell,
63 )
64 })?,
65 )
66 .and_then(|val| val.as_ref())
67 .ok_or_else(|| {
68 ExpandError::ValueNotSet(
69 CellAddress::try_from(
70 tape.get(*cell).expect("Would've failed before").unwrap(),
71 )
72 .expect("Would've failed before"),
73 )
74 }),
75 }
76 }
77}
78
79impl CellOperand {
80 pub fn expand(&self, tape: &[Option<CellValue>]) -> Result<CellAddress, ExpandError> {
81 use CellOperand::*;
82 match self {
83 AddressOfCell(cell) => Ok(*cell),
84 AddressOfCellInCell(cell) => CellAddress::try_from(
85 tape.get(*cell)
86 .ok_or(ExpandError::ValueNotSet(*cell))?
87 .ok_or(ExpandError::ValueNotSet(*cell))?,
88 )
89 .map_err(|_| {
90 ExpandError::ConvertError(
91 tape.get(*cell).expect("Didn't fail previously").unwrap(),
92 *cell,
93 )
94 }),
95 }
96 }
97}
98
99macro_rules! parse {
100 ($e:expr) => {
101 $e.parse().expect("Already checked if can be parsed")
102 };
103}
104
105fn is_number(s: &str) -> bool {
106 s.parse::<CellValue>().is_ok()
107}
108
109fn is_positive_number(s: &str) -> bool {
110 s.parse::<CellAddress>().is_ok()
111}
112
113fn is_operand_number(s: &str) -> bool {
114 s.starts_with('=') && is_number(&s[1..])
115}
116
117fn is_operand_value_in_cell(s: &str) -> bool {
118 is_positive_number(s)
119}
120
121fn is_operand_value_of_value_in_cell(s: &str) -> bool {
122 s.starts_with('^') && is_positive_number(&s[1..])
123}
124fn is_operand_address_of_cell(s: &str) -> bool {
125 is_operand_value_in_cell(s)
126}
127
128fn is_operand_address_of_cell_in_cell(s: &str) -> bool {
129 is_operand_value_of_value_in_cell(s)
130}
131
132impl FromStr for Operand {
133 type Err = InvalidOperandError;
134 fn from_str(s: &str) -> Result<Self, Self::Err> {
135 match s {
136 s if is_operand_number(s) => Ok(Self::Number(parse!(s[1..]))),
137 s if is_operand_value_in_cell(s) => Ok(Self::ValueInCell(parse!(s))),
138 s if is_operand_value_of_value_in_cell(s) => {
139 Ok(Self::ValueOfValueInCell(parse!(s[1..])))
140 }
141 _ => Err(InvalidOperandError(s.to_owned())),
142 }
143 }
144}
145
146impl TryFrom<(Option<&str>, &str)> for Operand {
147 type Error = OperandParseError;
148 fn try_from((s, keyword): (Option<&str>, &str)) -> Result<Self, Self::Error> {
149 match s {
150 Some(s) => Operand::from_str(s)
151 .map_err(|err| OperandParseError::InvalidOperand(err.0, keyword.to_owned())),
152 None => Err(OperandParseError::OperandNotFound(keyword.to_owned())),
153 }
154 }
155}
156
157impl FromStr for CellOperand {
158 type Err = InvalidOperandError;
159 fn from_str(s: &str) -> Result<Self, Self::Err> {
160 match s {
161 s if is_operand_address_of_cell(s) => Ok(Self::AddressOfCell(parse!(s))),
162 s if is_operand_address_of_cell_in_cell(s) => {
163 Ok(Self::AddressOfCellInCell(parse!(s[1..])))
164 }
165 _ => Err(InvalidOperandError(s.to_owned())),
166 }
167 }
168}
169
170impl TryFrom<(Option<&str>, &str)> for CellOperand {
171 type Error = OperandParseError;
172 fn try_from((s, keyword): (Option<&str>, &str)) -> Result<Self, Self::Error> {
173 match s {
174 Some(s) => CellOperand::from_str(s)
175 .map_err(|err| OperandParseError::InvalidOperand(err.0, keyword.to_owned())),
176 None => Err(OperandParseError::OperandNotFound(keyword.to_owned())),
177 }
178 }
179}
180
181impl fmt::Display for Operand {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 match self {
184 Operand::Number(value) => write!(f, "={}", value),
185 Operand::ValueInCell(address) => write!(f, "{}", address),
186 Operand::ValueOfValueInCell(address) => write!(f, "^{}", address),
187 }
188 }
189}
190
191impl fmt::Display for CellOperand {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 match self {
194 CellOperand::AddressOfCell(address) => write!(f, "{}", address),
195 CellOperand::AddressOfCellInCell(address) => write!(f, "^{}", address),
196 }
197 }
198}