From 26348fb82e5c407e93b01c716f9d8bcfb9b614ab Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 16 Aug 2024 00:41:52 -0400 Subject: [PATCH] Continue implementing the VM --- dust-lang/src/abstract_tree/expression.rs | 14 +- dust-lang/src/parser.rs | 56 +++--- dust-lang/src/vm.rs | 223 ++++++++++++++++++---- 3 files changed, 218 insertions(+), 75 deletions(-) diff --git a/dust-lang/src/abstract_tree/expression.rs b/dust-lang/src/abstract_tree/expression.rs index e2be0fb..9d01ad8 100644 --- a/dust-lang/src/abstract_tree/expression.rs +++ b/dust-lang/src/abstract_tree/expression.rs @@ -16,7 +16,7 @@ pub enum Expression { FieldAccess(Node>), Grouped(Node>), Identifier(Node), - If(Node>), + If(Node>), List(Node>), ListIndex(Node>), Literal(Node>), @@ -197,7 +197,7 @@ impl Expression { Self::ListIndex(Node::new(Box::new(list_index), position)) } - pub fn r#if(r#if: If, position: Span) -> Self { + pub fn r#if(r#if: IfExpression, position: Span) -> Self { Self::If(Node::new(Box::new(r#if), position)) } @@ -543,7 +543,7 @@ impl Display for LogicOperator { } #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum If { +pub enum IfExpression { If { condition: Expression, if_block: Node, @@ -558,7 +558,7 @@ pub enum If { #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum ElseExpression { Block(Node), - If(Box), + If(Node>), } impl Display for ElseExpression { @@ -570,16 +570,16 @@ impl Display for ElseExpression { } } -impl Display for If { +impl Display for IfExpression { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - If::If { + IfExpression::If { condition, if_block, } => { write!(f, "if {} {}", condition, if_block) } - If::IfElse { + IfExpression::IfElse { condition, if_block, r#else, diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 9cbd859..6881feb 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -774,7 +774,7 @@ impl<'src> Parser<'src> { } } - fn parse_if(&mut self) -> Result { + fn parse_if(&mut self) -> Result { // Assume that the "if" token has already been consumed self.mode = ParserMode::Condition; @@ -788,27 +788,30 @@ impl<'src> Parser<'src> { if let Token::Else = self.current_token { self.next_token()?; + let if_keyword_start = self.current_position.0; + if let Token::If = self.current_token { self.next_token()?; - let else_if = self.parse_if()?; + let if_expression = self.parse_if()?; + let position = (if_keyword_start, self.current_position.1); - Ok(If::IfElse { + Ok(IfExpression::IfElse { condition, if_block, - r#else: ElseExpression::If(Box::new(else_if)), + r#else: ElseExpression::If(Node::new(Box::new(if_expression), position)), }) } else { let else_block = self.parse_block()?; - Ok(If::IfElse { + Ok(IfExpression::IfElse { condition, if_block, r#else: ElseExpression::Block(else_block), }) } } else { - Ok(If::If { + Ok(IfExpression::If { condition, if_block, }) @@ -1383,7 +1386,7 @@ mod tests { parse(source), Ok(AbstractSyntaxTree::with_statements([ Statement::Expression(Expression::r#if( - If::If { + IfExpression::If { condition: Expression::identifier(Identifier::new("x"), (3, 4)), if_block: Node::new( Block::Sync(vec![Statement::Expression(Expression::identifier( @@ -1407,7 +1410,7 @@ mod tests { parse(source), Ok(AbstractSyntaxTree::with_statements([ Statement::Expression(Expression::r#if( - If::IfElse { + IfExpression::IfElse { condition: Expression::identifier(Identifier::new("x"), (3, 4)), if_block: Node::new( Block::Sync(vec![Statement::Expression(Expression::identifier( @@ -1438,7 +1441,7 @@ mod tests { parse(source), Ok(AbstractSyntaxTree::with_statements([ Statement::Expression(Expression::r#if( - If::IfElse { + IfExpression::IfElse { condition: Expression::identifier(Identifier::new("x"), (3, 4)), if_block: Node::new( Block::Sync(vec![Statement::Expression(Expression::identifier( @@ -1447,23 +1450,24 @@ mod tests { ))]), (5, 10) ), - r#else: ElseExpression::If(Box::new(If::IfElse { - condition: Expression::identifier(Identifier::new("z"), (19, 20)), - if_block: Node::new( - Block::Sync(vec![Statement::Expression(Expression::identifier( - Identifier::new("a"), - (23, 24) - ))]), - (21, 26) - ), - r#else: ElseExpression::Block(Node::new( - Block::Sync(vec![Statement::Expression(Expression::identifier( - Identifier::new("b"), - (34, 35) - ))]), - (32, 37) - )), - })), + r#else: ElseExpression::If(Node::new( + Box::new(IfExpression::IfElse { + condition: Expression::identifier(Identifier::new("z"), (19, 20)), + if_block: Node::new( + Block::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("a"), (23, 24)) + )]), + (21, 26) + ), + r#else: ElseExpression::Block(Node::new( + Block::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("b"), (34, 35)) + )]), + (32, 37) + )), + }), + (16, 37) + )), }, (0, 37) )) diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 921a474..beb949f 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -12,9 +12,12 @@ use std::{ use rayon::iter::{IntoParallelIterator, ParallelIterator}; use crate::{ - abstract_tree::{AbstractSyntaxTree, Block, CallExpression, FieldAccess, Node, Statement}, + abstract_tree::{ + AbstractSyntaxTree, Block, CallExpression, ElseExpression, FieldAccess, IfExpression, + ListExpression, Node, Statement, + }, parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError, - Span, Struct, StructType, Type, Value, ValueError, + Span, Value, ValueError, }; /// Run the source code and return the result. @@ -104,7 +107,8 @@ impl Vm { } fn run_statement(&self, statement: Statement) -> Result, VmError> { - match statement { + let position = statement.position(); + let result = match statement { Statement::Expression(expression) => self.run_expression(expression), Statement::ExpressionNullified(expression) => { self.run_expression(expression.inner)?; @@ -113,37 +117,18 @@ impl Vm { } Statement::Let(_) => todo!(), Statement::StructDefinition(_) => todo!(), - } + }; + + result.map_err(|error| VmError::Trace { + error: Box::new(error), + position, + }) } fn run_expression(&self, expression: Expression) -> Result, VmError> { - match expression { - Expression::Block(Node { inner, position }) => match *inner { - Block::Async(statements) => { - let error_option = statements - .into_par_iter() - .find_map_any(|statement| self.run_statement(statement).err()); - - if let Some(error) = error_option { - Err(error) - } else { - Ok(None) - } - } - Block::Sync(statements) => { - let mut previous_value = None; - - for statement in statements { - let position = statement.position(); - - previous_value = self.run_statement(statement)?; - - self.context.collect_garbage(position.1); - } - - Ok(previous_value) - } - }, + let position = expression.position(); + let result = match expression { + Expression::Block(Node { inner, .. }) => self.run_block(*inner), Expression::Call(Node { inner, .. }) => { let CallExpression { invoker, arguments } = *inner; @@ -195,10 +180,18 @@ impl Vm { Ok(container_value.get_field(&field.inner)) } - Expression::Grouped(_) => todo!(), - Expression::Identifier(_) => todo!(), - Expression::If(_) => todo!(), - Expression::List(_) => todo!(), + Expression::Grouped(expression) => self.run_expression(*expression.inner), + Expression::Identifier(identifier) => { + let value_option = self.context.get_value(&identifier.inner); + + if let Some(value) = value_option { + Ok(Some(value)) + } else { + Err(VmError::UndefinedVariable { identifier }) + } + } + Expression::If(if_expression) => self.run_if(*if_expression.inner), + Expression::List(list_expression) => self.run_list(*list_expression.inner), Expression::ListIndex(_) => todo!(), Expression::Literal(_) => todo!(), Expression::Loop(_) => todo!(), @@ -206,6 +199,147 @@ impl Vm { Expression::Range(_) => todo!(), Expression::Struct(_) => todo!(), Expression::TupleAccess(_) => todo!(), + }; + + result.map_err(|error| VmError::Trace { + error: Box::new(error), + position, + }) + } + + fn run_list(&self, list_expression: ListExpression) -> Result, VmError> { + match list_expression { + ListExpression::AutoFill { + repeat_operand, + length_operand, + } => { + let position = length_operand.position(); + let length = if let Some(value) = self.run_expression(length_operand)? { + if let Some(length) = value.as_integer() { + length + } else { + return Err(VmError::ExpectedInteger { position }); + } + } else { + return Err(VmError::ExpectedValue { position }); + }; + + let position = repeat_operand.position(); + let value = if let Some(value) = self.run_expression(repeat_operand)? { + value + } else { + return Err(VmError::ExpectedValue { position }); + }; + + Ok(Some(Value::list(vec![value; length as usize]))) + } + ListExpression::Ordered(expressions) => { + let mut values = Vec::new(); + + for expression in expressions { + let position = expression.position(); + + if let Some(value) = self.run_expression(expression)? { + values.push(value); + } else { + return Err(VmError::ExpectedValue { position }); + } + } + + Ok(Some(Value::list(values))) + } + } + } + + fn run_block(&self, block: Block) -> Result, VmError> { + match block { + Block::Async(statements) => { + let error_option = statements + .into_par_iter() + .find_map_any(|statement| self.run_statement(statement).err()); + + if let Some(error) = error_option { + Err(error) + } else { + Ok(None) + } + } + Block::Sync(statements) => { + let mut previous_value = None; + + for statement in statements { + let position = statement.position(); + + previous_value = self.run_statement(statement)?; + + self.context.collect_garbage(position.1); + } + + Ok(previous_value) + } + } + } + + fn run_if(&self, if_expression: IfExpression) -> Result, VmError> { + match if_expression { + IfExpression::If { + condition, + if_block, + } => { + let condition_position = condition.position(); + let condition_value = if let Some(value) = self.run_expression(condition)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; + + if let Some(boolean) = condition_value.as_boolean() { + if boolean { + self.run_expression(Expression::block(if_block.inner, if_block.position))?; + } + } else { + return Err(VmError::ExpectedBoolean { + position: condition_position, + }); + } + + Ok(None) + } + IfExpression::IfElse { + condition, + if_block, + r#else, + } => { + let condition_position = condition.position(); + let condition_value = if let Some(value) = self.run_expression(condition)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; + + if let Some(boolean) = condition_value.as_boolean() { + if boolean { + self.run_expression(Expression::block(if_block.inner, if_block.position))?; + } + } else { + return Err(VmError::ExpectedBoolean { + position: condition_position, + }); + } + + match r#else { + ElseExpression::If(if_expression) => { + self.run_expression(Expression::If(if_expression)) + } + ElseExpression::Block(block) => { + self.run_expression(Expression::block(block.inner, block.position)) + } + } + } } } } @@ -213,6 +347,10 @@ impl Vm { #[derive(Clone, Debug, PartialEq)] pub enum VmError { ParseError(ParseError), + Trace { + error: Box, + position: Span, + }, ValueError { error: ValueError, position: Span, @@ -274,6 +412,7 @@ impl VmError { pub fn position(&self) -> Span { match self { Self::ParseError(parse_error) => parse_error.position(), + Self::Trace { position, .. } => *position, Self::ValueError { position, .. } => *position, Self::CannotMutate { position, .. } => *position, Self::BuiltInFunctionError { position, .. } => *position, @@ -305,6 +444,13 @@ impl Display for VmError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::ParseError(parse_error) => write!(f, "{}", parse_error), + Self::Trace { error, position } => { + write!( + f, + "Error during execution at position: {:?}\n{}", + position, error + ) + } Self::ValueError { error, .. } => write!(f, "{}", error), Self::CannotMutate { value, .. } => { write!(f, "Cannot mutate immutable value {}", value) @@ -492,13 +638,6 @@ mod tests { assert_eq!(run(input), Ok(Some(Value::integer(42)))); } - #[test] - fn map_property_access_expression() { - let input = "{ foobar = 42 }.('foo' + 'bar')"; - - assert_eq!(run(input), Ok(Some(Value::integer(42)))); - } - #[test] fn list_index_range() { let input = "[1, 2, 3, 4, 5][1..3]";