Implement VM and Analyzer by using the new AST

This commit is contained in:
Jeff 2024-08-16 09:22:36 -04:00
parent fedefdb29f
commit 7d721beb31
5 changed files with 348 additions and 75 deletions

View File

@ -10,8 +10,8 @@ use std::{
};
use crate::{
ast::{AbstractSyntaxTree, Node, Statement},
parse, Context, DustError, Identifier, Span, Type,
ast::{AbstractSyntaxTree, LetStatement, Node, OperatorExpression, Statement},
parse, Context, DustError, Expression, Identifier, Span, Type,
};
/// Analyzes the abstract syntax tree for errors.
@ -65,14 +65,125 @@ impl<'a> Analyzer<'a> {
}
pub fn analyze(&mut self) -> Result<(), AnalyzerError> {
for node in &self.abstract_tree.statements {
self.analyze_statement(node)?;
for statement in &self.abstract_tree.statements {
self.analyze_statement(statement)?;
}
Ok(())
}
fn analyze_statement(&mut self, _: &Statement) -> Result<(), AnalyzerError> {
fn analyze_statement(&mut self, statement: &Statement) -> Result<(), AnalyzerError> {
match statement {
Statement::Expression(expression) => self.analyze_expression(expression)?,
Statement::ExpressionNullified(expression_node) => {
self.analyze_expression(&expression_node.inner)?;
}
Statement::Let(let_statement) => match &let_statement.inner {
LetStatement::Let { identifier, value } => {
let type_option = value.return_type(self.context);
if let Some(r#type) = type_option {
self.context.set_type(
identifier.inner.clone(),
r#type,
identifier.position,
);
} else {
return Err(AnalyzerError::UndefinedVariable {
identifier: identifier.clone(),
});
}
self.analyze_expression(value)?;
}
LetStatement::LetMut { identifier, value } => {
let type_option = value.return_type(self.context);
if let Some(r#type) = type_option {
self.context.set_type(
identifier.inner.clone(),
r#type,
identifier.position,
);
} else {
return Err(AnalyzerError::UndefinedVariable {
identifier: identifier.clone(),
});
}
self.analyze_expression(value)?;
}
LetStatement::LetType {
identifier,
r#type,
value,
} => todo!(),
LetStatement::LetMutType {
identifier,
r#type,
value,
} => todo!(),
},
Statement::StructDefinition(_) => {}
}
Ok(())
}
fn analyze_expression(&mut self, expression: &Expression) -> Result<(), AnalyzerError> {
match expression {
Expression::Block(_) => {}
Expression::Call(_) => {}
Expression::FieldAccess(_) => {}
Expression::Grouped(_) => {}
Expression::Identifier(identifier) => {
let found = self
.context
.update_last_position(&identifier.inner, identifier.position);
if !found {
return Err(AnalyzerError::UndefinedVariable {
identifier: identifier.clone(),
});
}
}
Expression::If(_) => {}
Expression::List(_) => {}
Expression::ListIndex(_) => {}
Expression::Literal(_) => {}
Expression::Loop(_) => {}
Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() {
OperatorExpression::Assignment { assignee, value } => {
self.analyze_expression(assignee)?;
self.analyze_expression(value)?;
}
OperatorExpression::Comparison { left, right, .. } => {
self.analyze_expression(left)?;
self.analyze_expression(right)?;
}
OperatorExpression::CompoundAssignment {
assignee, modifier, ..
} => {
self.analyze_expression(assignee)?;
self.analyze_expression(modifier)?;
}
OperatorExpression::ErrorPropagation(_) => todo!(),
OperatorExpression::Negation(_) => todo!(),
OperatorExpression::Not(_) => todo!(),
OperatorExpression::Math { left, right, .. } => {
self.analyze_expression(left)?;
self.analyze_expression(right)?;
}
OperatorExpression::Logic { left, right, .. } => {
self.analyze_expression(left)?;
self.analyze_expression(right)?;
}
},
Expression::Range(_) => {}
Expression::Struct(_) => {}
Expression::TupleAccess(_) => {}
}
Ok(())
}
}
@ -124,13 +235,13 @@ pub enum AnalyzerError {
identifier: Node<Identifier>,
},
UnexpectedIdentifier {
identifier: Statement,
identifier: Node<Identifier>,
},
UnexectedString {
actual: Statement,
},
UndefinedVariable {
identifier: Statement,
identifier: Node<Identifier>,
},
}
@ -151,8 +262,8 @@ impl AnalyzerError {
} => actual_statement.position(),
AnalyzerError::UndefinedField { identifier, .. } => identifier.position(),
AnalyzerError::UndefinedType { identifier } => identifier.position,
AnalyzerError::UndefinedVariable { identifier } => identifier.position(),
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position(),
AnalyzerError::UndefinedVariable { identifier } => identifier.position,
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position,
AnalyzerError::UnexectedString { actual } => actual.position(),
}
}

