dust/dust-lang/src/vm.rs

266 lines
8.0 KiB
Rust
Raw Normal View History

2024-08-07 15:38:08 +00:00
use std::collections::HashMap;
2024-08-05 02:15:31 +00:00
use crate::{
2024-08-07 15:38:08 +00:00
parse, AbstractSyntaxTree, Analyzer, AnalyzerError, Identifier, Node, ParseError,
ReservedIdentifier, Span, Statement, Value, ValueError,
};
2024-08-05 04:40:51 +00:00
pub fn run(
input: &str,
variables: &mut HashMap<Identifier, Value>,
2024-08-07 19:47:37 +00:00
) -> Result<Option<Value>, VmError<Span>> {
let abstract_syntax_tree = parse(input)?;
2024-08-07 15:57:15 +00:00
let analyzer = Analyzer::new(&abstract_syntax_tree, variables);
2024-08-07 15:38:08 +00:00
analyzer.analyze()?;
let mut vm = Vm::new(abstract_syntax_tree);
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
}
2024-08-07 19:47:37 +00:00
pub struct Vm<P> {
abstract_tree: AbstractSyntaxTree<P>,
2024-08-05 02:15:31 +00:00
}
2024-08-07 19:47:37 +00:00
impl<P: Copy> Vm<P> {
pub fn new(abstract_tree: AbstractSyntaxTree<P>) -> Self {
2024-08-07 15:38:08 +00:00
Self { abstract_tree }
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>,
2024-08-07 19:47:37 +00:00
) -> Result<Option<Value>, VmError<P>> {
2024-08-05 02:15:31 +00:00
let mut previous_value = None;
2024-08-07 15:38:08 +00:00
while let Some(node) = self.abstract_tree.nodes.pop_front() {
2024-08-05 04:40:51 +00:00
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,
2024-08-07 19:47:37 +00:00
node: Node<P>,
2024-08-05 04:40:51 +00:00
variables: &mut HashMap<Identifier, Value>,
2024-08-07 19:47:37 +00:00
) -> Result<Option<Value>, VmError<P>> {
2024-08-05 04:40:51 +00:00
match node.statement {
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::Identifier(_) => Ok(None),
Statement::ReservedIdentifier(_) => Ok(None),
2024-08-05 04:40:51 +00:00
Statement::Add(left, right) => {
2024-08-07 19:47:37 +00:00
let left_span = left.position;
2024-08-05 04:40:51 +00:00
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-07 19:47:37 +00:00
let right_span = right.position;
2024-08-05 04:40:51 +00:00
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::ExpectedIdentifier {
2024-08-07 19:47:37 +00:00
position: left.position,
2024-08-05 04:40:51 +00:00
});
};
2024-08-07 19:47:37 +00:00
let right_span = right.position;
2024-08-05 04:40:51 +00:00
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)
}
Statement::List(nodes) => {
let values = nodes
.into_iter()
.map(|node| {
2024-08-07 19:47:37 +00:00
let span = node.position;
2024-08-05 04:40:51 +00:00
if let Some(value) = self.run_node(node, variables)? {
Ok(value)
} else {
Err(VmError::ExpectedValue { position: span })
}
})
2024-08-07 19:47:37 +00:00
.collect::<Result<Vec<Value>, VmError<P>>>()?;
2024-08-05 04:40:51 +00:00
Ok(Some(Value::list(values)))
}
Statement::Multiply(_, _) => todo!(),
2024-08-05 18:31:08 +00:00
Statement::PropertyAccess(left, right) => {
2024-08-07 19:47:37 +00:00
let left_span = left.position;
2024-08-05 18:31:08 +00:00
let left = if let Some(value) = self.run_node(*left, variables)? {
value
} else {
return Err(VmError::ExpectedValue {
position: left_span,
});
};
2024-08-07 19:47:37 +00:00
let right_span = right.position;
2024-08-05 18:31:08 +00:00
if let Statement::ReservedIdentifier(reserved) = &right.statement {
match reserved {
ReservedIdentifier::IsEven => {
if let Some(integer) = left.as_integer() {
return Ok(Some(Value::boolean(integer % 2 == 0)));
} else {
return Err(VmError::ExpectedInteger {
position: right_span,
});
}
}
ReservedIdentifier::IsOdd => {
if let Some(integer) = left.as_integer() {
return Ok(Some(Value::boolean(integer % 2 != 0)));
} else {
return Err(VmError::ExpectedInteger {
position: right_span,
});
}
}
ReservedIdentifier::Length => {
if let Some(list) = left.as_list() {
return Ok(Some(Value::integer(list.len() as i64)));
} else {
return Err(VmError::ExpectedList {
position: right_span,
});
}
}
}
2024-08-05 18:58:58 +00:00
}
2024-08-05 18:31:08 +00:00
if let (Some(list), Statement::Constant(value)) = (left.as_list(), &right.statement)
{
2024-08-05 18:58:58 +00:00
if let Some(index) = value.as_integer() {
let value = list.get(index as usize).cloned();
2024-08-05 18:58:58 +00:00
return Ok(value);
2024-08-05 18:58:58 +00:00
}
}
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)]
2024-08-07 19:47:37 +00:00
pub enum VmError<P> {
AnaylyzerError(AnalyzerError<P>),
2024-08-05 02:15:31 +00:00
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
2024-08-07 19:47:37 +00:00
ExpectedIdentifier { position: P },
ExpectedIdentifierOrInteger { position: P },
ExpectedInteger { position: P },
ExpectedList { position: P },
ExpectedValue { position: P },
2024-08-05 02:15:31 +00:00
}
2024-08-07 19:47:37 +00:00
impl<P> From<AnalyzerError<P>> for VmError<P> {
fn from(error: AnalyzerError<P>) -> Self {
2024-08-07 15:38:08 +00:00
Self::AnaylyzerError(error)
}
}
2024-08-07 19:47:37 +00:00
impl<P> From<ParseError> for VmError<P> {
2024-08-05 04:40:51 +00:00
fn from(error: ParseError) -> Self {
Self::ParseError(error)
2024-08-05 02:15:31 +00:00
}
}
2024-08-07 19:47:37 +00:00
impl<P> From<ValueError> for VmError<P> {
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::*;
#[test]
fn boolean() {
let input = "true";
assert_eq!(
run(input, &mut HashMap::new()),
Ok(Some(Value::boolean(true)))
);
}
#[test]
fn is_even() {
let input = "42.is_even";
assert_eq!(
run(input, &mut HashMap::new()),
Ok(Some(Value::boolean(true)))
);
}
#[test]
fn is_odd() {
let input = "42.is_odd";
assert_eq!(
run(input, &mut HashMap::new()),
Ok(Some(Value::boolean(false)))
);
}
2024-08-05 18:58:58 +00:00
#[test]
fn list_access() {
let input = "[1, 2, 3].1";
2024-08-05 18:58:58 +00:00
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
}