2024-08-05 03:11:04 +00:00
|
|
|
use crate::{parse, Node, ParseError, Parser, Statement, Value, ValueError};
|
2024-08-05 02:15:31 +00:00
|
|
|
|
|
|
|
pub fn run(input: &str) -> Result<Option<Value>, VmError> {
|
|
|
|
let instructions = parse(input)?;
|
|
|
|
let vm = Vm::new(instructions);
|
|
|
|
|
|
|
|
vm.run()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Vm {
|
2024-08-05 03:11:04 +00:00
|
|
|
instructions: Vec<Node>,
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Vm {
|
2024-08-05 03:11:04 +00:00
|
|
|
pub fn new(instructions: Vec<Node>) -> Self {
|
2024-08-05 02:15:31 +00:00
|
|
|
Vm { instructions }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run(&self) -> Result<Option<Value>, VmError> {
|
|
|
|
let mut previous_value = None;
|
|
|
|
|
|
|
|
for instruction in &self.instructions {
|
|
|
|
previous_value = self.run_instruction(instruction)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(previous_value)
|
|
|
|
}
|
|
|
|
|
2024-08-05 03:11:04 +00:00
|
|
|
fn run_instruction(&self, instruction: &Node) -> Result<Option<Value>, VmError> {
|
2024-08-05 02:15:31 +00:00
|
|
|
match &instruction.operation {
|
2024-08-05 03:11:04 +00:00
|
|
|
Statement::Add(instructions) => {
|
2024-08-05 02:15:31 +00:00
|
|
|
let left = if let Some(value) = self.run_instruction(&instructions.0)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue(instructions.0.operation.clone()));
|
|
|
|
};
|
|
|
|
let right = if let Some(value) = self.run_instruction(&instructions.1)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue(instructions.1.operation.clone()));
|
|
|
|
};
|
|
|
|
let sum = left.add(&right)?;
|
|
|
|
|
|
|
|
Ok(Some(sum))
|
|
|
|
}
|
2024-08-05 03:11:04 +00:00
|
|
|
Statement::Assign(_) => todo!(),
|
|
|
|
Statement::Constant(value) => Ok(Some(value.clone())),
|
|
|
|
Statement::Identifier(_) => todo!(),
|
|
|
|
Statement::List(_) => todo!(),
|
|
|
|
Statement::Multiply(_) => todo!(),
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub enum VmError {
|
2024-08-05 03:11:04 +00:00
|
|
|
ExpectedValue(Statement),
|
|
|
|
InvalidOperation(Statement),
|
2024-08-05 02:15:31 +00:00
|
|
|
ParseError(ParseError),
|
|
|
|
ValueError(ValueError),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ParseError> for VmError {
|
|
|
|
fn from(v: ParseError) -> Self {
|
|
|
|
Self::ParseError(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ValueError> for VmError {
|
|
|
|
fn from(v: ValueError) -> Self {
|
|
|
|
Self::ValueError(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add() {
|
|
|
|
let input = "1 + 2";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
|
|
|
}
|
2024-08-05 03:11:04 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_multiple() {
|
|
|
|
let input = "(a + b = 1)";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(6))));
|
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|