View File

@ -170,6 +170,10 @@ impl<'src> Parser<'src> {
let value = self.parse_expression(0)?;
if let Token::Semicolon = self.current_token {
self.next_token()?;
}
let r#let = if is_mutable {
LetStatement::LetMut { identifier, value }
} else {

View File

@ -366,7 +366,7 @@ impl Display for TokenOwned {
TokenOwned::Async => Token::Async.fmt(f),
TokenOwned::Bang => Token::Bang.fmt(f),
TokenOwned::BangEqual => Token::BangEqual.fmt(f),
TokenOwned::Bool => write!(f, "bool"),
TokenOwned::Bool => Token::Bool.fmt(f),
TokenOwned::Boolean(boolean) => write!(f, "{boolean}"),
TokenOwned::Colon => Token::Colon.fmt(f),
TokenOwned::Comma => Token::Comma.fmt(f),
@ -379,12 +379,12 @@ impl Display for TokenOwned {
TokenOwned::Eof => Token::Eof.fmt(f),
TokenOwned::Equal => Token::Equal.fmt(f),
TokenOwned::Float(float) => write!(f, "{float}"),
TokenOwned::FloatKeyword => write!(f, "float"),
TokenOwned::FloatKeyword => Token::FloatKeyword.fmt(f),
TokenOwned::Greater => Token::Greater.fmt(f),
TokenOwned::GreaterOrEqual => Token::GreaterEqual.fmt(f),
TokenOwned::Identifier(text) => write!(f, "{text}"),
TokenOwned::If => Token::If.fmt(f),
TokenOwned::Int => write!(f, "int"),
TokenOwned::Int => Token::Int.fmt(f),
TokenOwned::Integer(integer) => write!(f, "{integer}"),
TokenOwned::IsEven => Token::IsEven.fmt(f),
TokenOwned::IsOdd => Token::IsOdd.fmt(f),
@ -408,7 +408,7 @@ impl Display for TokenOwned {
TokenOwned::Semicolon => Token::Semicolon.fmt(f),
TokenOwned::Star => Token::Star.fmt(f),
TokenOwned::Slash => Token::Slash.fmt(f),
TokenOwned::Str => write!(f, "str"),
TokenOwned::Str => Token::Str.fmt(f),
TokenOwned::String(string) => write!(f, "{string}"),
TokenOwned::Struct => Token::Struct.fmt(f),
TokenOwned::ToString => Token::ToString.fmt(f),

View File

@ -105,12 +105,17 @@ impl Value {
matches!(self, Value::Mutable(_))
}
pub fn to_mut(self) -> Self {
match self {
Value::Immutable(inner) => {
Value::Mutable(Arc::new(RwLock::new(inner.as_ref().clone())))
}
_ => self,
pub fn to_mut(self) -> Result<Value, ValueError> {
if let Value::Immutable(arc) = self {
let value_data = if let Some(value_data) = Arc::into_inner(arc) {
value_data
} else {
return Err(ValueError::CannotMakeMutable);
};
Ok(Value::Mutable(Arc::new(RwLock::new(value_data))))
} else {
Ok(self)
}
}
@ -317,7 +322,7 @@ impl Value {
Err(ValueError::CannotAdd(self.clone(), other.clone()))
}
pub fn add_mut(&self, other: &Value) -> Result<(), ValueError> {
pub fn add_assign(&self, other: &Value) -> Result<(), ValueError> {
match (self, other) {
(Value::Mutable(left), Value::Mutable(right)) => {
match (&mut *left.write().unwrap(), &*right.read().unwrap()) {
@ -412,7 +417,7 @@ impl Value {
Err(ValueError::CannotSubtract(self.clone(), other.clone()))
}
pub fn subtract_mut(&self, other: &Value) -> Result<(), ValueError> {
pub fn subtract_assign(&self, other: &Value) -> Result<(), ValueError> {
match (self, other) {
(Value::Mutable(left), Value::Mutable(right)) => {
match (&mut *left.write().unwrap(), &*right.read().unwrap()) {
@ -489,6 +494,42 @@ impl Value {
Err(ValueError::CannotMultiply(self.clone(), other.clone()))
}
pub fn multiply_assign(&self, other: &Value) -> Result<(), ValueError> {
match (self, other) {
(Value::Mutable(left), Value::Mutable(right)) => {
match (&mut *left.write().unwrap(), &*right.read().unwrap()) {
(ValueData::Float(left), ValueData::Float(right)) => {
*left *= right;
return Ok(());
}
(ValueData::Integer(left), ValueData::Integer(right)) => {
*left = left.saturating_mul(*right);
return Ok(());
}
_ => {}
}
}
(Value::Mutable(left), Value::Immutable(right)) => {
match (&mut *left.write().unwrap(), right.as_ref()) {
(ValueData::Float(left), ValueData::Float(right)) => {
*left *= right;
return Ok(());
}
(ValueData::Integer(left), ValueData::Integer(right)) => {
*left = left.saturating_mul(*right);
return Ok(());
}
_ => {}
}
}
(Value::Immutable(_), _) => {
return Err(ValueError::CannotMutate(self.clone()));
}
}
Err(ValueError::CannotMultiply(self.clone(), other.clone()))
}
pub fn divide(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(Value::Immutable(left), Value::Immutable(right)) => {
@ -564,6 +605,54 @@ impl Value {
Err(ValueError::CannotDivide(self.clone(), other.clone()))
}
pub fn divide_assign(&self, other: &Value) -> Result<(), ValueError> {
match (self, other) {
(Value::Mutable(left), Value::Mutable(right)) => {
match (&mut *left.write().unwrap(), &*right.read().unwrap()) {
(ValueData::Float(left), ValueData::Float(right)) => {
if *right == 0.0 {
return Err(ValueError::DivisionByZero);
}
*left /= right;
return Ok(());
}
(ValueData::Integer(left), ValueData::Integer(right)) => {
if *right == 0 {
return Err(ValueError::DivisionByZero);
}
*left = left.saturating_div(*right);
return Ok(());
}
_ => {}
}
}
(Value::Mutable(left), Value::Immutable(right)) => {
match (&mut *left.write().unwrap(), right.as_ref()) {
(ValueData::Float(left), ValueData::Float(right)) => {
if *right == 0.0 {
return Err(ValueError::DivisionByZero);
}
*left /= right;
return Ok(());
}
(ValueData::Integer(left), ValueData::Integer(right)) => {
if *right == 0 {
return Err(ValueError::DivisionByZero);
}
*left = left.saturating_div(*right);
return Ok(());
}
_ => {}
}
}
(Value::Immutable(_), _) => {
return Err(ValueError::CannotMutate(self.clone()));
}
}
Err(ValueError::CannotDivide(self.clone(), other.clone()))
}
pub fn modulo(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(Value::Immutable(left), Value::Immutable(right)) => {
@ -627,6 +716,48 @@ impl Value {
Err(ValueError::CannotModulo(self.clone(), other.clone()))
}
pub fn modulo_assign(&self, other: &Value) -> Result<(), ValueError> {
match (self, other) {
(Value::Mutable(left), Value::Mutable(right)) => {
match (&mut *left.write().unwrap(), &*right.read().unwrap()) {
(ValueData::Float(left), ValueData::Float(right)) => {
*left %= right;
return Ok(());
}
(ValueData::Integer(left), ValueData::Integer(right)) => {
if *right == 0 {
return Err(ValueError::DivisionByZero);
}
*left %= right;
return Ok(());
}
_ => {}
}
}
(Value::Mutable(left), Value::Immutable(right)) => {
match (&mut *left.write().unwrap(), right.as_ref()) {
(ValueData::Float(left), ValueData::Float(right)) => {
*left %= right;
return Ok(());
}
(ValueData::Integer(left), ValueData::Integer(right)) => {
if *right == 0 {
return Err(ValueError::DivisionByZero);
}
*left %= right;
return Ok(());
}
_ => {}
}
}
(Value::Immutable(_), _) => {
return Err(ValueError::CannotMutate(self.clone()));
}
}
Err(ValueError::CannotModulo(self.clone(), other.clone()))
}
pub fn equal(&self, other: &Value) -> Value {
let is_equal = match (self, other) {
(Value::Immutable(left), Value::Immutable(right)) => left == right,
@ -1614,6 +1745,7 @@ pub enum ValueError {
CannotGreaterThanOrEqual(Value, Value),
CannotLessThan(Value, Value),
CannotLessThanOrEqual(Value, Value),
CannotMakeMutable,
CannotModulo(Value, Value),
CannotMultiply(Value, Value),
CannotMutate(Value),
@ -1644,6 +1776,10 @@ impl Display for ValueError {
ValueError::CannotMultiply(left, right) => {
write!(f, "Cannot multiply {} and {}", left, right)
}
ValueError::CannotMakeMutable => write!(
f,
"Failed to make mutable value because the value has an immutable reference to it"
),
ValueError::CannotMutate(value) => write!(f, "Cannot mutate {}", value),
ValueError::CannotSubtract(left, right) => {
write!(f, "Cannot subtract {} and {}", left, right)

View File

@ -14,12 +14,12 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterato
use crate::{
ast::{
AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression,
FieldAccessExpression, IfExpression, ListExpression, ListIndexExpression,
FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression,
LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression,
Statement,
},
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError,
Span, Type, Value, ValueError,
Span, Value, ValueError,
};
/// Run the source code and return the result.
@ -90,21 +90,12 @@ impl Vm {
}
pub fn run(&mut self) -> Result<Option<Value>, VmError> {
let mut previous_position = (0, 0);
let mut previous_value = None;
while let Some(statement) = self.abstract_tree.statements.pop_front() {
let new_position = statement.position();
previous_value = self.run_statement(statement)?;
self.context.collect_garbage(previous_position.1);
previous_position = new_position;
}
self.context.collect_garbage(previous_position.1);
Ok(previous_value)
}
@ -119,16 +110,50 @@ impl Vm {
Ok(None)
}
Statement::Let(_) => todo!(),
Statement::Let(let_statement) => {
self.run_let_statement(let_statement.inner)?;
Ok(None)
}
Statement::StructDefinition(_) => todo!(),
};
self.context.collect_garbage(position.1);
result.map_err(|error| VmError::Trace {
error: Box::new(error),
position,
})
}
fn run_let_statement(&self, let_statement: LetStatement) -> Result<(), VmError> {
match let_statement {
LetStatement::Let { identifier, value } => {
let value_position = value.position();
let value = self.run_expression(value)?.expect_value(value_position)?;
self.context.set_value(identifier.inner, value);
Ok(())
}
LetStatement::LetMut { identifier, value } => {
let value_position = value.position();
let value = self.run_expression(value)?.expect_value(value_position)?;
let mutable_value = value.to_mut().map_err(|error| VmError::ValueError {
error,
left_position: identifier.position,
right_position: value_position,
})?;
self.context.set_value(identifier.inner, mutable_value);
Ok(())
}
LetStatement::LetType { .. } => todo!(),
LetStatement::LetMutType { .. } => todo!(),
}
}
fn run_expression(&self, expression: Expression) -> Result<Evaluation, VmError> {
let position = expression.position();
let evaluation_result = match expression {
@ -177,7 +202,13 @@ impl Vm {
let value_position = value.position();
let value = self.run_expression(value)?.expect_value(value_position)?;
assignee.mutate(value);
assignee
.mutate(value)
.map_err(|error| VmError::ValueError {
error,
left_position: assignee_position,
right_position: value_position,
})?;
Ok(Evaluation::Return(None))
}
@ -230,7 +261,31 @@ impl Vm {
assignee,
operator,
modifier,
} => todo!(),
} => {
let assignee_position = assignee.position();
let assignee = self
.run_expression(assignee)?
.expect_value(assignee_position)?;
let modifier_position = modifier.position();
let modifier = self
.run_expression(modifier)?
.expect_value(modifier_position)?;
match operator.inner {
MathOperator::Add => assignee.add_assign(&modifier),
MathOperator::Subtract => assignee.subtract_assign(&modifier),
MathOperator::Multiply => assignee.multiply_assign(&modifier),
MathOperator::Divide => assignee.divide_assign(&modifier),
MathOperator::Modulo => assignee.modulo_assign(&modifier),
}
.map_err(|error| VmError::ValueError {
error,
left_position: assignee_position,
right_position: modifier_position,
})?;
Ok(Evaluation::Return(None))
}
OperatorExpression::ErrorPropagation(_) => todo!(),
OperatorExpression::Negation(_) => todo!(),
OperatorExpression::Not(_) => todo!(),
@ -742,30 +797,16 @@ mod tests {
use super::*;
#[test]
fn mutate_variable() {
let input = "
mut x = ''
x += 'foo'
x += 'bar'
x
";
assert_eq!(run(input), Ok(Some(Value::string_mut("foobar"))));
}
#[test]
fn async_block() {
let input = "mut x = 1; async { x += 1; x -= 1; } x";
let input = "let mut x = 1; async { x += 1; x -= 1; } x";
assert!(run(input).unwrap().unwrap().as_integer().is_some());
}
#[test]
fn define_and_instantiate_fields_struct() {
let input = "struct Foo { bar: int, baz: float } Foo { bar = 42, baz = 4.0 }";
let input = "struct Foo { bar: int, baz: float } Foo { bar: 42, baz: 4.0 }";
assert_eq!(
run(input),
@ -844,20 +885,6 @@ mod tests {
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn map_property() {
let input = "{ x = 42 }.x";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn map_property_nested() {
let input = "{ x = { y = 42 } }.x.y";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn list_index_range() {
let input = "[1, 2, 3, 4, 5][1..3]";
@ -950,21 +977,23 @@ mod tests {
#[test]
fn while_loop() {
let input = "mut x = 0; while x < 5 { x += 1; } x";
let input = "let mut x = 0; while x < 5 { x += 1; } x";
assert_eq!(run(input), Ok(Some(Value::integer(5))));
}
#[test]
fn subtract_assign() {
let input = "mut x = 1; x -= 1; x";
let input = "let mut x = 1; x -= 1; x";
assert_eq!(run(input), Ok(Some(Value::integer(0))));
}
#[test]
fn add_assign() {
let input = "mut x = 1; x += 1; x";
env_logger::builder().is_test(true).try_init().ok();
let input = "let mut x = 1; x += 1; x";
assert_eq!(run(input), Ok(Some(Value::integer(2))));
}
@ -983,13 +1012,6 @@ mod tests {
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
}
#[test]
fn map_equal() {
let input = "{ y = 'foo' } == { y = 'foo' }";
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
}
#[test]
fn integer_equal() {
let input = "42 == 42";