ram_machine/parser/
operand.rs

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),               // =x
10    ValueInCell(CellAddress),        // x
11    ValueOfValueInCell(CellAddress), // ^x
12}
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),       // x
29    AddressOfCellInCell(CellAddress), // ^x
30}
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}