From e3d821a1c38b52cc564f57d2baaa5817525032d1 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 20 Aug 2024 00:15:19 -0400 Subject: [PATCH] Remimplement features --- Cargo.lock | 1 + dust-lang/src/analyzer.rs | 193 +++++++++++--------- dust-lang/src/ast/expression.rs | 59 +++--- dust-lang/src/ast/statement.rs | 20 +-- dust-lang/src/context.rs | 10 +- dust-lang/src/parser.rs | 301 +++++++++++++------------------ dust-lang/src/type.rs | 307 +++++++++++++++++++++++--------- dust-lang/src/value.rs | 157 +++++++++++++--- dust-lang/src/vm.rs | 192 ++++++++++++++------ dust-shell/Cargo.toml | 1 + dust-shell/src/main.rs | 28 ++- 11 files changed, 797 insertions(+), 472 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 697f3f2..4b46f0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,6 +165,7 @@ version = "0.1.0" dependencies = [ "clap", "dust-lang", + "env_logger", ] [[package]] diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 4be3653..f7f3cf1 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -16,8 +16,7 @@ use crate::{ MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement, StructDefinition, StructExpression, TupleAccessExpression, }, - parse, Context, DustError, Expression, FieldsStructType, Identifier, StructType, TupleType, - Type, + parse, Context, DustError, Expression, Identifier, StructType, Type, }; /// Analyzes the abstract syntax tree for errors. @@ -85,62 +84,44 @@ impl<'a> Analyzer<'a> { 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); + LetStatement::Let { identifier, value } + | LetStatement::LetMut { identifier, value } => { + self.analyze_expression(value)?; - if let Some(r#type) = type_option { - self.context.set_type( + let r#type = value.return_type(self.context); + + if let Some(r#type) = r#type { + self.context.set_variable_type( identifier.inner.clone(), r#type, identifier.position, ); } else { - return Err(AnalysisError::ExpectedValue { - actual: statement.clone(), + return Err(AnalysisError::ExpectedValueFromExpression { + actual: value.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(AnalysisError::ExpectedValue { - actual: statement.clone(), - }); - } - - self.analyze_expression(value)?; - } - LetStatement::LetType { - identifier, - r#type, - value, - } => todo!(), - LetStatement::LetMutType { - identifier, - r#type, - value, - } => todo!(), + LetStatement::LetType { .. } => todo!(), + LetStatement::LetMutType { .. } => todo!(), }, Statement::StructDefinition(struct_definition) => { let (name, struct_type) = match &struct_definition.inner { - StructDefinition::Unit { name } => { - (name.inner.clone(), Type::Struct(StructType::Unit)) - } + StructDefinition::Unit { name } => ( + name, + Type::Struct(StructType::Unit { + name: name.inner.clone(), + }), + ), StructDefinition::Tuple { name, items } => { let fields = items.iter().map(|item| item.inner.clone()).collect(); ( - name.inner.clone(), - Type::Struct(StructType::Tuple(TupleType { fields })), + name, + Type::Struct(StructType::Tuple { + name: name.inner.clone(), + fields, + }), ) } StructDefinition::Fields { name, fields } => { @@ -152,14 +133,16 @@ impl<'a> Analyzer<'a> { .collect(); ( - name.inner.clone(), - Type::Struct(StructType::Fields(FieldsStructType { fields })), + name, + Type::Struct(StructType::Fields { + name: name.inner.clone(), + fields, + }), ) } }; - self.context - .set_type(name, struct_type, struct_definition.position); + todo!("Set constructor") } } @@ -179,24 +162,19 @@ impl<'a> Analyzer<'a> { } } Expression::FieldAccess(field_access_expression) => { - let FieldAccessExpression { container, .. } = + let FieldAccessExpression { container, field } = field_access_expression.inner.as_ref(); + self.context + .update_last_position(&field.inner, field.position); self.analyze_expression(container)?; } Expression::Grouped(expression) => { self.analyze_expression(expression.inner.as_ref())?; } Expression::Identifier(identifier) => { - let found = self - .context + self.context .update_last_position(&identifier.inner, identifier.position); - - if !found { - return Err(AnalysisError::UndefinedVariable { - identifier: identifier.clone(), - }); - } } Expression::If(if_expression) => self.analyze_if(&if_expression.inner)?, Expression::List(list_expression) => match list_expression.inner.as_ref() { @@ -256,6 +234,31 @@ impl<'a> Analyzer<'a> { } => { self.analyze_expression(assignee)?; self.analyze_expression(modifier)?; + + let expected_type = assignee.return_type(self.context); + let actual_type = modifier.return_type(self.context); + + if expected_type.is_none() { + return Err(AnalysisError::ExpectedValueFromExpression { + actual: assignee.clone(), + }); + } + + if actual_type.is_none() { + return Err(AnalysisError::ExpectedValueFromExpression { + actual: modifier.clone(), + }); + } + + if let (Some(expected_type), Some(actual_type)) = (expected_type, actual_type) { + expected_type.check(&actual_type).map_err(|type_conflct| { + AnalysisError::TypeConflict { + actual_expression: modifier.clone(), + actual_type, + expected: expected_type, + } + })?; + } } OperatorExpression::ErrorPropagation(_) => todo!(), OperatorExpression::Negation(expression) => { @@ -285,30 +288,14 @@ impl<'a> Analyzer<'a> { }, Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { StructExpression::Unit { name } => { - let found = self - .context - .update_last_position(&name.inner, name.position); - - if !found { - return Err(AnalysisError::UndefinedType { - identifier: name.clone(), - }); - } + todo!("Update constructor position"); } StructExpression::Fields { name, fields } => { - let found = self - .context - .update_last_position(&name.inner, name.position); + todo!("Update constructor position"); - if !found { - return Err(AnalysisError::UndefinedType { - identifier: name.clone(), - }); - } - - for (_, expression) in fields { - self.analyze_expression(expression)?; - } + // for (_, expression) in fields { + // self.analyze_expression(expression)?; + // } } }, Expression::TupleAccess(tuple_access) => { @@ -390,9 +377,12 @@ pub enum AnalysisError { ExpectedMap { actual: Statement, }, - ExpectedValue { + ExpectedValueFromStatement { actual: Statement, }, + ExpectedValueFromExpression { + actual: Expression, + }, ExpectedValueArgumentCount { expected: usize, actual: usize, @@ -405,7 +395,7 @@ pub enum AnalysisError { length: usize, }, TypeConflict { - actual_statement: Statement, + actual_expression: Expression, actual_type: Type, expected: Type, }, @@ -436,12 +426,13 @@ impl AnalysisError { AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(), AnalysisError::ExpectedList { actual } => actual.position(), AnalysisError::ExpectedMap { actual } => actual.position(), - AnalysisError::ExpectedValue { actual } => actual.position(), + AnalysisError::ExpectedValueFromExpression { actual } => actual.position(), + AnalysisError::ExpectedValueFromStatement { actual } => actual.position(), AnalysisError::ExpectedValueArgumentCount { position, .. } => *position, AnalysisError::IndexOutOfBounds { index, .. } => index.position(), AnalysisError::TypeConflict { - actual_statement, .. - } => actual_statement.position(), + actual_expression, .. + } => actual_expression.position(), AnalysisError::UndefinedField { identifier, .. } => identifier.position(), AnalysisError::UndefinedType { identifier } => identifier.position, AnalysisError::UndefinedVariable { identifier } => identifier.position, @@ -470,8 +461,15 @@ impl Display for AnalysisError { } AnalysisError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual), AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual), - AnalysisError::ExpectedValue { actual, .. } => { - write!(f, "Expected value, found {}", actual) + AnalysisError::ExpectedValueFromExpression { actual, .. } => { + write!( + f, + "Expected expression to produce a value, found {}", + actual + ) + } + AnalysisError::ExpectedValueFromStatement { actual, .. } => { + write!(f, "Expected statement to produce a value, found {}", actual) } AnalysisError::ExpectedValueArgumentCount { expected, actual, .. @@ -487,7 +485,7 @@ impl Display for AnalysisError { index_value, list, length ), AnalysisError::TypeConflict { - actual_statement, + actual_expression: actual_statement, actual_type, expected, } => { @@ -521,18 +519,27 @@ impl Display for AnalysisError { #[cfg(test)] mod tests { - use crate::{Identifier, Value}; use super::*; #[test] fn add_assign_wrong_type() { let source = " - a = 1 + let mut a = 1; a += 1.0 "; - assert_eq!(analyze(source), todo!()); + assert_eq!( + analyze(source), + Err(DustError::AnalysisError { + analysis_error: AnalysisError::TypeConflict { + actual_expression: Expression::literal(1.0, (45, 48)), + actual_type: Type::Float, + expected: Type::Integer, + }, + source, + }) + ); } #[test] @@ -542,7 +549,17 @@ mod tests { a -= 1.0 "; - assert_eq!(analyze(source), todo!()); + assert_eq!( + analyze(source), + Err(DustError::AnalysisError { + analysis_error: AnalysisError::TypeConflict { + actual_expression: Expression::literal(1.0, (45, 48)), + actual_type: Type::Float, + expected: Type::Integer, + }, + source, + }) + ); } #[test] diff --git a/dust-lang/src/ast/expression.rs b/dust-lang/src/ast/expression.rs index 22e4b08..1c3cf7a 100644 --- a/dust-lang/src/ast/expression.rs +++ b/dust-lang/src/ast/expression.rs @@ -6,9 +6,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{ - Context, FieldsStructType, FunctionType, Identifier, RangeableType, StructType, TupleType, Type, -}; +use crate::{Context, FunctionType, Identifier, RangeableType, StructType, Type}; use super::{Node, Span, Statement}; @@ -268,17 +266,17 @@ impl Expression { pub fn return_type(&self, context: &Context) -> Option { match self { Expression::Block(block_expression) => { - block_expression.inner.as_ref().return_type(context) + Some(block_expression.inner.return_type(context)?) } Expression::Call(call_expression) => { let CallExpression { invoker, .. } = call_expression.inner.as_ref(); - let invoker_type = invoker.return_type(context)?; + let invoker_type = invoker.return_type(context); - if let Type::Function(FunctionType { return_type, .. }) = invoker_type { + if let Some(Type::Function(FunctionType { return_type, .. })) = invoker_type { return_type.map(|r#type| *r#type) - } else if let Type::Struct(_) = invoker_type { - Some(invoker_type) + } else if let Some(Type::Struct(_)) = invoker_type { + invoker_type } else { None } @@ -287,11 +285,9 @@ impl Expression { let FieldAccessExpression { container, field } = field_access_expression.inner.as_ref(); - let container_type = container.return_type(context)?; + let container_type = container.return_type(context); - if let Type::Struct(StructType::Fields(FieldsStructType { fields, .. })) = - container_type - { + if let Some(Type::Struct(StructType::Fields { fields, .. })) = container_type { fields .into_iter() .find(|(name, _)| name == &field.inner) @@ -301,12 +297,13 @@ impl Expression { } } Expression::Grouped(expression) => expression.inner.return_type(context), - Expression::Identifier(identifier) => context.get_type(&identifier.inner), - Expression::If(if_expression) => match if_expression.inner.as_ref() { - IfExpression::If { .. } => None, - IfExpression::IfElse { if_block, .. } => if_block.inner.return_type(context), - }, - + Expression::Identifier(identifier) => context.get_variable_type(&identifier.inner), + Expression::If(if_expression) => { + return match if_expression.inner.as_ref() { + IfExpression::If { .. } => None, + IfExpression::IfElse { if_block, .. } => if_block.inner.return_type(context), + } + } Expression::List(list_expression) => match list_expression.inner.as_ref() { ListExpression::AutoFill { repeat_operand, .. } => { let item_type = repeat_operand.return_type(context)?; @@ -396,7 +393,7 @@ impl Expression { }) } Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { - StructExpression::Fields { fields, .. } => { + StructExpression::Fields { name, fields } => { let mut types = HashMap::with_capacity(fields.len()); for (field, expression) in fields { @@ -405,17 +402,20 @@ impl Expression { types.insert(field.inner.clone(), r#type); } - Some(Type::Struct(StructType::Fields(FieldsStructType { + Some(Type::Struct(StructType::Fields { + name: name.inner.clone(), fields: types, - }))) + })) } - StructExpression::Unit { .. } => Some(Type::Struct(StructType::Unit)), + StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit { + name: name.inner.clone(), + })), }, Expression::TupleAccess(tuple_access_expression) => { let TupleAccessExpression { tuple, index } = tuple_access_expression.inner.as_ref(); let tuple_value = tuple.return_type(context)?; - if let Type::Tuple(TupleType { fields }) = tuple_value { + if let Type::Tuple(fields) = tuple_value { fields.get(index.inner).cloned() } else { None @@ -944,12 +944,13 @@ pub enum BlockExpression { impl BlockExpression { fn return_type(&self, context: &Context) -> Option { match self { - BlockExpression::Async(statements) => statements - .last() - .and_then(|statement| statement.return_type(context)), - BlockExpression::Sync(statements) => statements - .last() - .and_then(|statement| statement.return_type(context)), + BlockExpression::Async(statements) | BlockExpression::Sync(statements) => { + if let Some(statement) = statements.last() { + statement.return_type(context) + } else { + None + } + } } } } diff --git a/dust-lang/src/ast/statement.rs b/dust-lang/src/ast/statement.rs index a4e2fa7..6fc6aef 100644 --- a/dust-lang/src/ast/statement.rs +++ b/dust-lang/src/ast/statement.rs @@ -19,17 +19,6 @@ impl Statement { Statement::StructDefinition(Node::new(struct_definition, position)) } - pub fn return_type(&self, context: &Context) -> Option { - match self { - Statement::Expression(expression) => expression.return_type(context), - Statement::ExpressionNullified(expression_node) => { - expression_node.inner.return_type(context) - } - Statement::Let(_) => None, - Statement::StructDefinition(_) => None, - } - } - pub fn position(&self) -> Span { match self { Statement::Expression(expression) => expression.position(), @@ -38,6 +27,15 @@ impl Statement { Statement::StructDefinition(definition) => definition.position, } } + + pub fn return_type(&self, context: &Context) -> Option { + match self { + Statement::Expression(expression) => expression.return_type(context), + Statement::ExpressionNullified(expression) => None, + Statement::Let(_) => None, + Statement::StructDefinition(_) => None, + } + } } impl Display for Statement { diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 3b1c348..d7d4478 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -22,7 +22,7 @@ impl Context { } /// Creates a deep copy of another context. - pub fn with_variables_from(other: &Self) -> Self { + pub fn with_data_from(other: &Self) -> Self { Self { variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())), } @@ -44,7 +44,7 @@ impl Context { } /// Returns the type of the variable with the given identifier. - pub fn get_type(&self, identifier: &Identifier) -> Option { + pub fn get_variable_type(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { Some((VariableData::Type(r#type), _)) => Some(r#type.clone()), Some((VariableData::Value(value), _)) => Some(value.r#type()), @@ -61,7 +61,7 @@ impl Context { } /// Returns the value of the variable with the given identifier. - pub fn get_value(&self, identifier: &Identifier) -> Option { + pub fn get_variable_value(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { Some((VariableData::Value(value), _)) => Some(value.clone()), _ => None, @@ -69,7 +69,7 @@ impl Context { } /// Sets a variable to a type, with a position given for garbage collection. - pub fn set_type(&self, identifier: Identifier, r#type: Type, position: Span) { + pub fn set_variable_type(&self, identifier: Identifier, r#type: Type, position: Span) { log::trace!("Setting {identifier} to type {type} at {position:?}"); self.variables @@ -79,7 +79,7 @@ impl Context { } /// Sets a variable to a value. - pub fn set_value(&self, identifier: Identifier, value: Value) { + pub fn set_variable_value(&self, identifier: Identifier, value: Value) { log::trace!("Setting {identifier} to value {value}"); let mut variables = self.variables.write().unwrap(); diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 4bab951..4e2925a 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -314,21 +314,12 @@ impl<'src> Parser<'src> { } let expression = self.parse_expression(0)?; - let end = self.current_position.1; - let is_nullified = if let Token::Semicolon = self.current_token { + + if let Token::Semicolon = self.current_token { + let position = (start_position.0, self.current_position.1); + self.next_token()?; - true - } else { - matches!( - expression, - Expression::Block(_) | Expression::Loop(_) | Expression::If(_) - ) - }; - - if is_nullified { - let position = (start_position.0, end); - Ok(Statement::ExpressionNullified(Node::new( expression, position, ))) @@ -446,10 +437,9 @@ impl<'src> Parser<'src> { } if let Token::LeftCurlyBrace = self.current_token { - let name = Node::new(identifier, start_position); - self.next_token()?; + let name = Node::new(identifier, start_position); let mut fields = Vec::new(); loop { @@ -1274,35 +1264,26 @@ mod tests { assert_eq!( parse(source), Ok(AbstractSyntaxTree { - statements: [Statement::ExpressionNullified(Node::new( - Expression::block( - BlockExpression::Async(vec![ - Statement::ExpressionNullified(Node::new( - Expression::operator( - OperatorExpression::Assignment { - assignee: Expression::identifier( - Identifier::new("x"), - (8, 9) - ), - value: Expression::literal(42, (12, 14)), - }, - (8, 14) - ), - (8, 15) - )), - Statement::Expression(Expression::operator( + statements: [Statement::Expression(Expression::block( + BlockExpression::Async(vec![ + Statement::ExpressionNullified(Node::new( + Expression::operator( OperatorExpression::Assignment { - assignee: Expression::identifier( - Identifier::new("y"), - (16, 17) - ), - value: Expression::literal(4.0, (20, 23)), + assignee: Expression::identifier(Identifier::new("x"), (8, 9)), + value: Expression::literal(42, (12, 14)), }, - (16, 23) - )) - ]), - (0, 25) - ), + (8, 14) + ), + (8, 15) + )), + Statement::Expression(Expression::operator( + OperatorExpression::Assignment { + assignee: Expression::identifier(Identifier::new("y"), (16, 17)), + value: Expression::literal(4.0, (20, 23)), + }, + (16, 23) + )) + ]), (0, 25) ))] .into() @@ -1597,19 +1578,16 @@ mod tests { assert_eq!( parse(source), Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::r#if( - IfExpression::If { - condition: Expression::identifier(Identifier::new("x"), (3, 4)), - if_block: Node::new( - BlockExpression::Sync(vec![Statement::Expression( - Expression::identifier(Identifier::new("y"), (7, 8)) - )]), - (5, 10) - ) - }, - (0, 10) - ), + Statement::Expression(Expression::r#if( + IfExpression::If { + condition: Expression::identifier(Identifier::new("x"), (3, 4)), + if_block: Node::new( + BlockExpression::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("y"), (7, 8)) + )]), + (5, 10) + ) + }, (0, 10) )) ])) @@ -1623,25 +1601,22 @@ mod tests { assert_eq!( parse(source), Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::r#if( - IfExpression::IfElse { - condition: Expression::identifier(Identifier::new("x"), (3, 4)), - if_block: Node::new( - BlockExpression::Sync(vec![Statement::Expression( - Expression::identifier(Identifier::new("y"), (7, 8)) - )]), - (5, 10) - ), - r#else: ElseExpression::Block(Node::new( - BlockExpression::Sync(vec![Statement::Expression( - Expression::identifier(Identifier::new("z"), (18, 19)) - )]), - (16, 21) - )) - }, - (0, 21) - ), + Statement::Expression(Expression::r#if( + IfExpression::IfElse { + condition: Expression::identifier(Identifier::new("x"), (3, 4)), + if_block: Node::new( + BlockExpression::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("y"), (7, 8)) + )]), + (5, 10) + ), + r#else: ElseExpression::Block(Node::new( + BlockExpression::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("z"), (18, 19)) + )]), + (16, 21) + )) + }, (0, 21) )) ])) @@ -1655,40 +1630,34 @@ mod tests { assert_eq!( parse(source), Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::r#if( - IfExpression::IfElse { - condition: Expression::identifier(Identifier::new("x"), (3, 4)), - if_block: Node::new( - BlockExpression::Sync(vec![Statement::Expression( - Expression::identifier(Identifier::new("y"), (7, 8)) - )]), - (5, 10) - ), - r#else: ElseExpression::If(Node::new( - Box::new(IfExpression::IfElse { - condition: Expression::identifier( - Identifier::new("z"), - (19, 20) - ), - if_block: Node::new( - BlockExpression::Sync(vec![Statement::Expression( - Expression::identifier(Identifier::new("a"), (23, 24)) - )]), - (21, 26) - ), - r#else: ElseExpression::Block(Node::new( - BlockExpression::Sync(vec![Statement::Expression( - Expression::identifier(Identifier::new("b"), (34, 35)) - )]), - (32, 37) - )), - }), - (16, 37) - )), - }, - (0, 37) - ), + Statement::Expression(Expression::r#if( + IfExpression::IfElse { + condition: Expression::identifier(Identifier::new("x"), (3, 4)), + if_block: Node::new( + BlockExpression::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("y"), (7, 8)) + )]), + (5, 10) + ), + r#else: ElseExpression::If(Node::new( + Box::new(IfExpression::IfElse { + condition: Expression::identifier(Identifier::new("z"), (19, 20)), + if_block: Node::new( + BlockExpression::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("a"), (23, 24)) + )]), + (21, 26) + ), + r#else: ElseExpression::Block(Node::new( + BlockExpression::Sync(vec![Statement::Expression( + Expression::identifier(Identifier::new("b"), (34, 35)) + )]), + (32, 37) + )), + }), + (16, 37) + )), + }, (0, 37) )) ])) @@ -1702,33 +1671,25 @@ mod tests { assert_eq!( parse(source), Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::while_loop( - Expression::operator( - OperatorExpression::Comparison { - left: Expression::identifier(Identifier::new("x"), (6, 7)), - operator: Node::new(ComparisonOperator::LessThan, (8, 9)), - right: Expression::literal(10, (10, 12)), + Statement::Expression(Expression::while_loop( + Expression::operator( + OperatorExpression::Comparison { + left: Expression::identifier(Identifier::new("x"), (6, 7)), + operator: Node::new(ComparisonOperator::LessThan, (8, 9)), + right: Expression::literal(10, (10, 12)), + }, + (6, 12) + ), + Node::new( + BlockExpression::Sync(vec![Statement::Expression(Expression::operator( + OperatorExpression::CompoundAssignment { + assignee: Expression::identifier(Identifier::new("x"), (15, 16)), + operator: Node::new(MathOperator::Add, (17, 19)), + modifier: Expression::literal(1, (20, 21)), }, - (6, 12) - ), - Node::new( - BlockExpression::Sync(vec![Statement::Expression( - Expression::operator( - OperatorExpression::CompoundAssignment { - assignee: Expression::identifier( - Identifier::new("x"), - (15, 16) - ), - operator: Node::new(MathOperator::Add, (17, 19)), - modifier: Expression::literal(1, (20, 21)), - }, - (15, 21) - ) - )]), - (13, 23) - ), - (0, 23) + (15, 21) + ))]), + (13, 23) ), (0, 23) )) @@ -1781,18 +1742,15 @@ mod tests { assert_eq!( parse(source), Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::block( - BlockExpression::Sync(vec![Statement::Expression(Expression::operator( - OperatorExpression::Math { - left: Expression::literal(40, (2, 4)), - operator: Node::new(MathOperator::Add, (5, 6)), - right: Expression::literal(2, (7, 8)), - }, - (2, 8) - ))]), - (0, 10) - ), + Statement::Expression(Expression::block( + BlockExpression::Sync(vec![Statement::Expression(Expression::operator( + OperatorExpression::Math { + left: Expression::literal(40, (2, 4)), + operator: Node::new(MathOperator::Add, (5, 6)), + right: Expression::literal(2, (7, 8)), + }, + (2, 8) + ))]), (0, 10) )) ])) @@ -1806,33 +1764,30 @@ mod tests { assert_eq!( parse(source), Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::block( - BlockExpression::Sync(vec![ - Statement::ExpressionNullified(Node::new( - Expression::assignment( - Expression::identifier("foo", (2, 5)), - Expression::literal(42, (8, 10)), - (2, 10) - ), - (2, 11) - )), - Statement::ExpressionNullified(Node::new( - Expression::assignment( - Expression::identifier("bar", (12, 15)), - Expression::literal(42, (18, 20)), - (12, 20) - ), - (12, 21) - )), - Statement::Expression(Expression::assignment( - Expression::identifier("baz", (22, 25)), - Expression::literal("42", (28, 32)), - (22, 32) - )) - ]), - (0, 34) - ), + Statement::Expression(Expression::block( + BlockExpression::Sync(vec![ + Statement::ExpressionNullified(Node::new( + Expression::assignment( + Expression::identifier("foo", (2, 5)), + Expression::literal(42, (8, 10)), + (2, 10) + ), + (2, 11) + )), + Statement::ExpressionNullified(Node::new( + Expression::assignment( + Expression::identifier("bar", (12, 15)), + Expression::literal(42, (18, 20)), + (12, 20) + ), + (12, 21) + )), + Statement::Expression(Expression::assignment( + Expression::identifier("baz", (22, 25)), + Expression::literal("42", (28, 32)), + (22, 32) + )) + ]), (0, 34) )) ])) diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index 17fc188..27f0236 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -17,7 +17,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::Identifier; +use crate::{Enum, Identifier, Struct, Value}; /// Description of a kind of value. /// @@ -53,7 +53,7 @@ pub enum Type { }, String, Struct(StructType), - Tuple(TupleType), + Tuple(Vec), } impl Type { @@ -266,36 +266,8 @@ impl Display for Type { Type::Number => write!(f, "num"), Type::Range { r#type } => write!(f, "{type} range"), Type::String => write!(f, "str"), - Type::Struct(struct_type) => match struct_type { - StructType::Unit => write!(f, "()"), - StructType::Tuple(TupleType { fields }) => { - write!(f, "(")?; - - for (index, r#type) in fields.iter().enumerate() { - write!(f, "{type}")?; - - if index != fields.len() - 1 { - write!(f, ", ")?; - } - } - - write!(f, ")") - } - StructType::Fields(FieldsStructType { fields }) => { - write!(f, "{{")?; - - for (index, (name, r#type)) in fields.iter().enumerate() { - write!(f, "{name}: {type}")?; - - if index != fields.len() - 1 { - write!(f, ", ")?; - } - } - - write!(f, "}}") - } - }, - Type::Tuple(TupleType { fields }) => { + Type::Struct(struct_type) => write!(f, "{struct_type}"), + Type::Tuple(fields) => { write!(f, "(")?; for (index, r#type) in fields.iter().enumerate() { @@ -439,88 +411,257 @@ impl Display for FunctionType { } } -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum StructType { - Unit, - Tuple(TupleType), - Fields(FieldsStructType), + Unit { + name: Identifier, + }, + Tuple { + name: Identifier, + fields: Vec, + }, + Fields { + name: Identifier, + fields: HashMap, + }, +} + +impl StructType { + pub fn name(&self) -> &Identifier { + match self { + StructType::Unit { name } => name, + StructType::Tuple { name, .. } => name, + StructType::Fields { name, .. } => name, + } + } + + pub fn constructor(&self) -> Option { + let constructor = match self { + StructType::Unit { name } => Constructor::Unit { name: name.clone() }, + StructType::Tuple { name, fields } => Constructor::Tuple(TupleConstructor { + name: name.clone(), + tuple_arguments: Vec::with_capacity(fields.len()), + }), + StructType::Fields { name, fields } => Constructor::Fields { + name: name.clone(), + field_arguments: HashMap::with_capacity(fields.len()), + }, + }; + + Some(constructor) + } } impl Display for StructType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - StructType::Unit => write!(f, "()"), - StructType::Tuple(tuple) => write!(f, "{tuple}"), - StructType::Fields(fields) => write!(f, "{fields}"), - } - } -} + StructType::Unit { name } => write!(f, "{name}"), + StructType::Tuple { name, fields } => { + write!(f, "{name}(")?; -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct TupleType { - pub fields: Vec, -} + for (index, field) in fields.iter().enumerate() { + write!(f, "{field}")?; -impl Display for TupleType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "(")?; + if index != fields.len() - 1 { + write!(f, ", ")?; + } + } - for (index, field) in self.fields.iter().enumerate() { - write!(f, "{field}")?; + write!(f, ")") + } + StructType::Fields { name, fields } => { + write!(f, "{name} {{")?; - if index != self.fields.len() - 1 { - write!(f, ", ")?; + for (index, (identifier, r#type)) in fields.iter().enumerate() { + write!(f, "{identifier}: {type}")?; + + if index != fields.len() - 1 { + write!(f, ", ")?; + } + } + + write!(f, "}}") } } - - write!(f, ")") } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct FieldsStructType { - pub fields: HashMap, -} - -impl Display for FieldsStructType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{{ ")?; - - for (index, (identifier, r#type)) in self.fields.iter().enumerate() { - write!(f, "{identifier}: {type}")?; - - if index != self.fields.len() - 1 { - write!(f, ", ")?; - } - } - - write!(f, " }}") - } -} - -impl PartialOrd for FieldsStructType { +impl PartialOrd for StructType { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for FieldsStructType { +impl Ord for StructType { fn cmp(&self, other: &Self) -> Ordering { - self.fields.iter().cmp(other.fields.iter()) + match (self, other) { + (StructType::Unit { name: left_name }, StructType::Unit { name: right_name }) => { + left_name.cmp(right_name) + } + (StructType::Unit { .. }, _) => Ordering::Greater, + ( + StructType::Tuple { + name: left_name, + fields: left_fields, + }, + StructType::Tuple { + name: right_name, + fields: right_fields, + }, + ) => { + let name_cmp = left_name.cmp(right_name); + + if name_cmp == Ordering::Equal { + left_fields.cmp(right_fields) + } else { + name_cmp + } + } + (StructType::Tuple { .. }, _) => Ordering::Greater, + ( + StructType::Fields { + name: left_name, + fields: left_fields, + }, + StructType::Fields { + name: right_name, + fields: right_fields, + }, + ) => { + let name_cmp = left_name.cmp(right_name); + + if name_cmp == Ordering::Equal { + let len_cmp = left_fields.len().cmp(&right_fields.len()); + + if len_cmp == Ordering::Equal { + left_fields.iter().cmp(right_fields.iter()) + } else { + len_cmp + } + } else { + name_cmp + } + } + (StructType::Fields { .. }, _) => Ordering::Greater, + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum Constructor { + Unit { + name: Identifier, + }, + Tuple(TupleConstructor), + Fields { + name: Identifier, + field_arguments: HashMap, + }, + Enum { + name: Identifier, + r#type: EnumType, + variant_constructor: Box, + }, +} + +impl Constructor { + pub fn construct(self) -> Value { + match self { + Constructor::Unit { name } => Value::Struct(Struct::Unit { name }), + Constructor::Tuple(tuple_constructor) => tuple_constructor.construct(), + Constructor::Fields { + name, + field_arguments, + } => Value::Struct(Struct::Fields { + name, + fields: field_arguments, + }), + Constructor::Enum { + name, + r#type, + variant_constructor, + } => Value::Enum(Enum { + name, + r#type, + variant_data: Self::make_struct(*variant_constructor), + }), + } + } + + fn make_struct(this: Self) -> Struct { + match this { + Constructor::Unit { name } => Struct::Unit { name }, + Constructor::Tuple(TupleConstructor { + name, + tuple_arguments, + }) => Struct::Tuple { + name, + fields: tuple_arguments, + }, + Constructor::Fields { + name, + field_arguments, + } => Struct::Fields { + name, + fields: field_arguments, + }, + Constructor::Enum { + variant_constructor, + .. + } => Self::make_struct(*variant_constructor), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TupleConstructor { + pub name: Identifier, + pub tuple_arguments: Vec, +} + +impl TupleConstructor { + pub fn push_argument(&mut self, value: Value) { + self.tuple_arguments.push(value); + } + + pub fn construct(self) -> Value { + Value::Struct(Struct::Tuple { + name: self.name, + fields: self.tuple_arguments, + }) } } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct EnumType { - name: Identifier, - variants: Vec, + pub name: Identifier, + pub variants: Vec, +} + +impl EnumType { + pub fn constructor(&self) -> Option { + let get_variant_constructor = self + .variants + .iter() + .find_map(|struct_type| struct_type.constructor()); + + if let Some(variant_constructor) = get_variant_constructor { + Some(Constructor::Enum { + name: self.name.clone(), + r#type: self.clone(), + variant_constructor: Box::new(variant_constructor), + }) + } else { + None + } + } } impl Display for EnumType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let EnumType { name, variants } = self; - write!(f, "enum {name} {{")?; + write!(f, "enum {name} {{ ")?; for (index, variant) in variants.iter().enumerate() { write!(f, "{variant}")?; @@ -530,7 +671,7 @@ impl Display for EnumType { } } - write!(f, "}}") + write!(f, " }}") } } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index b9041fa..fe4c3a7 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -16,8 +16,8 @@ use serde::{ }; use crate::{ - AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier, - RangeableType, RuntimeError, StructType, TupleType, Type, Vm, + AbstractSyntaxTree, Context, EnumType, FunctionType, Identifier, RangeableType, RuntimeError, + StructType, Type, Vm, }; /// Dust value representation @@ -57,7 +57,7 @@ pub enum Value { Boolean(bool), Byte(u8), Character(char), - Enum { name: Identifier, r#type: EnumType }, + Enum(Enum), Float(f64), Function(Function), Integer(i64), @@ -80,6 +80,10 @@ impl Value { Value::Mutable(Arc::new(RwLock::new(value))) } + pub fn mutable_from>(into_value: T) -> Value { + Value::Mutable(Arc::new(RwLock::new(into_value.into()))) + } + pub fn byte_range(start: u8, end: u8) -> Value { Value::Range(Rangeable::Byte(start)..Rangeable::Byte(end)) } @@ -188,7 +192,7 @@ impl Value { Value::Boolean(_) => Type::Boolean, Value::Byte(_) => Type::Byte, Value::Character(_) => Type::Character, - Value::Enum { r#type, .. } => Type::Enum(r#type.clone()), + Value::Enum(Enum { r#type, .. }) => Type::Enum(r#type.clone()), Value::Float(_) => Type::Float, Value::Function(function) => Type::Function(function.r#type.clone()), Value::Integer(_) => Type::Integer, @@ -221,25 +225,31 @@ impl Value { } Value::String(_) => Type::String, Value::Struct(r#struct) => match r#struct { - Struct::Unit { .. } => Type::Struct(StructType::Unit), - Struct::Tuple { fields, .. } => { + Struct::Unit { name } => Type::Struct(StructType::Unit { name: name.clone() }), + Struct::Tuple { name, fields } => { let types = fields.iter().map(|field| field.r#type()).collect(); - Type::Struct(StructType::Tuple(TupleType { fields: types })) + Type::Struct(StructType::Tuple { + name: name.clone(), + fields: types, + }) } - Struct::Fields { fields, .. } => { + Struct::Fields { name, fields } => { let types = fields .iter() .map(|(identifier, value)| (identifier.clone(), value.r#type())) .collect(); - Type::Struct(StructType::Fields(FieldsStructType { fields: types })) + Type::Struct(StructType::Fields { + name: name.clone(), + fields: types, + }) } }, Value::Tuple(values) => { let fields = values.iter().map(|value| value.r#type()).collect(); - Type::Tuple(TupleType { fields }) + Type::Tuple(fields) } } } @@ -248,6 +258,7 @@ impl Value { match self { Value::Mutable(inner) => inner.read().unwrap().get_field(field), Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(), + Value::Map(pairs) => pairs.get(field).cloned(), _ => None, } } @@ -762,6 +773,54 @@ impl Value { } } +impl From for Value { + fn from(value: bool) -> Self { + Value::Boolean(value) + } +} + +impl From for Value { + fn from(value: u8) -> Self { + Value::Byte(value) + } +} + +impl From for Value { + fn from(value: char) -> Self { + Value::Character(value) + } +} + +impl From for Value { + fn from(value: f64) -> Self { + Value::Float(value) + } +} + +impl From for Value { + fn from(value: i32) -> Self { + Value::Integer(value as i64) + } +} + +impl From for Value { + fn from(value: i64) -> Self { + Value::Integer(value) + } +} + +impl From for Value { + fn from(value: String) -> Self { + Value::String(value) + } +} + +impl From<&str> for Value { + fn from(value: &str) -> Self { + Value::String(value.to_string()) + } +} + impl Display for Value { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -773,7 +832,7 @@ impl Display for Value { Value::Boolean(boolean) => write!(f, "{boolean}"), Value::Byte(byte) => write!(f, "{byte}"), Value::Character(character) => write!(f, "{character}"), - Value::Enum { name, r#type } => write!(f, "{name}::{type}"), + Value::Enum(r#enum) => write!(f, "{enum}"), Value::Float(float) => write!(f, "{float}"), Value::Function(function) => write!(f, "{function}"), Value::Integer(integer) => write!(f, "{integer}"), @@ -813,7 +872,7 @@ impl Display for Value { write!(f, "{start}..={end}") } Value::String(string) => write!(f, "{string}"), - Value::Struct(structure) => write!(f, "{structure}"), + Value::Struct(r#struct) => write!(f, "{struct}"), Value::Tuple(fields) => { write!(f, "(")?; @@ -934,14 +993,7 @@ impl Serialize for Value { Value::Boolean(boolean) => serializer.serialize_bool(*boolean), Value::Byte(byte) => serializer.serialize_u8(*byte), Value::Character(character) => serializer.serialize_char(*character), - Value::Enum { name, r#type } => { - let mut ser = serializer.serialize_struct_variant("Value", 4, "Enum", 2)?; - - ser.serialize_field("name", name)?; - ser.serialize_field("type", r#type)?; - - ser.end() - } + Value::Enum(r#emum) => r#emum.serialize(serializer), Value::Float(float) => serializer.serialize_f64(*float), Value::Function(function) => function.serialize(serializer), Value::Integer(integer) => serializer.serialize_i64(*integer), @@ -1021,13 +1073,13 @@ impl Function { value_arguments: Option>, context: &Context, ) -> Result, RuntimeError> { - let new_context = Context::with_variables_from(context); + let new_context = Context::with_data_from(context); if let (Some(value_parameters), Some(value_arguments)) = (&self.r#type.value_parameters, value_arguments) { for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) { - new_context.set_value(identifier.clone(), value); + new_context.set_variable_value(identifier.clone(), value); } } @@ -1226,9 +1278,9 @@ impl Ord for Struct { impl Display for Struct { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - Struct::Unit { .. } => write!(f, "()"), - Struct::Tuple { fields, .. } => { - write!(f, "(")?; + Struct::Unit { name } => write!(f, "{name}"), + Struct::Tuple { name, fields } => { + write!(f, "{name}(")?; for (index, field) in fields.iter().enumerate() { if index > 0 { @@ -1240,8 +1292,8 @@ impl Display for Struct { write!(f, ")") } - Struct::Fields { fields, .. } => { - write!(f, "{{ ")?; + Struct::Fields { name, fields } => { + write!(f, "{name} {{ ")?; for (index, (identifier, value)) in fields.iter().enumerate() { if index > 0 { @@ -1310,6 +1362,57 @@ impl Ord for Rangeable { } } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Enum { + pub r#type: EnumType, + pub name: Identifier, + pub variant_data: Struct, +} + +impl Display for Enum { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Enum { + name, variant_data, .. + } = self; + + match &variant_data { + Struct::Unit { name: variant_name } => write!(f, "{name}::{variant_name}"), + Struct::Tuple { + name: variant_name, + fields, + } => { + write!(f, "{name}::{variant_name}(")?; + + for (index, field) in fields.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + + write!(f, "{}", field)?; + } + + write!(f, ")") + } + Struct::Fields { + name: variant_name, + fields, + } => { + write!(f, "{name}::{variant_name} {{ ")?; + + for (index, (identifier, value)) in fields.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + + write!(f, "{}: {}", identifier, value)?; + } + + write!(f, " }}") + } + } + } +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum ValueError { CannotAdd(Value, Value), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index ec12eb8..04a8468 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -21,8 +21,9 @@ use crate::{ OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span, Statement, StructDefinition, StructExpression, }, - parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, FieldsStructType, - Identifier, ParseError, Struct, StructType, TupleType, Type, Value, ValueError, + parse, Analyzer, BuiltInFunctionError, Constructor, Context, DustError, Enum, EnumType, + Expression, Identifier, ParseError, Struct, StructType, TupleConstructor, Type, Value, + ValueError, }; /// Run the source code and return the result. @@ -126,11 +127,19 @@ impl Vm { } Statement::StructDefinition(struct_definition) => { let (name, struct_type) = match struct_definition.inner { - StructDefinition::Unit { name } => (name.inner.clone(), StructType::Unit), + StructDefinition::Unit { name } => { + (name.inner.clone(), StructType::Unit { name: name.inner }) + } StructDefinition::Tuple { name, items } => { let fields = items.into_iter().map(|item| item.inner).collect(); - (name.inner.clone(), StructType::Tuple(TupleType { fields })) + ( + name.inner.clone(), + StructType::Tuple { + name: name.inner, + fields, + }, + ) } StructDefinition::Fields { name, fields } => { let fields = fields @@ -140,23 +149,25 @@ impl Vm { ( name.inner.clone(), - StructType::Fields(FieldsStructType { fields }), + StructType::Fields { + name: name.inner, + fields, + }, ) } }; - self.context - .set_type(name, Type::Struct(struct_type), struct_definition.position); + todo!("Set constructor"); Ok(None) } }; if collect_garbage { - self.context.collect_garbage(position); + // self.context.collect_garbage(position); } - result.map_err(|error| RuntimeError::Trace { + result.map_err(|error| RuntimeError::Statement { error: Box::new(error), position, }) @@ -174,7 +185,7 @@ impl Vm { .run_expression(value, collect_garbage)? .expect_value(value_position)?; - self.context.set_value(identifier.inner, value); + self.context.set_variable_value(identifier.inner, value); Ok(()) } @@ -185,7 +196,8 @@ impl Vm { .expect_value(value_position)? .into_mutable(); - self.context.set_value(identifier.inner, mutable_value); + self.context + .set_variable_value(identifier.inner, mutable_value); Ok(()) } @@ -210,7 +222,7 @@ impl Vm { self.run_expression(*expression.inner, collect_garbage) } Expression::Identifier(identifier) => { - let get_value = self.context.get_value(&identifier.inner); + let get_value = self.context.get_variable_value(&identifier.inner); if let Some(value) = get_value { Ok(Evaluation::Return(Some(value))) @@ -243,7 +255,7 @@ impl Vm { Expression::TupleAccess(_) => todo!(), }; - evaluation_result.map_err(|error| RuntimeError::Trace { + evaluation_result.map_err(|error| RuntimeError::Expression { error: Box::new(error), position, }) @@ -257,20 +269,20 @@ impl Vm { match struct_expression { StructExpression::Unit { name } => { let position = name.position; - let r#type = self.context.get_type(&name.inner).ok_or_else(|| { + let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| { RuntimeError::UndefinedType { identifier: name.inner.clone(), position, } })?; - if let Type::Struct(StructType::Unit) = r#type { + if let Type::Struct(StructType::Unit { name }) = r#type { Ok(Evaluation::Return(Some(Value::Struct(Struct::Unit { - name: name.inner, + name, })))) } else { Err(RuntimeError::ExpectedType { - expected: Type::Struct(StructType::Unit), + expected: Type::Struct(StructType::Unit { name: name.inner }), actual: r#type, position, }) @@ -281,14 +293,14 @@ impl Vm { fields: expressions, } => { let position = name.position; - let r#type = self.context.get_type(&name.inner).ok_or_else(|| { + let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| { RuntimeError::UndefinedType { identifier: name.inner.clone(), position, } })?; - if let Type::Struct(StructType::Fields(FieldsStructType { .. })) = r#type { + if let Type::Struct(StructType::Fields { name, .. }) = r#type { let mut values = HashMap::with_capacity(expressions.len()); for (identifier, expression) in expressions { @@ -301,14 +313,15 @@ impl Vm { } Ok(Evaluation::Return(Some(Value::Struct(Struct::Fields { - name: name.inner, + name, fields: values, })))) } else { Err(RuntimeError::ExpectedType { - expected: Type::Struct(StructType::Fields(FieldsStructType { - fields: HashMap::new(), - })), + expected: Type::Struct(StructType::Fields { + name: name.inner, + fields: Default::default(), + }), actual: r#type, position, }) @@ -609,11 +622,7 @@ impl Vm { Ok(Evaluation::Return(None)) } - LoopExpression::For { - identifier, - iterator, - block, - } => todo!(), + LoopExpression::For { .. } => todo!(), } } @@ -668,14 +677,53 @@ impl Vm { let CallExpression { invoker, arguments } = call_expression; let invoker_position = invoker.position(); - let invoker_value = - if let Some(value) = self.run_expression(invoker, collect_garbage)?.value() { - value - } else { - return Err(RuntimeError::ExpectedValue { + let run_invoker = self.run_expression(invoker, collect_garbage)?; + + if let Evaluation::Constructor(Type::Struct(StructType::Tuple { name, fields })) = + &run_invoker + { + let struct_type = fields + .iter() + .find(|r#type| { + if let Type::Struct(struct_type) = r#type { + struct_type.name() == name + } else { + false + } + }) + .ok_or(RuntimeError::EnumVariantNotFound { + identifier: name.clone(), position: invoker_position, - }); - }; + })?; + + if let Type::Struct(StructType::Tuple { name, fields }) = struct_type { + let mut values = Vec::with_capacity(arguments.len()); + + for argument in arguments { + let position = argument.position(); + let value = self + .run_expression(argument, collect_garbage)? + .expect_value(position)?; + + values.push(value); + } + + let r#struct = Struct::Tuple { + name: name.clone(), + fields: values, + }; + + return Ok(Evaluation::Return(Some(Value::Struct(r#struct)))); + } + } + + let invoker_value = if let Some(value) = run_invoker.value() { + value + } else { + return Err(RuntimeError::ExpectedValue { + position: invoker_position, + }); + }; let function = if let Value::Function(function) = invoker_value { function @@ -814,7 +862,7 @@ impl Vm { previous_value = self.run_statement(statement, collect_garbage)?; if collect_garbage { - self.context.collect_garbage(position); + // self.context.collect_garbage(position); } } @@ -864,7 +912,7 @@ impl Vm { match r#else { ElseExpression::If(if_expression) => { - self.run_expression(Expression::If(if_expression), collect_garbage) + self.run_if(*if_expression.inner, collect_garbage) } ElseExpression::Block(block) => self.run_block(block.inner, collect_garbage), } @@ -875,14 +923,15 @@ impl Vm { enum Evaluation { Break, + Constructor(Type), Return(Option), } impl Evaluation { pub fn value(self) -> Option { match self { - Evaluation::Break => None, Evaluation::Return(value_option) => value_option, + _ => None, } } @@ -898,7 +947,11 @@ impl Evaluation { #[derive(Clone, Debug, PartialEq)] pub enum RuntimeError { ParseError(ParseError), - Trace { + Expression { + error: Box, + position: Span, + }, + Statement { error: Box, position: Span, }, @@ -914,9 +967,17 @@ pub enum RuntimeError { error: BuiltInFunctionError, position: Span, }, + EnumVariantNotFound { + identifier: Identifier, + position: Span, + }, ExpectedBoolean { position: Span, }, + ExpectedConstructor { + actual: Type, + position: Span, + }, ExpectedIdentifier { position: Span, }, @@ -974,14 +1035,17 @@ impl RuntimeError { pub fn position(&self) -> Span { match self { Self::ParseError(parse_error) => parse_error.position(), - Self::Trace { position, .. } => *position, + Self::Expression { position, .. } => *position, + Self::Statement { position, .. } => *position, Self::ValueError { left_position, right_position, .. } => (left_position.0, right_position.1), Self::BuiltInFunctionError { position, .. } => *position, + Self::EnumVariantNotFound { position, .. } => *position, Self::ExpectedBoolean { position } => *position, + Self::ExpectedConstructor { position, .. } => *position, Self::ExpectedFunction { position, .. } => *position, Self::ExpectedIdentifier { position } => *position, Self::ExpectedIdentifierOrString { position } => *position, @@ -1016,10 +1080,17 @@ impl Display for RuntimeError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::ParseError(parse_error) => write!(f, "{}", parse_error), - Self::Trace { error, position } => { + Self::Expression { error, position } => { write!( f, - "Error during execution at position: {:?}\n{}", + "Error while running expression at {:?}: {}", + position, error + ) + } + Self::Statement { error, position } => { + write!( + f, + "Error while running statement at {:?}: {}", position, error ) } @@ -1037,9 +1108,26 @@ impl Display for RuntimeError { Self::BuiltInFunctionError { error, .. } => { write!(f, "{}", error) } + Self::EnumVariantNotFound { + identifier, + position, + } => { + write!( + f, + "Enum variant not found: {} at position: {:?}", + identifier, position + ) + } Self::ExpectedBoolean { position } => { write!(f, "Expected a boolean at position: {:?}", position) } + Self::ExpectedConstructor { actual, position } => { + write!( + f, + "Expected a constructor, but got {} at position: {:?}", + actual, position + ) + } Self::ExpectedFunction { actual, position } => { write!( f, @@ -1110,7 +1198,7 @@ impl Display for RuntimeError { } => { write!( f, - "Undefined variable {} at position: {:?}", + "Undefined value {} at position: {:?}", identifier, position ) } @@ -1187,8 +1275,8 @@ mod tests { #[test] fn assign_tuple_struct_variable() { let input = " - struct Foo(int) - x = Foo(42) + struct Foo(int); + let x = Foo(42); x "; @@ -1203,7 +1291,7 @@ mod tests { #[test] fn define_and_instantiate_tuple_struct() { - let input = "struct Foo(int) Foo(42)"; + let input = "struct Foo(int); Foo(42)"; assert_eq!( run(input), @@ -1232,7 +1320,7 @@ mod tests { #[test] fn define_and_instantiate_unit_struct() { - let input = "struct Foo Foo"; + let input = "struct Foo; Foo"; assert_eq!( run(input), @@ -1271,6 +1359,8 @@ mod tests { #[test] fn negate_expression() { + env_logger::builder().is_test(true).try_init().unwrap(); + let input = "let x = -42; -x"; assert_eq!(run(input), Ok(Some(Value::Integer(42)))); @@ -1292,7 +1382,7 @@ mod tests { #[test] fn map_property_access() { - let input = "{ a = 42 }.a"; + let input = "map { a = 42 }.a"; assert_eq!(run(input), Ok(Some(Value::Integer(42)))); } @@ -1343,21 +1433,21 @@ mod tests { fn while_loop() { let input = "let mut x = 0; while x < 5 { x += 1 } x"; - assert_eq!(run(input), Ok(Some(Value::Integer(5)))); + assert_eq!(run(input), Ok(Some(Value::mutable_from(5)))); } #[test] fn subtract_assign() { let input = "let mut x = 1; x -= 1; x"; - assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(0))))); + assert_eq!(run(input), Ok(Some(Value::mutable_from(0)))); } #[test] fn add_assign() { let input = "let mut x = 1; x += 1; x"; - assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(2))))); + assert_eq!(run(input), Ok(Some(Value::mutable_from(2)))); } #[test] diff --git a/dust-shell/Cargo.toml b/dust-shell/Cargo.toml index 84bb94d..cbf4d8d 100644 --- a/dust-shell/Cargo.toml +++ b/dust-shell/Cargo.toml @@ -10,3 +10,4 @@ repository.workspace = true [dependencies] clap = { version = "4.5.14", features = ["derive"] } dust-lang = { path = "../dust-lang" } +env_logger = "0.11.5" diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index bb4b913..d31553d 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -8,21 +8,39 @@ struct Cli { #[arg(short, long)] command: Option, + #[arg(short, long)] + parse: bool, + path: Option, } fn main() { + env_logger::init(); + let args = Cli::parse(); if let Some(command) = &args.command { - run_and_display_errors(command); + if args.parse { + parse_and_display_errors(command); + } else { + run_and_display_errors(command); + } } else if let Some(path) = &args.path { let source = read_to_string(path).expect("Failed to read file"); - run_and_display_errors(&source) - } else { - panic!("No command or path provided"); - }; + if args.parse { + parse_and_display_errors(&source); + } else { + run_and_display_errors(&source); + } + } +} + +fn parse_and_display_errors(source: &str) { + match dust_lang::parse(source) { + Ok(ast) => println!("{:#?}", ast), + Err(error) => eprintln!("{}", error.report()), + } } fn run_and_display_errors(source: &str) {