diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs deleted file mode 100644 index b2abb98..0000000 --- a/dust-lang/src/analyzer.rs +++ /dev/null @@ -1,1385 +0,0 @@ -//! Tools for analyzing an abstract syntax tree and catching errors before running the virtual -//! machine. -//! -//! This module provides two anlysis options: -//! - `analyze` convenience function, which takes a string input -//! - `Analyzer` struct, which borrows an abstract syntax tree and a context -use std::{ - error::Error, - fmt::{self, Display, Formatter}, -}; - -use crate::{ - ast::{ - AbstractSyntaxTree, AstError, BlockExpression, CallExpression, ElseExpression, - FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression, - LiteralExpression, LoopExpression, MapExpression, Node, OperatorExpression, - PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition, - StructExpression, TupleAccessExpression, - }, - parse, Context, ContextData, ContextError, DustError, Expression, Identifier, RangeableType, - StructType, Type, TypeConflict, TypeEvaluation, -}; - -/// Analyzes the abstract syntax tree for errors. -/// -/// # Examples -/// ``` -/// # use std::collections::HashMap; -/// # use dust_lang::*; -/// let input = "x = 1 + false"; -/// let result = analyze(input); -/// -/// assert!(result.is_err()); -/// ``` -pub fn analyze(source: &str) -> Result<(), DustError> { - let abstract_tree = parse(source)?; - let mut analyzer = Analyzer::new(&abstract_tree); - - analyzer.analyze()?; - - if analyzer.errors.is_empty() { - Ok(()) - } else { - Err(DustError::analysis(analyzer.errors, source)) - } -} - -/// Static analyzer that checks for potential runtime errors. -/// -/// # Examples -/// ``` -/// # use std::collections::HashMap; -/// # use dust_lang::*; -/// let input = "x = 1 + false"; -/// let abstract_tree = parse(input).unwrap(); -/// let mut analyzer = Analyzer::new(&abstract_tree); -/// let result = analyzer.analyze(); -/// -/// assert!(!analyzer.errors.is_empty()); -pub struct Analyzer<'a> { - abstract_tree: &'a AbstractSyntaxTree, - pub errors: Vec, -} - -impl<'a> Analyzer<'a> { - pub fn new(abstract_tree: &'a AbstractSyntaxTree) -> Self { - Self { - abstract_tree, - errors: Vec::new(), - } - } - - pub fn analyze(&mut self) -> Result<(), ContextError> { - for statement in &self.abstract_tree.statements { - self.analyze_statement(statement, &self.abstract_tree.context)?; - } - - Ok(()) - } - - fn analyze_statement( - &mut self, - statement: &Statement, - context: &Context, - ) -> Result<(), ContextError> { - log::trace!( - "Analyzing statement {statement} at {:?} with context {}", - statement.position(), - context.id() - ); - - match statement { - Statement::Expression(expression) => self.analyze_expression(expression, context)?, - Statement::ExpressionNullified(expression_node) => { - self.analyze_expression(&expression_node.inner, context)?; - } - Statement::Let(let_statement) => match &let_statement.inner { - LetStatement::Let { identifier, value } - | LetStatement::LetMut { identifier, value } => { - let r#type = match value.type_evaluation(&self.abstract_tree.context) { - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - Ok(TypeEvaluation::Constructor(StructType::Unit { name })) => { - self.abstract_tree.context.set_variable_type( - identifier.inner.clone(), - Type::Struct(StructType::Unit { name }), - )?; - - self.analyze_expression(value, context)?; - - return Ok(()); - } - Ok(evaluation) => evaluation.r#type(), - }; - - if let Some(r#type) = r#type { - context.set_variable_type(identifier.inner.clone(), r#type.clone())?; - } else { - self.errors - .push(AnalysisError::LetExpectedValueFromStatement { - actual: value.clone(), - }); - } - - self.analyze_expression(value, context)?; - } - LetStatement::LetType { .. } => todo!(), - LetStatement::LetMutType { .. } => todo!(), - }, - Statement::StructDefinition(struct_definition) => { - match &struct_definition.inner { - StructDefinition::Unit { name } => { - self.abstract_tree.context.set_constructor_type( - name.inner.clone(), - StructType::Unit { - name: name.inner.clone(), - }, - )?; - } - StructDefinition::Tuple { name, items } => { - let fields = items.iter().map(|item| item.inner.clone()).collect(); - - self.abstract_tree.context.set_constructor_type( - name.inner.clone(), - StructType::Tuple { - name: name.inner.clone(), - fields, - }, - )?; - } - StructDefinition::Fields { name, fields } => { - let fields = fields - .iter() - .map(|(identifier, r#type)| { - (identifier.inner.clone(), r#type.inner.clone()) - }) - .collect(); - - self.abstract_tree.context.set_constructor_type( - name.inner.clone(), - StructType::Fields { - name: name.inner.clone(), - fields, - }, - )?; - } - }; - } - } - - Ok(()) - } - - fn analyze_expression( - &mut self, - expression: &Expression, - context: &Context, - ) -> Result<(), ContextError> { - log::trace!( - "Analyzing expression {expression} at {:?} with context {}", - expression.position(), - context.id() - ); - - match expression { - Expression::Block(block_expression) => { - self.analyze_block(&block_expression.inner, context)?; - } - Expression::Break(break_node) => { - if let Some(expression) = &break_node.inner { - self.analyze_expression(expression, context)?; - } - } - Expression::Call(call_expression) => { - let CallExpression { invoker, arguments } = call_expression.inner.as_ref(); - - self.analyze_expression(invoker, context)?; - - let invoker_evaluation = match invoker.type_evaluation(&self.abstract_tree.context) - { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - - if let TypeEvaluation::Constructor(StructType::Tuple { fields, .. }) = - invoker_evaluation - { - for (expected_type, argument) in fields.iter().zip(arguments.iter()) { - let actual_type = - match argument.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation.r#type(), - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - - if let Some(r#type) = actual_type { - let check = expected_type.check(&r#type); - - if let Err(type_conflict) = check { - self.errors.push(AnalysisError::TypeConflict { - actual_expression: argument.clone(), - type_conflict, - }); - } - } - } - - return Ok(()); - } - - let invoked_type = if let Some(r#type) = invoker_evaluation.r#type() { - r#type - } else { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: invoker.clone(), - }); - - return Ok(()); - }; - let function_type = if let Type::Function(function_type) = invoked_type { - function_type - } else { - self.errors.push(AnalysisError::ExpectedFunction { - actual: invoked_type, - actual_expression: invoker.clone(), - }); - - return Ok(()); - }; - - let value_parameters = - if let Some(value_parameters) = &function_type.value_parameters { - value_parameters - } else { - if !arguments.is_empty() { - self.errors.push(AnalysisError::ExpectedValueArgumentCount { - expected: 0, - actual: arguments.len(), - position: invoker.position(), - }); - } - - return Ok(()); - }; - - for ((_, expected_type), argument) in value_parameters.iter().zip(arguments) { - self.analyze_expression(argument, context)?; - - let argument_evaluation = - match argument.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(error) => { - self.errors.push(AnalysisError::AstError(error)); - - continue; - } - }; - - let actual_type = if let Some(r#type) = argument_evaluation.r#type() { - r#type - } else { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: argument.clone(), - }); - - continue; - }; - - if let Err(type_conflict) = expected_type.check(&actual_type) { - self.errors.push(AnalysisError::TypeConflict { - type_conflict, - actual_expression: argument.clone(), - }); - } - } - - for argument in arguments { - self.analyze_expression(argument, context)?; - } - } - Expression::Dereference(expression) => { - self.analyze_expression(&expression.inner, context)?; - } - Expression::FieldAccess(field_access_expression) => { - let FieldAccessExpression { container, field } = - field_access_expression.inner.as_ref(); - - let evaluation = match container.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - let container_type = match evaluation.r#type() { - Some(r#type) => r#type, - None => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: container.clone(), - }); - - return Ok(()); - } - }; - - if !container_type.has_field(&field.inner) { - self.errors.push(AnalysisError::UndefinedFieldIdentifier { - identifier: field.clone(), - container: container.clone(), - }); - } - - self.analyze_expression(container, context)?; - } - Expression::Grouped(expression) => { - self.analyze_expression(expression.inner.as_ref(), context)?; - } - Expression::Identifier(identifier) => { - let context_data = context.get_data(&identifier.inner)?; - - if let Some(ContextData::Reserved) | None = context_data { - self.errors.push(AnalysisError::UndefinedVariable { - identifier: identifier.clone(), - }); - } - } - Expression::If(if_expression) => self.analyze_if(&if_expression.inner, context)?, - Expression::List(list_expression) => match list_expression.inner.as_ref() { - ListExpression::AutoFill { - repeat_operand, - length_operand, - } => { - self.analyze_expression(repeat_operand, context)?; - self.analyze_expression(length_operand, context)?; - } - ListExpression::Ordered(expressions) => { - for expression in expressions { - self.analyze_expression(expression, context)?; - } - } - }, - Expression::ListIndex(list_index_expression) => { - let ListIndexExpression { list, index } = list_index_expression.inner.as_ref(); - - self.analyze_expression(list, context)?; - self.analyze_expression(index, context)?; - - let list_type_evaluation = match list.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - let list_type = match list_type_evaluation.r#type() { - Some(r#type) => r#type, - None => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: list.clone(), - }); - - return Ok(()); - } - }; - let index_type_evaluation = match index.type_evaluation(&self.abstract_tree.context) - { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - let index_type = match index_type_evaluation.r#type() { - Some(r#type) => r#type, - None => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: list.clone(), - }); - - return Ok(()); - } - }; - let literal_type = if let Expression::Literal(Node { inner, .. }) = index { - Some(inner.as_ref().clone()) - } else { - None - }; - - if let Some(LiteralExpression::Primitive(PrimitiveValueExpression::Integer( - integer, - ))) = literal_type - { - if integer < 0 { - self.errors.push(AnalysisError::NegativeIndex { - index: index.clone(), - index_value: integer, - list: list.clone(), - }); - } - } - - if let Type::List { length, .. } = list_type { - if let Some(LiteralExpression::Primitive(PrimitiveValueExpression::Integer( - integer, - ))) = literal_type - { - if integer >= length as i64 { - self.errors.push(AnalysisError::ListIndexOutOfBounds { - index: index.clone(), - length, - list: list.clone(), - index_value: integer, - }); - } - } else if let Type::Integer - | Type::Range { - r#type: RangeableType::Integer, - } = index_type - { - } else { - self.errors.push(AnalysisError::ExpectedTypeMultiple { - expected: vec![ - Type::Integer, - Type::Range { - r#type: RangeableType::Integer, - }, - ], - actual: index_type.clone(), - actual_expression: index.clone(), - }); - } - } - - if let Type::String { - length: Some(length), - } = list_type - { - if let Some(LiteralExpression::Primitive(PrimitiveValueExpression::Integer( - integer, - ))) = literal_type - { - if integer >= length as i64 { - self.errors.push(AnalysisError::ListIndexOutOfBounds { - index: index.clone(), - length, - list: list.clone(), - index_value: integer, - }); - } - } - } - } - Expression::Literal(_) => { - // Literals don't need to be analyzed - } - Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() { - LoopExpression::Infinite { block } => self.analyze_block(&block.inner, context)?, - LoopExpression::While { condition, block } => { - self.analyze_expression(condition, context)?; - self.analyze_block(&block.inner, context)?; - } - LoopExpression::For { - iterator, block, .. - } => { - self.analyze_expression(iterator, context)?; - self.analyze_block(&block.inner, context)?; - } - }, - Expression::Map(map_expression) => { - let MapExpression { pairs } = map_expression.inner.as_ref(); - - for (_, expression) in pairs { - self.analyze_expression(expression, context)?; - } - } - Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() { - OperatorExpression::Assignment { assignee, value } => { - self.analyze_expression(assignee, context)?; - self.analyze_expression(value, context)?; - } - OperatorExpression::Comparison { left, right, .. } => { - self.analyze_expression(left, context)?; - self.analyze_expression(right, context)?; - } - OperatorExpression::CompoundAssignment { - assignee, modifier, .. - } => { - self.analyze_expression(assignee, context)?; - self.analyze_expression(modifier, context)?; - - let assignee_type_evaluation = - match assignee.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - let modifier_type_evaluation = - match modifier.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - - let (expected_type, actual_type) = match ( - assignee_type_evaluation.r#type(), - modifier_type_evaluation.r#type(), - ) { - (Some(expected_type), Some(actual_type)) => (expected_type, actual_type), - (None, None) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: assignee.clone(), - }); - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: modifier.clone(), - }); - return Ok(()); - } - (None, _) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: assignee.clone(), - }); - return Ok(()); - } - (_, None) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: modifier.clone(), - }); - return Ok(()); - } - }; - - if actual_type != expected_type { - self.errors.push(AnalysisError::ExpectedType { - expected: expected_type, - actual: actual_type, - actual_expression: modifier.clone(), - }); - } - } - OperatorExpression::ErrorPropagation(_) => todo!(), - OperatorExpression::Negation(expression) => { - self.analyze_expression(expression, context)?; - } - OperatorExpression::Not(expression) => { - self.analyze_expression(expression, context)?; - } - OperatorExpression::Math { left, right, .. } => { - self.analyze_expression(left, context)?; - self.analyze_expression(right, context)?; - - let left_type_evaluation = - match left.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - let right_type_evaluation = - match right.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - - let (left_type, right_type) = match ( - left_type_evaluation.r#type(), - right_type_evaluation.r#type(), - ) { - (Some(left_type), Some(right_type)) => (left_type, right_type), - (None, None) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: left.clone(), - }); - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: right.clone(), - }); - return Ok(()); - } - (None, _) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: left.clone(), - }); - return Ok(()); - } - (_, None) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: right.clone(), - }); - return Ok(()); - } - }; - - match left_type { - Type::Integer => { - if right_type != Type::Integer { - self.errors.push(AnalysisError::ExpectedType { - expected: Type::Integer, - actual: right_type, - actual_expression: right.clone(), - }); - } - } - Type::Float => { - if right_type != Type::Float { - self.errors.push(AnalysisError::ExpectedType { - expected: Type::Float, - actual: right_type, - actual_expression: right.clone(), - }); - } - } - - Type::String { .. } => { - if let Type::String { .. } = right_type { - } else { - self.errors.push(AnalysisError::ExpectedType { - expected: Type::String { length: None }, - actual: right_type, - actual_expression: right.clone(), - }); - } - } - _ => { - self.errors.push(AnalysisError::ExpectedTypeMultiple { - expected: vec![ - Type::Float, - Type::Integer, - Type::String { length: None }, - ], - actual: left_type, - actual_expression: left.clone(), - }); - } - } - } - OperatorExpression::Logic { left, right, .. } => { - self.analyze_expression(left, context)?; - self.analyze_expression(right, context)?; - - let left_type_evaluation = - match left.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - let right_type_evaluation = - match right.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - - return Ok(()); - } - }; - - let (left_type, right_type) = match ( - left_type_evaluation.r#type(), - right_type_evaluation.r#type(), - ) { - (Some(left_type), Some(right_type)) => (left_type, right_type), - (None, None) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: left.clone(), - }); - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: right.clone(), - }); - return Ok(()); - } - (None, _) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: left.clone(), - }); - return Ok(()); - } - (_, None) => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: right.clone(), - }); - return Ok(()); - } - }; - - if left_type != right_type { - self.errors.push(AnalysisError::ExpectedType { - expected: left_type, - actual: right_type, - actual_expression: right.clone(), - }); - } - } - }, - Expression::Range(range_expression) => match range_expression.inner.as_ref() { - RangeExpression::Exclusive { start, end } => { - self.analyze_expression(start, context)?; - self.analyze_expression(end, context)?; - } - RangeExpression::Inclusive { start, end } => { - self.analyze_expression(start, context)?; - self.analyze_expression(end, context)?; - } - }, - Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { - StructExpression::Fields { fields, .. } => { - for (_, expression) in fields { - self.analyze_expression(expression, context)?; - } - } - }, - Expression::TupleAccess(tuple_access) => { - let TupleAccessExpression { tuple, index } = tuple_access.inner.as_ref(); - - let type_evaluation = match tuple.type_evaluation(&self.abstract_tree.context) { - Ok(evaluation) => evaluation, - Err(ast_error) => { - self.errors.push(AnalysisError::AstError(ast_error)); - return Ok(()); - } - }; - - let tuple_type = match type_evaluation.r#type() { - Some(tuple_type) => tuple_type, - None => { - self.errors - .push(AnalysisError::ExpectedValueFromExpression { - expression: tuple.clone(), - }); - return Ok(()); - } - }; - - if let Type::Tuple { - fields: Some(fields), - } = tuple_type - { - if index.inner >= fields.len() { - self.errors.push(AnalysisError::TupleIndexOutOfBounds { - index: expression.clone(), - tuple: tuple.clone(), - index_value: index.inner as i64, - length: fields.len(), - }); - } - } else { - self.errors.push(AnalysisError::ExpectedType { - expected: Type::Tuple { fields: None }, - actual: tuple_type, - actual_expression: tuple.clone(), - }); - } - - self.analyze_expression(tuple, context)?; - } - } - - Ok(()) - } - - fn analyze_block( - &mut self, - block_expression: &BlockExpression, - _context: &Context, - ) -> Result<(), ContextError> { - let ast = match block_expression { - BlockExpression::Async(ast) => ast, - BlockExpression::Sync(ast) => ast, - }; - - log::trace!("Analyzing block with context {}", ast.context.id()); - - for statement in &ast.statements { - self.analyze_statement(statement, &ast.context)?; - } - - Ok(()) - } - - fn analyze_if( - &mut self, - if_expression: &IfExpression, - context: &Context, - ) -> Result<(), ContextError> { - match if_expression { - IfExpression::If { - condition, - if_block, - } => { - self.analyze_expression(condition, context)?; - self.analyze_block(&if_block.inner, context)?; - } - IfExpression::IfElse { - condition, - if_block, - r#else, - } => { - self.analyze_expression(condition, context)?; - self.analyze_block(&if_block.inner, context)?; - - match r#else { - ElseExpression::Block(block_expression) => { - self.analyze_block(&block_expression.inner, context)?; - } - ElseExpression::If(if_expression) => { - self.analyze_if(&if_expression.inner, context)?; - } - } - } - } - - Ok(()) - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum AnalysisError { - AstError(AstError), - ExpectedFunction { - actual: Type, - actual_expression: Expression, - }, - ExpectedType { - expected: Type, - actual: Type, - actual_expression: Expression, - }, - ExpectedTypeMultiple { - expected: Vec, - actual: Type, - actual_expression: Expression, - }, - ExpectedIdentifier { - actual: Expression, - }, - ExpectedIdentifierOrString { - actual: Expression, - }, - LetExpectedValueFromStatement { - actual: Expression, - }, - ExpectedValueFromExpression { - expression: Expression, - }, - ExpectedValueArgumentCount { - expected: usize, - actual: usize, - position: Span, - }, - ListIndexOutOfBounds { - list: Expression, - index: Expression, - index_value: i64, - length: usize, - }, - TupleIndexOutOfBounds { - tuple: Expression, - index: Expression, - index_value: i64, - length: usize, - }, - NegativeIndex { - list: Expression, - index: Expression, - index_value: i64, - }, - TypeConflict { - actual_expression: Expression, - type_conflict: TypeConflict, - }, - UnexpectedArguments { - expected: Option>, - actual: Vec, - }, - UndefinedFieldIdentifier { - identifier: Node, - container: Expression, - }, - UndefinedType { - identifier: Node, - }, - UnexpectedIdentifier { - identifier: Node, - }, - UnexectedString { - actual: Expression, - }, - UndefinedVariable { - identifier: Node, - }, -} - -impl From for AnalysisError { - fn from(error: AstError) -> Self { - Self::AstError(error) - } -} - -impl AnalysisError { - pub fn position(&self) -> Span { - match self { - AnalysisError::AstError(ast_error) => ast_error.position(), - AnalysisError::ExpectedFunction { - actual_expression, .. - } => actual_expression.position(), - AnalysisError::ExpectedType { - actual_expression, .. - } => actual_expression.position(), - AnalysisError::ExpectedTypeMultiple { - actual_expression, .. - } => actual_expression.position(), - AnalysisError::ExpectedIdentifier { actual } => actual.position(), - AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(), - AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(), - AnalysisError::ExpectedValueArgumentCount { position, .. } => *position, - AnalysisError::ListIndexOutOfBounds { index, .. } => index.position(), - AnalysisError::TupleIndexOutOfBounds { index, .. } => index.position(), - AnalysisError::LetExpectedValueFromStatement { actual } => actual.position(), - AnalysisError::NegativeIndex { index, .. } => index.position(), - AnalysisError::TypeConflict { - actual_expression, .. - } => actual_expression.position(), - AnalysisError::UndefinedFieldIdentifier { identifier, .. } => identifier.position, - AnalysisError::UndefinedType { identifier } => identifier.position, - AnalysisError::UndefinedVariable { identifier } => identifier.position, - AnalysisError::UnexpectedArguments { actual, .. } => actual[0].position(), - AnalysisError::UnexpectedIdentifier { identifier } => identifier.position, - AnalysisError::UnexectedString { actual } => actual.position(), - } - } -} - -impl Error for AnalysisError {} - -impl Display for AnalysisError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - AnalysisError::AstError(ast_error) => write!(f, "{}", ast_error), - AnalysisError::ExpectedFunction { - actual, - actual_expression, - } => { - write!( - f, - "Expected function, found {} in {}", - actual, actual_expression - ) - } - AnalysisError::ExpectedType { - expected, - actual, - actual_expression, - } => { - write!( - f, - "Expected type {}, found {} in {}", - expected, actual, actual_expression - ) - } - AnalysisError::ExpectedTypeMultiple { - expected, - actual, - actual_expression, - } => { - write!(f, "Expected ")?; - - for (i, expected_type) in expected.iter().enumerate() { - if i == expected.len() - 1 { - write!(f, "or ")?; - } else if i > 0 { - write!(f, ", ")?; - } - - write!(f, "{}", expected_type)?; - } - - write!(f, ", found {} in {}", actual, actual_expression) - } - - AnalysisError::ExpectedIdentifier { actual, .. } => { - write!(f, "Expected identifier, found {}", actual) - } - AnalysisError::ExpectedIdentifierOrString { actual } => { - write!(f, "Expected identifier or string, found {}", actual) - } - AnalysisError::ExpectedValueFromExpression { expression } => { - write!(f, "Expected {} to produce a value", expression) - } - AnalysisError::ExpectedValueArgumentCount { - expected, actual, .. - } => write!(f, "Expected {} value arguments, found {}", expected, actual), - AnalysisError::ListIndexOutOfBounds { - list, - index_value, - length, - .. - } => write!( - f, - "Index {} out of bounds for list {} with length {}", - index_value, list, length - ), - AnalysisError::LetExpectedValueFromStatement { actual, .. } => { - write!( - f, - "Cannot assign to nothing. This expression should produce a value, but {} does not", - actual - ) - } - AnalysisError::NegativeIndex { - list, index_value, .. - } => write!(f, "Negative index {} for list {}", index_value, list), - AnalysisError::TupleIndexOutOfBounds { - tuple, - index_value, - length, - .. - } => write!( - f, - "Index {} out of bounds for tuple {} with length {}", - index_value, tuple, length - ), - AnalysisError::TypeConflict { - actual_expression: actual_statement, - type_conflict: TypeConflict { expected, actual }, - } => { - write!( - f, - "Expected type {}, found {}, which has type {}", - expected, actual_statement, actual - ) - } - AnalysisError::UnexpectedArguments { - actual, expected, .. - } => { - write!( - f, - "Unexpected arguments {:?}, expected {:?}", - actual, expected - ) - } - AnalysisError::UndefinedFieldIdentifier { - identifier, - container, - } => { - write!( - f, - "Undefined field {} in container {}", - identifier, container - ) - } - AnalysisError::UndefinedType { identifier } => { - write!(f, "Undefined type {}", identifier) - } - AnalysisError::UndefinedVariable { identifier } => { - write!(f, "Undefined variable {}", identifier) - } - AnalysisError::UnexpectedIdentifier { identifier, .. } => { - write!(f, "Unexpected identifier {}", identifier) - } - AnalysisError::UnexectedString { actual, .. } => { - write!(f, "Unexpected string {}", actual) - } - } - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use crate::RangeableType; - - use super::*; - - #[test] - fn multiple_errors() { - let source = "1 + 1.0; 'a' + 1"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![ - AnalysisError::ExpectedType { - expected: Type::Integer, - actual: Type::Float, - actual_expression: Expression::literal(1.0, (4, 7)), - }, - AnalysisError::ExpectedTypeMultiple { - expected: vec![Type::Float, Type::Integer, Type::String { length: None }], - actual: Type::Character, - actual_expression: Expression::literal('a', (9, 12)), - } - ], - source, - }) - ); - } - - #[test] - fn add_assign_wrong_type() { - let source = " - let mut a = 1; - a += 1.0 - "; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::ExpectedType { - expected: Type::Integer, - actual: Type::Float, - actual_expression: Expression::literal(1.0, (45, 48)), - }], - source, - }) - ); - } - - #[test] - fn subtract_assign_wrong_type() { - let source = " - let mut a = 1; - a -= 1.0 - "; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::ExpectedType { - expected: Type::Integer, - actual: Type::Float, - actual_expression: Expression::literal(1.0, (45, 48)), - }], - source, - }) - ); - } - - #[test] - fn tuple_struct_with_wrong_field_types() { - let source = " - struct Foo(int, float); - Foo(1, 2) - "; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::TypeConflict { - actual_expression: Expression::literal(2, (56, 57)), - type_conflict: TypeConflict { - expected: Type::Float, - actual: Type::Integer, - }, - }], - source, - }) - ); - } - - #[test] - fn constant_list_index_out_of_bounds() { - let source = "[1, 2, 3][3]"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::ListIndexOutOfBounds { - list: Expression::list( - vec![ - Expression::literal(1, (1, 2)), - Expression::literal(2, (4, 5)), - Expression::literal(3, (7, 8)), - ], - (0, 9) - ), - index: Expression::literal(3, (10, 11)), - index_value: 3, - length: 3, - }], - source, - }) - ); - } - - #[test] - fn nonexistant_map_field_identifier() { - let source = "map { x = 1 }.y"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::UndefinedFieldIdentifier { - container: Expression::map( - [( - Node::new(Identifier::new("x"), (6, 7)), - Expression::literal(1, (10, 11)) - )], - (0, 13) - ), - identifier: Node::new(Identifier::new("y"), (14, 15)), - }], - source, - }) - ); - } - - #[test] - fn malformed_list_index() { - let source = "[1, 2, 3][\"foo\"]"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::ExpectedTypeMultiple { - expected: vec![ - Type::Integer, - Type::Range { - r#type: RangeableType::Integer - } - ], - actual: Type::String { length: Some(3) }, - actual_expression: Expression::literal("foo", (10, 15)), - }], - source, - }) - ); - } - - #[test] - fn malformed_field_access() { - let source = "struct Foo { x: int } Foo { x: 1 }.0"; - - assert_eq!( - analyze(source), - Err(DustError::analysis( - [AnalysisError::ExpectedType { - expected: Type::Tuple { fields: None }, - actual: Type::Struct(StructType::Fields { - name: Identifier::new("Foo"), - fields: HashMap::from([(Identifier::new("x"), Type::Integer)]) - }), - actual_expression: Expression::r#struct( - StructExpression::Fields { - name: Node::new(Identifier::new("Foo"), (22, 25)), - fields: vec![( - Node::new(Identifier::new("x"), (28, 29)), - Expression::literal(1, (31, 32)) - )], - }, - (22, 35) - ), - }], - source - )) - ); - } - - #[test] - fn float_plus_integer() { - let source = "42.0 + 2"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::ExpectedType { - expected: Type::Float, - actual: Type::Integer, - actual_expression: Expression::literal(2, (7, 8)), - }], - source, - }) - ); - } - - #[test] - fn integer_plus_boolean() { - let source = "42 + true"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::ExpectedType { - expected: Type::Integer, - actual: Type::Boolean, - actual_expression: Expression::literal(true, (5, 9)), - }], - source, - }) - ); - } - - #[test] - fn nonexistant_field() { - let source = "\"hello\".foo"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::UndefinedFieldIdentifier { - container: Expression::literal("hello", (0, 7)), - identifier: Node::new(Identifier::new("foo"), (8, 11)), - }], - source, - }) - ); - } - - #[test] - fn undefined_variable() { - let source = "foo"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::UndefinedVariable { - identifier: Node::new(Identifier::new("foo"), (0, 3)) - }], - source, - }) - ); - } -} diff --git a/dust-lang/src/ast/expression.rs b/dust-lang/src/ast/expression.rs deleted file mode 100644 index 05665f9..0000000 --- a/dust-lang/src/ast/expression.rs +++ /dev/null @@ -1,1253 +0,0 @@ -use std::{ - cmp::Ordering, - collections::HashMap, - fmt::{self, Display, Formatter}, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - BuiltInFunction, Context, FunctionType, Identifier, RangeableType, StructType, Type, - TypeEvaluation, ValueData, -}; - -use super::{AbstractSyntaxTree, AstError, Node, Span}; - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum Expression { - Block(Node>), - Break(Node>>), - Call(Node>), - Dereference(Node>), - FieldAccess(Node>), - Grouped(Node>), - Identifier(Node), - If(Node>), - List(Node>), - ListIndex(Node>), - Literal(Node>), - Loop(Node>), - Map(Node>), - Operator(Node>), - Range(Node>), - Struct(Node>), - TupleAccess(Node>), -} - -impl Expression { - pub fn dereference(expression: Expression, position: Span) -> Self { - Self::Dereference(Node::new(Box::new(expression), position)) - } - - pub fn r#break(expression: Option, position: Span) -> Self { - Self::Break(Node::new(expression.map(Box::new), position)) - } - - pub fn map, Expression)>>>(pairs: T, position: Span) -> Self { - Self::Map(Node::new( - Box::new(MapExpression { - pairs: pairs.into(), - }), - position, - )) - } - - pub fn operator(operator_expression: OperatorExpression, position: Span) -> Self { - Self::Operator(Node::new(Box::new(operator_expression), position)) - } - - pub fn exclusive_range(start: Expression, end: Expression, position: Span) -> Self { - Self::Range(Node::new( - Box::new(RangeExpression::Exclusive { start, end }), - position, - )) - } - - pub fn inclusive_range(start: Expression, end: Expression, position: Span) -> Self { - Self::Range(Node::new( - Box::new(RangeExpression::Inclusive { start, end }), - position, - )) - } - - pub fn call(invoker: Expression, arguments: Vec, position: Span) -> Self { - Self::Call(Node::new( - Box::new(CallExpression { invoker, arguments }), - position, - )) - } - - pub fn field_access(container: Expression, field: Node, position: Span) -> Self { - Self::FieldAccess(Node::new( - Box::new(FieldAccessExpression { container, field }), - position, - )) - } - - pub fn tuple_access(tuple: Expression, index: Node, position: Span) -> Self { - Self::TupleAccess(Node::new( - Box::new(TupleAccessExpression { tuple, index }), - position, - )) - } - - pub fn assignment(assignee: Expression, value: Expression, position: Span) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::Assignment { assignee, value }), - position, - )) - } - - pub fn comparison( - left: Expression, - operator: Node, - right: Expression, - position: Span, - ) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::Comparison { - left, - operator, - right, - }), - position, - )) - } - - pub fn compound_assignment( - assignee: Expression, - operator: Node, - modifier: Expression, - position: Span, - ) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::CompoundAssignment { - assignee, - operator, - modifier, - }), - position, - )) - } - - pub fn math( - left: Expression, - operator: Node, - right: Expression, - position: Span, - ) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::Math { - left, - operator, - right, - }), - position, - )) - } - - pub fn negation(expression: Expression, position: Span) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::Negation(expression)), - position, - )) - } - - pub fn not(expression: Expression, position: Span) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::Not(expression)), - position, - )) - } - - pub fn logic( - left: Expression, - operator: Node, - right: Expression, - position: Span, - ) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::Logic { - left, - operator, - right, - }), - position, - )) - } - - pub fn error_propagation(expression: Expression, position: Span) -> Self { - Self::Operator(Node::new( - Box::new(OperatorExpression::ErrorPropagation(expression)), - position, - )) - } - - pub fn infinite_loop(block: Node, position: Span) -> Self { - Self::Loop(Node::new( - Box::new(LoopExpression::Infinite { block }), - position, - )) - } - - pub fn while_loop(condition: Expression, block: Node, position: Span) -> Self { - Self::Loop(Node::new( - Box::new(LoopExpression::While { condition, block }), - position, - )) - } - - pub fn for_loop( - identifier: Node, - iterator: Expression, - block: Node, - position: Span, - ) -> Self { - Self::Loop(Node::new( - Box::new(LoopExpression::For { - identifier, - iterator, - block, - }), - position, - )) - } - - pub fn block(block: BlockExpression, position: Span) -> Self { - Self::Block(Node::new(Box::new(block), position)) - } - - pub fn grouped(expression: Expression, position: Span) -> Self { - Self::Grouped(Node::new(Box::new(expression), position)) - } - - pub fn r#struct(struct_expression: StructExpression, position: Span) -> Self { - Self::Struct(Node::new(Box::new(struct_expression), position)) - } - - pub fn identifier(to_string: T, position: Span) -> Self { - Self::Identifier(Node::new(Identifier::new(to_string), position)) - } - - pub fn list>>(expressions: T, position: Span) -> Self { - Self::List(Node::new( - Box::new(ListExpression::Ordered(expressions.into())), - position, - )) - } - - pub fn auto_fill_list(repeat: Expression, length: Expression, position: Span) -> Self { - Self::List(Node::new( - Box::new(ListExpression::AutoFill { - repeat_operand: repeat, - length_operand: length, - }), - position, - )) - } - - pub fn list_index(list: Expression, index: Expression, position: Span) -> Self { - Self::ListIndex(Node::new( - Box::new(ListIndexExpression { list, index }), - position, - )) - } - - pub fn r#if(if_expression: IfExpression, position: Span) -> Self { - Self::If(Node::new(Box::new(if_expression), position)) - } - - pub fn literal>(into_literal: T, position: Span) -> Self { - Self::Literal(Node::new(Box::new(into_literal.into()), position)) - } - - pub fn has_block(&self) -> bool { - matches!( - self, - Expression::Block(_) | Expression::If(_) | Expression::Loop(_) - ) - } - - pub fn as_identifier(&self) -> Option<&Identifier> { - if let Expression::Identifier(identifier) = self { - Some(&identifier.inner) - } else { - None - } - } - - pub fn type_evaluation(&self, context: &Context) -> Result { - let evaluation = match self { - Expression::Block(block_expression) => { - block_expression.inner.type_evaluation(context)? - } - Expression::Break(expression_node) => { - if let Some(expression) = expression_node.inner.as_ref() { - let type_evaluation = expression.type_evaluation(context)?; - - TypeEvaluation::Break(type_evaluation.r#type()) - } else { - TypeEvaluation::Break(None) - } - } - Expression::Call(call_expression) => { - let CallExpression { invoker, .. } = call_expression.inner.as_ref(); - let invoker_evaluation = invoker.type_evaluation(context)?; - - match invoker_evaluation { - TypeEvaluation::Return(Some(Type::Function(FunctionType { - return_type, - .. - }))) => TypeEvaluation::Return(return_type.map(|boxed| *boxed)), - TypeEvaluation::Constructor(struct_type) => { - TypeEvaluation::Return(Some(Type::Struct(struct_type))) - } - _ => { - return Err(AstError::ExpectedFunctionOrConstructor { - position: invoker.position(), - }); - } - } - } - Expression::Dereference(expression) => expression.inner.type_evaluation(context)?, - Expression::FieldAccess(field_access_expression) => { - let FieldAccessExpression { container, field } = - field_access_expression.inner.as_ref(); - - let container_type = match container.type_evaluation(context)?.r#type() { - Some(r#type) => r#type, - None => { - return Err(AstError::ExpectedNonEmptyEvaluation { - position: container.position(), - }) - } - }; - - if let Type::Struct(StructType::Fields { fields, .. }) = container_type { - let found_type = fields - .into_iter() - .find(|(name, _)| name == &field.inner) - .map(|(_, r#type)| r#type); - - TypeEvaluation::Return(found_type) - } else if let Some(field_type) = container_type.get_field_type(&field.inner) { - TypeEvaluation::Return(Some(field_type)) - } else { - return Err(AstError::ExpectedNonEmptyEvaluation { - position: container.position(), - }); - } - } - Expression::Grouped(expression) => expression.inner.type_evaluation(context)?, - Expression::Identifier(identifier) => { - if let Some(struct_type) = - context - .get_constructor_type(&identifier.inner) - .map_err(|error| AstError::ContextError { - error, - position: identifier.position, - })? - { - TypeEvaluation::Constructor(struct_type) - } else { - let type_option = context.get_type(&identifier.inner).map_err(|error| { - AstError::ContextError { - error, - position: identifier.position, - } - })?; - - TypeEvaluation::Return(type_option) - } - } - Expression::If(if_expression) => match if_expression.inner.as_ref() { - IfExpression::If { .. } => TypeEvaluation::Return(None), - IfExpression::IfElse { if_block, .. } => if_block.inner.type_evaluation(context)?, - }, - Expression::List(list_expression) => match list_expression.inner.as_ref() { - ListExpression::AutoFill { - repeat_operand, - length_operand, - } => { - let item_type = repeat_operand - .type_evaluation(context)? - .r#type() - .ok_or_else(|| AstError::ExpectedListType { - position: repeat_operand.position(), - })?; - - let list_type = if let Expression::Literal(literal_expression) = length_operand - { - if let Some(index) = literal_expression.inner.as_integer() { - let length = match usize::try_from(index) { - Ok(usize) => usize, - Err(error) => { - return Err(AstError::FromIntError { - error, - position: length_operand.position(), - }) - } - }; - - Type::List { - item_type: Box::new(item_type), - length, - } - } else { - return Err(AstError::ExpectedInteger { - position: literal_expression.position, - }); - } - } else { - Type::ListOf { - item_type: Box::new(item_type), - } - }; - - TypeEvaluation::Return(Some(list_type)) - } - ListExpression::Ordered(expressions) => { - if expressions.is_empty() { - return Ok(TypeEvaluation::Return(Some(Type::ListEmpty))); - } - - let item_type = expressions - .first() - .unwrap() - .type_evaluation(context)? - .r#type() - .ok_or_else(|| AstError::ExpectedNonEmptyEvaluation { - position: expressions.first().unwrap().position(), - })?; - let length = expressions.len(); - - TypeEvaluation::Return(Some(Type::List { - item_type: Box::new(item_type), - length, - })) - } - }, - Expression::ListIndex(list_index_expression) => { - let ListIndexExpression { list, .. } = list_index_expression.inner.as_ref(); - - let list_type = list.type_evaluation(context)?.r#type().ok_or_else(|| { - AstError::ExpectedListType { - position: list.position(), - } - })?; - - if let Type::List { item_type, .. } = list_type { - TypeEvaluation::Return(Some(*item_type)) - } else { - return Err(AstError::ExpectedListType { - position: list.position(), - }); - } - } - Expression::Literal(literal_expression) => { - let type_option = match literal_expression.inner.as_ref() { - LiteralExpression::BuiltInFunction(built_in_function) => { - built_in_function.return_type() - } - LiteralExpression::Primitive(primitive_value) => match primitive_value { - PrimitiveValueExpression::Boolean(_) => Some(Type::Boolean), - PrimitiveValueExpression::Character(_) => Some(Type::Character), - PrimitiveValueExpression::Integer(_) => Some(Type::Integer), - PrimitiveValueExpression::Float(_) => Some(Type::Float), - }, - LiteralExpression::String(string) => Some(Type::String { - length: Some(string.len()), - }), - }; - - TypeEvaluation::Return(type_option) - } - Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() { - LoopExpression::For { block, .. } => block.inner.type_evaluation(context)?, - LoopExpression::Infinite { block } => block.inner.type_evaluation(context)?, - LoopExpression::While { block, .. } => block.inner.type_evaluation(context)?, - }, - Expression::Map(map_expression) => { - let MapExpression { pairs } = map_expression.inner.as_ref(); - - let mut types = HashMap::with_capacity(pairs.len()); - - for (key, value) in pairs { - let value_type = value.type_evaluation(context)?.r#type().ok_or_else(|| { - AstError::ExpectedNonEmptyEvaluation { - position: value.position(), - } - })?; - - types.insert(key.inner.clone(), value_type); - } - - TypeEvaluation::Return(Some(Type::Map { pairs: types })) - } - Expression::Operator(operator_expression) => { - let expected_type = match operator_expression.inner.as_ref() { - OperatorExpression::Assignment { .. } => None, - OperatorExpression::Comparison { .. } => Some(Type::Boolean), - OperatorExpression::CompoundAssignment { .. } => None, - OperatorExpression::ErrorPropagation(expression) => { - expression.type_evaluation(context)?.r#type() - } - OperatorExpression::Negation(expression) => { - expression.type_evaluation(context)?.r#type() - } - OperatorExpression::Not(_) => Some(Type::Boolean), - OperatorExpression::Math { left, .. } => { - left.type_evaluation(context)?.r#type() - } - OperatorExpression::Logic { .. } => Some(Type::Boolean), - }; - - TypeEvaluation::Return(expected_type) - } - Expression::Range(range_expression) => { - let start = match range_expression.inner.as_ref() { - RangeExpression::Exclusive { start, .. } => start, - RangeExpression::Inclusive { start, .. } => start, - }; - let start_type = start.type_evaluation(context)?.r#type().ok_or_else(|| { - AstError::ExpectedListType { - position: start.position(), - } - })?; - let rangeable_type = match start_type { - Type::Byte => RangeableType::Byte, - Type::Character => RangeableType::Character, - Type::Float => RangeableType::Float, - Type::Integer => RangeableType::Integer, - _ => { - return Err(AstError::ExpectedRangeableType { - position: start.position(), - }) - } - }; - - TypeEvaluation::Return(Some(Type::Range { - r#type: rangeable_type, - })) - } - Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { - StructExpression::Fields { name, fields } => { - let mut types = HashMap::with_capacity(fields.len()); - - for (field, expression) in fields { - let r#type = - expression - .type_evaluation(context)? - .r#type() - .ok_or_else(|| AstError::ExpectedListType { - position: expression.position(), - })?; - - types.insert(field.inner.clone(), r#type); - } - - TypeEvaluation::Return(Some(Type::Struct(StructType::Fields { - name: name.inner.clone(), - fields: types, - }))) - } - }, - Expression::TupleAccess(tuple_access_expression) => { - let TupleAccessExpression { tuple, index } = tuple_access_expression.inner.as_ref(); - let tuple_value = tuple.type_evaluation(context)?.r#type(); - - if let Some(Type::Tuple { - fields: Some(fields), - }) = tuple_value - { - TypeEvaluation::Return(fields.get(index.inner).cloned()) - } else { - Err(AstError::ExpectedTupleType { - position: tuple.position(), - })? - } - } - }; - - Ok(evaluation) - } - - pub fn position(&self) -> Span { - match self { - Expression::Block(block) => block.position, - Expression::Break(expression_node) => expression_node.position, - Expression::Call(call) => call.position, - Expression::Dereference(expression_node) => expression_node.position, - Expression::FieldAccess(field_access) => field_access.position, - Expression::Grouped(grouped) => grouped.position, - Expression::Identifier(identifier) => identifier.position, - Expression::If(r#if) => r#if.position, - Expression::List(list) => list.position, - Expression::ListIndex(list_index) => list_index.position, - Expression::Literal(literal) => literal.position, - Expression::Loop(r#loop) => r#loop.position, - Expression::Map(map) => map.position, - Expression::Operator(operator) => operator.position, - Expression::Range(range) => range.position, - Expression::Struct(r#struct) => r#struct.position, - Expression::TupleAccess(tuple_access) => tuple_access.position, - } - } -} - -impl Display for Expression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Expression::Block(block) => write!(f, "{}", block.inner), - Expression::Break(break_node) => { - if let Some(expression_node) = &break_node.inner { - write!(f, "break {};", expression_node) - } else { - write!(f, "break;") - } - } - Expression::Call(call) => write!(f, "{}", call.inner), - Expression::Dereference(expression_node) => write!(f, "*{}", expression_node.inner), - Expression::FieldAccess(field_access) => write!(f, "{}", field_access.inner), - Expression::Grouped(grouped) => write!(f, "({})", grouped.inner), - Expression::Identifier(identifier) => write!(f, "{}", identifier.inner), - Expression::If(r#if) => write!(f, "{}", r#if.inner), - Expression::List(list) => write!(f, "{}", list.inner), - Expression::ListIndex(list_index) => write!(f, "{}", list_index.inner), - Expression::Literal(literal) => write!(f, "{}", literal.inner), - Expression::Loop(r#loop) => write!(f, "{}", r#loop.inner), - Expression::Map(map) => write!(f, "{}", map.inner), - Expression::Operator(operator) => write!(f, "{}", operator.inner), - Expression::Range(range) => write!(f, "{}", range), - Expression::Struct(r#struct) => write!(f, "{}", r#struct.inner), - Expression::TupleAccess(tuple_access) => write!(f, "{}", tuple_access), - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct MapExpression { - pub pairs: Vec<(Node, Expression)>, -} - -impl Display for MapExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{{")?; - - for (index, (key, value)) in self.pairs.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{} = {}", key.inner, value)?; - } - - write!(f, "}}") - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct TupleAccessExpression { - pub tuple: Expression, - pub index: Node, -} - -impl Display for TupleAccessExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}.{}", self.tuple, self.index) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum RangeExpression { - Exclusive { start: Expression, end: Expression }, - Inclusive { start: Expression, end: Expression }, -} - -impl Display for RangeExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - RangeExpression::Exclusive { start, end } => write!(f, "{}..{}", start, end), - RangeExpression::Inclusive { start, end } => write!(f, "{}..={}", start, end), - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct ListIndexExpression { - pub list: Expression, - pub index: Expression, -} - -impl Display for ListIndexExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}[{}]", self.list, self.index) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct CallExpression { - pub invoker: Expression, - pub arguments: Vec, -} - -impl Display for CallExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}(", self.invoker)?; - - for (index, argument) in self.arguments.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{}", argument)?; - } - - write!(f, ")") - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct FieldAccessExpression { - pub container: Expression, - pub field: Node, -} - -impl Display for FieldAccessExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}.{}", self.container, self.field) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum ListExpression { - AutoFill { - repeat_operand: Expression, - length_operand: Expression, - }, - Ordered(Vec), -} - -impl Display for ListExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - ListExpression::AutoFill { - repeat_operand, - length_operand, - } => { - write!(f, "[{};{}]", repeat_operand, length_operand) - } - ListExpression::Ordered(expressions) => { - write!(f, "[")?; - - for (index, expression) in expressions.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{}", expression)?; - } - - write!(f, "]") - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum PrimitiveValueExpression { - Boolean(bool), - Character(char), - Float(f64), - Integer(i64), -} - -impl Display for PrimitiveValueExpression { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - PrimitiveValueExpression::Boolean(boolean) => ValueData::Boolean(*boolean).fmt(f), - PrimitiveValueExpression::Character(character) => { - ValueData::Character(*character).fmt(f) - } - PrimitiveValueExpression::Float(float) => ValueData::Float(*float).fmt(f), - PrimitiveValueExpression::Integer(integer) => ValueData::Integer(*integer).fmt(f), - } - } -} - -impl Eq for PrimitiveValueExpression {} - -impl PartialOrd for PrimitiveValueExpression { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for PrimitiveValueExpression { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (PrimitiveValueExpression::Boolean(left), PrimitiveValueExpression::Boolean(right)) => { - left.cmp(right) - } - (PrimitiveValueExpression::Boolean(_), _) => Ordering::Greater, - ( - PrimitiveValueExpression::Character(left), - PrimitiveValueExpression::Character(right), - ) => left.cmp(right), - (PrimitiveValueExpression::Character(_), _) => Ordering::Greater, - (PrimitiveValueExpression::Float(left), PrimitiveValueExpression::Float(right)) => { - left.to_bits().cmp(&right.to_bits()) - } - (PrimitiveValueExpression::Float(_), _) => Ordering::Greater, - (PrimitiveValueExpression::Integer(left), PrimitiveValueExpression::Integer(right)) => { - left.cmp(right) - } - (PrimitiveValueExpression::Integer(_), _) => Ordering::Greater, - } - } -} - -impl From for LiteralExpression { - fn from(value: i64) -> Self { - LiteralExpression::Primitive(PrimitiveValueExpression::Integer(value)) - } -} - -impl From for LiteralExpression { - fn from(value: String) -> Self { - LiteralExpression::String(value) - } -} - -impl From<&str> for LiteralExpression { - fn from(value: &str) -> Self { - LiteralExpression::String(value.to_string()) - } -} - -impl From for LiteralExpression { - fn from(value: f64) -> Self { - LiteralExpression::Primitive(PrimitiveValueExpression::Float(value)) - } -} - -impl From for LiteralExpression { - fn from(value: bool) -> Self { - LiteralExpression::Primitive(PrimitiveValueExpression::Boolean(value)) - } -} - -impl From for LiteralExpression { - fn from(value: char) -> Self { - LiteralExpression::Primitive(PrimitiveValueExpression::Character(value)) - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum LiteralExpression { - BuiltInFunction(BuiltInFunction), - Primitive(PrimitiveValueExpression), - String(String), -} - -impl LiteralExpression { - pub fn as_integer(&self) -> Option { - match self { - LiteralExpression::Primitive(PrimitiveValueExpression::Integer(value)) => Some(*value), - _ => None, - } - } -} - -impl Display for LiteralExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - LiteralExpression::BuiltInFunction(built_in_function) => { - write!(f, "{built_in_function}") - } - LiteralExpression::Primitive(primitive) => { - write!(f, "{primitive}") - } - LiteralExpression::String(string) => write!(f, "\"{string}\""), - } - } -} - -impl Eq for LiteralExpression {} - -impl PartialOrd for LiteralExpression { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for LiteralExpression { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - ( - LiteralExpression::BuiltInFunction(left), - LiteralExpression::BuiltInFunction(right), - ) => left.cmp(right), - (LiteralExpression::BuiltInFunction(_), _) => Ordering::Greater, - (LiteralExpression::Primitive(left), LiteralExpression::Primitive(right)) => { - left.cmp(right) - } - (LiteralExpression::Primitive(_), _) => Ordering::Greater, - (LiteralExpression::String(left), LiteralExpression::String(right)) => left.cmp(right), - (LiteralExpression::String(_), _) => Ordering::Greater, - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum OperatorExpression { - Assignment { - assignee: Expression, - value: Expression, - }, - Comparison { - left: Expression, - operator: Node, - right: Expression, - }, - CompoundAssignment { - assignee: Expression, - operator: Node, - modifier: Expression, - }, - ErrorPropagation(Expression), - Negation(Expression), - Not(Expression), - Math { - left: Expression, - operator: Node, - right: Expression, - }, - Logic { - left: Expression, - operator: Node, - right: Expression, - }, -} - -impl Display for OperatorExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - OperatorExpression::Assignment { assignee, value } => { - write!(f, "{} = {}", assignee, value) - } - OperatorExpression::Comparison { - left, - operator, - right, - } => { - write!(f, "{} {} {}", left, operator, right) - } - OperatorExpression::CompoundAssignment { - assignee, - operator, - modifier: value, - } => write!(f, "{} {}= {}", assignee, operator, value), - OperatorExpression::ErrorPropagation(expression) => write!(f, "{}?", expression), - OperatorExpression::Negation(expression) => write!(f, "-{}", expression), - OperatorExpression::Not(expression) => write!(f, "!{}", expression), - OperatorExpression::Math { - left, - operator, - right, - } => { - write!(f, "{} {} {}", left, operator, right) - } - OperatorExpression::Logic { - left, - operator, - right, - } => { - write!(f, "{} {} {}", left, operator, right) - } - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum ComparisonOperator { - Equal, - NotEqual, - GreaterThan, - GreaterThanOrEqual, - LessThan, - LessThanOrEqual, -} - -impl Display for ComparisonOperator { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let operator = match self { - ComparisonOperator::Equal => "==", - ComparisonOperator::NotEqual => "!=", - ComparisonOperator::GreaterThan => ">", - ComparisonOperator::GreaterThanOrEqual => ">=", - ComparisonOperator::LessThan => "<", - ComparisonOperator::LessThanOrEqual => "<=", - }; - - write!(f, "{}", operator) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum MathOperator { - Add, - Subtract, - Multiply, - Divide, - Modulo, -} - -impl MathOperator { - pub fn add(position: Span) -> Node { - Node::new(MathOperator::Add, position) - } - - pub fn subtract(position: Span) -> Node { - Node::new(MathOperator::Subtract, position) - } - - pub fn multiply(position: Span) -> Node { - Node::new(MathOperator::Multiply, position) - } - - pub fn divide(position: Span) -> Node { - Node::new(MathOperator::Divide, position) - } - - pub fn modulo(position: Span) -> Node { - Node::new(MathOperator::Modulo, position) - } -} - -impl Display for MathOperator { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let operator = match self { - MathOperator::Add => "+", - MathOperator::Subtract => "-", - MathOperator::Multiply => "*", - MathOperator::Divide => "/", - MathOperator::Modulo => "%", - }; - - write!(f, "{}", operator) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum LogicOperator { - And, - Or, -} - -impl Display for LogicOperator { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let operator = match self { - LogicOperator::And => "&&", - LogicOperator::Or => "||", - }; - - write!(f, "{}", operator) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum IfExpression { - If { - condition: Expression, - if_block: Node, - }, - IfElse { - condition: Expression, - if_block: Node, - r#else: ElseExpression, - }, -} - -impl IfExpression { - pub fn r#if(condition: Expression, if_block: Node) -> Self { - IfExpression::If { - condition, - if_block, - } - } - - pub fn if_else( - condition: Expression, - if_block: Node, - else_block: Node, - ) -> Self { - IfExpression::IfElse { - condition, - if_block, - r#else: ElseExpression::Block(else_block), - } - } - - pub fn if_else_if( - condition: Expression, - if_block: Node, - else_if: Node>, - ) -> Self { - IfExpression::IfElse { - condition, - if_block, - r#else: ElseExpression::If(else_if), - } - } -} - -impl Display for IfExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - IfExpression::If { - condition, - if_block, - } => { - write!(f, "if {} {}", condition, if_block) - } - IfExpression::IfElse { - condition, - if_block, - r#else, - } => { - write!(f, "if {} {} else {}", condition, if_block, r#else) - } - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum ElseExpression { - Block(Node), - If(Node>), -} - -impl Display for ElseExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - ElseExpression::Block(block) => write!(f, "{}", block), - ElseExpression::If(r#if) => write!(f, "{}", r#if), - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum BlockExpression { - Async(AbstractSyntaxTree), - Sync(AbstractSyntaxTree), -} - -impl BlockExpression { - fn type_evaluation(&self, _: &Context) -> Result { - match self { - BlockExpression::Async(ast) | BlockExpression::Sync(ast) => { - if let Some(statement) = ast.statements.back() { - statement.type_evaluation(&ast.context) - } else { - Ok(TypeEvaluation::Return(None)) - } - } - } - } -} - -impl Display for BlockExpression { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - BlockExpression::Async(ast) => { - write!(f, "async {{ ")?; - - for (i, statement) in ast.statements.iter().enumerate() { - if i > 0 { - write!(f, " ")?; - } - - write!(f, "{}", statement)?; - } - - write!(f, " }}") - } - BlockExpression::Sync(ast) => { - write!(f, "{{ ")?; - - for (i, statement) in ast.statements.iter().enumerate() { - if i > 0 { - write!(f, " ")?; - } - - write!(f, "{}", statement)?; - } - - write!(f, " }}") - } - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum LoopExpression { - Infinite { - block: Node, - }, - While { - condition: Expression, - block: Node, - }, - For { - identifier: Node, - iterator: Expression, - block: Node, - }, -} - -impl Display for LoopExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - LoopExpression::Infinite { block } => write!(f, "loop {}", block), - LoopExpression::While { condition, block } => { - write!(f, "while {} {}", condition, block) - } - LoopExpression::For { - identifier, - iterator, - block, - } => write!(f, "for {} in {} {}", identifier, iterator, block), - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum StructExpression { - // The unit struct expression is omitted because it is redundant with identifier expressions - // The tuple struct expression is omitted because it is redundant with call expression - Fields { - name: Node, - fields: Vec<(Node, Expression)>, - }, -} - -impl Display for StructExpression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - StructExpression::Fields { name, fields } => { - write!(f, "{} {{", name)?; - - for (index, (field, value)) in fields.iter().enumerate() { - write!(f, "{}: {}", field, value)?; - - if index < fields.len() - 1 { - write!(f, ", ")?; - } - } - - write!(f, "}}") - } - } - } -} diff --git a/dust-lang/src/ast/mod.rs b/dust-lang/src/ast/mod.rs deleted file mode 100644 index 6afaafc..0000000 --- a/dust-lang/src/ast/mod.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! In-memory representation of a Dust program. -mod expression; -mod statement; - -pub use expression::*; -pub use statement::*; - -use std::{ - collections::VecDeque, - fmt::{self, Debug, Display, Formatter}, - num::TryFromIntError, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{core_library, Context, ContextError}; - -pub type Span = (usize, usize); - -/// In-memory representation of a Dust program. -#[derive(Clone, Serialize, Deserialize)] -pub struct AbstractSyntaxTree { - pub statements: VecDeque, - - #[serde(skip)] - pub context: Context, -} - -impl Debug for AbstractSyntaxTree { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct("AbstractSyntaxTree") - .field("statements", &self.statements) - .finish() - } -} - -impl Eq for AbstractSyntaxTree {} - -impl PartialEq for AbstractSyntaxTree { - fn eq(&self, other: &Self) -> bool { - self.statements == other.statements - } -} - -impl PartialOrd for AbstractSyntaxTree { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for AbstractSyntaxTree { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.statements.cmp(&other.statements) - } -} - -impl AbstractSyntaxTree { - pub fn new() -> Self { - Self { - statements: VecDeque::new(), - context: Context::new(), - } - } - - pub fn with_statements>>(statements: T) -> Self { - Self { - statements: statements.into(), - context: Context::new(), - } - } - - pub fn with_core_library() -> Self { - Self { - statements: VecDeque::new(), - context: core_library().create_child(), - } - } -} - -impl Default for AbstractSyntaxTree { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Node { - pub inner: T, - pub position: Span, -} - -impl Node { - pub fn new(inner: T, position: Span) -> Self { - Self { inner, position } - } -} - -impl Display for Node { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.inner) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum AstError { - ContextError { - error: ContextError, - position: Span, - }, - ExpectedFunctionOrConstructor { - position: Span, - }, - ExpectedInteger { - position: Span, - }, - ExpectedListType { - position: Span, - }, - ExpectedNonEmptyEvaluation { - position: Span, - }, - ExpectedNonEmptyList { - position: Span, - }, - ExpectedRangeableType { - position: Span, - }, - ExpectedStructFieldsType { - position: Span, - }, - ExpectedTupleType { - position: Span, - }, - FromIntError { - error: TryFromIntError, - position: Span, - }, -} - -impl AstError { - pub fn position(&self) -> Span { - match self { - AstError::ContextError { position, .. } => *position, - AstError::ExpectedFunctionOrConstructor { position } => *position, - AstError::ExpectedInteger { position } => *position, - AstError::ExpectedListType { position } => *position, - AstError::ExpectedNonEmptyEvaluation { position } => *position, - AstError::ExpectedNonEmptyList { position } => *position, - AstError::ExpectedRangeableType { position } => *position, - AstError::ExpectedStructFieldsType { position } => *position, - AstError::ExpectedTupleType { position } => *position, - AstError::FromIntError { position, .. } => *position, - } - } -} - -impl Display for AstError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - AstError::ContextError { error, position } => { - write!(f, "Context error at {:?}: {}", position, error) - } - AstError::ExpectedFunctionOrConstructor { position } => { - write!(f, "Expected a function or constructor at {:?}", position) - } - AstError::ExpectedInteger { position } => { - write!(f, "Expected an integer at {:?}", position) - } - AstError::ExpectedListType { position } => { - write!(f, "Expected a type at {:?}", position) - } - AstError::ExpectedTupleType { position } => { - write!(f, "Expected a tuple type at {:?}", position) - } - AstError::ExpectedNonEmptyEvaluation { position } => { - write!(f, "Expected a type at {:?}", position) - } - AstError::ExpectedNonEmptyList { position } => { - write!(f, "Expected a non-empty list at {:?}", position) - } - AstError::ExpectedRangeableType { position } => { - write!(f, "Expected a rangeable type at {:?}", position) - } - AstError::ExpectedStructFieldsType { position } => { - write!(f, "Expected a struct type with fields at {:?}", position) - } - AstError::FromIntError { error, position } => { - write!(f, "Integer conversion error at {:?}: {}", position, error) - } - } - } -} diff --git a/dust-lang/src/ast/statement.rs b/dust-lang/src/ast/statement.rs deleted file mode 100644 index d4d35e9..0000000 --- a/dust-lang/src/ast/statement.rs +++ /dev/null @@ -1,187 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{Context, Identifier, Type, TypeEvaluation}; - -use super::{AstError, Expression, Node, Span}; - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum Statement { - Expression(Expression), - ExpressionNullified(Node), - Let(Node), - StructDefinition(Node), -} - -impl Statement { - pub fn struct_definition(struct_definition: StructDefinition, position: Span) -> Self { - Statement::StructDefinition(Node::new(struct_definition, position)) - } - - pub fn position(&self) -> Span { - match self { - Statement::Expression(expression) => expression.position(), - Statement::ExpressionNullified(expression_node) => expression_node.position, - Statement::Let(r#let) => r#let.position, - Statement::StructDefinition(definition) => definition.position, - } - } - - pub fn type_evaluation(&self, context: &Context) -> Result { - match self { - Statement::Expression(expression) => expression.type_evaluation(context), - Statement::ExpressionNullified(expression_node) => { - let type_evaluation = expression_node.inner.type_evaluation(context)?; - - if let TypeEvaluation::Break(_) = type_evaluation { - Ok(type_evaluation) - } else { - Ok(TypeEvaluation::Return(None)) - } - } - Statement::Let(_) => Ok(TypeEvaluation::Return(None)), - Statement::StructDefinition(_) => Ok(TypeEvaluation::Return(None)), - } - } -} - -impl Display for Statement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Statement::Expression(expression) => write!(f, "{}", expression), - Statement::ExpressionNullified(expression) => write!(f, "{};", expression), - Statement::Let(r#let) => write!(f, "{};", r#let), - Statement::StructDefinition(struct_definition) => match &struct_definition.inner { - StructDefinition::Unit { name } => write!(f, "struct {};", name), - StructDefinition::Tuple { name, items } => { - write!(f, "struct {name} {{ ")?; - - for (index, item) in items.iter().enumerate() { - write!(f, "{}: {}", item, index)?; - - if index < items.len() - 1 { - write!(f, ", ")?; - } - } - - write!(f, " }}") - } - StructDefinition::Fields { name, fields } => { - write!(f, "struct {name} {{ ")?; - - for (index, (field, r#type)) in fields.iter().enumerate() { - write!(f, "{}: {}", field, r#type)?; - - if index < fields.len() - 1 { - write!(f, ", ")?; - } - } - - write!(f, " }}") - } - }, - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum LetStatement { - Let { - identifier: Node, - value: Expression, - }, - LetMut { - identifier: Node, - value: Expression, - }, - LetType { - identifier: Node, - r#type: Node, - value: Expression, - }, - LetMutType { - identifier: Node, - r#type: Node, - value: Expression, - }, -} - -impl Display for LetStatement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - LetStatement::Let { identifier, value } => { - write!(f, "let {identifier} = {value}") - } - LetStatement::LetMut { identifier, value } => { - write!(f, "let mut {identifier} = {value}") - } - LetStatement::LetType { - identifier, - r#type, - value, - } => { - write!(f, "let {identifier}: {type} = {value}") - } - LetStatement::LetMutType { - identifier, - r#type, - value, - } => { - write!(f, "let mut {identifier}: {type} = {value}") - } - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum StructDefinition { - Unit { - name: Node, - }, - Tuple { - name: Node, - items: Vec>, - }, - Fields { - name: Node, - fields: Vec<(Node, Node)>, - }, -} - -impl Display for StructDefinition { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - StructDefinition::Unit { name } => write!(f, "struct {name}"), - StructDefinition::Tuple { - name, - items: fields, - } => { - write!(f, "struct {name} {{")?; - - for (i, field) in fields.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - - write!(f, "{field}")?; - } - - write!(f, "}}") - } - StructDefinition::Fields { name, fields } => { - write!(f, "struct {name} {{")?; - - for (i, (field_name, field_type)) in fields.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - - write!(f, "{field_name}: {field_type}")?; - } - - write!(f, "}}") - } - } - } -} diff --git a/dust-lang/src/built_in_function.rs b/dust-lang/src/built_in_function.rs deleted file mode 100644 index da7bea4..0000000 --- a/dust-lang/src/built_in_function.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! Integrated functions that can be called from Dust code. -use std::{ - error::Error, - fmt::{self, Display, Formatter}, - io::{self, stdin, stdout, Write}, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{FunctionType, Identifier, Type, Value, ValueData, ValueError}; - -/// Integrated function that can be called from Dust code. -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum BuiltInFunction { - // String tools - ToString, - - // Integer and float tools - IsEven, - IsOdd, - - // I/O - ReadLine, - WriteLine, -} - -impl BuiltInFunction { - pub fn name(&self) -> &'static str { - match self { - BuiltInFunction::IsEven => "is_even", - BuiltInFunction::IsOdd => "is_odd", - BuiltInFunction::ReadLine => "read_line", - BuiltInFunction::ToString { .. } => "to_string", - BuiltInFunction::WriteLine => "write_line", - } - } - - pub fn type_parameters(&self) -> Option> { - match self { - BuiltInFunction::ToString { .. } => None, - BuiltInFunction::IsEven => None, - BuiltInFunction::IsOdd => None, - BuiltInFunction::ReadLine => None, - BuiltInFunction::WriteLine => None, - } - } - - pub fn value_parameters(&self) -> Option> { - match self { - BuiltInFunction::ToString { .. } => Some(vec![("value".into(), Type::Any)]), - BuiltInFunction::IsEven => Some(vec![("value".into(), Type::Number)]), - BuiltInFunction::IsOdd => Some(vec![("value".into(), Type::Number)]), - BuiltInFunction::ReadLine => None, - BuiltInFunction::WriteLine => Some(vec![("value".into(), Type::Any)]), - } - } - - pub fn return_type(&self) -> Option { - match self { - BuiltInFunction::ToString { .. } => Some(Type::String { length: None }), - BuiltInFunction::IsEven => Some(Type::Boolean), - BuiltInFunction::IsOdd => Some(Type::Boolean), - BuiltInFunction::ReadLine => Some(Type::String { length: None }), - BuiltInFunction::WriteLine => None, - } - } - - pub fn r#type(&self) -> Type { - Type::Function(FunctionType { - name: Identifier::new(self.name()), - type_parameters: self.type_parameters(), - value_parameters: self.value_parameters(), - return_type: self.return_type().map(Box::new), - }) - } - - pub fn call( - &self, - _type_arguments: Option>, - value_arguments: Option>, - ) -> Result, BuiltInFunctionError> { - match (self.value_parameters(), &value_arguments) { - (Some(value_parameters), Some(value_arguments)) => { - if value_parameters.len() != value_arguments.len() { - return Err(BuiltInFunctionError::WrongNumberOfValueArguments); - } - } - (Some(_), None) | (None, Some(_)) => { - return Err(BuiltInFunctionError::WrongNumberOfValueArguments); - } - (None, None) => {} - } - - match self { - BuiltInFunction::ToString => { - Ok(Some(Value::string(value_arguments.unwrap()[0].to_string()))) - } - BuiltInFunction::IsEven => { - let is_even = value_arguments.unwrap()[0].is_even()?; - - Ok(Some(is_even)) - } - BuiltInFunction::IsOdd => { - let is_odd = value_arguments.unwrap()[0].is_odd()?; - - Ok(Some(is_odd)) - } - BuiltInFunction::ReadLine => { - let mut input = String::new(); - - stdin().read_line(&mut input)?; - - Ok(Some(Value::string(input.trim_end_matches('\n')))) - } - BuiltInFunction::WriteLine => { - let first_argument = &value_arguments.unwrap()[0]; - - match first_argument { - Value::Raw(ValueData::String(string)) => { - let mut stdout = stdout(); - - stdout.write_all(string.as_bytes())?; - stdout.write_all(b"\n")?; - - Ok(None) - } - - Value::Reference(reference) => match reference.as_ref() { - ValueData::String(string) => { - let mut stdout = stdout(); - - stdout.write_all(string.as_bytes())?; - stdout.write_all(b"\n")?; - - Ok(None) - } - _ => Err(BuiltInFunctionError::ExpectedString), - }, - Value::Mutable(locked) => { - let value_data = &*locked.read().unwrap(); - let string = match value_data { - ValueData::String(string) => string, - _ => return Err(BuiltInFunctionError::ExpectedString), - }; - - let mut stdout = stdout(); - - stdout.write_all(string.as_bytes())?; - stdout.write_all(b"\n")?; - - Ok(None) - } - - _ => Err(BuiltInFunctionError::ExpectedString), - } - } - } - } -} - -impl Display for BuiltInFunction { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.name()) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum BuiltInFunctionError { - Io(io::ErrorKind), - ValueError(ValueError), - - ExpectedString, - ExpectedList, - ExpectedInteger, - - WrongNumberOfValueArguments, -} - -impl From for BuiltInFunctionError { - fn from(v: ValueError) -> Self { - Self::ValueError(v) - } -} - -impl From for BuiltInFunctionError { - fn from(error: io::Error) -> Self { - Self::Io(error.kind()) - } -} - -impl Error for BuiltInFunctionError {} - -impl Display for BuiltInFunctionError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - BuiltInFunctionError::Io(error_kind) => write!(f, "I/O error: {}", error_kind), - BuiltInFunctionError::ValueError(value_error) => { - write!(f, "Value error: {}", value_error) - } - BuiltInFunctionError::ExpectedInteger => write!(f, "Expected an integer"), - BuiltInFunctionError::ExpectedString => write!(f, "Expected a string"), - BuiltInFunctionError::ExpectedList => write!(f, "Expected a list"), - BuiltInFunctionError::WrongNumberOfValueArguments => { - write!(f, "Wrong number of value arguments") - } - } - } -} diff --git a/dust-lang/src/bytecode.rs b/dust-lang/src/bytecode.rs new file mode 100644 index 0000000..d1a0f7a --- /dev/null +++ b/dust-lang/src/bytecode.rs @@ -0,0 +1,186 @@ +use serde::{Deserialize, Serialize}; + +use crate::{Span, Value, ValueError}; + +const STACK_SIZE: usize = 256; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Vm { + chunk: Chunk, + ip: usize, + stack: Vec, +} + +impl Vm { + pub fn new(chunk: Chunk) -> Self { + Self { + chunk, + ip: 0, + stack: Vec::with_capacity(STACK_SIZE), + } + } + + pub fn interpret(&mut self) -> Result, VmError> { + loop { + let instruction = self.read_instruction(); + + match instruction { + Instruction::Constant(index) => { + let value = self.read_constant(*index); + + self.stack.push(value.clone()); + } + Instruction::Negate => { + let negated = self.pop()?.negate()?; + + self.stack.push(negated); + } + Instruction::Return => { + let value = self.pop()?; + + return Ok(Some(value)); + } + } + + self.ip += 1; + } + } + + pub fn push(&mut self, value: Value) -> Result<(), VmError> { + if self.stack.len() == STACK_SIZE { + Err(VmError::StackOverflow) + } else { + self.stack.push(value); + + Ok(()) + } + } + + pub fn pop(&mut self) -> Result { + if let Some(value) = self.stack.pop() { + Ok(value) + } else { + Err(VmError::StackUnderflow) + } + } + + pub fn read_instruction(&self) -> &Instruction { + let (instruction, _) = &self.chunk.code[self.ip]; + + instruction + } + + pub fn read_constant(&self, index: usize) -> Value { + self.chunk.constants[index].clone() + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum VmError { + StackUnderflow, + StackOverflow, + Value(ValueError), +} + +impl From for VmError { + fn from(error: ValueError) -> Self { + Self::Value(error) + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] +pub enum Instruction { + Constant(usize), + Negate, + Return, +} + +impl Instruction { + pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String { + match self { + Instruction::Constant(index) => { + let value = &chunk.constants[*index]; + + format!("{:04} CONSTANT {} {}", offset, index, value) + } + Instruction::Negate => format!("{:04} NEGATE", offset), + Instruction::Return => format!("{:04} RETURN", offset), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct Chunk { + code: Vec<(Instruction, Span)>, + constants: Vec, +} + +impl Chunk { + pub fn new() -> Self { + Self { + code: Vec::new(), + constants: Vec::new(), + } + } + + pub fn len(&self) -> usize { + self.code.len() + } + + pub fn is_empty(&self) -> bool { + self.code.is_empty() + } + + pub fn capacity(&self) -> usize { + self.code.capacity() + } + + pub fn write(&mut self, instruction: Instruction, position: Span) { + self.code.push((instruction, position)); + } + + pub fn push_constant(&mut self, value: Value) -> usize { + self.constants.push(value); + + self.constants.len() - 1 + } + + pub fn clear(&mut self) { + self.code.clear(); + self.constants.clear(); + } + + pub fn disassemble(&self, name: &str) { + println!("== {} ==", name); + + for (offset, (instruction, position)) in self.code.iter().enumerate() { + println!("{} {}", position, instruction.disassemble(self, offset)); + } + } +} + +impl Default for Chunk { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + + #[test] + fn negation() { + let mut chunk = Chunk::new(); + let constant = chunk.push_constant(Value::integer(42)); + + chunk.write(Instruction::Constant(constant), Span(0, 1)); + chunk.write(Instruction::Negate, Span(4, 5)); + chunk.write(Instruction::Return, Span(2, 3)); + + let mut vm = Vm::new(chunk); + let result = vm.interpret(); + + assert_eq!(result, Ok(Some(Value::integer(-42)))); + } +} diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs deleted file mode 100644 index 51bdb84..0000000 --- a/dust-lang/src/context.rs +++ /dev/null @@ -1,651 +0,0 @@ -//! Garbage-collecting context for variables. -use std::{ - collections::HashMap, - fmt::{self, Display, Formatter}, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak, - }, -}; - -use crate::{Constructor, Identifier, StructType, Type, Value}; - -pub type Associations = HashMap; - -static ID_COUNTER: AtomicUsize = AtomicUsize::new(0); - -fn next_id() -> usize { - ID_COUNTER.fetch_add(1, Ordering::SeqCst) -} - -/// Garbage-collecting context for variables. -#[derive(Debug, Clone)] -pub struct Context { - inner: Arc, -} - -impl Context { - pub fn new() -> Self { - Self::with_data(HashMap::new()) - } - - pub fn with_data(data: Associations) -> Self { - Self { - inner: Arc::new(ContextInner { - associations: RwLock::new(data), - parent: None, - is_immutable: false, - id: next_id(), - }), - } - } - - pub fn with_data_immutable(data: Associations) -> Self { - Self { - inner: Arc::new(ContextInner { - associations: RwLock::new(data), - parent: None, - is_immutable: true, - id: next_id(), - }), - } - } - - /// Creates a deep copy of another context. - pub fn with_data_from(other: &Self) -> Result { - let mut associations = HashMap::new(); - - for (identifier, (context_data, position)) in other.inner.associations.read()?.iter() { - associations.insert(identifier.clone(), (context_data.clone(), *position)); - } - - Ok(Self::with_data(associations)) - } - - pub fn create_child(&self) -> Self { - Self { - inner: Arc::new(ContextInner { - associations: RwLock::new(HashMap::new()), - parent: Some(Arc::downgrade(&self.inner)), - is_immutable: false, - id: next_id(), - }), - } - } - - pub fn id(&self) -> usize { - self.inner.id - } - - /// Returns the number of associated identifiers in the context. - pub fn association_count(&self) -> Result { - self.inner.association_count() - } - - /// Returns a boolean indicating whether the identifier is in the context. - pub fn contains(&self, identifier: &Identifier) -> Result { - self.inner.contains(identifier) - } - - /// Returns the full ContextData and Span if the context contains the given identifier. - pub fn get( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - self.inner.get(identifier) - } - - /// Returns the type associated with the given identifier. - pub fn get_type(&self, identifier: &Identifier) -> Result, ContextError> { - self.inner.get_type(identifier) - } - - /// Returns the ContextData associated with the identifier. - pub fn get_data(&self, identifier: &Identifier) -> Result, ContextError> { - self.inner.get_data(identifier) - } - - /// Returns the value associated with the identifier. - pub fn get_variable_value( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - self.inner.get_variable_value(identifier) - } - - /// Returns the constructor associated with the identifier. - pub fn get_constructor( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - self.inner.get_constructor(identifier) - } - - /// Returns the constructor type associated with the identifier. - pub fn get_constructor_type( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - self.inner.get_constructor_type(identifier) - } - - /// Associates an identifier with a variable type, with a position given for garbage collection. - pub fn set_variable_type( - &self, - identifier: Identifier, - r#type: Type, - ) -> Result<(), ContextError> { - self.inner.set_variable_type(identifier, r#type) - } - - /// Associates an identifier with a variable value. - pub fn set_variable_value( - &self, - identifier: Identifier, - value: Value, - ) -> Result<(), ContextError> { - self.inner.set_variable_value(identifier, value) - } - - /// Associates an identifier with a constructor. - pub fn set_constructor( - &self, - identifier: Identifier, - constructor: Constructor, - ) -> Result<(), ContextError> { - self.inner.set_constructor(identifier, constructor) - } - - /// Associates an identifier with a constructor type, with a position given for garbage - /// collection. - pub fn set_constructor_type( - &self, - identifier: Identifier, - struct_type: StructType, - ) -> Result<(), ContextError> { - self.inner.set_constructor_type(identifier, struct_type) - } - - /// Collects garbage up to the given position, removing all variables with lesser positions. - pub fn collect_garbage(&self, position: usize) -> Result<(), ContextError> { - self.inner.collect_garbage(position) - } - - /// Updates an associated identifier's last known position, allowing it to live longer in the - /// program. Returns a boolean indicating whether the identifier was found. If the identifier is - /// not found in the current context, the parent context is searched but parent context's - /// position is not updated. - pub fn set_position( - &self, - identifier: &Identifier, - position: usize, - ) -> Result { - self.inner.set_position(identifier, position) - } - - /// Recovers the context from a poisoned state by recovering data from an error. - /// - /// This method is not used. - pub fn _recover_from_poison(&mut self, recovered: &RwLockReadGuard) { - log::debug!("Context is recovering from poison error"); - - let mut new_associations = HashMap::new(); - - for (identifier, (context_data, position)) in recovered.iter() { - new_associations.insert(identifier.clone(), (context_data.clone(), *position)); - } - - self.inner = Arc::new(ContextInner { - associations: RwLock::new(new_associations), - parent: None, - is_immutable: false, - id: next_id(), - }); - } -} - -impl Default for Context { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug)] -pub struct ContextInner { - id: usize, - associations: RwLock, - parent: Option>, - is_immutable: bool, -} - -impl ContextInner { - fn parent(&self) -> Option> { - self.parent.as_ref().and_then(|parent| parent.upgrade()) - } - - /// Returns the number of associated identifiers in the context. - pub fn association_count(&self) -> Result { - Ok(self.associations.read()?.len()) - } - - /// Returns a boolean indicating whether the identifier is in the context. - pub fn contains(&self, identifier: &Identifier) -> Result { - if self.associations.read()?.contains_key(identifier) { - Ok(true) - } else if let Some(parent) = &self.parent { - if let Some(parent) = parent.upgrade() { - parent.contains(identifier) - } else { - Ok(false) - } - } else { - Ok(false) - } - } - - /// Returns the full ContextData and Span if the context contains the given identifier. - pub fn get( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - if let Some((variable_data, position)) = self.associations.read()?.get(identifier) { - return Ok(Some((variable_data.clone(), *position))); - } else if let Some(parent) = &self.parent { - if let Some(parent) = parent.upgrade() { - return parent.get(identifier); - } - } - - Ok(None) - } - - /// Returns the type associated with the given identifier. - pub fn get_type(&self, identifier: &Identifier) -> Result, ContextError> { - match self.associations.read()?.get(identifier) { - Some((ContextData::VariableType(r#type), _)) => return Ok(Some(r#type.clone())), - Some((ContextData::VariableValue(value), _)) => return Ok(Some(value.r#type())), - Some((ContextData::ConstructorType(struct_type), _)) => { - return Ok(Some(Type::Struct(struct_type.clone()))) - } - _ => {} - } - - if let Some(parent) = &self.parent { - if let Some(parent) = parent.upgrade() { - return parent.get_type(identifier); - } - } - - Ok(None) - } - - /// Returns the ContextData associated with the identifier. - pub fn get_data(&self, identifier: &Identifier) -> Result, ContextError> { - if let Some((variable_data, _)) = self.associations.read()?.get(identifier) { - return Ok(Some(variable_data.clone())); - } else if let Some(parent) = &self.parent { - if let Some(parent) = parent.upgrade() { - return parent.get_data(identifier); - } - } - - Ok(None) - } - - /// Returns the value associated with the identifier. - pub fn get_variable_value( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - if let Some((ContextData::VariableValue(value), _)) = - self.associations.read()?.get(identifier) - { - return Ok(Some(value.clone())); - } else if let Some(parent) = &self.parent { - if let Some(parent) = parent.upgrade() { - return parent.get_variable_value(identifier); - } - } - - Ok(None) - } - - /// Returns the constructor associated with the identifier. - pub fn get_constructor( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - if let Some((ContextData::Constructor(constructor), _)) = - self.associations.read()?.get(identifier) - { - return Ok(Some(constructor.clone())); - } else if let Some(parent) = &self.parent { - if let Some(parent) = parent.upgrade() { - return parent.get_constructor(identifier); - } - } - - Ok(None) - } - - /// Returns the constructor type associated with the identifier. - pub fn get_constructor_type( - &self, - identifier: &Identifier, - ) -> Result, ContextError> { - let read_associations = self.associations.read()?; - - if let Some((context_data, _)) = read_associations.get(identifier) { - return match context_data { - ContextData::Constructor(constructor) => Ok(Some(constructor.struct_type.clone())), - ContextData::ConstructorType(struct_type) => Ok(Some(struct_type.clone())), - _ => Ok(None), - }; - } else if let Some(parent) = &self.parent { - if let Some(parent) = parent.upgrade() { - return parent.get_constructor_type(identifier); - } - } - - Ok(None) - } - - /// Associates an identifier with a variable type. - pub fn set_variable_type( - &self, - identifier: Identifier, - r#type: Type, - ) -> Result<(), ContextError> { - if self.is_immutable { - return Err(ContextError::CannotMutateImmutableContext); - } - - log::trace!("Setting {identifier} to type {type} in context {}", self.id); - - let mut associations = self.associations.write()?; - let last_position = associations - .get(&identifier) - .map(|(_, last_position)| *last_position) - .unwrap_or_default(); - - associations.insert( - identifier, - (ContextData::VariableType(r#type), last_position), - ); - - Ok(()) - } - - /// Associates an identifier with a variable value. - pub fn set_variable_value( - &self, - identifier: Identifier, - value: Value, - ) -> Result<(), ContextError> { - if self.is_immutable { - return Err(ContextError::CannotMutateImmutableContext); - } - - log::trace!( - "Setting {identifier} to value {value} in context {}", - self.id - ); - - let mut associations = self.associations.write()?; - let last_position = associations - .get(&identifier) - .map(|(_, last_position)| *last_position) - .unwrap_or_default(); - - associations.insert( - identifier, - (ContextData::VariableValue(value), last_position), - ); - - Ok(()) - } - - /// Associates an identifier with a constructor. - pub fn set_constructor( - &self, - identifier: Identifier, - constructor: Constructor, - ) -> Result<(), ContextError> { - if self.is_immutable { - return Err(ContextError::CannotMutateImmutableContext); - } - - log::trace!( - "Setting {identifier} to constructor {constructor:?} in context {}", - self.id - ); - - let mut associations = self.associations.write()?; - let last_position = associations - .get(&identifier) - .map(|(_, last_position)| *last_position) - .unwrap_or_default(); - - associations.insert( - identifier, - (ContextData::Constructor(constructor), last_position), - ); - - Ok(()) - } - - /// Associates an identifier with a constructor type, with a position given for garbage - /// collection. - pub fn set_constructor_type( - &self, - identifier: Identifier, - struct_type: StructType, - ) -> Result<(), ContextError> { - if self.is_immutable { - return Err(ContextError::CannotMutateImmutableContext); - } - - log::trace!( - "Setting {identifier} to constructor of type {struct_type} in context {}", - self.id - ); - - let mut variables = self.associations.write()?; - let last_position = variables - .get(&identifier) - .map(|(_, last_position)| *last_position) - .unwrap_or_default(); - - variables.insert( - identifier, - (ContextData::ConstructorType(struct_type), last_position), - ); - - Ok(()) - } - - /// Collects garbage up to the given position, removing all variables with lesser positions. - pub fn collect_garbage(&self, position: usize) -> Result<(), ContextError> { - if self.is_immutable { - return Err(ContextError::CannotMutateImmutableContext); - } - - log::trace!("Collecting garbage up to {position} in context {}", self.id); - - let mut variables = self.associations.write()?; - - variables.retain(|identifier, (_, last_used)| { - let should_drop = position >= *last_used; - - if should_drop { - log::trace!("Removing {identifier} from context {}", self.id); - } - - !should_drop - }); - variables.shrink_to_fit(); - - Ok(()) - } - - /// Updates an associated identifier's last known position, allowing it to live longer in the - /// program. Returns a boolean indicating whether the identifier was found. If the identifier is - /// not found in the current context, the parent context is searched but parent context's - /// position is not updated. - pub fn set_position( - &self, - identifier: &Identifier, - position: usize, - ) -> Result { - let found = self.update_position_if_found(identifier, position)?; - - if found { - return Ok(true); - } - - let found_in_ancestor = if let Some(parent) = &self.parent() { - if parent.is_immutable { - false - } else { - parent.update_position_if_found(identifier, position)? - } - } else { - false - }; - - if found_in_ancestor { - return Ok(true); - } - - let mut associations = self.associations.write()?; - - log::trace!( - "Reserving {identifier} at position {position:?} in context {}", - self.id - ); - - associations.insert(identifier.clone(), (ContextData::Reserved, position)); - - Ok(false) - } - - fn update_position_if_found( - &self, - identifier: &Identifier, - position: usize, - ) -> Result { - if self.is_immutable { - return Err(ContextError::CannotMutateImmutableContext); - } - - let mut associations = self.associations.write()?; - - if let Some((_, last_position)) = associations.get_mut(identifier) { - log::trace!( - "Updating {identifier}'s last position to {position:?} in context {}", - self.id - ); - - *last_position = position; - - Ok(true) - } else { - Ok(false) - } - } -} - -#[derive(Debug, Clone)] -pub enum ContextData { - Constructor(Constructor), - ConstructorType(StructType), - VariableValue(Value), - VariableType(Type), - Reserved, -} - -#[derive(Debug, Clone)] -pub enum ContextError { - CannotMutateImmutableContext, - PoisonErrorRecovered(Arc), -} - -impl From>> for ContextError { - fn from(error: PoisonError>) -> Self { - let associations = error.into_inner().clone(); - - Self::PoisonErrorRecovered(Arc::new(associations)) - } -} - -impl From>> for ContextError { - fn from(error: PoisonError>) -> Self { - let associations = error.into_inner().clone(); - - Self::PoisonErrorRecovered(Arc::new(associations)) - } -} - -impl PartialEq for ContextError { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::CannotMutateImmutableContext, Self::CannotMutateImmutableContext) => true, - (Self::PoisonErrorRecovered(left), Self::PoisonErrorRecovered(right)) => { - Arc::ptr_eq(left, right) - } - _ => false, - } - } -} - -impl Display for ContextError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::CannotMutateImmutableContext => write!(f, "Cannot mutate immutable context"), - Self::PoisonErrorRecovered(associations) => { - write!( - f, - "Context poisoned with {} associations recovered", - associations.len() - ) - } - } - } -} - -#[cfg(test)] -mod tests { - use crate::{parse, Vm}; - - use super::*; - - #[test] - fn context_removes_variables() { - let source = " - let x = 5; - let y = 10; - let z = x + y; - z - "; - let ast = parse(source).unwrap(); - let context = ast.context.clone(); - - assert_eq!(Vm.run(ast), Ok(Some(Value::integer(15)))); - assert_eq!(context.association_count().unwrap(), 0); - } - - #[test] - fn garbage_collector_does_not_break_loops() { - let source = " - let mut z = 0; - while z < 10 { - z += 1; - } - "; - let ast = parse(source).unwrap(); - let context = ast.context.clone(); - - assert_eq!(Vm.run(ast), Ok(None)); - assert_eq!(context.association_count().unwrap(), 0); - } -} diff --git a/dust-lang/src/core_library.rs b/dust-lang/src/core_library.rs deleted file mode 100644 index 13fcf01..0000000 --- a/dust-lang/src/core_library.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::{collections::HashMap, sync::OnceLock}; - -use crate::{BuiltInFunction, Context, ContextData, Function, Identifier, Value}; - -static CORE_LIBRARY: OnceLock = OnceLock::new(); - -pub fn core_library<'a>() -> &'a Context { - CORE_LIBRARY.get_or_init(|| { - Context::with_data_immutable(HashMap::from([ - ( - Identifier::new("to_string"), - ( - ContextData::VariableValue(Value::function(Function::BuiltIn( - BuiltInFunction::ToString, - ))), - 0, - ), - ), - ( - Identifier::new("read_line"), - ( - ContextData::VariableValue(Value::function(Function::BuiltIn( - BuiltInFunction::ReadLine, - ))), - 0, - ), - ), - ( - Identifier::new("write_line"), - ( - ContextData::VariableValue(Value::function(Function::BuiltIn( - BuiltInFunction::WriteLine, - ))), - 0, - ), - ), - ])) - }) -} diff --git a/dust-lang/src/dust_error.rs b/dust-lang/src/dust_error.rs deleted file mode 100644 index 95fff49..0000000 --- a/dust-lang/src/dust_error.rs +++ /dev/null @@ -1,193 +0,0 @@ -//! Top-level error handling for the Dust language. -use annotate_snippets::{Level, Renderer, Snippet}; -use std::fmt::Display; - -use crate::{AnalysisError, ContextError, LexError, ParseError, RuntimeError}; - -/// An error that occurred during the execution of the Dust language and its -/// corresponding source code. -#[derive(Debug, Clone, PartialEq)] -pub enum DustError<'src> { - ContextError(ContextError), - Runtime { - runtime_error: RuntimeError, - source: &'src str, - }, - Analysis { - analysis_errors: Vec, - source: &'src str, - }, - Parse { - parse_error: ParseError, - source: &'src str, - }, - Lex { - lex_error: LexError, - source: &'src str, - }, -} - -impl<'src> From for DustError<'src> { - fn from(error: ContextError) -> Self { - Self::ContextError(error) - } -} - -impl<'src> DustError<'src> { - pub fn runtime(runtime_error: RuntimeError, source: &'src str) -> Self { - DustError::Runtime { - runtime_error, - source, - } - } - - pub fn analysis>>(analysis_errors: T, source: &'src str) -> Self { - DustError::Analysis { - analysis_errors: analysis_errors.into(), - source, - } - } - - pub fn parse(parse_error: ParseError, source: &'src str) -> Self { - DustError::Parse { - parse_error, - source, - } - } - - pub fn lex(lex_error: LexError, source: &'src str) -> Self { - DustError::Lex { lex_error, source } - } - - pub fn title(&self) -> &'static str { - match self { - DustError::ContextError(_) => "Context error", - DustError::Runtime { .. } => "Runtime error", - DustError::Analysis { .. } => "Analysis error", - DustError::Parse { .. } => "Parse error", - DustError::Lex { .. } => "Lex error", - } - } - - pub fn source(&self) -> &'src str { - match self { - DustError::ContextError(_) => "", - DustError::Runtime { source, .. } => source, - DustError::Analysis { source, .. } => source, - DustError::Parse { source, .. } => source, - DustError::Lex { source, .. } => source, - } - } - - pub fn report(&self) -> String { - let mut report = String::new(); - let renderer = Renderer::styled(); - - match self { - DustError::ContextError(_) => { - let message = Level::Error.title("Context error"); - - report.push_str(&renderer.render(message).to_string()); - } - DustError::Runtime { - runtime_error, - source, - } => { - let error = runtime_error.root_error(); - let position = error.position(); - let label = error.to_string(); - let message = Level::Error - .title("Runtime error") - .snippet( - Snippet::source(source) - .fold(true) - .annotation(Level::Error.span(position.0..position.1).label(&label)), - ) - .footer( - Level::Error - .title("This error occured during the execution of the Dust program."), - ); - - report.push_str(&renderer.render(message).to_string()); - report.push_str("\n\n"); - } - DustError::Analysis { - analysis_errors, - source, - } => { - for error in analysis_errors { - let position = error.position(); - let label = error.to_string(); - let message = - Level::Warning - .title("Analysis error") - .snippet(Snippet::source(source).fold(true).annotation( - Level::Warning.span(position.0..position.1).label(&label), - )) - .footer( - Level::Warning - .title("This error was found without running the program."), - ); - - report.push_str(&renderer.render(message).to_string()); - report.push_str("\n\n"); - } - } - DustError::Parse { - parse_error, - source, - } => { - if let ParseError::Lex(lex_error) = parse_error { - let lex_error_report = DustError::lex(lex_error.clone(), source).report(); - - report.push_str(&lex_error_report); - - return report; - } - - let position = parse_error.position(); - let label = parse_error.to_string(); - let message = Level::Error.title("Parse error").snippet( - Snippet::source(source) - .fold(true) - .annotation(Level::Error.span(position.0..position.1).label(&label)), - ); - - report.push_str(&renderer.render(message).to_string()); - } - DustError::Lex { lex_error, source } => { - let position = lex_error.position(); - let label = lex_error.to_string(); - let message = Level::Error.title("Lex error").snippet( - Snippet::source(source) - .fold(true) - .annotation(Level::Error.span(position.0..position.1).label(&label)), - ); - - report.push_str(&renderer.render(message).to_string()); - } - } - - report - } -} - -impl Display for DustError<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DustError::ContextError(context_error) => write!(f, "{context_error}"), - DustError::Runtime { runtime_error, .. } => write!(f, "{runtime_error}"), - DustError::Analysis { - analysis_errors, .. - } => { - for error in analysis_errors { - write!(f, "{error} ")?; - } - - Ok(()) - } - DustError::Parse { parse_error, .. } => write!(f, "{parse_error}"), - DustError::Lex { lex_error, .. } => write!(f, "{lex_error}"), - } - } -} diff --git a/dust-lang/src/evaluation.rs b/dust-lang/src/evaluation.rs deleted file mode 100644 index 29649d7..0000000 --- a/dust-lang/src/evaluation.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{Constructor, RuntimeError, Span, StructType, Type, Value}; - -#[derive(Debug, Clone, PartialEq)] -pub enum Evaluation { - Break(Option), - Constructor(Constructor), - Return(Option), -} - -impl Evaluation { - pub fn value(self) -> Option { - match self { - Evaluation::Return(value_option) => value_option, - _ => None, - } - } - - pub fn expect_value(self, position: Span) -> Result { - if let Evaluation::Return(Some(value)) = self { - Ok(value) - } else { - Err(RuntimeError::ExpectedValue { position }) - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum TypeEvaluation { - Break(Option), - Constructor(StructType), - Return(Option), -} - -impl TypeEvaluation { - pub fn r#type(self) -> Option { - match self { - TypeEvaluation::Return(type_option) => type_option, - _ => None, - } - } -} diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs deleted file mode 100644 index bb9dbf7..0000000 --- a/dust-lang/src/lexer.rs +++ /dev/null @@ -1,1251 +0,0 @@ -//! Lexing tools. -//! -//! This module provides two lexing options: -//! - [`lex`], which lexes the entire input and returns a vector of tokens and their positions -//! - [`Lexer`], which lexes the input a token at a time -use std::fmt::{self, Display, Formatter}; - -use crate::{Span, Token}; - -/// Lexes the input and return a vector of tokens and their positions. -/// -/// # Examples -/// ``` -/// # use dust_lang::*; -/// let input = "x = 1 + 2"; -/// let tokens = lex(input).unwrap(); -/// -/// assert_eq!( -/// tokens, -/// [ -/// (Token::Identifier("x"), (0, 1)), -/// (Token::Equal, (2, 3)), -/// (Token::Integer("1"), (4, 5)), -/// (Token::Plus, (6, 7)), -/// (Token::Integer("2"), (8, 9)), -/// (Token::Eof, (9, 9)), -/// ] -/// ); -/// ``` -pub fn lex<'chars, 'src: 'chars>( - source: &'src str, -) -> Result, Span)>, LexError> { - let mut lexer = Lexer::new(source); - let mut tokens = Vec::new(); - - loop { - let (token, span) = lexer.next_token()?; - let is_eof = matches!(token, Token::Eof); - - tokens.push((token, span)); - - if is_eof { - break; - } - } - - Ok(tokens) -} - -/// Low-level tool for lexing a single token at a time. -/// -/// # Examples -/// ``` -/// # use dust_lang::*; -/// let input = "x = 1 + 2"; -/// let mut lexer = Lexer::new(input); -/// let mut tokens = Vec::new(); -/// -/// loop { -/// let (token, span) = lexer.next_token().unwrap(); -/// let is_eof = matches!(token, Token::Eof); -/// -/// tokens.push((token, span)); -/// -/// if is_eof { -/// break; -/// } -/// } -/// -/// assert_eq!( -/// tokens, -/// [ -/// (Token::Identifier("x"), (0, 1)), -/// (Token::Equal, (2, 3)), -/// (Token::Integer("1"), (4, 5)), -/// (Token::Plus, (6, 7)), -/// (Token::Integer("2"), (8, 9)), -/// (Token::Eof, (9, 9)), -/// ] -/// ) -/// ``` -#[derive(Debug, Clone)] -pub struct Lexer<'src> { - source: &'src str, - position: usize, -} - -impl<'src> Lexer<'src> { - /// Create a new lexer for the given input. - pub fn new(source: &'src str) -> Self { - Lexer { - source, - position: 0, - } - } - - /// Produce the next token. - pub fn next_token(&mut self) -> Result<(Token<'src>, Span), LexError> { - self.skip_whitespace(); - - let (token, span) = if let Some(c) = self.peek_char() { - match c { - '0'..='9' => self.lex_number()?, - '-' => { - let second_char = self.peek_second_char(); - - if let Some('=') = second_char { - self.position += 2; - - (Token::MinusEqual, (self.position - 2, self.position)) - } else if let Some('0'..='9') = second_char { - self.lex_number()? - } else if "-Infinity" == self.peek_chars(9) { - self.position += 9; - - ( - Token::Float("-Infinity"), - (self.position - 9, self.position), - ) - } else { - self.position += 1; - - (Token::Minus, (self.position - 1, self.position)) - } - } - 'a'..='z' | 'A'..='Z' => self.lex_alphanumeric()?, - '"' => self.lex_string()?, - '\'' => { - self.position += 1; - - if let Some(c) = self.peek_char() { - self.position += 1; - - if let Some('\'') = self.peek_char() { - self.position += 1; - - (Token::Character(c), (self.position - 3, self.position)) - } else { - return Err(LexError::ExpectedCharacter { - expected: '\'', - actual: c, - position: self.position, - }); - } - } else { - return Err(LexError::UnexpectedEndOfFile { - position: self.position, - }); - } - } - '+' => { - if let Some('=') = self.peek_second_char() { - self.position += 2; - - (Token::PlusEqual, (self.position - 2, self.position)) - } else { - self.position += 1; - - (Token::Plus, (self.position - 1, self.position)) - } - } - '*' => { - self.position += 1; - - (Token::Star, (self.position - 1, self.position)) - } - '(' => { - self.position += 1; - - (Token::LeftParenthesis, (self.position - 1, self.position)) - } - ')' => { - self.position += 1; - - (Token::RightParenthesis, (self.position - 1, self.position)) - } - '=' => { - if let Some('=') = self.peek_second_char() { - self.position += 2; - - (Token::DoubleEqual, (self.position - 2, self.position)) - } else { - self.position += 1; - - (Token::Equal, (self.position - 1, self.position)) - } - } - '[' => { - self.position += 1; - - (Token::LeftSquareBrace, (self.position - 1, self.position)) - } - ']' => { - self.position += 1; - - (Token::RightSquareBrace, (self.position - 1, self.position)) - } - ',' => { - self.position += 1; - - (Token::Comma, (self.position - 1, self.position)) - } - '.' => { - if let Some('.') = self.peek_second_char() { - self.position += 2; - - (Token::DoubleDot, (self.position - 2, self.position)) - } else { - self.position += 1; - - (Token::Dot, (self.position - 1, self.position)) - } - } - '>' => { - if let Some('=') = self.peek_second_char() { - self.position += 2; - - (Token::GreaterEqual, (self.position - 2, self.position)) - } else { - self.position += 1; - - (Token::Greater, (self.position - 1, self.position)) - } - } - '<' => { - if let Some('=') = self.peek_second_char() { - self.position += 2; - - (Token::LessEqual, (self.position - 2, self.position)) - } else { - self.position += 1; - - (Token::Less, (self.position - 1, self.position)) - } - } - '{' => { - self.position += 1; - - (Token::LeftCurlyBrace, (self.position - 1, self.position)) - } - '}' => { - self.position += 1; - - (Token::RightCurlyBrace, (self.position - 1, self.position)) - } - '/' => { - self.position += 1; - - (Token::Slash, (self.position - 1, self.position)) - } - '%' => { - self.position += 1; - - (Token::Percent, (self.position - 1, self.position)) - } - '&' => { - if let Some('&') = self.peek_second_char() { - self.position += 2; - - (Token::DoubleAmpersand, (self.position - 2, self.position)) - } else { - self.position += 1; - - return Err(LexError::UnexpectedCharacter { - actual: c, - position: self.position, - }); - } - } - ';' => { - self.position += 1; - - (Token::Semicolon, (self.position - 1, self.position)) - } - '|' => { - if let Some('|') = self.peek_second_char() { - self.position += 2; - - (Token::DoublePipe, (self.position - 2, self.position)) - } else { - self.position += 1; - - return Err(LexError::UnexpectedCharacter { - actual: c, - position: self.position, - }); - } - } - '!' => { - self.position += 1; - - (Token::Bang, (self.position - 1, self.position)) - } - ':' => { - self.position += 1; - - (Token::Colon, (self.position - 1, self.position)) - } - _ => { - return Err(LexError::UnexpectedCharacter { - actual: c, - position: self.position, - }); - } - } - } else { - (Token::Eof, (self.position, self.position)) - }; - - Ok((token, span)) - } - - /// Peek at the next token without consuming the source. - pub fn peek_token(&mut self) -> Result<(Token<'src>, Span), LexError> { - let token = self.next_token()?; - - self.position -= token.0.len(); - - Ok(token) - } - - /// Progress to the next character. - fn next_char(&mut self) -> Option { - if let Some(c) = self.source[self.position..].chars().next() { - self.position += c.len_utf8(); - - Some(c) - } else { - None - } - } - - /// Skip whitespace characters. - fn skip_whitespace(&mut self) { - while let Some(c) = self.peek_char() { - if c.is_whitespace() { - self.next_char(); - } else { - break; - } - } - } - - /// Peek at the next character without consuming it. - fn peek_char(&self) -> Option { - self.source[self.position..].chars().next() - } - - /// Peek at the second-to-next character without consuming it. - fn peek_second_char(&self) -> Option { - self.source[self.position..].chars().nth(1) - } - - /// Peek the next `n` characters without consuming them. - fn peek_chars(&self, n: usize) -> &'src str { - let remaining_source = &self.source[self.position..]; - - if remaining_source.len() < n { - remaining_source - } else { - &remaining_source[..n] - } - } - - /// Lex an integer or float token. - fn lex_number(&mut self) -> Result<(Token<'src>, Span), LexError> { - let start_pos = self.position; - let mut is_float = false; - - if let Some('-') = self.peek_char() { - self.next_char(); - } - - while let Some(c) = self.peek_char() { - if c == '.' { - if let Some('0'..='9') = self.peek_second_char() { - if !is_float { - self.next_char(); - } - - self.next_char(); - - loop { - let peek_char = self.peek_char(); - - if let Some('0'..='9') = peek_char { - self.next_char(); - } else if let Some('e') = peek_char { - if let Some('0'..='9') = self.peek_second_char() { - self.next_char(); - self.next_char(); - } else { - break; - } - } else { - break; - } - } - - is_float = true; - } else { - break; - } - } - - if c.is_ascii_digit() { - self.next_char(); - } else { - break; - } - } - - let text = &self.source[start_pos..self.position]; - - if is_float { - Ok((Token::Float(text), (start_pos, self.position))) - } else { - Ok((Token::Integer(text), (start_pos, self.position))) - } - } - - /// Lex an identifier token. - fn lex_alphanumeric(&mut self) -> Result<(Token<'src>, Span), LexError> { - let start_pos = self.position; - - while let Some(c) = self.peek_char() { - if c.is_ascii_alphanumeric() || c == '_' { - self.next_char(); - } else { - break; - } - } - - let string = &self.source[start_pos..self.position]; - let token = match string { - "Infinity" => Token::Float("Infinity"), - "NaN" => Token::Float("NaN"), - "async" => Token::Async, - "bool" => Token::Bool, - "break" => Token::Break, - "else" => Token::Else, - "false" => Token::Boolean("false"), - "float" => Token::FloatKeyword, - "if" => Token::If, - "int" => Token::Int, - "let" => Token::Let, - "loop" => Token::Loop, - "map" => Token::Map, - "mut" => Token::Mut, - "struct" => Token::Struct, - "true" => Token::Boolean("true"), - "while" => Token::While, - _ => Token::Identifier(string), - }; - - Ok((token, (start_pos, self.position))) - } - - fn lex_string(&mut self) -> Result<(Token<'src>, Span), LexError> { - let start_pos = self.position; - - self.next_char(); - - while let Some(c) = self.peek_char() { - if c == '"' { - self.next_char(); - break; - } else { - self.next_char(); - } - } - - let text = &self.source[start_pos + 1..self.position - 1]; - - Ok((Token::String(text), (start_pos, self.position))) - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum LexError { - ExpectedCharacter { - expected: char, - actual: char, - position: usize, - }, - UnexpectedCharacter { - actual: char, - position: usize, - }, - UnexpectedEndOfFile { - position: usize, - }, -} - -impl LexError { - pub fn position(&self) -> Span { - match self { - Self::ExpectedCharacter { position, .. } => (*position, *position), - Self::UnexpectedCharacter { position, .. } => (*position, *position), - Self::UnexpectedEndOfFile { position } => (*position, *position), - } - } -} - -impl Display for LexError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::ExpectedCharacter { - expected, actual, .. - } => write!(f, "Expected character '{expected}', found '{actual}'"), - Self::UnexpectedCharacter { actual, .. } => { - write!(f, "Unexpected character '{actual}'") - } - Self::UnexpectedEndOfFile { .. } => { - write!(f, "Unexpected end of file") - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn character() { - let input = "'a'"; - - assert_eq!( - lex(input), - Ok(vec![(Token::Character('a'), (0, 3)), (Token::Eof, (3, 3)),]) - ); - } - - #[test] - fn map_expression() { - let input = "map { x = \"1\", y = 2, z = 3.0 }"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Map, (0, 3)), - (Token::LeftCurlyBrace, (4, 5)), - (Token::Identifier("x"), (6, 7)), - (Token::Equal, (8, 9)), - (Token::String("1"), (10, 13)), - (Token::Comma, (13, 14)), - (Token::Identifier("y"), (15, 16)), - (Token::Equal, (17, 18)), - (Token::Integer("2"), (19, 20)), - (Token::Comma, (20, 21)), - (Token::Identifier("z"), (22, 23)), - (Token::Equal, (24, 25)), - (Token::Float("3.0"), (26, 29)), - (Token::RightCurlyBrace, (30, 31)), - (Token::Eof, (31, 31)), - ]) - ); - } - - #[test] - fn let_statement() { - let input = "let x = 42"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Let, (0, 3)), - (Token::Identifier("x"), (4, 5)), - (Token::Equal, (6, 7)), - (Token::Integer("42"), (8, 10)), - (Token::Eof, (10, 10)), - ]) - ); - } - - #[test] - fn unit_struct() { - let input = "struct Foo"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Struct, (0, 6)), - (Token::Identifier("Foo"), (7, 10)), - (Token::Eof, (10, 10)), - ]) - ); - } - - #[test] - fn tuple_struct() { - let input = "struct Foo(int, float)"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Struct, (0, 6)), - (Token::Identifier("Foo"), (7, 10)), - (Token::LeftParenthesis, (10, 11)), - (Token::Int, (11, 14)), - (Token::Comma, (14, 15)), - (Token::FloatKeyword, (16, 21)), - (Token::RightParenthesis, (21, 22)), - (Token::Eof, (22, 22)) - ]) - ); - } - - #[test] - fn fields_struct() { - let input = "struct FooBar { foo: int, bar: float }"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Struct, (0, 6)), - (Token::Identifier("FooBar"), (7, 13)), - (Token::LeftCurlyBrace, (14, 15)), - (Token::Identifier("foo"), (16, 19)), - (Token::Colon, (19, 20)), - (Token::Int, (21, 24)), - (Token::Comma, (24, 25)), - (Token::Identifier("bar"), (26, 29)), - (Token::Colon, (29, 30)), - (Token::FloatKeyword, (31, 36)), - (Token::RightCurlyBrace, (37, 38)), - (Token::Eof, (38, 38)) - ]) - ); - } - - #[test] - fn list_index() { - let input = "[1, 2, 3][1]"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::LeftSquareBrace, (0, 1)), - (Token::Integer("1"), (1, 2)), - (Token::Comma, (2, 3)), - (Token::Integer("2"), (4, 5)), - (Token::Comma, (5, 6)), - (Token::Integer("3"), (7, 8)), - (Token::RightSquareBrace, (8, 9)), - (Token::LeftSquareBrace, (9, 10)), - (Token::Integer("1"), (10, 11)), - (Token::RightSquareBrace, (11, 12)), - (Token::Eof, (12, 12)), - ]) - ) - } - - #[test] - fn list() { - let input = "[1, 2, 3]"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::LeftSquareBrace, (0, 1)), - (Token::Integer("1"), (1, 2)), - (Token::Comma, (2, 3)), - (Token::Integer("2"), (4, 5)), - (Token::Comma, (5, 6)), - (Token::Integer("3"), (7, 8)), - (Token::RightSquareBrace, (8, 9)), - (Token::Eof, (9, 9)), - ]) - ) - } - - #[test] - fn map_field_access() { - let input = "{a = 1, b = 2, c = 3}.c"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::LeftCurlyBrace, (0, 1)), - (Token::Identifier("a"), (1, 2)), - (Token::Equal, (3, 4)), - (Token::Integer("1"), (5, 6)), - (Token::Comma, (6, 7)), - (Token::Identifier("b"), (8, 9)), - (Token::Equal, (10, 11)), - (Token::Integer("2"), (12, 13)), - (Token::Comma, (13, 14)), - (Token::Identifier("c"), (15, 16)), - (Token::Equal, (17, 18)), - (Token::Integer("3"), (19, 20)), - (Token::RightCurlyBrace, (20, 21)), - (Token::Dot, (21, 22)), - (Token::Identifier("c"), (22, 23)), - (Token::Eof, (23, 23)), - ]) - ) - } - #[test] - fn range() { - let input = "0..42"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("0"), (0, 1)), - (Token::DoubleDot, (1, 3)), - (Token::Integer("42"), (3, 5)), - (Token::Eof, (5, 5)) - ]) - ); - } - - #[test] - fn negate_expression() { - let input = "x = -42; -x"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Identifier("x"), (0, 1)), - (Token::Equal, (2, 3)), - (Token::Integer("-42"), (4, 7)), - (Token::Semicolon, (7, 8)), - (Token::Minus, (9, 10)), - (Token::Identifier("x"), (10, 11)), - (Token::Eof, (11, 11)) - ]) - ); - } - - #[test] - fn not_expression() { - let input = "!true; !false"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Bang, (0, 1)), - (Token::Boolean("true"), (1, 5)), - (Token::Semicolon, (5, 6)), - (Token::Bang, (7, 8)), - (Token::Boolean("false"), (8, 13)), - (Token::Eof, (13, 13)) - ]) - ); - } - - #[test] - fn if_else() { - let input = "if x < 10 { x + 1 } else { x }"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::If, (0, 2)), - (Token::Identifier("x"), (3, 4)), - (Token::Less, (5, 6)), - (Token::Integer("10"), (7, 9)), - (Token::LeftCurlyBrace, (10, 11)), - (Token::Identifier("x"), (12, 13)), - (Token::Plus, (14, 15)), - (Token::Integer("1"), (16, 17)), - (Token::RightCurlyBrace, (18, 19)), - (Token::Else, (20, 24)), - (Token::LeftCurlyBrace, (25, 26)), - (Token::Identifier("x"), (27, 28)), - (Token::RightCurlyBrace, (29, 30)), - (Token::Eof, (30, 30)), - ]) - ) - } - - #[test] - fn while_loop() { - let input = "while x < 10 { x += 1 }"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::While, (0, 5)), - (Token::Identifier("x"), (6, 7)), - (Token::Less, (8, 9)), - (Token::Integer("10"), (10, 12)), - (Token::LeftCurlyBrace, (13, 14)), - (Token::Identifier("x"), (15, 16)), - (Token::PlusEqual, (17, 19)), - (Token::Integer("1"), (20, 21)), - (Token::RightCurlyBrace, (22, 23)), - (Token::Eof, (23, 23)), - ]) - ) - } - - #[test] - fn add_assign() { - let input = "x += 42"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Identifier("x"), (0, 1)), - (Token::PlusEqual, (2, 4)), - (Token::Integer("42"), (5, 7)), - (Token::Eof, (7, 7)), - ]) - ) - } - - #[test] - fn or() { - let input = "true || false"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Boolean("true"), (0, 4)), - (Token::DoublePipe, (5, 7)), - (Token::Boolean("false"), (8, 13)), - (Token::Eof, (13, 13)), - ]) - ) - } - - #[test] - fn block() { - let input = "{ x = 42; y = \"foobar\" }"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::LeftCurlyBrace, (0, 1)), - (Token::Identifier("x"), (2, 3)), - (Token::Equal, (4, 5)), - (Token::Integer("42"), (6, 8)), - (Token::Semicolon, (8, 9)), - (Token::Identifier("y"), (10, 11)), - (Token::Equal, (12, 13)), - (Token::String("foobar"), (14, 22)), - (Token::RightCurlyBrace, (23, 24)), - (Token::Eof, (24, 24)), - ]) - ) - } - - #[test] - fn equal() { - let input = "42 == 42"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("42"), (0, 2)), - (Token::DoubleEqual, (3, 5)), - (Token::Integer("42"), (6, 8)), - (Token::Eof, (8, 8)), - ]) - ) - } - - #[test] - fn modulo() { - let input = "42 % 2"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("42"), (0, 2)), - (Token::Percent, (3, 4)), - (Token::Integer("2"), (5, 6)), - (Token::Eof, (6, 6)), - ]) - ) - } - - #[test] - fn divide() { - let input = "42 / 2"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("42"), (0, 2)), - (Token::Slash, (3, 4)), - (Token::Integer("2"), (5, 6)), - (Token::Eof, (6, 6)), - ]) - ) - } - - #[test] - fn greater_than() { - let input = ">"; - - assert_eq!( - lex(input), - Ok(vec![(Token::Greater, (0, 1)), (Token::Eof, (1, 1))]) - ) - } - - #[test] - fn greater_than_or_equal() { - let input = ">="; - - assert_eq!( - lex(input), - Ok(vec![(Token::GreaterEqual, (0, 2)), (Token::Eof, (2, 2))]) - ) - } - - #[test] - fn less_than() { - let input = "<"; - - assert_eq!( - lex(input), - Ok(vec![(Token::Less, (0, 1)), (Token::Eof, (1, 1))]) - ) - } - - #[test] - fn less_than_or_equal() { - let input = "<="; - - assert_eq!( - lex(input), - Ok(vec![(Token::LessEqual, (0, 2)), (Token::Eof, (2, 2))]) - ) - } - - #[test] - fn infinity() { - let input = "Infinity"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Float("Infinity"), (0, 8)), - (Token::Eof, (8, 8)), - ]) - ) - } - - #[test] - fn negative_infinity() { - let input = "-Infinity"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Float("-Infinity"), (0, 9)), - (Token::Eof, (9, 9)), - ]) - ) - } - - #[test] - fn nan() { - let input = "NaN"; - - assert!(lex(input).is_ok_and(|tokens| tokens[0].0 == Token::Float("NaN"))); - } - - #[test] - fn complex_float() { - let input = "42.42e42"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Float("42.42e42"), (0, 8)), - (Token::Eof, (8, 8)), - ]) - ) - } - - #[test] - fn max_integer() { - let input = "9223372036854775807"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("9223372036854775807"), (0, 19)), - (Token::Eof, (19, 19)), - ]) - ) - } - - #[test] - fn min_integer() { - let input = "-9223372036854775808"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("-9223372036854775808"), (0, 20)), - (Token::Eof, (20, 20)), - ]) - ) - } - - #[test] - fn subtract_negative_integers() { - let input = "-42 - -42"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("-42"), (0, 3)), - (Token::Minus, (4, 5)), - (Token::Integer("-42"), (6, 9)), - (Token::Eof, (9, 9)), - ]) - ) - } - - #[test] - fn negative_integer() { - let input = "-42"; - - assert_eq!( - lex(input), - Ok(vec![(Token::Integer("-42"), (0, 3)), (Token::Eof, (3, 3))]) - ) - } - - #[test] - fn read_line() { - let input = "read_line()"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Identifier("read_line"), (0, 9)), - (Token::LeftParenthesis, (9, 10)), - (Token::RightParenthesis, (10, 11)), - (Token::Eof, (11, 11)), - ]) - ) - } - - #[test] - fn write_line() { - let input = "write_line(\"Hello, world!\")"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Identifier("write_line"), (0, 10)), - (Token::LeftParenthesis, (10, 11)), - (Token::String("Hello, world!"), (11, 26)), - (Token::RightParenthesis, (26, 27)), - (Token::Eof, (27, 27)), - ]) - ) - } - - #[test] - fn string_concatenation() { - let input = "\"Hello, \" + \"world!\""; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::String("Hello, "), (0, 9)), - (Token::Plus, (10, 11)), - (Token::String("world!"), (12, 20)), - (Token::Eof, (20, 20)), - ]) - ) - } - - #[test] - fn string() { - let input = "\"Hello, world!\""; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::String("Hello, world!"), (0, 15)), - (Token::Eof, (15, 15)), - ]) - ) - } - - #[test] - fn r#true() { - let input = "true"; - - assert_eq!( - lex(input), - Ok(vec![(Token::Boolean("true"), (0, 4)), (Token::Eof, (4, 4)),]) - ) - } - - #[test] - fn r#false() { - let input = "false"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Boolean("false"), (0, 5)), - (Token::Eof, (5, 5)) - ]) - ) - } - - #[test] - fn property_access_function_call() { - let input = "42.is_even()"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("42"), (0, 2)), - (Token::Dot, (2, 3)), - (Token::Identifier("is_even"), (3, 10)), - (Token::LeftParenthesis, (10, 11)), - (Token::RightParenthesis, (11, 12)), - (Token::Eof, (12, 12)), - ]) - ) - } - - #[test] - fn empty() { - let input = ""; - - assert_eq!(lex(input), Ok(vec![(Token::Eof, (0, 0))])) - } - - #[test] - fn reserved_identifier() { - let input = "length"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Identifier("length"), (0, 6)), - (Token::Eof, (6, 6)), - ]) - ) - } - - #[test] - fn square_braces() { - let input = "[]"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::LeftSquareBrace, (0, 1)), - (Token::RightSquareBrace, (1, 2)), - (Token::Eof, (2, 2)), - ]) - ) - } - - #[test] - fn small_float() { - let input = "1.23"; - - assert_eq!( - lex(input), - Ok(vec![(Token::Float("1.23"), (0, 4)), (Token::Eof, (4, 4)),]) - ) - } - - #[test] - #[allow(clippy::excessive_precision)] - fn big_float() { - let input = "123456789.123456789"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Float("123456789.123456789"), (0, 19)), - (Token::Eof, (19, 19)), - ]) - ) - } - - #[test] - fn add() { - let input = "1 + 2"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("1"), (0, 1)), - (Token::Plus, (2, 3)), - (Token::Integer("2"), (4, 5)), - (Token::Eof, (5, 5)), - ]) - ) - } - - #[test] - fn multiply() { - let input = "1 * 2"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("1"), (0, 1)), - (Token::Star, (2, 3)), - (Token::Integer("2"), (4, 5)), - (Token::Eof, (5, 5)), - ]) - ) - } - - #[test] - fn add_and_multiply() { - let input = "1 + 2 * 3"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer("1"), (0, 1)), - (Token::Plus, (2, 3)), - (Token::Integer("2"), (4, 5)), - (Token::Star, (6, 7)), - (Token::Integer("3"), (8, 9)), - (Token::Eof, (9, 9)), - ]) - ); - } - - #[test] - fn assignment() { - let input = "a = 1 + 2 * 3"; - - assert_eq!( - lex(input,), - Ok(vec![ - (Token::Identifier("a"), (0, 1)), - (Token::Equal, (2, 3)), - (Token::Integer("1"), (4, 5)), - (Token::Plus, (6, 7)), - (Token::Integer("2"), (8, 9)), - (Token::Star, (10, 11)), - (Token::Integer("3"), (12, 13)), - (Token::Eof, (13, 13)), - ]) - ); - } -} diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index cc74702..fce38b5 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -15,34 +15,27 @@ //! //! assert_eq!(the_answer, Some(Value::integer(42))); //! ``` -pub mod analyzer; -pub mod ast; -pub mod built_in_function; +pub mod bytecode; pub mod constructor; -pub mod context; -pub mod core_library; -pub mod dust_error; -pub mod evaluation; pub mod identifier; -pub mod lexer; -pub mod parser; -pub mod token; pub mod r#type; pub mod value; -pub mod vm; -pub use analyzer::{analyze, AnalysisError, Analyzer}; -pub use ast::{AbstractSyntaxTree, AstError, Expression, Node, Span, Statement}; -pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; -pub use constructor::{ConstructError, Constructor}; -pub use context::{Context, ContextData, ContextError}; -pub use core_library::core_library; -pub use dust_error::DustError; -pub use evaluation::{Evaluation, TypeEvaluation}; -pub use identifier::Identifier; -pub use lexer::{lex, LexError, Lexer}; -pub use parser::{parse, ParseError, Parser}; +pub use bytecode::*; +pub use constructor::*; +pub use identifier::*; pub use r#type::*; -pub use token::{Token, TokenKind, TokenOwned}; pub use value::*; -pub use vm::{run, RuntimeError, Vm}; + +use std::fmt::{self, Display, Formatter}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct Span(usize, usize); + +impl Display for Span { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "({}, {})", self.0, self.1) + } +} diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs deleted file mode 100644 index 37338c2..0000000 --- a/dust-lang/src/parser.rs +++ /dev/null @@ -1,2309 +0,0 @@ -//! Parsing tools. -//! -//! This module provides two parsing options: -//! - `parse` convenience function -//! - `Parser` struct, which parses the input a statement at a time -use std::{ - collections::VecDeque, - fmt::{self, Display, Formatter}, - num::{ParseFloatError, ParseIntError}, - str::ParseBoolError, -}; - -use crate::{ - ast::*, Context, ContextError, DustError, Identifier, LexError, Lexer, Token, TokenKind, - TokenOwned, Type, -}; - -/// Parses the input into an abstract syntax tree. -/// -/// # Examples -/// ``` -/// # use dust_lang::*; -/// let source = "42.to_string()"; -/// -/// assert_eq!( -/// parse(source), -/// Ok(AbstractSyntaxTree::with_statements([ -/// Statement::Expression(Expression::call( -/// Expression::field_access( -/// Expression::literal(42, (0, 2)), -/// Node::new(Identifier::new("to_string"), (3, 12)), -/// (0, 12) -/// ), -/// vec![], -/// (0, 14) -/// )) -/// ])) -/// ); -/// ``` -pub fn parse(source: &str) -> Result { - let mut tree = AbstractSyntaxTree::with_core_library(); - - let lexer = Lexer::new(source); - let mut parser = Parser::new(lexer); - - loop { - let statement = parser - .parse_statement(&tree.context) - .map_err(|parse_error| DustError::Parse { - parse_error, - source, - })?; - - tree.statements.push_back(statement); - - if let Token::Eof = parser.current_token { - break; - } - } - - Ok(tree) -} - -/// Low-level tool for parsing the input a statement at a time. -/// -/// # Examples -/// ``` -/// # use std::collections::VecDeque; -/// # use dust_lang::*; -/// let source = "x = 42"; -/// let lexer = Lexer::new(source); -/// let mut parser = Parser::new(lexer); -/// let mut ast = AbstractSyntaxTree::new(); -/// -/// loop { -/// let statement = parser.parse_statement(&ast.context).unwrap(); -/// -/// ast.statements.push_back(statement); -/// -/// if parser.is_eof() { -/// break; -/// } -/// } -/// ``` -pub struct Parser<'src> { - lexer: Lexer<'src>, - current_token: Token<'src>, - current_position: Span, - mode: ParserMode, -} - -impl<'src> Parser<'src> { - pub fn new(mut lexer: Lexer<'src>) -> Self { - let (current_token, current_position) = lexer.next_token().unwrap_or((Token::Eof, (0, 0))); - - Parser { - lexer, - current_token, - current_position, - mode: ParserMode::Normal, - } - } - - pub fn is_eof(&self) -> bool { - matches!(self.current_token, Token::Eof) - } - - pub fn parse_statement(&mut self, context: &Context) -> Result { - let start_position = self.current_position; - - if let Token::Let = self.current_token { - log::trace!("Parsing let statement"); - - self.next_token()?; - - let is_mutable = if let Token::Mut = self.current_token { - self.next_token()?; - - true - } else { - false - }; - - let identifier = self.parse_identifier(context)?; - - if let Token::Equal = self.current_token { - self.next_token()?; - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::Equal, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - - let value = self.parse_expression(0, context)?; - - let end = if let Token::Semicolon = self.current_token { - let end = self.current_position.1; - - self.next_token()?; - - end - } else { - value.position().1 - }; - let r#let = if is_mutable { - LetStatement::LetMut { identifier, value } - } else { - LetStatement::Let { identifier, value } - }; - let position = (start_position.0, end); - - return Ok(Statement::Let(Node::new(r#let, position))); - } - - if let Token::Struct = self.current_token { - log::trace!("Parsing struct definition"); - - self.next_token()?; - - let name = if let Token::Identifier(_) = self.current_token { - self.parse_identifier(context)? - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::Identifier, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - }; - - if let Token::Semicolon = self.current_token { - let end = self.current_position.1; - - self.next_token()?; - - return Ok(Statement::struct_definition( - StructDefinition::Unit { name }, - (start_position.0, end), - )); - } - - if let Token::LeftParenthesis = self.current_token { - self.next_token()?; - - let mut types = Vec::new(); - - loop { - if let Token::RightParenthesis = self.current_token { - self.next_token()?; - - break; - } - - let type_node = self.parse_type()?; - - types.push(type_node); - - if let Token::Comma = self.current_token { - self.next_token()?; - - continue; - } - } - - let position = (start_position.0, self.current_position.1); - - if let Token::Semicolon = self.current_token { - self.next_token()?; - } - - return if types.is_empty() { - Ok(Statement::struct_definition( - StructDefinition::Unit { name }, - position, - )) - } else { - Ok(Statement::struct_definition( - StructDefinition::Tuple { name, items: types }, - position, - )) - }; - } - - if let Token::LeftCurlyBrace = self.current_token { - self.next_token()?; - - let mut fields = Vec::new(); - - loop { - if let Token::RightCurlyBrace = self.current_token { - self.next_token()?; - - break; - } - - let field_name = self.parse_identifier(context)?; - - if let Token::Colon = self.current_token { - self.next_token()?; - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::Colon, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - - let field_type = self.parse_type()?; - - fields.push((field_name, field_type)); - - if let Token::Comma = self.current_token { - self.next_token()?; - - continue; - } - } - - let position = (start_position.0, self.current_position.1); - - if let Token::Semicolon = self.current_token { - self.next_token()?; - } - - return if fields.is_empty() { - Ok(Statement::struct_definition( - StructDefinition::Unit { name }, - position, - )) - } else { - Ok(Statement::struct_definition( - StructDefinition::Fields { name, fields }, - position, - )) - }; - } - - return Err(ParseError::ExpectedTokenMultiple { - expected: vec![ - TokenKind::LeftParenthesis, - TokenKind::LeftCurlyBrace, - TokenKind::Semicolon, - ], - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - - let expression = self.parse_expression(0, context)?; - - if let Token::Semicolon = self.current_token { - let position = (start_position.0, self.current_position.1); - - self.next_token()?; - - Ok(Statement::ExpressionNullified(Node::new( - expression, position, - ))) - } else { - Ok(Statement::Expression(expression)) - } - } - - fn next_token(&mut self) -> Result<(), ParseError> { - let (token, position) = self.lexer.next_token()?; - - self.current_token = token; - self.current_position = position; - - Ok(()) - } - - fn parse_expression( - &mut self, - mut precedence: u8, - context: &Context, - ) -> Result { - // Parse a statement starting from the current node. - let mut left = if self.current_token.is_prefix() { - self.parse_prefix(context)? - } else { - self.parse_primary(context)? - }; - - // While the current token has a higher precedence than the given precedence - while precedence < self.current_token.precedence() { - // Give precedence to postfix operations - left = if self.current_token.is_postfix() { - let statement = self.parse_postfix(left, context)?; - - precedence = self.current_token.precedence(); - - // Replace the left-hand side with the postfix operation - statement - } else { - // Replace the left-hand side with the infix operation - self.parse_infix(left, context)? - }; - } - - Ok(left) - } - - fn parse_prefix(&mut self, context: &Context) -> Result { - log::trace!("Parsing {} as prefix operator", self.current_token); - - let operator_start = self.current_position.0; - - match self.current_token { - Token::Bang => { - self.next_token()?; - - let operand = self.parse_expression(0, context)?; - let position = (operator_start, self.current_position.1); - - Ok(Expression::not(operand, position)) - } - Token::Minus => { - self.next_token()?; - - let operand = self.parse_expression(0, context)?; - let position = (operator_start, self.current_position.1); - - Ok(Expression::negation(operand, position)) - } - Token::Star => { - self.next_token()?; - - let operand = self.parse_expression(0, context)?; - let position = (operator_start, self.current_position.1); - - Ok(Expression::dereference(operand, position)) - } - _ => Err(ParseError::ExpectedTokenMultiple { - expected: vec![TokenKind::Bang, TokenKind::Minus, TokenKind::Star], - actual: self.current_token.to_owned(), - position: self.current_position, - }), - } - } - - fn parse_primary(&mut self, context: &Context) -> Result { - log::trace!("Parsing {} as primary", self.current_token); - - let start_position = self.current_position; - - match self.current_token { - Token::Async => { - let block = self.parse_block(context)?; - let position = (start_position.0, block.position.1); - - Ok(Expression::block(block.inner, position)) - } - Token::Boolean(text) => { - self.next_token()?; - - let boolean = text.parse::().map_err(|error| ParseError::Boolean { - error, - position: start_position, - })?; - let expression = Expression::literal(boolean, start_position); - - Ok(expression) - } - Token::Break => { - let break_end = self.current_position.1; - - self.next_token()?; - - let (expression_option, end) = if let Token::Semicolon = self.current_token { - // Do not consume the semicolon, allowing it to nullify the expression - - (None, break_end) - } else if let Ok(expression) = self.parse_expression(0, context) { - let end = expression.position().1; - - (Some(expression), end) - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::Semicolon, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - }; - let position = (start_position.0, end); - - Ok(Expression::r#break(expression_option, position)) - } - Token::Character(character) => { - self.next_token()?; - - let expression = Expression::literal(character, start_position); - - Ok(expression) - } - Token::Float(text) => { - self.next_token()?; - - let float = text.parse::().map_err(|error| ParseError::Float { - error, - position: start_position, - })?; - - Ok(Expression::literal(float, start_position)) - } - Token::Identifier(text) => { - self.next_token()?; - - let identifier = Identifier::new(text); - - if let ParserMode::Condition = self.mode { - context.set_position(&identifier, start_position.1)?; - - return Ok(Expression::identifier(identifier, start_position)); - } - - if let Token::LeftCurlyBrace = self.current_token { - self.next_token()?; - - let name = Node::new(identifier.clone(), start_position); - let mut fields = Vec::new(); - - loop { - if let Token::RightCurlyBrace = self.current_token { - self.next_token()?; - - break; - } - - let field_name = self.parse_identifier(context)?; - - if let Token::Colon = self.current_token { - self.next_token()?; - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::Colon, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - - let field_value = self.parse_expression(0, context)?; - - fields.push((field_name, field_value)); - - if let Token::Comma = self.current_token { - self.next_token()?; - } - } - - let position = (start_position.0, self.current_position.1); - - context.set_position(&identifier, position.1)?; - - return Ok(Expression::r#struct( - StructExpression::Fields { name, fields }, - position, - )); - } - - context.set_position(&identifier, start_position.1)?; - - Ok(Expression::identifier(identifier, start_position)) - } - Token::Integer(text) => { - self.next_token()?; - - let integer = text.parse::().map_err(|error| ParseError::Integer { - error, - position: start_position, - })?; - - Ok(Expression::literal(integer, start_position)) - } - Token::If => { - self.next_token()?; - - let r#if = self.parse_if(context)?; - let position = (start_position.0, self.current_position.1); - - Ok(Expression::r#if(r#if, position)) - } - Token::String(text) => { - self.next_token()?; - - Ok(Expression::literal(text.to_string(), start_position)) - } - Token::LeftCurlyBrace => { - let block_node = self.parse_block(context)?; - - Ok(Expression::block(block_node.inner, block_node.position)) - } - Token::LeftParenthesis => { - self.next_token()?; - - let node = self.parse_expression(0, context)?; - - if let Token::RightParenthesis = self.current_token { - let position = (start_position.0, self.current_position.1); - - self.next_token()?; - - Ok(Expression::grouped(node, position)) - } else { - Err(ParseError::ExpectedToken { - expected: TokenKind::RightParenthesis, - actual: self.current_token.to_owned(), - position: self.current_position, - }) - } - } - Token::LeftSquareBrace => { - self.next_token()?; - - if let Token::RightSquareBrace = self.current_token { - let position = (start_position.0, self.current_position.1); - - self.next_token()?; - - return Ok(Expression::list(Vec::new(), position)); - } - - let first_expression = self.parse_expression(0, context)?; - - if let Token::Semicolon = self.current_token { - self.next_token()?; - - let repeat_operand = self.parse_expression(0, context)?; - - if let Token::RightSquareBrace = self.current_token { - let position = (start_position.0, self.current_position.1); - - self.next_token()?; - - return Ok(Expression::auto_fill_list( - first_expression, - repeat_operand, - position, - )); - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::RightSquareBrace, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - } - - let mut expressions = vec![first_expression]; - - loop { - if let Token::RightSquareBrace = self.current_token { - let position = (start_position.0, self.current_position.1); - - self.next_token()?; - - return Ok(Expression::list(expressions, position)); - } - - if let Token::Comma = self.current_token { - self.next_token()?; - - continue; - } - - let expression = self.parse_expression(0, context)?; - - expressions.push(expression); - } - } - Token::Loop => { - self.next_token()?; - - let block = self.parse_block(context)?; - let position = (start_position.0, block.position.1); - - Ok(Expression::infinite_loop(block, position)) - } - Token::Map => { - self.next_token()?; - - if let Token::LeftCurlyBrace = self.current_token { - self.next_token()?; - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::LeftCurlyBrace, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - - let mut fields = Vec::new(); - - loop { - if let Token::RightCurlyBrace = self.current_token { - let position = (start_position.0, self.current_position.1); - - self.next_token()?; - - return Ok(Expression::map(fields, position)); - } - - let field_name = self.parse_identifier(context)?; - - if let Token::Equal = self.current_token { - self.next_token()?; - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::Equal, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - - let field_value = self.parse_expression(0, context)?; - - fields.push((field_name, field_value)); - - if let Token::Comma = self.current_token { - self.next_token()?; - } - } - } - Token::While => { - self.next_token()?; - - let condition = self.parse_expression(0, context)?; - let block = self.parse_block(context)?; - let position = (start_position.0, block.position.1); - - Ok(Expression::while_loop(condition, block, position)) - } - _ => Err(ParseError::ExpectedTokenMultiple { - expected: vec![ - TokenKind::Async, - TokenKind::Boolean, - TokenKind::Float, - TokenKind::Identifier, - TokenKind::Integer, - TokenKind::If, - TokenKind::LeftCurlyBrace, - TokenKind::LeftParenthesis, - TokenKind::LeftSquareBrace, - TokenKind::String, - TokenKind::While, - ], - actual: self.current_token.to_owned(), - position: self.current_position, - }), - } - } - - fn parse_infix( - &mut self, - left: Expression, - context: &Context, - ) -> Result { - log::trace!("Parsing {} as infix operator", self.current_token); - - let operator_precedence = self.current_token.precedence() - - if self.current_token.is_right_associative() { - 1 - } else { - 0 - }; - let left_start = left.position().0; - - if let Token::Equal = &self.current_token { - self.next_token()?; - - let value = self.parse_expression(operator_precedence, context)?; - let position = (left_start, value.position().1); - - return Ok(Expression::assignment(left, value, position)); - } - - if let Token::PlusEqual | Token::MinusEqual = &self.current_token { - let math_operator = match self.current_token { - Token::PlusEqual => MathOperator::Add, - Token::MinusEqual => MathOperator::Subtract, - _ => unreachable!(), - }; - let operator = Node::new(math_operator, self.current_position); - - self.next_token()?; - - let value = self.parse_expression(operator_precedence, context)?; - let position = (left_start, value.position().1); - - return Ok(Expression::operator( - OperatorExpression::CompoundAssignment { - assignee: left, - operator, - modifier: value, - }, - position, - )); - } - - if let Token::DoubleDot = &self.current_token { - self.next_token()?; - - let end = self.parse_expression(operator_precedence, context)?; - let position = (left_start, end.position().1); - - return Ok(Expression::exclusive_range(left, end, position)); - } - - if let Token::Minus | Token::Plus | Token::Star | Token::Slash | Token::Percent = - &self.current_token - { - let math_operator = match &self.current_token { - Token::Minus => Node::new(MathOperator::Subtract, self.current_position), - Token::Plus => Node::new(MathOperator::Add, self.current_position), - Token::Star => Node::new(MathOperator::Multiply, self.current_position), - Token::Slash => Node::new(MathOperator::Divide, self.current_position), - Token::Percent => Node::new(MathOperator::Modulo, self.current_position), - _ => unreachable!(), - }; - - self.next_token()?; - - let right = self.parse_expression(operator_precedence, context)?; - let position = (left_start, right.position().1); - - return Ok(Expression::operator( - OperatorExpression::Math { - left, - operator: math_operator, - right, - }, - position, - )); - } - - if let Token::DoubleEqual - | Token::BangEqual - | Token::Less - | Token::LessEqual - | Token::Greater - | Token::GreaterEqual = &self.current_token - { - let comparison_operator = match &self.current_token { - Token::DoubleEqual => Node::new(ComparisonOperator::Equal, self.current_position), - Token::BangEqual => Node::new(ComparisonOperator::NotEqual, self.current_position), - Token::Less => Node::new(ComparisonOperator::LessThan, self.current_position), - Token::LessEqual => { - Node::new(ComparisonOperator::LessThanOrEqual, self.current_position) - } - Token::Greater => Node::new(ComparisonOperator::GreaterThan, self.current_position), - Token::GreaterEqual => Node::new( - ComparisonOperator::GreaterThanOrEqual, - self.current_position, - ), - _ => unreachable!(), - }; - - self.next_token()?; - - let right = self.parse_expression(operator_precedence, context)?; - let position = (left_start, right.position().1); - - return Ok(Expression::operator( - OperatorExpression::Comparison { - left, - operator: comparison_operator, - right, - }, - position, - )); - } - - let logic_operator = match &self.current_token { - Token::DoubleAmpersand => Node::new(LogicOperator::And, self.current_position), - Token::DoublePipe => Node::new(LogicOperator::Or, self.current_position), - _ => { - return Err(ParseError::UnexpectedToken { - actual: self.current_token.to_owned(), - position: self.current_position, - }) - } - }; - - self.next_token()?; - - let right = self.parse_expression(operator_precedence, context)?; - let position = (left_start, right.position().1); - - Ok(Expression::operator( - OperatorExpression::Logic { - left, - operator: logic_operator, - right, - }, - position, - )) - } - - fn parse_postfix( - &mut self, - left: Expression, - context: &Context, - ) -> Result { - log::trace!("Parsing {} as postfix operator", self.current_token); - - let expression = match &self.current_token { - Token::Dot => { - self.next_token()?; - - if let Token::Integer(text) = &self.current_token { - let index = text.parse::().map_err(|error| ParseError::Integer { - error, - position: self.current_position, - })?; - let index_node = Node::new(index, self.current_position); - let position = (left.position().0, self.current_position.1); - - self.next_token()?; - - Expression::tuple_access(left, index_node, position) - } else { - let field = self.parse_identifier(context)?; - let position = (left.position().0, field.position.1); - - Expression::field_access(left, field, position) - } - } - Token::LeftParenthesis => { - self.next_token()?; - - let mut arguments = Vec::new(); - - while self.current_token != Token::RightParenthesis { - let argument = self.parse_expression(0, context)?; - - arguments.push(argument); - - if let Token::Comma = self.current_token { - self.next_token()?; - } else { - break; - } - } - - let position = (left.position().0, self.current_position.1); - - self.next_token()?; - - Expression::call(left, arguments, position) - } - Token::LeftSquareBrace => { - self.next_token()?; - - let index = self.parse_expression(0, context)?; - - let operator_end = if let Token::RightSquareBrace = self.current_token { - let end = self.current_position.1; - - self.next_token()?; - - end - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::RightSquareBrace, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - }; - - let position = (left.position().0, operator_end); - - Expression::list_index(left, index, position) - } - _ => { - return Err(ParseError::ExpectedTokenMultiple { - expected: vec![ - TokenKind::Dot, - TokenKind::LeftParenthesis, - TokenKind::LeftSquareBrace, - ], - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - }; - - if self.current_token.is_postfix() { - self.parse_postfix(expression, context) - } else { - Ok(expression) - } - } - - fn parse_if(&mut self, context: &Context) -> Result { - // Assume that the "if" token has already been consumed - - self.mode = ParserMode::Condition; - - let condition = self.parse_expression(0, context)?; - - self.mode = ParserMode::Normal; - - let if_block = self.parse_block(context)?; - - 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 if_expression = self.parse_if(context)?; - let position = (if_keyword_start, self.current_position.1); - - Ok(IfExpression::IfElse { - condition, - if_block, - r#else: ElseExpression::If(Node::new(Box::new(if_expression), position)), - }) - } else { - let else_block = self.parse_block(context)?; - - Ok(IfExpression::IfElse { - condition, - if_block, - r#else: ElseExpression::Block(else_block), - }) - } - } else { - Ok(IfExpression::If { - condition, - if_block, - }) - } - } - - fn parse_identifier(&mut self, context: &Context) -> Result, ParseError> { - if let Token::Identifier(text) = self.current_token { - let position = self.current_position; - let identifier = Identifier::new(text); - - self.next_token()?; - - context.set_position(&identifier, position.1)?; - - Ok(Node::new(identifier, position)) - } else { - Err(ParseError::ExpectedToken { - expected: TokenKind::Identifier, - actual: self.current_token.to_owned(), - position: self.current_position, - }) - } - } - - fn parse_block(&mut self, context: &Context) -> Result, ParseError> { - let left_start = self.current_position.0; - let is_async = if let Token::Async = self.current_token { - self.next_token()?; - - true - } else { - false - }; - - if let Token::LeftCurlyBrace = self.current_token { - self.next_token()?; - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::LeftCurlyBrace, - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - - let context = context.create_child(); - - log::trace!("Creating new block context {}", context.id()); - - let mut ast = AbstractSyntaxTree { - statements: VecDeque::new(), - context, - }; - - loop { - if let Token::RightCurlyBrace = self.current_token { - let position = (left_start, self.current_position.1); - - self.next_token()?; - - return if is_async { - Ok(Node::new(BlockExpression::Async(ast), position)) - } else { - Ok(Node::new(BlockExpression::Sync(ast), position)) - }; - } - - let statement = self.parse_statement(&ast.context)?; - - ast.statements.push_back(statement); - } - } - - fn parse_type(&mut self) -> Result, ParseError> { - let r#type = match self.current_token { - Token::Bool => Type::Boolean, - Token::FloatKeyword => Type::Float, - Token::Int => Type::Integer, - _ => { - return Err(ParseError::ExpectedTokenMultiple { - expected: vec![TokenKind::Bool, TokenKind::FloatKeyword, TokenKind::Int], - actual: self.current_token.to_owned(), - position: self.current_position, - }); - } - }; - let position = self.current_position; - - self.next_token()?; - - Ok(Node::new(r#type, position)) - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum ParserMode { - Condition, - Normal, -} - -#[derive(Debug, PartialEq, Clone)] -pub enum ParseError { - ContextError(ContextError), - Boolean { - error: ParseBoolError, - position: Span, - }, - Lex(LexError), - ExpectedAssignment { - actual: Statement, - }, - ExpectedExpression { - actual: Statement, - }, - ExpectedIdentifierNode { - actual: Expression, - }, - ExpectedIdentifierToken { - actual: TokenOwned, - position: Span, - }, - ExpectedToken { - expected: TokenKind, - actual: TokenOwned, - position: Span, - }, - ExpectedTokenMultiple { - expected: Vec, - actual: TokenOwned, - position: Span, - }, - UnexpectedToken { - actual: TokenOwned, - position: Span, - }, - Float { - error: ParseFloatError, - position: Span, - }, - Integer { - error: ParseIntError, - position: Span, - }, -} - -impl From for ParseError { - fn from(error: ContextError) -> Self { - Self::ContextError(error) - } -} - -impl From for ParseError { - fn from(v: LexError) -> Self { - Self::Lex(v) - } -} - -impl ParseError { - pub fn position(&self) -> Span { - match self { - ParseError::Boolean { position, .. } => *position, - ParseError::ContextError { .. } => (0, 0), - ParseError::ExpectedAssignment { actual } => actual.position(), - ParseError::ExpectedExpression { actual } => actual.position(), - ParseError::ExpectedIdentifierNode { actual } => actual.position(), - ParseError::ExpectedIdentifierToken { position, .. } => *position, - ParseError::ExpectedToken { position, .. } => *position, - ParseError::ExpectedTokenMultiple { position, .. } => *position, - ParseError::Float { position, .. } => *position, - ParseError::Integer { position, .. } => *position, - ParseError::Lex(error) => error.position(), - ParseError::UnexpectedToken { position, .. } => *position, - } - } -} - -impl Display for ParseError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Boolean { error, .. } => write!(f, "{}", error), - Self::ContextError(error) => write!(f, "{}", error), - Self::ExpectedAssignment { .. } => write!(f, "Expected assignment"), - Self::ExpectedExpression { .. } => write!(f, "Expected expression"), - Self::ExpectedIdentifierNode { actual } => { - write!(f, "Expected identifier, found {actual}") - } - Self::ExpectedIdentifierToken { actual, .. } => { - write!(f, "Expected identifier, found {actual}") - } - Self::ExpectedToken { - expected, actual, .. - } => write!(f, "Expected token {expected}, found {actual}"), - Self::ExpectedTokenMultiple { - expected, actual, .. - } => { - write!(f, "Expected one of")?; - - for (i, token_kind) in expected.iter().enumerate() { - if i == 0 { - write!(f, " {token_kind}")?; - } else if i == expected.len() - 1 { - write!(f, " or {token_kind}")?; - } else { - write!(f, ", {token_kind}")?; - } - } - - write!(f, ", found {actual}") - } - Self::Float { error, .. } => write!(f, "{}", error), - Self::Integer { error, .. } => write!(f, "{}", error), - Self::Lex(error) => write!(f, "{}", error), - Self::UnexpectedToken { actual, .. } => write!(f, "Unexpected token {actual}"), - } - } -} - -#[cfg(test)] -mod tests { - use crate::{Identifier, Type}; - - use super::*; - - #[test] - fn dereference() { - let source = "*a"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::dereference( - Expression::identifier(Identifier::new("a"), (1, 2)), - (0, 2) - ),) - ])) - ); - } - - #[test] - fn character_literal() { - let source = "'a'"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::literal('a', (0, 3))) - ])) - ); - } - - #[test] - fn break_loop() { - let source = "loop { break; }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::infinite_loop( - Node::new( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::r#break(None, (7, 12)), - (7, 13) - )) - ])), - (5, 15) - ), - (0, 15) - )) - ])) - ); - } - - #[test] - fn built_in_function() { - let source = "42.to_string()"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::call( - Expression::field_access( - Expression::literal(42, (0, 2)), - Node::new(Identifier::new("to_string"), (3, 12)), - (0, 12) - ), - vec![], - (0, 14) - )) - ])) - ); - } - - #[test] - fn map_expression() { - let source = "map { x = \"1\", y = 2, z = 3.0 }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::map( - vec![ - ( - Node::new(Identifier::new("x"), (6, 7)), - Expression::literal("1".to_string(), (10, 13)), - ), - ( - Node::new(Identifier::new("y"), (15, 16)), - Expression::literal(2, (19, 20)), - ), - ( - Node::new(Identifier::new("z"), (22, 23)), - Expression::literal(3.0, (26, 29)), - ), - ], - (0, 31), - )) - ])) - ); - } - - #[test] - fn let_mut_while_loop() { - let source = "let mut x = 0; while x < 10 { x += 1 }; x"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Let(Node::new( - LetStatement::LetMut { - identifier: Node::new(Identifier::new("x"), (8, 9)), - value: Expression::literal(0, (12, 13)), - }, - (0, 14), - )), - Statement::ExpressionNullified(Node::new( - Expression::while_loop( - Expression::comparison( - Expression::identifier(Identifier::new("x"), (21, 22)), - Node::new(ComparisonOperator::LessThan, (23, 24)), - Expression::literal(10, (25, 27)), - (21, 27), - ), - Node::new( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::compound_assignment( - Expression::identifier(Identifier::new("x"), (30, 31)), - Node::new(MathOperator::Add, (32, 34)), - Expression::literal(1, (35, 36)), - (30, 36), - ),) - ])), - (28, 38), - ), - (15, 38), - ), - (15, 39) - )), - Statement::Expression(Expression::identifier(Identifier::new("x"), (40, 41)),), - ])) - ); - } - - #[test] - fn let_statement() { - let source = "let x = 42;"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([Statement::Let( - Node::new( - LetStatement::Let { - identifier: Node::new(Identifier::new("x"), (4, 5)), - value: Expression::literal(42, (8, 10)), - }, - (0, 11), - ) - )])) - ); - } - - #[test] - fn let_mut_statement() { - let source = "let mut x = false;"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([Statement::Let( - Node::new( - LetStatement::LetMut { - identifier: Node::new(Identifier::new("x"), (8, 9)), - value: Expression::literal(false, (12, 17)), - }, - (0, 18), - ) - )])) - ); - } - - #[test] - fn async_block() { - let source = "async { x = 42; y = 4.0 }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::block( - BlockExpression::Async(AbstractSyntaxTree::with_statements([ - 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( - OperatorExpression::Assignment { - assignee: Expression::identifier(Identifier::new("y"), (16, 17)), - value: Expression::literal(4.0, (20, 23)), - }, - (16, 23) - )) - ])), - (0, 25) - )) - ])) - ); - } - - #[test] - fn tuple_struct_access() { - let source = "Foo(42, \"bar\").0"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::tuple_access( - Expression::call( - Expression::identifier(Identifier::new("Foo"), (0, 3)), - vec![ - Expression::literal(42, (4, 6)), - Expression::literal("bar".to_string(), (8, 13)), - ], - (0, 14) - ), - Node::new(0, (15, 16)), - (0, 16) - )) - ])) - ); - } - - #[test] - fn fields_struct_instantiation() { - let source = "Foo { a: 42, b: 4.0 }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::r#struct( - StructExpression::Fields { - name: Node::new(Identifier::new("Foo"), (0, 3)), - fields: vec![ - ( - Node::new(Identifier::new("a"), (6, 7)), - Expression::literal(42, (9, 11)), - ), - ( - Node::new(Identifier::new("b"), (13, 14)), - Expression::literal(4.0, (16, 19)) - ) - ] - }, - (0, 21) - )) - ])) - ); - } - - #[test] - fn fields_struct() { - let source = "struct Foo { a: int, b: float }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::struct_definition( - StructDefinition::Fields { - name: Node::new(Identifier::new("Foo"), (7, 10)), - fields: vec![ - ( - Node::new(Identifier::new("a"), (13, 14)), - Node::new(Type::Integer, (16, 19)) - ), - ( - Node::new(Identifier::new("b"), (21, 22)), - Node::new(Type::Float, (24, 29)) - ) - ] - }, - (0, 31) - ) - ])) - ); - } - - #[test] - fn tuple_struct_instantiation() { - let source = "Foo(1, 2.0)"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::call( - Expression::identifier(Identifier::new("Foo"), (0, 3)), - vec![ - Expression::literal(1, (4, 5)), - Expression::literal(2.0, (7, 10)) - ], - (0, 11) - )) - ])) - ); - } - - #[test] - fn tuple_struct_definition() { - let source = "struct Foo(int, float);"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::StructDefinition(Node::new( - StructDefinition::Tuple { - name: Node::new(Identifier::new("Foo"), (7, 10)), - items: vec![ - Node::new(Type::Integer, (11, 14)), - Node::new(Type::Float, (16, 21)), - ], - }, - (0, 23) - )) - ])) - ); - } - - #[test] - fn unit_struct() { - let source = "struct Foo;"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::StructDefinition(Node::new( - StructDefinition::Unit { - name: Node::new(Identifier::new("Foo"), (7, 10)), - }, - (0, 11) - )) - ])) - ); - } - - #[test] - fn list_index_nested() { - let source = "[1, [2], 3][1][0]"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::list_index( - Expression::list_index( - Expression::list( - [ - Expression::literal(1, (1, 2)), - Expression::list([Expression::literal(2, (5, 6))], (4, 7)), - Expression::literal(3, (9, 10)), - ], - (0, 11) - ), - Expression::literal(1, (12, 13)), - (0, 14) - ), - Expression::literal(0, (15, 16)), - (0, 17) - ),) - ])) - ); - } - - #[test] - fn range() { - let source = "0..42"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::exclusive_range( - Expression::literal(0, (0, 1)), - Expression::literal(42, (3, 5)), - (0, 5) - )) - ])) - ); - } - - #[test] - fn negate_variable() { - let source = "a = 1; -a"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::operator( - OperatorExpression::Assignment { - assignee: Expression::identifier(Identifier::new("a"), (0, 1)), - value: Expression::literal(1, (4, 5)), - }, - (0, 5) - ), - (0, 6) - )), - Statement::Expression(Expression::operator( - OperatorExpression::Negation(Expression::identifier( - Identifier::new("a"), - (8, 9) - )), - (7, 9) - )) - ])) - ); - } - - #[test] - fn negate_expression() { - let source = "-(1 + 1)"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::operator( - OperatorExpression::Negation(Expression::grouped( - Expression::operator( - OperatorExpression::Math { - left: Expression::literal(1, (2, 3)), - operator: Node::new(MathOperator::Add, (4, 5)), - right: Expression::literal(1, (6, 7)), - }, - (2, 7) - ), - (1, 8) - )), - (0, 8) - )) - ])) - ); - } - - #[test] - fn not_expression() { - let source = "!(1 > 42)"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::operator( - OperatorExpression::Not(Expression::grouped( - Expression::operator( - OperatorExpression::Comparison { - left: Expression::literal(1, (2, 3)), - operator: Node::new(ComparisonOperator::GreaterThan, (4, 5)), - right: Expression::literal(42, (6, 8)), - }, - (2, 8) - ), - (1, 9) - )), - (0, 9) - )) - ])) - ); - } - - #[test] - fn not_variable() { - let source = "a = false; !a"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::ExpressionNullified(Node::new( - Expression::operator( - OperatorExpression::Assignment { - assignee: Expression::identifier(Identifier::new("a"), (0, 1)), - value: Expression::literal(false, (4, 9)), - }, - (0, 9) - ), - (0, 10) - )), - Statement::Expression(Expression::operator( - OperatorExpression::Not(Expression::identifier(Identifier::new("a"), (12, 13))), - (11, 13) - )), - ])) - ); - } - - #[test] - fn r#if() { - let source = "if x { y }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::r#if( - IfExpression::If { - condition: Expression::identifier(Identifier::new("x"), (3, 4)), - if_block: Node::new( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::identifier( - Identifier::new("y"), - (7, 8) - )) - ])), - (5, 10) - ) - }, - (0, 10) - )) - ])) - ); - } - - #[test] - fn if_else() { - let source = "if x { y } else { z }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::r#if( - IfExpression::IfElse { - condition: Expression::identifier(Identifier::new("x"), (3, 4)), - if_block: Node::new( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::identifier( - Identifier::new("y"), - (7, 8) - )) - ])), - (5, 10) - ), - r#else: ElseExpression::Block(Node::new( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::identifier( - Identifier::new("z"), - (18, 19) - )) - ])), - (16, 21) - )) - }, - (0, 21) - )) - ])) - ); - } - - #[test] - fn if_else_if_else() { - let source = "if x { y } else if z { a } else { b }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::r#if( - IfExpression::IfElse { - condition: Expression::identifier(Identifier::new("x"), (3, 4)), - if_block: Node::new( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - 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(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::identifier( - Identifier::new("a"), - (23, 24) - )) - ])), - (21, 26) - ), - r#else: ElseExpression::Block(Node::new( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::identifier( - Identifier::new("b"), - (34, 35) - )) - ])), - (32, 37) - )), - }), - (16, 37) - )), - }, - (0, 37) - )) - ])) - ) - } - - #[test] - fn while_loop() { - let source = "while x < 10 { x += 1 }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - 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(AbstractSyntaxTree::with_statements([ - 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) - )) - ])) - ) - } - - #[test] - fn add_assign() { - let source = "a += 1"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::operator( - OperatorExpression::CompoundAssignment { - assignee: Expression::identifier(Identifier::new("a"), (0, 1)), - operator: Node::new(MathOperator::Add, (2, 4)), - modifier: Expression::literal(1, (5, 6)), - }, - (0, 6) - )) - ])) - ) - } - - #[test] - fn or() { - let source = "true || false"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::operator( - OperatorExpression::Logic { - left: Expression::literal(true, (0, 4)), - operator: Node::new(LogicOperator::Or, (5, 7)), - right: Expression::literal(false, (8, 13)), - }, - (0, 13) - )) - ])) - ) - } - - #[test] - fn block_with_one_statement() { - let source = "{ 40 + 2 }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::block( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - 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) - )) - ])) - ) - } - - #[test] - fn block_with_assignment() { - let source = "{ foo = 42; bar = 42; baz = \"42\" }"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::block( - BlockExpression::Sync(AbstractSyntaxTree::with_statements([ - 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) - )) - ])) - ) - } - - #[test] - fn equal() { - let source = "42 == 42"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::comparison( - Expression::literal(42, (0, 2)), - Node::new(ComparisonOperator::Equal, (3, 5)), - Expression::literal(42, (6, 8)), - (0, 8) - )) - ])) - ); - } - - #[test] - fn less_than() { - let source = "1 < 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::comparison( - Expression::literal(1, (0, 1)), - Node::new(ComparisonOperator::LessThan, (2, 3)), - Expression::literal(2, (4, 5)), - (0, 5) - )) - ])) - ); - } - - #[test] - fn less_than_or_equal() { - let source = "1 <= 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::comparison( - Expression::literal(1, (0, 1)), - Node::new(ComparisonOperator::LessThanOrEqual, (2, 4)), - Expression::literal(2, (5, 6)), - (0, 6) - )) - ])) - ); - } - - #[test] - fn greater_than_or_equal() { - let source = "1 >= 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::comparison( - Expression::literal(1, (0, 1)), - Node::new(ComparisonOperator::GreaterThanOrEqual, (2, 4)), - Expression::literal(2, (5, 6)), - (0, 6) - )) - ])) - ); - } - - #[test] - fn greater_than() { - let source = "1 > 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::comparison( - Expression::literal(1, (0, 1)), - Node::new(ComparisonOperator::GreaterThan, (2, 3)), - Expression::literal(2, (4, 5)), - (0, 5) - )) - ])) - ); - } - - #[test] - fn subtract_negative_integers() { - let source = "-1 - -2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::math( - Expression::literal(-1, (0, 2)), - MathOperator::subtract((3, 4)), - Expression::literal(-2, (5, 7)), - (0, 7) - )) - ])) - ); - } - - #[test] - fn modulo() { - let source = "42 % 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::math( - Expression::literal(42, (0, 2)), - MathOperator::modulo((3, 4)), - Expression::literal(2, (5, 6)), - (0, 6) - )) - ])) - ); - } - - #[test] - fn divide() { - let source = "42 / 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::math( - Expression::literal(42, (0, 2)), - MathOperator::divide((3, 4)), - Expression::literal(2, (5, 6)), - (0, 6) - )) - ])) - ); - } - - #[test] - fn string_concatenation() { - let source = "\"Hello, \" + \"World!\""; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::math( - Expression::literal("Hello, ", (0, 9)), - MathOperator::add((10, 11)), - Expression::literal("World!", (12, 20)), - (0, 20) - )) - ])) - ); - } - - #[test] - fn string() { - let source = "\"Hello, World!\""; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::literal("Hello, World!", (0, 15))) - ])) - ); - } - - #[test] - fn boolean() { - let source = "true"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::literal(true, (0, 4))) - ])) - ); - } - - #[test] - fn list_index() { - let source = "[1, 2, 3][0]"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::list_index( - Expression::list( - [ - Expression::literal(1, (1, 2)), - Expression::literal(2, (4, 5)), - Expression::literal(3, (7, 8)), - ], - (0, 9) - ), - Expression::literal(0, (10, 11)), - (0, 12) - )) - ])) - ); - } - - #[test] - fn property_access() { - let source = "a.b"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::field_access( - Expression::identifier(Identifier::new("a"), (0, 1)), - Node::new(Identifier::new("b"), (2, 3)), - (0, 3) - )) - ])) - ); - } - - #[test] - fn complex_list() { - let source = "[1, 1 + 1, 2 + (4 * 10)]"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::list( - [ - Expression::literal(1, (1, 2)), - Expression::math( - Expression::literal(1, (4, 5)), - MathOperator::add((6, 7)), - Expression::literal(1, (8, 9)), - (4, 9) - ), - Expression::math( - Expression::literal(2, (11, 12)), - Node::new(MathOperator::Add, (13, 14)), - Expression::grouped( - Expression::math( - Expression::literal(4, (16, 17)), - MathOperator::multiply((18, 19)), - Expression::literal(10, (20, 22)), - (16, 22) - ), - (15, 23) - ), - (11, 23) - ), - ], - (0, 24) - )) - ])) - ); - } - - #[test] - fn list() { - let source = "[1, 2]"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::list( - [ - Expression::literal(1, (1, 2)), - Expression::literal(2, (4, 5)) - ], - (0, 6) - )) - ])) - ); - } - - #[test] - fn empty_list() { - let source = "[]"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::list(vec![], (0, 2))) - ])) - ); - } - - #[test] - fn float() { - let source = "42.0"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::literal(42.0, (0, 4))) - ])) - ); - } - - #[test] - fn add() { - let source = "1 + 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::math( - Expression::literal(1, (0, 1)), - MathOperator::add((2, 3)), - Expression::literal(2, (4, 5)), - (0, 5) - )) - ])) - ); - } - - #[test] - fn multiply() { - let source = "1 * 2"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::math( - Expression::literal(1, (0, 1)), - MathOperator::multiply((2, 3)), - Expression::literal(2, (4, 5)), - (0, 5) - ),) - ])) - ); - } - - #[test] - fn add_and_multiply() { - let source = "1 + 2 * 3"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::math( - Expression::literal(1, (0, 1)), - MathOperator::add((2, 3)), - Expression::math( - Expression::literal(2, (4, 5)), - MathOperator::multiply((6, 7)), - Expression::literal(3, (8, 9)), - (4, 9) - ), - (0, 9) - )), - ])) - ); - } - - #[test] - fn assignment() { - let source = "a = 1 + 2 * 3"; - - assert_eq!( - parse(source), - Ok(AbstractSyntaxTree::with_statements([ - Statement::Expression(Expression::assignment( - Expression::identifier("a", (0, 1)), - Expression::math( - Expression::literal(1, (4, 5)), - MathOperator::add((6, 7)), - Expression::math( - Expression::literal(2, (8, 9)), - MathOperator::multiply((10, 11)), - Expression::literal(3, (12, 13)), - (8, 13) - ), - (4, 13) - ), - (0, 13) - )) - ])) - ); - } -} diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs deleted file mode 100644 index 2e41d95..0000000 --- a/dust-lang/src/token.rs +++ /dev/null @@ -1,651 +0,0 @@ -//! Token and TokenOwned types. -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -/// Source code token. -#[derive(Debug, Serialize, Deserialize, PartialEq)] -pub enum Token<'src> { - // End of file - Eof, - - // Hard-coded values - Boolean(&'src str), - Character(char), - Float(&'src str), - Identifier(&'src str), - Integer(&'src str), - String(&'src str), - - // Keywords - Async, - Bool, - Break, - Else, - FloatKeyword, - If, - Int, - Let, - Loop, - Map, - Mut, - Str, - Struct, - While, - - // Symbols - BangEqual, - Bang, - Colon, - Comma, - Dot, - DoubleAmpersand, - DoubleDot, - DoubleEqual, - DoublePipe, - Equal, - Greater, - GreaterEqual, - LeftCurlyBrace, - LeftParenthesis, - LeftSquareBrace, - Less, - LessEqual, - Minus, - MinusEqual, - Percent, - Plus, - PlusEqual, - RightCurlyBrace, - RightParenthesis, - RightSquareBrace, - Semicolon, - Slash, - Star, -} - -impl<'src> Token<'src> { - #[allow(clippy::len_without_is_empty)] - pub fn len(&self) -> usize { - match self { - Token::Eof => 0, - Token::Boolean(text) => text.len(), - Token::Character(_) => 3, - Token::Float(text) => text.len(), - Token::Identifier(text) => text.len(), - Token::Integer(text) => text.len(), - Token::String(text) => text.len() + 2, - Token::Async => 5, - Token::Bool => 4, - Token::Break => 5, - Token::Else => 4, - Token::FloatKeyword => 5, - Token::If => 2, - Token::Int => 3, - Token::Let => 3, - Token::Loop => 4, - Token::Map => 3, - Token::Mut => 3, - Token::Str => 3, - Token::Struct => 6, - Token::While => 5, - Token::BangEqual => 2, - Token::Bang => 1, - Token::Colon => 1, - Token::Comma => 1, - Token::Dot => 1, - Token::DoubleAmpersand => 2, - Token::DoubleDot => 2, - Token::DoubleEqual => 2, - Token::DoublePipe => 2, - Token::Equal => 1, - Token::Greater => 1, - Token::GreaterEqual => 2, - Token::LeftCurlyBrace => 1, - Token::LeftParenthesis => 1, - Token::LeftSquareBrace => 1, - Token::Less => 1, - Token::LessEqual => 2, - Token::Minus => 1, - Token::MinusEqual => 2, - Token::Percent => 1, - Token::Plus => 1, - Token::PlusEqual => 2, - Token::RightCurlyBrace => 1, - Token::RightParenthesis => 1, - Token::RightSquareBrace => 1, - Token::Semicolon => 1, - Token::Slash => 1, - Token::Star => 1, - } - } - - pub fn to_owned(&self) -> TokenOwned { - match self { - Token::Async => TokenOwned::Async, - Token::BangEqual => TokenOwned::BangEqual, - Token::Bang => TokenOwned::Bang, - Token::Bool => TokenOwned::Bool, - Token::Boolean(boolean) => TokenOwned::Boolean(boolean.to_string()), - Token::Break => TokenOwned::Break, - Token::Character(character) => TokenOwned::Character(*character), - Token::Colon => TokenOwned::Colon, - Token::Comma => TokenOwned::Comma, - Token::Dot => TokenOwned::Dot, - Token::DoubleAmpersand => TokenOwned::DoubleAmpersand, - Token::DoubleDot => TokenOwned::DoubleDot, - Token::DoubleEqual => TokenOwned::DoubleEqual, - Token::DoublePipe => TokenOwned::DoublePipe, - Token::Else => TokenOwned::Else, - Token::Eof => TokenOwned::Eof, - Token::Equal => TokenOwned::Equal, - Token::Float(float) => TokenOwned::Float(float.to_string()), - Token::FloatKeyword => TokenOwned::FloatKeyword, - Token::Greater => TokenOwned::Greater, - Token::GreaterEqual => TokenOwned::GreaterOrEqual, - Token::Identifier(text) => TokenOwned::Identifier(text.to_string()), - Token::If => TokenOwned::If, - Token::Int => TokenOwned::Int, - Token::Integer(integer) => TokenOwned::Integer(integer.to_string()), - Token::LeftCurlyBrace => TokenOwned::LeftCurlyBrace, - Token::LeftParenthesis => TokenOwned::LeftParenthesis, - Token::LeftSquareBrace => TokenOwned::LeftSquareBrace, - Token::Let => TokenOwned::Let, - Token::Less => TokenOwned::Less, - Token::LessEqual => TokenOwned::LessOrEqual, - Token::Loop => TokenOwned::Loop, - Token::Map => TokenOwned::Map, - Token::Minus => TokenOwned::Minus, - Token::MinusEqual => TokenOwned::MinusEqual, - Token::Mut => TokenOwned::Mut, - Token::Percent => TokenOwned::Percent, - Token::Plus => TokenOwned::Plus, - Token::PlusEqual => TokenOwned::PlusEqual, - Token::RightCurlyBrace => TokenOwned::RightCurlyBrace, - Token::RightParenthesis => TokenOwned::RightParenthesis, - Token::RightSquareBrace => TokenOwned::RightSquareBrace, - Token::Semicolon => TokenOwned::Semicolon, - Token::Star => TokenOwned::Star, - Token::Slash => TokenOwned::Slash, - Token::String(text) => TokenOwned::String(text.to_string()), - Token::Str => TokenOwned::Str, - Token::Struct => TokenOwned::Struct, - Token::While => TokenOwned::While, - } - } - - pub fn kind(&self) -> TokenKind { - match self { - Token::Async => TokenKind::Async, - Token::BangEqual => TokenKind::BangEqual, - Token::Bang => TokenKind::Bang, - Token::Bool => TokenKind::Bool, - Token::Boolean(_) => TokenKind::Boolean, - Token::Break => TokenKind::Break, - Token::Character(_) => TokenKind::Character, - Token::Colon => TokenKind::Colon, - Token::Comma => TokenKind::Comma, - Token::Dot => TokenKind::Dot, - Token::DoubleAmpersand => TokenKind::DoubleAmpersand, - Token::DoubleDot => TokenKind::DoubleDot, - Token::DoubleEqual => TokenKind::DoubleEqual, - Token::DoublePipe => TokenKind::DoublePipe, - Token::Else => TokenKind::Else, - Token::Eof => TokenKind::Eof, - Token::Equal => TokenKind::Equal, - Token::Float(_) => TokenKind::Float, - Token::FloatKeyword => TokenKind::FloatKeyword, - Token::Greater => TokenKind::Greater, - Token::GreaterEqual => TokenKind::GreaterOrEqual, - Token::Identifier(_) => TokenKind::Identifier, - Token::If => TokenKind::If, - Token::Int => TokenKind::Int, - Token::Integer(_) => TokenKind::Integer, - Token::LeftCurlyBrace => TokenKind::LeftCurlyBrace, - Token::LeftParenthesis => TokenKind::LeftParenthesis, - Token::LeftSquareBrace => TokenKind::LeftSquareBrace, - Token::Let => TokenKind::Let, - Token::Less => TokenKind::Less, - Token::LessEqual => TokenKind::LessOrEqual, - Token::Loop => TokenKind::Loop, - Token::Map => TokenKind::Map, - Token::Minus => TokenKind::Minus, - Token::MinusEqual => TokenKind::MinusEqual, - Token::Mut => TokenKind::Mut, - Token::Percent => TokenKind::Percent, - Token::Plus => TokenKind::Plus, - Token::PlusEqual => TokenKind::PlusEqual, - Token::RightCurlyBrace => TokenKind::RightCurlyBrace, - Token::RightParenthesis => TokenKind::RightParenthesis, - Token::RightSquareBrace => TokenKind::RightSquareBrace, - Token::Semicolon => TokenKind::Semicolon, - Token::Star => TokenKind::Star, - Token::Slash => TokenKind::Slash, - Token::Str => TokenKind::Str, - Token::String(_) => TokenKind::String, - Token::Struct => TokenKind::Struct, - Token::While => TokenKind::While, - } - } - - pub fn is_eof(&self) -> bool { - matches!(self, Token::Eof) - } - - pub fn precedence(&self) -> u8 { - match self { - Token::Dot => 9, - Token::LeftParenthesis | Token::LeftSquareBrace => 8, - Token::Star | Token::Slash | Token::Percent => 7, - Token::Minus | Token::Plus => 6, - Token::DoubleEqual - | Token::Less - | Token::LessEqual - | Token::Greater - | Token::GreaterEqual => 5, - Token::DoubleAmpersand => 4, - Token::DoublePipe => 3, - Token::DoubleDot => 2, - Token::Equal | Token::MinusEqual | Token::PlusEqual => 1, - _ => 0, - } - } - - pub fn is_left_associative(&self) -> bool { - matches!( - self, - Token::Dot - | Token::DoubleAmpersand - | Token::DoublePipe - | Token::Plus - | Token::Minus - | Token::Star - | Token::Slash - | Token::Percent - ) - } - - pub fn is_right_associative(&self) -> bool { - matches!(self, Token::Equal | Token::MinusEqual | Token::PlusEqual) - } - - pub fn is_prefix(&self) -> bool { - matches!(self, Token::Bang | Token::Minus | Token::Star) - } - - pub fn is_postfix(&self) -> bool { - matches!( - self, - Token::Dot | Token::LeftCurlyBrace | Token::LeftParenthesis | Token::LeftSquareBrace - ) - } -} - -impl<'src> Display for Token<'src> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Token::Async => write!(f, "async"), - Token::BangEqual => write!(f, "!="), - Token::Bang => write!(f, "!"), - Token::Bool => write!(f, "bool"), - Token::Boolean(value) => write!(f, "{}", value), - Token::Break => write!(f, "break"), - Token::Character(value) => write!(f, "'{}'", value), - Token::Colon => write!(f, ":"), - Token::Comma => write!(f, ","), - Token::Dot => write!(f, "."), - Token::DoubleAmpersand => write!(f, "&&"), - Token::DoubleDot => write!(f, ".."), - Token::DoubleEqual => write!(f, "=="), - Token::DoublePipe => write!(f, "||"), - Token::Else => write!(f, "else"), - Token::Eof => write!(f, "EOF"), - Token::Equal => write!(f, "="), - Token::Float(value) => write!(f, "{}", value), - Token::FloatKeyword => write!(f, "float"), - Token::Greater => write!(f, ">"), - Token::GreaterEqual => write!(f, ">="), - Token::Identifier(value) => write!(f, "{}", value), - Token::If => write!(f, "if"), - Token::Int => write!(f, "int"), - Token::Integer(value) => write!(f, "{}", value), - Token::LeftCurlyBrace => write!(f, "{{"), - Token::LeftParenthesis => write!(f, "("), - Token::LeftSquareBrace => write!(f, "["), - Token::Let => write!(f, "let"), - Token::Less => write!(f, "<"), - Token::LessEqual => write!(f, "<="), - Token::Loop => write!(f, "loop"), - Token::Map => write!(f, "map"), - Token::Minus => write!(f, "-"), - Token::MinusEqual => write!(f, "-="), - Token::Mut => write!(f, "mut"), - Token::Percent => write!(f, "%"), - Token::Plus => write!(f, "+"), - Token::PlusEqual => write!(f, "+="), - Token::RightCurlyBrace => write!(f, "}}"), - Token::RightParenthesis => write!(f, ")"), - Token::RightSquareBrace => write!(f, "]"), - Token::Semicolon => write!(f, ";"), - Token::Slash => write!(f, "/"), - Token::Star => write!(f, "*"), - Token::Str => write!(f, "str"), - Token::String(value) => write!(f, "\"{}\"", value), - Token::Struct => write!(f, "struct"), - Token::While => write!(f, "while"), - } - } -} - -/// Owned version of `Token`, which owns all the strings. -/// -/// This is used for errors. -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -pub enum TokenOwned { - Eof, - - Identifier(String), - - // Hard-coded values - Boolean(String), - Character(char), - Float(String), - Integer(String), - String(String), - - // Keywords - Bool, - Break, - Else, - FloatKeyword, - If, - Int, - Let, - Loop, - Map, - Mut, - Str, - While, - - // Symbols - Async, - Bang, - BangEqual, - Colon, - Comma, - Dot, - DoubleAmpersand, - DoubleDot, - DoubleEqual, - DoublePipe, - Equal, - Greater, - GreaterOrEqual, - LeftCurlyBrace, - LeftParenthesis, - LeftSquareBrace, - Less, - LessOrEqual, - Minus, - MinusEqual, - Percent, - Plus, - PlusEqual, - RightCurlyBrace, - RightParenthesis, - RightSquareBrace, - Semicolon, - Star, - Struct, - Slash, -} - -impl Display for TokenOwned { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - TokenOwned::Async => Token::Async.fmt(f), - TokenOwned::Bang => Token::Bang.fmt(f), - TokenOwned::BangEqual => Token::BangEqual.fmt(f), - TokenOwned::Bool => Token::Bool.fmt(f), - TokenOwned::Boolean(boolean) => Token::Boolean(boolean).fmt(f), - TokenOwned::Break => Token::Break.fmt(f), - TokenOwned::Character(character) => Token::Character(*character).fmt(f), - TokenOwned::Colon => Token::Colon.fmt(f), - TokenOwned::Comma => Token::Comma.fmt(f), - TokenOwned::Dot => Token::Dot.fmt(f), - TokenOwned::DoubleAmpersand => Token::DoubleAmpersand.fmt(f), - TokenOwned::DoubleDot => Token::DoubleDot.fmt(f), - TokenOwned::DoubleEqual => Token::DoubleEqual.fmt(f), - TokenOwned::DoublePipe => Token::DoublePipe.fmt(f), - TokenOwned::Else => Token::Else.fmt(f), - TokenOwned::Eof => Token::Eof.fmt(f), - TokenOwned::Equal => Token::Equal.fmt(f), - TokenOwned::Float(float) => Token::Float(float).fmt(f), - TokenOwned::FloatKeyword => Token::FloatKeyword.fmt(f), - TokenOwned::Greater => Token::Greater.fmt(f), - TokenOwned::GreaterOrEqual => Token::GreaterEqual.fmt(f), - TokenOwned::Identifier(text) => Token::Identifier(text).fmt(f), - TokenOwned::If => Token::If.fmt(f), - TokenOwned::Int => Token::Int.fmt(f), - TokenOwned::Integer(integer) => Token::Integer(integer).fmt(f), - TokenOwned::LeftCurlyBrace => Token::LeftCurlyBrace.fmt(f), - TokenOwned::LeftParenthesis => Token::LeftParenthesis.fmt(f), - TokenOwned::LeftSquareBrace => Token::LeftSquareBrace.fmt(f), - TokenOwned::Let => Token::Let.fmt(f), - TokenOwned::Less => Token::Less.fmt(f), - TokenOwned::LessOrEqual => Token::LessEqual.fmt(f), - TokenOwned::Loop => Token::Loop.fmt(f), - TokenOwned::Map => Token::Map.fmt(f), - TokenOwned::Minus => Token::Minus.fmt(f), - TokenOwned::MinusEqual => Token::MinusEqual.fmt(f), - TokenOwned::Mut => Token::Mut.fmt(f), - TokenOwned::Percent => Token::Percent.fmt(f), - TokenOwned::Plus => Token::Plus.fmt(f), - TokenOwned::PlusEqual => Token::PlusEqual.fmt(f), - TokenOwned::RightCurlyBrace => Token::RightCurlyBrace.fmt(f), - TokenOwned::RightParenthesis => Token::RightParenthesis.fmt(f), - TokenOwned::RightSquareBrace => Token::RightSquareBrace.fmt(f), - TokenOwned::Semicolon => Token::Semicolon.fmt(f), - TokenOwned::Star => Token::Star.fmt(f), - TokenOwned::Slash => Token::Slash.fmt(f), - TokenOwned::Str => Token::Str.fmt(f), - TokenOwned::String(string) => Token::String(string).fmt(f), - TokenOwned::Struct => Token::Struct.fmt(f), - TokenOwned::While => Token::While.fmt(f), - } - } -} - -/// Token representation that holds no data. -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -pub enum TokenKind { - Eof, - - Identifier, - - // Hard-coded values - Boolean, - Character, - Float, - Integer, - String, - - // Keywords - Async, - Bool, - Break, - Else, - FloatKeyword, - If, - Int, - Let, - Loop, - Map, - Str, - While, - - // Symbols - BangEqual, - Bang, - Colon, - Comma, - Dot, - DoubleAmpersand, - DoubleDot, - DoubleEqual, - DoublePipe, - Equal, - Greater, - GreaterOrEqual, - LeftCurlyBrace, - LeftParenthesis, - LeftSquareBrace, - Less, - LessOrEqual, - Minus, - MinusEqual, - Mut, - Percent, - Plus, - PlusEqual, - RightCurlyBrace, - RightParenthesis, - RightSquareBrace, - Semicolon, - Star, - Struct, - Slash, -} - -impl Display for TokenKind { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - TokenKind::Async => Token::Async.fmt(f), - TokenKind::Bang => Token::Bang.fmt(f), - TokenKind::BangEqual => Token::BangEqual.fmt(f), - TokenKind::Bool => Token::Bool.fmt(f), - TokenKind::Boolean => write!(f, "boolean value"), - TokenKind::Break => Token::Break.fmt(f), - TokenKind::Character => write!(f, "character value"), - TokenKind::Colon => Token::Colon.fmt(f), - TokenKind::Comma => Token::Comma.fmt(f), - TokenKind::Dot => Token::Dot.fmt(f), - TokenKind::DoubleAmpersand => Token::DoubleAmpersand.fmt(f), - TokenKind::DoubleDot => Token::DoubleDot.fmt(f), - TokenKind::DoubleEqual => Token::DoubleEqual.fmt(f), - TokenKind::DoublePipe => Token::DoublePipe.fmt(f), - TokenKind::Else => Token::Else.fmt(f), - TokenKind::Eof => Token::Eof.fmt(f), - TokenKind::Equal => Token::Equal.fmt(f), - TokenKind::Float => write!(f, "float value"), - TokenKind::FloatKeyword => Token::FloatKeyword.fmt(f), - TokenKind::Greater => Token::Greater.fmt(f), - TokenKind::GreaterOrEqual => Token::GreaterEqual.fmt(f), - TokenKind::Identifier => write!(f, "identifier"), - TokenKind::If => Token::If.fmt(f), - TokenKind::Int => Token::Int.fmt(f), - TokenKind::Integer => write!(f, "integer value"), - TokenKind::LeftCurlyBrace => Token::LeftCurlyBrace.fmt(f), - TokenKind::LeftParenthesis => Token::LeftParenthesis.fmt(f), - TokenKind::LeftSquareBrace => Token::LeftSquareBrace.fmt(f), - TokenKind::Let => Token::Let.fmt(f), - TokenKind::Less => Token::Less.fmt(f), - TokenKind::LessOrEqual => Token::LessEqual.fmt(f), - TokenKind::Loop => Token::Loop.fmt(f), - TokenKind::Map => Token::Map.fmt(f), - TokenKind::Minus => Token::Minus.fmt(f), - TokenKind::MinusEqual => Token::MinusEqual.fmt(f), - TokenKind::Mut => Token::Mut.fmt(f), - TokenKind::Percent => Token::Percent.fmt(f), - TokenKind::Plus => Token::Plus.fmt(f), - TokenKind::PlusEqual => Token::PlusEqual.fmt(f), - TokenKind::RightCurlyBrace => Token::RightCurlyBrace.fmt(f), - TokenKind::RightParenthesis => Token::RightParenthesis.fmt(f), - TokenKind::RightSquareBrace => Token::RightSquareBrace.fmt(f), - TokenKind::Semicolon => Token::Semicolon.fmt(f), - TokenKind::Star => Token::Star.fmt(f), - TokenKind::Str => Token::Str.fmt(f), - TokenKind::Slash => Token::Slash.fmt(f), - TokenKind::String => write!(f, "string value"), - TokenKind::Struct => Token::Struct.fmt(f), - TokenKind::While => Token::While.fmt(f), - } - } -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - - pub fn all_tokens<'src>() -> [Token<'src>; 47] { - [ - Token::Async, - Token::Bang, - Token::BangEqual, - Token::Bool, - Token::Break, - Token::Colon, - Token::Comma, - Token::Dot, - Token::DoubleAmpersand, - Token::DoubleDot, - Token::DoubleEqual, - Token::DoublePipe, - Token::Else, - Token::Eof, - Token::Equal, - Token::FloatKeyword, - Token::Greater, - Token::GreaterEqual, - Token::If, - Token::Int, - Token::LeftCurlyBrace, - Token::LeftParenthesis, - Token::LeftSquareBrace, - Token::Let, - Token::Less, - Token::LessEqual, - Token::Map, - Token::Minus, - Token::MinusEqual, - Token::Mut, - Token::Percent, - Token::Plus, - Token::PlusEqual, - Token::RightCurlyBrace, - Token::RightParenthesis, - Token::RightSquareBrace, - Token::Semicolon, - Token::Star, - Token::Str, - Token::Slash, - Token::Boolean("true"), - Token::Float("0.0"), - Token::Integer("0"), - Token::String("string"), - Token::Identifier("foobar"), - Token::Struct, - Token::While, - ] - } - - #[test] - fn token_displays() { - for token in all_tokens().iter() { - let display = token.to_string(); - - assert_eq!(display, token.to_owned().to_string()); - - if let Token::Boolean(_) - | Token::Float(_) - | Token::Identifier(_) - | Token::Integer(_) - | Token::String(_) = token - { - continue; - } else { - assert_eq!(display, token.kind().to_string()); - } - } - } -} diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index 82ad9d6..5161f28 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::{Constructor, BuiltInFunction, Identifier}; +use crate::{Constructor, Identifier}; /// Description of a kind of value. /// @@ -258,7 +258,6 @@ impl Type { pub fn get_field_type(&self, field: &Identifier) -> Option { match field.as_str() { - "to_string" => Some(BuiltInFunction::ToString.r#type()), "length" => match self { Type::List { .. } => Some(Type::Integer), Type::ListOf { .. } => Some(Type::Integer), diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 767928b..c2b8a3a 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -14,10 +14,7 @@ use serde::{ Deserialize, Deserializer, Serialize, Serializer, }; -use crate::{ - AbstractSyntaxTree, BuiltInFunction, BuiltInFunctionError, Context, ContextError, EnumType, - FunctionType, Identifier, RangeableType, RuntimeError, StructType, Type, Vm, -}; +use crate::{EnumType, FunctionType, Identifier, RangeableType, StructType, Type}; /// Dust value representation /// @@ -98,10 +95,6 @@ impl Value { } } - pub fn function(value: Function) -> Self { - Value::Raw(ValueData::Function(value)) - } - pub fn range>(range: T) -> Self { Value::Raw(ValueData::Range(range.into())) } @@ -359,9 +352,6 @@ impl Value { ValueData::Float(float) => Some(Value::boolean(float % 2.0 != 0.0)), _ => None, }, - "to_string" => Some(Value::function(Function::BuiltIn( - BuiltInFunction::ToString, - ))), "length" => match data { ValueData::List(values) => Some(Value::integer(values.len() as i64)), ValueData::String(string) => Some(Value::integer(string.len() as i64)), @@ -934,7 +924,6 @@ pub enum ValueData { Character(char), Enum(Enum), Float(f64), - Function(Function), Integer(i64), List(Vec), Map(HashMap), @@ -952,15 +941,6 @@ impl ValueData { ValueData::Character(_) => Type::Character, ValueData::Enum(Enum { r#type, .. }) => Type::Enum(r#type.clone()), ValueData::Float(_) => Type::Float, - ValueData::Function(Function::BuiltIn(built_in_function)) => { - Type::Function(FunctionType { - name: Identifier::new(built_in_function.name()), - type_parameters: built_in_function.type_parameters(), - value_parameters: built_in_function.value_parameters(), - return_type: built_in_function.return_type().map(Box::new), - }) - } - ValueData::Function(Function::Parsed { r#type, .. }) => Type::Function(r#type.clone()), ValueData::Integer(_) => Type::Integer, ValueData::List(values) => { let item_type = values.first().unwrap().r#type(); @@ -1202,7 +1182,6 @@ impl Display for ValueData { Ok(()) } - ValueData::Function(function) => write!(f, "{function}"), ValueData::Integer(integer) => write!(f, "{integer}"), ValueData::Map(pairs) => { write!(f, "{{ ")?; @@ -1261,7 +1240,6 @@ impl PartialEq for ValueData { (ValueData::Byte(left), ValueData::Byte(right)) => left == right, (ValueData::Character(left), ValueData::Character(right)) => left == right, (ValueData::Float(left), ValueData::Float(right)) => left == right, - (ValueData::Function(left), ValueData::Function(right)) => left == right, (ValueData::Integer(left), ValueData::Integer(right)) => left == right, (ValueData::List(left), ValueData::List(right)) => left == right, (ValueData::Map(left), ValueData::Map(right)) => left == right, @@ -1291,8 +1269,6 @@ impl Ord for ValueData { (ValueData::Character(_), _) => Ordering::Greater, (ValueData::Float(left), ValueData::Float(right)) => left.partial_cmp(right).unwrap(), (ValueData::Float(_), _) => Ordering::Greater, - (ValueData::Function(left), ValueData::Function(right)) => left.cmp(right), - (ValueData::Function(_), _) => Ordering::Greater, (ValueData::Integer(left), ValueData::Integer(right)) => left.cmp(right), (ValueData::Integer(_), _) => Ordering::Greater, (ValueData::List(left), ValueData::List(right)) => left.cmp(right), @@ -1320,7 +1296,6 @@ impl Serialize for ValueData { ValueData::Character(character) => serializer.serialize_char(*character), ValueData::Enum(r#emum) => r#emum.serialize(serializer), ValueData::Float(float) => serializer.serialize_f64(*float), - ValueData::Function(function) => function.serialize(serializer), ValueData::Integer(integer) => serializer.serialize_i64(*integer), ValueData::List(list) => list.serialize(serializer), ValueData::Map(pairs) => { @@ -1385,11 +1360,9 @@ impl<'de> Deserialize<'de> for ValueData { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Function { - BuiltIn(BuiltInFunction), Parsed { name: Identifier, r#type: FunctionType, - body: AbstractSyntaxTree, }, } @@ -1398,92 +1371,8 @@ impl Function { self, _type_arguments: Option>, value_arguments: Option>, - context: &Context, - ) -> Result, FunctionCallError> { - match self { - Function::BuiltIn(built_in_function) => built_in_function - .call(_type_arguments, value_arguments) - .map_err(FunctionCallError::BuiltInFunction), - Function::Parsed { r#type, body, .. } => { - let new_context = - Context::with_data_from(context).map_err(FunctionCallError::Context)?; - - if let (Some(value_parameters), Some(value_arguments)) = - (&r#type.value_parameters, value_arguments) - { - for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) { - new_context - .set_variable_value(identifier.clone(), value) - .map_err(FunctionCallError::Context)?; - } - } - - Vm.run(body) - .map_err(|error| FunctionCallError::Runtime(Box::new(error))) - } - } - } -} - -impl Display for Function { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Function::BuiltIn(built_in_function) => write!(f, "{}", built_in_function), - Function::Parsed { name, r#type, body } => { - write!(f, "fn {}", name)?; - - if let Some(type_parameters) = &r#type.type_parameters { - write!(f, "<")?; - - for (index, type_parameter) in type_parameters.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{}", type_parameter)?; - } - - write!(f, ">")?; - } - - write!(f, "(")?; - - if let Some(value_paramers) = &r#type.value_parameters { - for (index, (identifier, r#type)) in value_paramers.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{identifier}: {type}")?; - } - } - - write!(f, ") {{")?; - - for statement in &body.statements { - write!(f, "{}", statement)?; - } - - write!(f, "}}") - } - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum FunctionCallError { - BuiltInFunction(BuiltInFunctionError), - Context(ContextError), - Runtime(Box), -} - -impl Display for FunctionCallError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - FunctionCallError::BuiltInFunction(error) => write!(f, "{}", error), - FunctionCallError::Context(error) => write!(f, "{}", error), - FunctionCallError::Runtime(error) => write!(f, "{}", error), - } + ) -> Result, ()> { + todo!() } } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs deleted file mode 100644 index b002cd5..0000000 --- a/dust-lang/src/vm.rs +++ /dev/null @@ -1,1850 +0,0 @@ -//! Virtual machine for running the abstract syntax tree. -//! -//! This module provides three running option: -//! - `run` convenience function that takes a source code string and runs it -//! - `run_with_context` convenience function that takes a source code string and a context -//! - `Vm` struct that can be used to run an abstract syntax tree -use std::{ - collections::HashMap, - fmt::{self, Display, Formatter}, - sync::{Arc, Mutex}, -}; - -use rayon::prelude::*; - -use crate::{ - ast::{ - AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression, - FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression, - LiteralExpression, LogicOperator, LoopExpression, MapExpression, MathOperator, Node, - OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement, - StructDefinition, StructExpression, - }, - parse, Analyzer, BuiltInFunctionError, ConstructError, Context, ContextData, ContextError, - DustError, Evaluation, Expression, Function, FunctionCallError, Identifier, ParseError, - StructType, Type, Value, ValueData, ValueError, -}; - -/// Run the source code and return the result. -/// -/// # Example -/// ``` -/// # use dust_lang::vm::run; -/// # use dust_lang::value::Value; -/// let result = run("40 + 2"); -/// -/// assert_eq!(result, Ok(Some(Value::integer(42)))); -/// ``` -pub fn run(source: &str) -> Result, DustError> { - let abstract_syntax_tree = parse(source)?; - let mut analyzer = Analyzer::new(&abstract_syntax_tree); - - analyzer.analyze()?; - - if !analyzer.errors.is_empty() { - return Err(DustError::Analysis { - analysis_errors: analyzer.errors, - source, - }); - } - - Vm.run(abstract_syntax_tree) - .map_err(|runtime_error| DustError::Runtime { - runtime_error, - source, - }) -} - -/// Dust virtual machine. -/// -/// See the `run` function for an example of how to parse, analyze and run code. -pub struct Vm; - -impl Vm { - pub fn run(&self, mut tree: AbstractSyntaxTree) -> Result, RuntimeError> { - let mut previous_evaluation = Evaluation::Return(None); - - while let Some(statement) = tree.statements.pop_front() { - let statement_end = statement.position().1; - - previous_evaluation = self.run_statement(statement, &tree.context, true)?; - - tree.context.collect_garbage(statement_end).unwrap(); - } - - match previous_evaluation { - Evaluation::Break(value_option) => Ok(value_option), - Evaluation::Return(value_option) => Ok(value_option), - _ => Ok(None), - } - } - - fn run_async(&self, tree: AbstractSyntaxTree) -> Result, RuntimeError> { - let final_result = Arc::new(Mutex::new(Evaluation::Return(None))); - let statements_length = tree.statements.len(); - - let error_option = - tree.statements - .into_par_iter() - .enumerate() - .find_map_any(|(i, statement)| { - let evaluation_result = self.run_statement(statement, &tree.context, false); - - match evaluation_result { - Ok(evaluation_option) => { - if i == statements_length - 1 { - let mut final_result = final_result.lock().unwrap(); - - *final_result = evaluation_option; - } - - None - } - Err(error) => Some(error), - } - }); - - if let Some(error) = error_option { - return Err(error); - } - - let final_result = final_result.lock().unwrap(); - - match &*final_result { - Evaluation::Break(value_option) => Ok(value_option.clone()), - Evaluation::Return(value_option) => Ok(value_option.clone()), - _ => Ok(None), - } - } - - fn run_statement( - &self, - statement: Statement, - context: &Context, - collect_garbage: bool, - ) -> Result { - log::trace!( - "Running statement at {:?}: {}", - statement.position(), - statement - ); - - let position = statement.position(); - let result = match statement { - Statement::Expression(expression) => { - Ok(self.run_expression(expression, context, collect_garbage)?) - } - Statement::ExpressionNullified(expression) => { - let evaluation = self.run_expression(expression.inner, context, collect_garbage)?; - - if let Evaluation::Break(_) = evaluation { - Ok(evaluation) - } else { - Ok(Evaluation::Return(None)) - } - } - Statement::Let(let_statement) => { - self.run_let_statement(let_statement.inner, context, collect_garbage)?; - - Ok(Evaluation::Return(None)) - } - Statement::StructDefinition(struct_definition) => { - let (name, struct_type) = match struct_definition.inner { - 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 { - name: name.inner, - fields, - }, - ) - } - StructDefinition::Fields { name, fields } => { - let fields = fields - .into_iter() - .map(|(identifier, r#type)| (identifier.inner, r#type.inner)) - .collect(); - - ( - name.inner.clone(), - StructType::Fields { - name: name.inner, - fields, - }, - ) - } - }; - let constructor = struct_type.constructor(); - - context - .set_constructor(name, constructor) - .map_err(|error| RuntimeError::ContextError { - error, - position: struct_definition.position, - })?; - - Ok(Evaluation::Return(None)) - } - }; - - result.map_err(|error| RuntimeError::Statement { - error: Box::new(error), - position, - }) - } - - fn run_let_statement( - &self, - let_statement: LetStatement, - context: &Context, - collect_garbage: bool, - ) -> Result<(), RuntimeError> { - match let_statement { - LetStatement::Let { identifier, value } => { - let position = value.position(); - let value = self - .run_expression(value, context, collect_garbage)? - .expect_value(position)?; - let new_value = match value { - Value::Mutable(_) => { - return Err(RuntimeError::CannotAssignToMutable { position }) - } - _ => value, - }; - - context - .set_variable_value(identifier.inner, new_value) - .map_err(|error| RuntimeError::ContextError { error, position })?; - - Ok(()) - } - LetStatement::LetMut { identifier, value } => { - let position = value.position(); - let mutable_value = self - .run_expression(value, context, collect_garbage)? - .expect_value(position)? - .into_mutable(); - - context - .set_variable_value(identifier.inner, mutable_value) - .map_err(|error| RuntimeError::ContextError { error, position })?; - - Ok(()) - } - LetStatement::LetType { .. } => todo!(), - LetStatement::LetMutType { .. } => todo!(), - } - } - - fn run_expression( - &self, - expression: Expression, - context: &Context, - collect_garbage: bool, - ) -> Result { - log::trace!( - "Running expression at {:?}: {}", - expression.position(), - expression - ); - - let position = expression.position(); - let evaluation_result = match expression { - Expression::Block(Node { inner, .. }) => { - self.run_block(*inner, context, collect_garbage) - } - Expression::Break(Node { inner, .. }) => { - let break_expression = if let Some(expression) = inner { - *expression - } else { - return Ok(Evaluation::Break(None)); - }; - let run_break = self.run_expression(break_expression, context, collect_garbage)?; - let evaluation = match run_break { - Evaluation::Break(value_option) => Evaluation::Break(value_option), - Evaluation::Return(value_option) => Evaluation::Break(value_option), - Evaluation::Constructor(_) => { - return Err(RuntimeError::ExpectedValue { position }) - } - }; - - Ok(evaluation) - } - Expression::Call(call) => self.run_call(*call.inner, context, collect_garbage), - Expression::Dereference(Node { inner, .. }) => { - let run_expression = self.run_expression(*inner, context, collect_garbage)?; - let evaluation = match run_expression { - Evaluation::Constructor(_) => { - return Err(RuntimeError::ExpectedValue { position }) - } - Evaluation::Return(value_option) => { - Evaluation::Return(value_option.map(|value| value.into_raw())) - } - Evaluation::Break(value_option) => { - Evaluation::Break(value_option.map(|value| value.into_raw())) - } - }; - - Ok(evaluation) - } - Expression::FieldAccess(field_access) => { - self.run_field_access(*field_access.inner, context, collect_garbage) - } - Expression::Grouped(expression) => { - self.run_expression(*expression.inner, context, collect_garbage) - } - Expression::Identifier(identifier) => self.run_identifier(identifier, context), - Expression::If(if_expression) => { - self.run_if(*if_expression.inner, context, collect_garbage) - } - Expression::List(list_expression) => { - self.run_list(*list_expression.inner, context, collect_garbage) - } - Expression::ListIndex(list_index) => { - self.run_list_index(*list_index.inner, context, collect_garbage) - } - Expression::Literal(literal) => self.run_literal(*literal.inner), - Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner, context), - Expression::Map(map_expression) => { - self.run_map(*map_expression.inner, context, collect_garbage) - } - Expression::Operator(operator_expression) => { - self.run_operator(*operator_expression.inner, context, collect_garbage) - } - Expression::Range(range_expression) => { - self.run_range(*range_expression.inner, context, collect_garbage) - } - Expression::Struct(struct_expression) => { - self.run_struct(*struct_expression.inner, context, collect_garbage) - } - Expression::TupleAccess(_) => todo!(), - }; - - evaluation_result.map_err(|error| { - if error.position() == position { - error - } else { - RuntimeError::Expression { - error: Box::new(error), - position, - } - } - }) - } - - fn run_identifier( - &self, - identifier: Node, - context: &Context, - ) -> Result { - let get_data = - context - .get_data(&identifier.inner) - .map_err(|error| RuntimeError::ContextError { - error, - position: identifier.position, - })?; - - if let Some(ContextData::VariableValue(value)) = get_data { - return Ok(Evaluation::Return(Some(value))); - } - - if let Some(ContextData::Constructor(constructor)) = get_data { - let construct_result = constructor.construct_unit(); - - return match construct_result { - Ok(value) => Ok(Evaluation::Return(Some(value))), - Err(ConstructError::ExpectedUnit) => Ok(Evaluation::Constructor(constructor)), - Err(error) => Err(RuntimeError::ConstructError { - error, - position: identifier.position, - }), - }; - } - - Err(RuntimeError::UnassociatedIdentifier { - identifier: identifier.inner, - position: identifier.position, - }) - } - - fn run_struct( - &self, - struct_expression: StructExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - let StructExpression::Fields { name, fields } = struct_expression; - - let position = name.position; - let constructor = context - .get_constructor(&name.inner) - .map_err(|error| RuntimeError::ContextError { error, position })?; - - if let Some(constructor) = constructor { - let mut arguments = HashMap::with_capacity(fields.len()); - - for (identifier, expression) in fields { - let position = expression.position(); - let value = self - .run_expression(expression, context, collect_garbage)? - .expect_value(position)?; - - arguments.insert(identifier.inner, value); - } - - let value = constructor - .construct_fields(arguments.clone()) - .map_err(|error| RuntimeError::ConstructError { error, position })?; - - Ok(Evaluation::Return(Some(value))) - } else { - Err(RuntimeError::ExpectedConstructor { position }) - } - } - - fn run_range( - &self, - range: RangeExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - match range { - RangeExpression::Exclusive { start, end } => { - let start_position = start.position(); - let start = self - .run_expression(start, context, collect_garbage)? - .expect_value(start_position)?; - - let start_data = match start { - Value::Raw(data) => data, - Value::Reference(reference) => reference.as_ref().clone(), - Value::Mutable(locked) => locked.read().unwrap().clone(), - }; - let end_position = end.position(); - let end = self - .run_expression(end, context, collect_garbage)? - .expect_value(end_position)?; - let end_data = match end { - Value::Raw(data) => data, - Value::Reference(reference) => reference.as_ref().clone(), - Value::Mutable(locked) => locked.read().unwrap().clone(), - }; - - match (start_data, end_data) { - (ValueData::Byte(start), ValueData::Byte(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..end)))) - } - (ValueData::Character(start), ValueData::Character(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..end)))) - } - (ValueData::Float(start), ValueData::Float(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..end)))) - } - (ValueData::Integer(start), ValueData::Integer(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..end)))) - } - _ => Err(RuntimeError::InvalidRange { - start_position, - end_position, - }), - } - } - RangeExpression::Inclusive { start, end } => { - let start_position = start.position(); - let start = self - .run_expression(start, context, collect_garbage)? - .expect_value(start_position)?; - - let start_data = match start { - Value::Raw(data) => data, - Value::Reference(reference) => reference.as_ref().clone(), - Value::Mutable(locked) => locked.read().unwrap().clone(), - }; - let end_position = end.position(); - let end = self - .run_expression(end, context, collect_garbage)? - .expect_value(end_position)?; - let end_data = match end { - Value::Raw(data) => data, - Value::Reference(reference) => reference.as_ref().clone(), - Value::Mutable(locked) => locked.read().unwrap().clone(), - }; - - match (start_data, end_data) { - (ValueData::Byte(start), ValueData::Byte(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..=end)))) - } - (ValueData::Character(start), ValueData::Character(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..=end)))) - } - (ValueData::Float(start), ValueData::Float(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..=end)))) - } - (ValueData::Integer(start), ValueData::Integer(end)) => { - Ok(Evaluation::Return(Some(Value::range(start..=end)))) - } - _ => Err(RuntimeError::InvalidRange { - start_position, - end_position, - }), - } - } - } - } - - fn run_map( - &self, - map: MapExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - let MapExpression { pairs } = map; - - let mut map = HashMap::new(); - - for (identifier, expression) in pairs { - let expression_position = expression.position(); - let value = self - .run_expression(expression, context, collect_garbage)? - .expect_value(expression_position)?; - - map.insert(identifier.inner, value); - } - - Ok(Evaluation::Return(Some(Value::map(map)))) - } - - fn run_operator( - &self, - operator: OperatorExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - match operator { - OperatorExpression::Assignment { assignee, value } => { - let assignee_position = assignee.position(); - let assignee = self - .run_expression(assignee, context, collect_garbage)? - .expect_value(assignee_position)?; - let value_position = value.position(); - let value = self - .run_expression(value, context, collect_garbage)? - .expect_value(value_position)?; - - assignee - .mutate(value) - .map_err(|error| RuntimeError::ValueError { - error, - left_position: assignee_position, - right_position: value_position, - })?; - - Ok(Evaluation::Return(None)) - } - OperatorExpression::Comparison { - left, - operator, - right, - } => { - let left_position = left.position(); - let left_value = self - .run_expression(left, context, collect_garbage)? - .expect_value(left_position)?; - let right_position = right.position(); - let right_value = self - .run_expression(right, context, collect_garbage)? - .expect_value(right_position)?; - let result = match operator.inner { - ComparisonOperator::Equal => left_value.equal(&right_value), - ComparisonOperator::NotEqual => left_value.not_equal(&right_value), - ComparisonOperator::GreaterThan => left_value.greater_than(&right_value), - ComparisonOperator::GreaterThanOrEqual => { - left_value.greater_than_or_equal(&right_value) - } - ComparisonOperator::LessThan => left_value.less_than(&right_value), - ComparisonOperator::LessThanOrEqual => { - left_value.less_than_or_equal(&right_value) - } - }; - let value = result.map_err(|error| RuntimeError::ValueError { - error, - left_position, - right_position, - })?; - - Ok(Evaluation::Return(Some(value))) - } - OperatorExpression::CompoundAssignment { - assignee, - operator, - modifier, - } => { - let assignee_position = assignee.position(); - let assignee = self - .run_expression(assignee, context, collect_garbage)? - .expect_value(assignee_position)?; - let modifier_position = modifier.position(); - let modifier = self - .run_expression(modifier, context, collect_garbage)? - .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| RuntimeError::ValueError { - error, - left_position: assignee_position, - right_position: modifier_position, - })?; - - Ok(Evaluation::Return(None)) - } - OperatorExpression::ErrorPropagation(_) => todo!(), - OperatorExpression::Negation(expression) => { - let position = expression.position(); - let value = self - .run_expression(expression, context, collect_garbage)? - .expect_value(position)?; - let negated = value.negate().map_err(|error| RuntimeError::ValueError { - error, - left_position: position, - right_position: position, - })?; - - Ok(Evaluation::Return(Some(negated))) - } - OperatorExpression::Not(expression) => { - let position = expression.position(); - let value = self - .run_expression(expression, context, collect_garbage)? - .expect_value(position)?; - let not = value.not().map_err(|error| RuntimeError::ValueError { - error, - left_position: position, - right_position: position, - })?; - - Ok(Evaluation::Return(Some(not))) - } - OperatorExpression::Math { - left, - operator, - right, - } => { - let left_position = left.position(); - let left_value = self - .run_expression(left, context, collect_garbage)? - .expect_value(left_position)?; - let right_position = right.position(); - let right_value = self - .run_expression(right, context, collect_garbage)? - .expect_value(right_position)?; - let outcome = match operator.inner { - MathOperator::Add => left_value.add(&right_value), - MathOperator::Subtract => left_value.subtract(&right_value), - MathOperator::Multiply => left_value.multiply(&right_value), - MathOperator::Divide => left_value.divide(&right_value), - MathOperator::Modulo => left_value.modulo(&right_value), - } - .map_err(|value_error| RuntimeError::ValueError { - error: value_error, - left_position, - right_position, - })?; - - Ok(Evaluation::Return(Some(outcome))) - } - OperatorExpression::Logic { - left, - operator, - right, - } => { - let left_position = left.position(); - let left_value = self - .run_expression(left, context, collect_garbage)? - .expect_value(left_position)?; - let right_position = right.position(); - let right_value = self - .run_expression(right, context, collect_garbage)? - .expect_value(right_position)?; - let outcome = match operator.inner { - LogicOperator::And => left_value.and(&right_value), - LogicOperator::Or => left_value.or(&right_value), - } - .map_err(|value_error| RuntimeError::ValueError { - error: value_error, - left_position, - right_position, - })?; - - Ok(Evaluation::Return(Some(outcome))) - } - } - } - - fn run_loop( - &self, - loop_expression: LoopExpression, - context: &Context, - ) -> Result { - match loop_expression { - LoopExpression::Infinite { - block: Node { inner, .. }, - } => match inner { - BlockExpression::Sync(ast) => 'outer: loop { - for statement in ast.statements.clone() { - let evaluation = self.run_statement(statement, &ast.context, false)?; - - if let Evaluation::Break(value_option) = evaluation { - break 'outer Ok(Evaluation::Return(value_option)); - } - } - }, - BlockExpression::Async(_) => todo!(), - }, - LoopExpression::While { condition, block } => { - while self - .run_expression(condition.clone(), context, false)? - .expect_value(condition.position())? - .as_boolean() - .ok_or_else(|| RuntimeError::ExpectedBoolean { - position: condition.position(), - })? - { - self.run_block(block.inner.clone(), context, false)?; - } - - Ok(Evaluation::Return(None)) - } - LoopExpression::For { .. } => todo!(), - } - } - - fn run_literal(&self, literal: LiteralExpression) -> Result { - let value = match literal { - LiteralExpression::BuiltInFunction(built_in_function) => { - Value::function(Function::BuiltIn(built_in_function)) - } - LiteralExpression::String(string) => Value::string(string), - LiteralExpression::Primitive(primitive_expression) => match primitive_expression { - PrimitiveValueExpression::Boolean(boolean) => Value::boolean(boolean), - PrimitiveValueExpression::Character(character) => Value::character(character), - PrimitiveValueExpression::Integer(integer) => Value::integer(integer), - PrimitiveValueExpression::Float(float) => Value::float(float), - }, - }; - - Ok(Evaluation::Return(Some(value))) - } - - fn run_list_index( - &self, - list_index: ListIndexExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - let ListIndexExpression { list, index } = list_index; - - let list_position = list.position(); - let list_value = self - .run_expression(list, context, collect_garbage)? - .expect_value(list_position)?; - - let index_position = index.position(); - let index_value = self - .run_expression(index, context, collect_garbage)? - .expect_value(index_position)?; - - let get_index = - list_value - .index(&index_value) - .map_err(|error| RuntimeError::ValueError { - error, - left_position: list_position, - right_position: index_position, - })?; - - Ok(Evaluation::Return(Some(get_index))) - } - - fn run_call( - &self, - call_expression: CallExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - let CallExpression { invoker, arguments } = call_expression; - let invoker_position = invoker.position(); - - if let Expression::FieldAccess(field_access) = invoker { - let FieldAccessExpression { container, field } = *field_access.inner; - - let container_position = container.position(); - let container_value = self - .run_expression(container, context, collect_garbage)? - .expect_value(container_position)?; - - let function = if let Some(value) = container_value.get_field(&field.inner) { - match value { - Value::Raw(ValueData::Function(function)) => function, - Value::Reference(arc) => match arc.as_ref().clone() { - ValueData::Function(function) => function, - _ => { - return Err(RuntimeError::ExpectedFunction { - position: container_position, - actual: container_value, - }); - } - }, - Value::Mutable(locked) => match locked.read().unwrap().clone() { - ValueData::Function(function) => function, - _ => { - return Err(RuntimeError::ExpectedFunction { - position: container_position, - actual: container_value, - }); - } - }, - _ => { - return Err(RuntimeError::ExpectedFunction { - position: container_position, - actual: container_value, - }); - } - } - } else { - return Err(RuntimeError::UndefinedField { - value: container_value, - value_position: container_position, - field: field.inner, - field_position: field.position, - }); - }; - - let mut value_arguments = vec![container_value]; - - for argument in arguments { - let position = argument.position(); - let value = self - .run_expression(argument, context, collect_garbage)? - .expect_value(position)?; - - value_arguments.push(value); - } - - let context = Context::new(); - - return function - .call(None, Some(value_arguments), &context) - .map(Evaluation::Return) - .map_err(|error| RuntimeError::FunctionCall { - error, - position: invoker_position, - }); - } - - let invoker_position = invoker.position(); - let run_invoker = self.run_expression(invoker, context, collect_garbage)?; - - match run_invoker { - Evaluation::Constructor(constructor) => { - let mut fields = Vec::new(); - - for argument in arguments { - let position = argument.position(); - - if let Some(value) = self - .run_expression(argument, context, collect_garbage)? - .value() - { - fields.push(value); - } else { - return Err(RuntimeError::ExpectedValue { position }); - } - } - - let value = constructor.construct_tuple(fields).map_err(|error| { - RuntimeError::ConstructError { - error, - position: invoker_position, - } - })?; - - Ok(Evaluation::Return(Some(value))) - } - Evaluation::Return(Some(value)) => { - let function = match value { - Value::Raw(ValueData::Function(function)) => function, - Value::Reference(arc) => match arc.as_ref() { - ValueData::Function(function) => function.clone(), - _ => { - return Err(RuntimeError::ExpectedFunction { - position: invoker_position, - actual: Value::Reference(arc.clone()), - }); - } - }, - Value::Mutable(locked) => match locked.read().unwrap().clone() { - ValueData::Function(function) => function, - _ => { - return Err(RuntimeError::ExpectedFunction { - position: invoker_position, - actual: Value::Mutable(locked.clone()), - }); - } - }, - _ => { - return Err(RuntimeError::ExpectedFunction { - position: invoker_position, - actual: value, - }); - } - }; - - let mut value_arguments: Option> = None; - - for argument in arguments { - let position = argument.position(); - let value = self - .run_expression(argument, context, collect_garbage)? - .expect_value(position)?; - - if let Some(value_arguments) = &mut value_arguments { - value_arguments.push(value); - } else { - value_arguments = Some(vec![value]); - } - } - - let context = Context::new(); - - function - .call(None, value_arguments, &context) - .map(Evaluation::Return) - .map_err(|error| RuntimeError::FunctionCall { - error, - position: invoker_position, - }) - } - _ => Err(RuntimeError::ExpectedValueOrConstructor { - position: invoker_position, - }), - } - } - - fn run_field_access( - &self, - field_access: FieldAccessExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - let FieldAccessExpression { container, field } = field_access; - - let container_position = container.position(); - let container_value = if let Some(value) = self - .run_expression(container, context, collect_garbage)? - .value() - { - value - } else { - return Err(RuntimeError::ExpectedValue { - position: container_position, - }); - }; - - Ok(Evaluation::Return(container_value.get_field(&field.inner))) - } - - fn run_list( - &self, - list_expression: ListExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - match list_expression { - ListExpression::AutoFill { - repeat_operand, - length_operand, - } => { - let position = length_operand.position(); - let length = self - .run_expression(length_operand, context, collect_garbage)? - .expect_value(position)? - .as_integer() - .ok_or(RuntimeError::ExpectedInteger { position })?; - - let position = repeat_operand.position(); - let value = self - .run_expression(repeat_operand, context, collect_garbage)? - .expect_value(position)?; - - Ok(Evaluation::Return(Some(Value::list(vec![ - value; - length as usize - ])))) - } - ListExpression::Ordered(expressions) => { - let mut values = Vec::with_capacity(expressions.len()); - - for expression in expressions { - let position = expression.position(); - let value = self - .run_expression(expression, context, collect_garbage)? - .expect_value(position)?; - - values.push(value); - } - - Ok(Evaluation::Return(Some(Value::list(values)))) - } - } - } - - fn run_block( - &self, - block: BlockExpression, - _context: &Context, - collect_garbage: bool, - ) -> Result { - match block { - BlockExpression::Async(ast) => Vm.run_async(ast).map(Evaluation::Return), - BlockExpression::Sync(ast) => { - let mut evaluation = Evaluation::Return(None); - - for statement in ast.statements { - let position = statement.position(); - evaluation = Vm.run_statement(statement, &ast.context, collect_garbage)?; - - ast.context - .collect_garbage(position.1) - .map_err(|error| RuntimeError::ContextError { error, position })?; - - if let Evaluation::Break(_) = evaluation { - return Ok(evaluation); - } - } - - Ok(evaluation) - } - } - } - - fn run_if( - &self, - if_expression: IfExpression, - context: &Context, - collect_garbage: bool, - ) -> Result { - match if_expression { - IfExpression::If { - condition, - if_block, - } => { - let position = condition.position(); - let boolean = self - .run_expression(condition, context, collect_garbage)? - .expect_value(position)? - .as_boolean() - .ok_or(RuntimeError::ExpectedBoolean { position })?; - - if boolean { - let evaluation = self.run_block(if_block.inner, context, collect_garbage)?; - - if let Evaluation::Break(_) = evaluation { - return Ok(evaluation); - } - } - - Ok(Evaluation::Return(None)) - } - IfExpression::IfElse { - condition, - if_block, - r#else, - } => { - let position = condition.position(); - let boolean = self - .run_expression(condition, context, collect_garbage)? - .expect_value(position)? - .as_boolean() - .ok_or(RuntimeError::ExpectedBoolean { position })?; - - if boolean { - self.run_block(if_block.inner, context, collect_garbage) - } else { - match r#else { - ElseExpression::If(if_expression) => { - self.run_if(*if_expression.inner, context, collect_garbage) - } - ElseExpression::Block(block) => { - self.run_block(block.inner, context, collect_garbage) - } - } - } - } - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum RuntimeError { - CannotAssignToMutable { - position: Span, - }, - ConstructError { - error: ConstructError, - position: Span, - }, - ContextError { - error: ContextError, - position: Span, - }, - FunctionCall { - error: FunctionCallError, - position: Span, - }, - ParseError(ParseError), - Expression { - error: Box, - position: Span, - }, - Statement { - error: Box, - position: Span, - }, - ValueError { - error: ValueError, - left_position: Span, - right_position: Span, - }, - BuiltInFunctionError { - error: BuiltInFunctionError, - position: Span, - }, - EnumVariantNotFound { - identifier: Identifier, - position: Span, - }, - ExpectedBoolean { - position: Span, - }, - ExpectedConstructor { - position: Span, - }, - ExpectedFieldsConstructor { - position: Span, - }, - ExpectedIdentifier { - position: Span, - }, - ExpectedIntegerOrRange { - position: Span, - }, - ExpectedIdentifierOrString { - position: Span, - }, - ExpectedInteger { - position: Span, - }, - ExpectedNumber { - position: Span, - }, - ExpectedMap { - position: Span, - }, - ExpectedType { - expected: Type, - actual: Type, - position: Span, - }, - ExpectedFunction { - actual: Value, - position: Span, - }, - ExpectedList { - position: Span, - }, - ExpectedValue { - position: Span, - }, - ExpectedValueOrConstructor { - position: Span, - }, - InvalidRange { - start_position: Span, - end_position: Span, - }, - UnassociatedIdentifier { - identifier: Identifier, - position: Span, - }, - UndefinedType { - identifier: Identifier, - position: Span, - }, - UndefinedField { - value: Value, - value_position: Span, - field: Identifier, - field_position: Span, - }, -} - -impl RuntimeError { - pub fn position(&self) -> Span { - match self { - Self::CannotAssignToMutable { position } => *position, - Self::ConstructError { position, .. } => *position, - Self::ContextError { position, .. } => *position, - Self::BuiltInFunctionError { position, .. } => *position, - Self::FunctionCall { position, .. } => *position, - Self::UnassociatedIdentifier { position, .. } => *position, - Self::ParseError(parse_error) => parse_error.position(), - Self::Expression { position, .. } => *position, - Self::Statement { position, .. } => *position, - Self::ValueError { - left_position, - right_position, - .. - } => (left_position.0, right_position.1), - Self::EnumVariantNotFound { position, .. } => *position, - Self::ExpectedBoolean { position } => *position, - Self::ExpectedConstructor { position, .. } => *position, - Self::ExpectedFieldsConstructor { position } => *position, - Self::ExpectedFunction { position, .. } => *position, - Self::ExpectedIdentifier { position } => *position, - Self::ExpectedIdentifierOrString { position } => *position, - Self::ExpectedInteger { position } => *position, - Self::ExpectedIntegerOrRange { position } => *position, - Self::ExpectedList { position } => *position, - Self::ExpectedMap { position } => *position, - Self::ExpectedNumber { position } => *position, - Self::ExpectedType { position, .. } => *position, - Self::ExpectedValue { position } => *position, - Self::ExpectedValueOrConstructor { position } => *position, - Self::InvalidRange { - start_position, - end_position, - .. - } => (start_position.0, end_position.1), - Self::UndefinedType { position, .. } => *position, - Self::UndefinedField { field_position, .. } => *field_position, - } - } - - pub fn root_error(&self) -> &Self { - match self { - Self::Expression { error, .. } => error.root_error(), - Self::Statement { error, .. } => error.root_error(), - error => error, - } - } -} - -impl From for RuntimeError { - fn from(error: ParseError) -> Self { - Self::ParseError(error) - } -} - -impl Display for RuntimeError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::CannotAssignToMutable { position } => { - write!( - f, - "Cannot use immutable assignment with a mutable value at {:?}", - position - ) - } - Self::ConstructError { error, position } => { - write!(f, "Constructor error at {:?}: {}", position, error) - } - Self::ContextError { error, position } => { - write!(f, "Context error at {:?}: {}", position, error) - } - Self::FunctionCall { error, position } => { - write!(f, "Function call error at {:?}: {}", position, error) - } - Self::ParseError(parse_error) => write!(f, "{}", parse_error), - Self::Expression { .. } => { - write!(f, "Error while running expression") - } - Self::Statement { error, position } => { - write!( - f, - "Error while running statement at {:?}: {}", - position, error - ) - } - Self::ValueError { - error, - left_position, - right_position, - } => { - write!( - f, - "Value error with values at positions: {:?} and {:?} {}", - left_position, right_position, error - ) - } - 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 { position } => { - write!(f, "Expected a constructor at position: {:?}", position) - } - Self::ExpectedFieldsConstructor { position } => { - write!( - f, - "Expected a fields constructor at position: {:?}", - position - ) - } - Self::ExpectedFunction { actual, position } => { - write!( - f, - "Expected a function, but got {} at position: {:?}", - actual, position - ) - } - Self::ExpectedIdentifier { position } => { - write!(f, "Expected an identifier at position: {:?}", position) - } - Self::ExpectedIdentifierOrString { position } => { - write!( - f, - "Expected an identifier or string at position: {:?}", - position - ) - } - Self::ExpectedIntegerOrRange { position } => { - write!( - f, - "Expected an identifier, integer, or range at position: {:?}", - position - ) - } - Self::ExpectedInteger { position } => { - write!(f, "Expected an integer at position: {:?}", position) - } - Self::ExpectedList { position } => { - write!(f, "Expected a list at position: {:?}", position) - } - Self::ExpectedType { - expected, - actual, - position, - } => { - write!( - f, - "Expected type {}, but got {} at position: {:?}", - expected, actual, position - ) - } - Self::ExpectedMap { position } => { - write!(f, "Expected a map at position: {:?}", position) - } - Self::ExpectedNumber { position } => { - write!( - f, - "Expected an integer or float at position: {:?}", - position - ) - } - Self::ExpectedValue { position } => { - write!(f, "Expected a value at position: {:?}", position) - } - Self::ExpectedValueOrConstructor { position } => { - write!( - f, - "Expected a value or constructor at position: {:?}", - position - ) - } - Self::InvalidRange { - start_position, - end_position, - } => { - write!( - f, - "Invalid range with start position: {:?} and end position: {:?}", - start_position, end_position - ) - } - Self::UnassociatedIdentifier { identifier, .. } => { - write!( - f, - "Identifier \"{identifier}\" is not associated with a value or constructor" - ) - } - Self::UndefinedField { - value, - field: property, - .. - } => { - write!(f, "Value {} does not have the field {}", value, property) - } - Self::UndefinedType { - identifier, - position, - } => { - write!( - f, - "Undefined type {} at position: {:?}", - identifier, position - ) - } - } - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use crate::Struct; - - use super::*; - - #[test] - fn dereference_deep_copy() { - let source = "let mut x = 42; let mut y = *x; y += 1; x"; - - assert_eq!(run(source), Ok(Some(Value::integer(42)))); - } - - #[test] - fn dereference_variable() { - let source = "let x = 42; let y = x; *y"; - - assert!(run(source).unwrap().unwrap().is_raw()); - } - - #[test] - fn dereference_copied_variable() { - let source = "let mut x = 42; let y = [*x; 3]; x += 1; y"; - - assert_eq!( - run(source), - Ok(Some(Value::list([42.into(), 42.into(), 42.into()]))) - ); - } - - #[test] - fn auto_fill_list() { - let source = "[42; 3]"; - - assert_eq!( - run(source), - Ok(Some(Value::list(vec![ - Value::integer(42), - Value::integer(42), - Value::integer(42) - ]))) - ); - } - - #[test] - fn dereference_mutable_variable() { - let source = "let mut x = 42; let y = *x; x += 1; y"; - - assert_eq!(run(source), Ok(Some(Value::integer(42)))); - } - - #[test] - fn assign_to_variable() { - let source = "let x = 42; let y = x; y"; - - assert_eq!(run(source), Ok(Some(Value::integer(42)))); - } - - #[test] - fn character() { - let input = "'a'"; - - assert_eq!(run(input), Ok(Some(Value::character('a')))); - } - - #[test] - fn break_loop() { - let input = "let mut x = 0; loop { x += 1; if x == 10 { break; } } x"; - - assert_eq!(run(input), Ok(Some(Value::integer(10)))); - } - - #[test] - fn string_index() { - let input = "\"foo\"[0]"; - - assert_eq!(run(input), Ok(Some(Value::character('f')))); - } - - #[test] - fn map_expression() { - let input = "let x = map { foo = 42, bar = 4.2 }; x"; - - assert_eq!( - run(input), - Ok(Some(Value::map([ - (Identifier::new("foo"), Value::integer(42)), - (Identifier::new("bar"), Value::float(4.2)) - ]))) - ); - } - - #[test] - fn async_block() { - let input = "let mut x = 1; async { x += 1; x -= 1; } x"; - - assert_eq!(run(input), Ok(Some(Value::mutable(Value::integer(1))))); - } - - #[test] - fn define_and_instantiate_fields_struct() { - let input = "struct Foo { bar: int, baz: float } Foo { bar: 42, baz: 4.0 }"; - - assert_eq!( - run(input), - Ok(Some(Value::r#struct(Struct::Fields { - name: Identifier::new("Foo"), - fields: HashMap::from([ - (Identifier::new("bar"), Value::integer(42)), - (Identifier::new("baz"), Value::float(4.0)) - ]) - }))) - ); - } - - #[test] - fn assign_tuple_struct_variable() { - let input = " - struct Foo(int); - let x = Foo(42); - x - "; - - assert_eq!( - run(input), - Ok(Some(Value::r#struct(Struct::Tuple { - name: Identifier::new("Foo"), - fields: vec![Value::integer(42)] - }))) - ) - } - - #[test] - fn define_and_instantiate_tuple_struct() { - let input = "struct Foo(int); Foo(42)"; - - assert_eq!( - run(input), - Ok(Some(Value::r#struct(Struct::Tuple { - name: Identifier::new("Foo"), - fields: vec![Value::integer(42)] - }))) - ); - } - - #[test] - fn assign_unit_struct_variable() { - let input = " - struct Foo; - let x = Foo; - x - "; - - assert_eq!( - run(input), - Ok(Some(Value::r#struct(Struct::Unit { - name: Identifier::new("Foo") - }))) - ) - } - - #[test] - fn define_and_instantiate_unit_struct() { - let input = "struct Foo; Foo"; - - assert_eq!( - run(input), - Ok(Some(Value::r#struct(Struct::Unit { - name: Identifier::new("Foo") - }))) - ); - } - - #[test] - fn list_index_nested() { - let input = "[[1, 2], [42, 4], [5, 6]][1][0]"; - - assert_eq!(run(input), Ok(Some(Value::integer(42)))); - } - - #[test] - fn list_index_range() { - let input = "[1, 2, 3, 4, 5][1..3]"; - - assert_eq!( - run(input), - Ok(Some(Value::list(vec![ - Value::integer(2), - Value::integer(3) - ]))) - ); - } - - #[test] - fn range() { - let input = "1..5"; - - assert_eq!(run(input), Ok(Some(Value::range(1..5)))); - } - - #[test] - fn negate_expression() { - let input = "let x = -42; -x"; - - assert_eq!(run(input), Ok(Some(Value::integer(42)))); - } - - #[test] - fn not_expression() { - let input = "!(1 == 2 || 3 == 4 || 5 == 6)"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn list_index() { - let input = "[1, 42, 3][1]"; - - assert_eq!(run(input), Ok(Some(Value::integer(42)))); - } - - #[test] - fn map_property_access() { - let input = "map { a = 42 }.a"; - - assert_eq!(run(input), Ok(Some(Value::integer(42)))); - } - - #[test] - fn to_string() { - let input = "42.to_string()"; - - assert_eq!(run(input), Ok(Some(Value::string("42")))); - } - - #[test] - fn r#if() { - let input = "if true { 1 }"; - - assert_eq!(run(input), Ok(None)); - } - - #[test] - fn if_else() { - let input = "let x = if false { 1 } else { 2 }; x"; - - assert_eq!(run(input), Ok(Some(Value::integer(2)))); - } - - #[test] - fn if_else_if() { - let input = "if false { 1 } else if true { 2 }"; - - assert_eq!(run(input), Ok(None)); - } - - #[test] - fn if_else_if_else() { - let input = "if false { 1 } else if false { 2 } else { 3 }"; - - assert_eq!(run(input), Ok(Some(Value::integer(3)))); - } - - #[test] - fn while_loop() { - 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 = "let mut x = 1; x -= 1; x"; - - assert_eq!(run(input), Ok(Some(Value::integer(0)))); - } - - #[test] - fn add_assign() { - let input = "let mut x = 1; x += 1; x"; - - assert_eq!(run(input), Ok(Some(Value::integer(2)))); - } - - #[test] - fn and() { - let input = "true && true"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn or() { - let input = "true || false"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn integer_equal() { - let input = "42 == 42"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn modulo() { - let input = "42 % 2"; - - assert_eq!(run(input), Ok(Some(Value::integer(0)))); - } - - #[test] - fn divide() { - let input = "42 / 2"; - - assert_eq!(run(input), Ok(Some(Value::integer(21)))); - } - - #[test] - fn less_than() { - let input = "2 < 3"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn less_than_or_equal() { - let input = "42 <= 42"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn greater_than() { - let input = "2 > 3"; - - assert_eq!(run(input), Ok(Some(Value::boolean(false)))); - } - - #[test] - fn greater_than_or_equal() { - let input = "42 >= 42"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn integer_saturating_add() { - let input = "9223372036854775807 + 1"; - - assert_eq!(run(input), Ok(Some(Value::integer(i64::MAX)))); - } - - #[test] - fn integer_saturating_sub() { - let input = "-9223372036854775808 - 1"; - - assert_eq!(run(input), Ok(Some(Value::integer(i64::MIN)))); - } - - #[test] - fn multiply() { - let input = "2 * 3"; - - assert_eq!(run(input), Ok(Some(Value::integer(6)))); - } - - #[test] - fn boolean() { - let input = "true"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn is_even() { - let input = "42.is_even"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - - #[test] - fn is_odd() { - let input = "42.is_odd"; - - assert_eq!(run(input), Ok(Some(Value::boolean(false)))); - } - - #[test] - fn list_length() { - let input = "[1, 2, 3].length"; - - assert_eq!(run(input), Ok(Some(Value::integer(3)))); - } - - #[test] - fn string_length() { - let input = "\"hello\".length"; - - assert_eq!(run(input), Ok(Some(Value::integer(5)))); - } - - #[test] - fn map_length() { - let input = "map { a = 42, b = 4.0 }.length"; - - assert_eq!(run(input), Ok(Some(Value::integer(2)))); - } - - #[test] - fn add() { - let input = "1 + 2"; - - assert_eq!(run(input), Ok(Some(Value::integer(3)))); - } - - #[test] - fn add_multiple() { - let input = "1 + 2 + 3"; - - assert_eq!(run(input), Ok(Some(Value::integer(6)))); - } -} diff --git a/dust-lang/tests/scopes.rs b/dust-lang/tests/scopes.rs deleted file mode 100644 index c27e39e..0000000 --- a/dust-lang/tests/scopes.rs +++ /dev/null @@ -1,47 +0,0 @@ -use dust_lang::*; - -#[test] -fn block_scope_captures_parent() { - let source = "let x = 42; { x }"; - - assert_eq!(run(source), Ok(Some(Value::integer(42)))); -} - -#[test] -fn block_scope_does_not_capture_child() { - env_logger::builder().is_test(true).try_init().unwrap(); - - let source = "{ let x = 42; } x"; - - assert_eq!( - run(source), - Err(DustError::analysis( - [AnalysisError::UndefinedVariable { - identifier: Node::new(Identifier::new("x"), (16, 17)) - }], - source - )) - ); -} - -#[test] -fn block_scope_does_not_capture_sibling() { - let source = "{ let x = 42; } { x }"; - - assert_eq!( - run(source), - Err(DustError::analysis( - [AnalysisError::UndefinedVariable { - identifier: Node::new(Identifier::new("x"), (18, 19)) - }], - source - )) - ); -} - -#[test] -fn block_scope_does_not_pollute_parent() { - let source = "let x = 42; { let x = \"foo\"; let x = \"bar\"; } x"; - - assert_eq!(run(source), Ok(Some(Value::integer(42)))); -} diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index d31553d..06dd3f1 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -1,7 +1,6 @@ use std::fs::read_to_string; use clap::Parser; -use dust_lang::run; #[derive(Parser)] struct Cli { @@ -37,19 +36,9 @@ fn main() { } fn parse_and_display_errors(source: &str) { - match dust_lang::parse(source) { - Ok(ast) => println!("{:#?}", ast), - Err(error) => eprintln!("{}", error.report()), - } + todo!() } fn run_and_display_errors(source: &str) { - match run(source) { - Ok(return_value) => { - if let Some(value) = return_value { - println!("{}", value); - } - } - Err(error) => eprintln!("{}", error.report()), - } + todo!() }