2024-08-05 04:40:51 +00:00
|
|
|
use std::collections::{HashMap, VecDeque};
|
2024-08-05 02:15:31 +00:00
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
use crate::{parse, Identifier, Node, ParseError, Span, Statement, Value, ValueError};
|
|
|
|
|
|
|
|
pub fn run(
|
|
|
|
input: &str,
|
|
|
|
variables: &mut HashMap<Identifier, Value>,
|
|
|
|
) -> Result<Option<Value>, VmError> {
|
2024-08-05 02:15:31 +00:00
|
|
|
let instructions = parse(input)?;
|
2024-08-05 04:40:51 +00:00
|
|
|
let mut vm = Vm::new(instructions);
|
2024-08-05 02:15:31 +00:00
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
vm.run(variables)
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Vm {
|
2024-08-05 04:40:51 +00:00
|
|
|
statement_nodes: VecDeque<Node>,
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Vm {
|
2024-08-05 04:40:51 +00:00
|
|
|
pub fn new(statement_nodes: VecDeque<Node>) -> Self {
|
|
|
|
Vm { statement_nodes }
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
pub fn run(
|
|
|
|
&mut self,
|
|
|
|
variables: &mut HashMap<Identifier, Value>,
|
|
|
|
) -> Result<Option<Value>, VmError> {
|
2024-08-05 02:15:31 +00:00
|
|
|
let mut previous_value = None;
|
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
while let Some(node) = self.statement_nodes.pop_front() {
|
|
|
|
previous_value = self.run_node(node, variables)?;
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(previous_value)
|
|
|
|
}
|
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
fn run_node(
|
|
|
|
&self,
|
|
|
|
node: Node,
|
|
|
|
variables: &mut HashMap<Identifier, Value>,
|
|
|
|
) -> Result<Option<Value>, VmError> {
|
|
|
|
match node.statement {
|
|
|
|
Statement::Add(left, right) => {
|
|
|
|
let left_span = left.span;
|
|
|
|
let left = if let Some(value) = self.run_node(*left, variables)? {
|
2024-08-05 02:15:31 +00:00
|
|
|
value
|
|
|
|
} else {
|
2024-08-05 04:40:51 +00:00
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left_span,
|
|
|
|
});
|
2024-08-05 02:15:31 +00:00
|
|
|
};
|
2024-08-05 04:40:51 +00:00
|
|
|
let right_span = right.span;
|
|
|
|
let right = if let Some(value) = self.run_node(*right, variables)? {
|
2024-08-05 02:15:31 +00:00
|
|
|
value
|
|
|
|
} else {
|
2024-08-05 04:40:51 +00:00
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: right_span,
|
|
|
|
});
|
2024-08-05 02:15:31 +00:00
|
|
|
};
|
|
|
|
let sum = left.add(&right)?;
|
|
|
|
|
|
|
|
Ok(Some(sum))
|
|
|
|
}
|
2024-08-05 04:40:51 +00:00
|
|
|
Statement::Assign(left, right) => {
|
|
|
|
let identifier = if let Statement::Identifier(identifier) = &left.statement {
|
|
|
|
identifier
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left.span,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
let right_span = right.span;
|
|
|
|
let value = if let Some(value) = self.run_node(*right, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: right_span,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
variables.insert(identifier.clone(), value);
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-08-05 03:11:04 +00:00
|
|
|
Statement::Constant(value) => Ok(Some(value.clone())),
|
2024-08-05 04:40:51 +00:00
|
|
|
Statement::Identifier(_) => Ok(None),
|
|
|
|
Statement::List(nodes) => {
|
|
|
|
let values = nodes
|
|
|
|
.into_iter()
|
|
|
|
.map(|node| {
|
|
|
|
let span = node.span;
|
|
|
|
if let Some(value) = self.run_node(node, variables)? {
|
|
|
|
Ok(value)
|
|
|
|
} else {
|
|
|
|
Err(VmError::ExpectedValue { position: span })
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<Value>, VmError>>()?;
|
|
|
|
|
|
|
|
Ok(Some(Value::list(values)))
|
|
|
|
}
|
|
|
|
Statement::Multiply(_, _) => todo!(),
|
2024-08-05 18:31:08 +00:00
|
|
|
Statement::PropertyAccess(left, right) => {
|
|
|
|
let left_span = left.span;
|
|
|
|
let left = if let Some(value) = self.run_node(*left, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left_span,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
let right_span = right.span;
|
|
|
|
|
2024-08-05 18:58:58 +00:00
|
|
|
if let Statement::Identifier(identifier) = &right.statement {
|
|
|
|
let value = left.property_access(identifier)?;
|
|
|
|
|
|
|
|
return Ok(Some(value));
|
|
|
|
}
|
2024-08-05 18:31:08 +00:00
|
|
|
|
2024-08-05 18:58:58 +00:00
|
|
|
if let Statement::Constant(value) = &right.statement {
|
|
|
|
if let Some(index) = value.as_integer() {
|
|
|
|
let value = left.list_access(index)?;
|
|
|
|
|
|
|
|
return Ok(Some(value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(VmError::ExpectedIdentifierOrInteger {
|
|
|
|
position: right_span,
|
|
|
|
})
|
2024-08-05 18:31:08 +00:00
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub enum VmError {
|
|
|
|
ParseError(ParseError),
|
|
|
|
ValueError(ValueError),
|
2024-08-05 04:40:51 +00:00
|
|
|
|
|
|
|
// Anaylsis Failures
|
|
|
|
// These should be prevented by running the analyzer before the VM
|
|
|
|
ExpectedValue { position: Span },
|
2024-08-05 18:58:58 +00:00
|
|
|
ExpectedIdentifierOrInteger { position: (usize, usize) },
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ParseError> for VmError {
|
2024-08-05 04:40:51 +00:00
|
|
|
fn from(error: ParseError) -> Self {
|
|
|
|
Self::ParseError(error)
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ValueError> for VmError {
|
2024-08-05 04:40:51 +00:00
|
|
|
fn from(error: ValueError) -> Self {
|
|
|
|
Self::ValueError(error)
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
2024-08-05 18:58:58 +00:00
|
|
|
#[test]
|
|
|
|
fn list_access() {
|
|
|
|
let input = "[1, 2, 3][1]";
|
|
|
|
|
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2))));
|
|
|
|
}
|
|
|
|
|
2024-08-05 18:31:08 +00:00
|
|
|
#[test]
|
|
|
|
fn property_access() {
|
|
|
|
let input = "[1, 2, 3].length";
|
|
|
|
|
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3))));
|
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[test]
|
|
|
|
fn add() {
|
|
|
|
let input = "1 + 2";
|
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3))));
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
2024-08-05 03:11:04 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_multiple() {
|
2024-08-05 04:40:51 +00:00
|
|
|
let input = "1 + 2 + 3";
|
2024-08-05 03:11:04 +00:00
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(6))));
|
2024-08-05 03:11:04 +00:00
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|