ram_machine/parser/
instruction.rs

1use std::fmt;
2
3use crate::operand::{CellOperand, Operand, OperandParseError};
4use thiserror::Error;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum Instruction {
8    Load(Operand),
9    Store(CellOperand),
10    Add(Operand),
11    Sub(Operand),
12    Mult(Operand),
13    Div(Operand),
14    Read(CellOperand),
15    Write(Operand),
16    Jump(String),
17    Jgtz(String),
18    Jzero(String),
19    Halt,
20}
21
22#[derive(Error, Debug, PartialEq, Eq)]
23pub enum InstructionParseError {
24    #[error("Expected a label after keyword {0}, got nothing")]
25    LabelNotFound(String),
26    #[error("Keyword `{0}` is not a valid keyword")]
27    InvalidKeyword(String),
28    #[error(transparent)]
29    OperandParseError(#[from] OperandParseError),
30    #[error("Expected nothing, found `{0}`")]
31    UnexpectedArgument(String),
32}
33
34fn parse_label(keyword: &str, s: Option<&str>) -> Result<String, InstructionParseError> {
35    match s {
36        Some(v) => Ok(v.to_owned()),
37        None => Err(InstructionParseError::LabelNotFound(keyword.to_owned())),
38    }
39}
40
41impl TryFrom<(&str, Option<&str>)> for Instruction {
42    type Error = InstructionParseError;
43    fn try_from((keyword, argument): (&str, Option<&str>)) -> Result<Self, Self::Error> {
44        match keyword.to_lowercase().as_str() {
45            "load" => Ok(Self::Load(Operand::try_from((argument, keyword))?)),
46            "store" => Ok(Self::Store(CellOperand::try_from((argument, keyword))?)),
47            "add" => Ok(Self::Add(Operand::try_from((argument, keyword))?)),
48            "sub" => Ok(Self::Sub(Operand::try_from((argument, keyword))?)),
49            "mult" => Ok(Self::Mult(Operand::try_from((argument, keyword))?)),
50            "div" => Ok(Self::Div(Operand::try_from((argument, keyword))?)),
51            "read" => Ok(Self::Read(CellOperand::try_from((argument, keyword))?)),
52            "write" => Ok(Self::Write(Operand::try_from((argument, keyword))?)),
53            "jump" => Ok(Self::Jump(parse_label(keyword, argument)?)),
54            "jgtz" => Ok(Self::Jgtz(parse_label(keyword, argument)?)),
55            "jzero" => Ok(Self::Jzero(parse_label(keyword, argument)?)),
56            "halt" => {
57                if let Some(v) = argument {
58                    Err(InstructionParseError::UnexpectedArgument(v.to_owned()))
59                } else {
60                    Ok(Self::Halt)
61                }
62            }
63            _ => Err(InstructionParseError::InvalidKeyword(keyword.to_owned())),
64        }
65    }
66}
67
68impl fmt::Display for Instruction {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        match self {
71            Instruction::Load(op) => write!(f, "LOAD {}", op),
72            Instruction::Store(cell_op) => write!(f, "STORE {}", cell_op),
73            Instruction::Add(op) => write!(f, "ADD {}", op),
74            Instruction::Sub(op) => write!(f, "SUB {}", op),
75            Instruction::Mult(op) => write!(f, "MULT {}", op),
76            Instruction::Div(op) => write!(f, "DIV {}", op),
77            Instruction::Read(cell_op) => write!(f, "READ {}", cell_op),
78            Instruction::Write(op) => write!(f, "WRITE {}", op),
79            Instruction::Jump(label) => write!(f, "JUMP {}", label),
80            Instruction::Jgtz(label) => write!(f, "JGTZ {}", label),
81            Instruction::Jzero(label) => write!(f, "JZERO {}", label),
82            Instruction::Halt => write!(f, "HALT"),
83        }
84    }
85}