From e643ebe1144cab65810b536a64da65ae69489223 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 31 Aug 2024 07:24:45 -0400 Subject: [PATCH] Fix parsing bug --- dust-lang/src/analyzer.rs | 299 ++++++++++++++++-------------------- dust-lang/src/context.rs | 40 +++-- dust-lang/src/dust_error.rs | 13 +- dust-lang/src/parser.rs | 193 ++++++++++++----------- dust-lang/src/vm.rs | 66 +------- dust-lang/tests/scopes.rs | 45 ++++++ 6 files changed, 328 insertions(+), 328 deletions(-) create mode 100644 dust-lang/tests/scopes.rs diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index a6f99c3..caced44 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -17,8 +17,8 @@ use crate::{ PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition, StructExpression, TupleAccessExpression, }, - parse, ContextError, DustError, Expression, Identifier, RangeableType, StructType, Type, - TypeConflict, TypeEvaluation, + parse, Context, ContextData, ContextError, DustError, Expression, Identifier, RangeableType, + StructType, Type, TypeConflict, TypeEvaluation, }; /// Analyzes the abstract syntax tree for errors. @@ -36,7 +36,7 @@ pub fn analyze(source: &str) -> Result<(), DustError> { let abstract_tree = parse(source)?; let mut analyzer = Analyzer::new(&abstract_tree); - analyzer.analyze(); + analyzer.analyze()?; if analyzer.errors.is_empty() { Ok(()) @@ -71,19 +71,23 @@ impl<'a> Analyzer<'a> { } } - pub fn analyze(&mut self) { + pub fn analyze(&mut self) -> Result<(), ContextError> { for statement in &self.abstract_tree.statements { - self.analyze_statement(statement); + self.analyze_statement(statement, &self.abstract_tree.context)?; } + + Ok(()) } - fn analyze_statement(&mut self, statement: &Statement) { + fn analyze_statement( + &mut self, + statement: &Statement, + context: &Context, + ) -> Result<(), ContextError> { match statement { - Statement::Expression(expression) => { - self.analyze_expression(expression, statement.position()) - } + Statement::Expression(expression) => self.analyze_expression(expression, context)?, Statement::ExpressionNullified(expression_node) => { - self.analyze_expression(&expression_node.inner, statement.position()); + self.analyze_expression(&expression_node.inner, context)?; } Statement::Let(let_statement) => match &let_statement.inner { LetStatement::Let { identifier, value } @@ -92,42 +96,25 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } Ok(TypeEvaluation::Constructor(StructType::Unit { name })) => { - let set_type = self.abstract_tree.context.set_variable_type( + self.abstract_tree.context.set_variable_type( identifier.inner.clone(), Type::Struct(StructType::Unit { name }), - statement.position(), - ); + )?; - if let Err(context_error) = set_type { - self.errors.push(AnalysisError::ContextError { - error: context_error, - position: identifier.position, - }); - } + self.analyze_expression(value, context)?; - self.analyze_expression(value, statement.position()); - - return; + return Ok(()); } Ok(evaluation) => evaluation.r#type(), }; if let Some(r#type) = r#type { - let set_type = self.abstract_tree.context.set_variable_type( - identifier.inner.clone(), - r#type.clone(), - statement.position(), - ); - - if let Err(context_error) = set_type { - self.errors.push(AnalysisError::ContextError { - error: context_error, - position: identifier.position, - }); - } + self.abstract_tree + .context + .set_variable_type(identifier.inner.clone(), r#type.clone())?; } else { self.errors .push(AnalysisError::LetExpectedValueFromStatement { @@ -135,13 +122,13 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_expression(value, statement.position()); + self.analyze_expression(value, context)?; } LetStatement::LetType { .. } => todo!(), LetStatement::LetMutType { .. } => todo!(), }, Statement::StructDefinition(struct_definition) => { - let set_constructor_type = match &struct_definition.inner { + match &struct_definition.inner { StructDefinition::Unit { name } => { self.abstract_tree.context.set_constructor_type( name.inner.clone(), @@ -149,7 +136,7 @@ impl<'a> Analyzer<'a> { name: name.inner.clone(), }, statement.position(), - ) + )?; } StructDefinition::Tuple { name, items } => { let fields = items.iter().map(|item| item.inner.clone()).collect(); @@ -161,7 +148,7 @@ impl<'a> Analyzer<'a> { fields, }, statement.position(), - ) + )?; } StructDefinition::Fields { name, fields } => { let fields = fields @@ -178,32 +165,33 @@ impl<'a> Analyzer<'a> { fields, }, statement.position(), - ) + )?; } }; - - if let Err(context_error) = set_constructor_type { - self.errors.push(AnalysisError::ContextError { - error: context_error, - position: struct_definition.position, - }); - } } } + + Ok(()) } - fn analyze_expression(&mut self, expression: &Expression, statement_position: Span) { + fn analyze_expression( + &mut self, + expression: &Expression, + context: &Context, + ) -> Result<(), ContextError> { match expression { - Expression::Block(block_expression) => self.analyze_block(&block_expression.inner), + 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, statement_position); + self.analyze_expression(expression, context)?; } } Expression::Call(call_expression) => { let CallExpression { invoker, arguments } = call_expression.inner.as_ref(); - self.analyze_expression(invoker, statement_position); + self.analyze_expression(invoker, context)?; let invoker_evaluation = match invoker.type_evaluation(&self.abstract_tree.context) { @@ -211,7 +199,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; @@ -225,7 +213,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; @@ -241,7 +229,7 @@ impl<'a> Analyzer<'a> { } } - return; + return Ok(()); } let invoked_type = if let Some(r#type) = invoker_evaluation.r#type() { @@ -252,7 +240,7 @@ impl<'a> Analyzer<'a> { expression: invoker.clone(), }); - return; + return Ok(()); }; let function_type = if let Type::Function(function_type) = invoked_type { function_type @@ -262,7 +250,7 @@ impl<'a> Analyzer<'a> { actual_expression: invoker.clone(), }); - return; + return Ok(()); }; let value_parameters = @@ -277,11 +265,11 @@ impl<'a> Analyzer<'a> { }); } - return; + return Ok(()); }; for ((_, expected_type), argument) in value_parameters.iter().zip(arguments) { - self.analyze_expression(argument, statement_position); + self.analyze_expression(argument, context)?; let argument_evaluation = match argument.type_evaluation(&self.abstract_tree.context) { @@ -313,11 +301,11 @@ impl<'a> Analyzer<'a> { } for argument in arguments { - self.analyze_expression(argument, statement_position); + self.analyze_expression(argument, context)?; } } Expression::Dereference(expression) => { - self.analyze_expression(&expression.inner, statement_position); + self.analyze_expression(&expression.inner, context)?; } Expression::FieldAccess(field_access_expression) => { let FieldAccessExpression { container, field } = @@ -328,7 +316,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; let container_type = match evaluation.r#type() { @@ -339,7 +327,7 @@ impl<'a> Analyzer<'a> { expression: container.clone(), }); - return; + return Ok(()); } }; @@ -350,59 +338,47 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_expression(container, statement_position); + self.analyze_expression(container, context)?; } Expression::Grouped(expression) => { - self.analyze_expression(expression.inner.as_ref(), statement_position); + self.analyze_expression(expression.inner.as_ref(), context)?; } Expression::Identifier(identifier) => { - let find_identifier = self - .abstract_tree - .context - .update_last_position(&identifier.inner, statement_position); + let context_data = context.get_data(&identifier.inner)?; - if let Ok(false) = find_identifier { + if let Some(ContextData::Reserved) | None = context_data { self.errors.push(AnalysisError::UndefinedVariable { identifier: identifier.clone(), }); } - - if let Err(context_error) = find_identifier { - self.errors.push(AnalysisError::ContextError { - error: context_error, - position: identifier.position, - }); - } - } - Expression::If(if_expression) => { - self.analyze_if(&if_expression.inner, statement_position) } + 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, statement_position); - self.analyze_expression(length_operand, statement_position); + self.analyze_expression(repeat_operand, context)?; + self.analyze_expression(length_operand, context)?; } ListExpression::Ordered(expressions) => { for expression in expressions { - self.analyze_expression(expression, statement_position); + self.analyze_expression(expression, context)?; } } }, Expression::ListIndex(list_index_expression) => { let ListIndexExpression { list, index } = list_index_expression.inner.as_ref(); - self.analyze_expression(list, statement_position); - self.analyze_expression(index, statement_position); + 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; + return Ok(()); } }; let list_type = match list_type_evaluation.r#type() { @@ -413,7 +389,7 @@ impl<'a> Analyzer<'a> { expression: list.clone(), }); - return; + return Ok(()); } }; let index_type_evaluation = match index.type_evaluation(&self.abstract_tree.context) @@ -422,7 +398,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; let index_type = match index_type_evaluation.r#type() { @@ -433,7 +409,7 @@ impl<'a> Analyzer<'a> { expression: list.clone(), }); - return; + return Ok(()); } }; let literal_type = if let Expression::Literal(Node { inner, .. }) = index { @@ -510,39 +486,39 @@ impl<'a> Analyzer<'a> { // 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), + LoopExpression::Infinite { block } => self.analyze_block(&block.inner, context)?, LoopExpression::While { condition, block } => { - self.analyze_expression(condition, statement_position); - self.analyze_block(&block.inner); + self.analyze_expression(condition, context)?; + self.analyze_block(&block.inner, context)?; } LoopExpression::For { iterator, block, .. } => { - self.analyze_expression(iterator, statement_position); - self.analyze_block(&block.inner); + 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, statement_position); + self.analyze_expression(expression, context)?; } } Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() { OperatorExpression::Assignment { assignee, value } => { - self.analyze_expression(assignee, statement_position); - self.analyze_expression(value, statement_position); + self.analyze_expression(assignee, context)?; + self.analyze_expression(value, context)?; } OperatorExpression::Comparison { left, right, .. } => { - self.analyze_expression(left, statement_position); - self.analyze_expression(right, statement_position); + self.analyze_expression(left, context)?; + self.analyze_expression(right, context)?; } OperatorExpression::CompoundAssignment { assignee, modifier, .. } => { - self.analyze_expression(assignee, statement_position); - self.analyze_expression(modifier, statement_position); + self.analyze_expression(assignee, context)?; + self.analyze_expression(modifier, context)?; let assignee_type_evaluation = match assignee.type_evaluation(&self.abstract_tree.context) { @@ -550,7 +526,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; let modifier_type_evaluation = @@ -559,7 +535,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; @@ -577,21 +553,21 @@ impl<'a> Analyzer<'a> { .push(AnalysisError::ExpectedValueFromExpression { expression: modifier.clone(), }); - return; + return Ok(()); } (None, _) => { self.errors .push(AnalysisError::ExpectedValueFromExpression { expression: assignee.clone(), }); - return; + return Ok(()); } (_, None) => { self.errors .push(AnalysisError::ExpectedValueFromExpression { expression: modifier.clone(), }); - return; + return Ok(()); } }; @@ -605,14 +581,14 @@ impl<'a> Analyzer<'a> { } OperatorExpression::ErrorPropagation(_) => todo!(), OperatorExpression::Negation(expression) => { - self.analyze_expression(expression, statement_position); + self.analyze_expression(expression, context)?; } OperatorExpression::Not(expression) => { - self.analyze_expression(expression, statement_position); + self.analyze_expression(expression, context)?; } OperatorExpression::Math { left, right, .. } => { - self.analyze_expression(left, statement_position); - self.analyze_expression(right, statement_position); + self.analyze_expression(left, context)?; + self.analyze_expression(right, context)?; let left_type_evaluation = match left.type_evaluation(&self.abstract_tree.context) { @@ -620,7 +596,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; let right_type_evaluation = @@ -629,7 +605,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; @@ -647,21 +623,21 @@ impl<'a> Analyzer<'a> { .push(AnalysisError::ExpectedValueFromExpression { expression: right.clone(), }); - return; + return Ok(()); } (None, _) => { self.errors .push(AnalysisError::ExpectedValueFromExpression { expression: left.clone(), }); - return; + return Ok(()); } (_, None) => { self.errors .push(AnalysisError::ExpectedValueFromExpression { expression: right.clone(), }); - return; + return Ok(()); } }; @@ -709,8 +685,8 @@ impl<'a> Analyzer<'a> { } } OperatorExpression::Logic { left, right, .. } => { - self.analyze_expression(left, statement_position); - self.analyze_expression(right, statement_position); + self.analyze_expression(left, context)?; + self.analyze_expression(right, context)?; let left_type_evaluation = match left.type_evaluation(&self.abstract_tree.context) { @@ -718,7 +694,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; let right_type_evaluation = @@ -727,7 +703,7 @@ impl<'a> Analyzer<'a> { Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; @@ -745,21 +721,21 @@ impl<'a> Analyzer<'a> { .push(AnalysisError::ExpectedValueFromExpression { expression: right.clone(), }); - return; + return Ok(()); } (None, _) => { self.errors .push(AnalysisError::ExpectedValueFromExpression { expression: left.clone(), }); - return; + return Ok(()); } (_, None) => { self.errors .push(AnalysisError::ExpectedValueFromExpression { expression: right.clone(), }); - return; + return Ok(()); } }; @@ -774,32 +750,18 @@ impl<'a> Analyzer<'a> { }, Expression::Range(range_expression) => match range_expression.inner.as_ref() { RangeExpression::Exclusive { start, end } => { - self.analyze_expression(start, statement_position); - self.analyze_expression(end, statement_position); + self.analyze_expression(start, context)?; + self.analyze_expression(end, context)?; } RangeExpression::Inclusive { start, end } => { - self.analyze_expression(start, statement_position); - self.analyze_expression(end, statement_position); + self.analyze_expression(start, context)?; + self.analyze_expression(end, context)?; } }, Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { - StructExpression::Fields { name, fields } => { - let update_position = self - .abstract_tree - .context - .update_last_position(&name.inner, statement_position); - - if let Err(error) = update_position { - self.errors.push(AnalysisError::ContextError { - error, - position: name.position, - }); - - return; - } - + StructExpression::Fields { fields, .. } => { for (_, expression) in fields { - self.analyze_expression(expression, statement_position); + self.analyze_expression(expression, context)?; } } }, @@ -810,7 +772,7 @@ impl<'a> Analyzer<'a> { Ok(evaluation) => evaluation, Err(ast_error) => { self.errors.push(AnalysisError::AstError(ast_error)); - return; + return Ok(()); } }; @@ -821,7 +783,7 @@ impl<'a> Analyzer<'a> { .push(AnalysisError::ExpectedValueFromExpression { expression: tuple.clone(), }); - return; + return Ok(()); } }; @@ -845,64 +807,69 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_expression(tuple, statement_position); + self.analyze_expression(tuple, context)?; } } + + Ok(()) } - fn analyze_block(&mut self, block_expression: &BlockExpression) { + 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, }; - ast.context - .assign_parent(self.abstract_tree.context.clone()); + for statement in &ast.statements { + self.analyze_statement(statement, &ast.context)?; + } - let mut analyzer = Analyzer::new(ast); - - analyzer.analyze(); - - self.errors.append(&mut analyzer.errors); + Ok(()) } - fn analyze_if(&mut self, if_expression: &IfExpression, statement_position: Span) { + fn analyze_if( + &mut self, + if_expression: &IfExpression, + context: &Context, + ) -> Result<(), ContextError> { match if_expression { IfExpression::If { condition, if_block, } => { - self.analyze_expression(condition, statement_position); - self.analyze_block(&if_block.inner); + self.analyze_expression(condition, context)?; + self.analyze_block(&if_block.inner, context)?; } IfExpression::IfElse { condition, if_block, r#else, } => { - self.analyze_expression(condition, statement_position); - self.analyze_block(&if_block.inner); + 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); + self.analyze_block(&block_expression.inner, context)?; } ElseExpression::If(if_expression) => { - self.analyze_if(&if_expression.inner, statement_position); + self.analyze_if(&if_expression.inner, context)?; } } } } + + Ok(()) } } #[derive(Clone, Debug, PartialEq)] pub enum AnalysisError { AstError(AstError), - ContextError { - error: ContextError, - position: Span, - }, ExpectedFunction { actual: Type, actual_expression: Expression, @@ -978,8 +945,8 @@ pub enum AnalysisError { } impl From for AnalysisError { - fn from(v: AstError) -> Self { - Self::AstError(v) + fn from(error: AstError) -> Self { + Self::AstError(error) } } @@ -987,7 +954,6 @@ impl AnalysisError { pub fn position(&self) -> Span { match self { AnalysisError::AstError(ast_error) => ast_error.position(), - AnalysisError::ContextError { position, .. } => *position, AnalysisError::ExpectedFunction { actual_expression, .. } => actual_expression.position(), @@ -1024,7 +990,6 @@ impl Display for AnalysisError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { AnalysisError::AstError(ast_error) => write!(f, "{}", ast_error), - AnalysisError::ContextError { error, .. } => write!(f, "{}", error), AnalysisError::ExpectedFunction { actual, actual_expression, diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 3d1b5c8..2998bc9 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -156,20 +156,13 @@ impl Context { &self, identifier: Identifier, r#type: Type, - position: Span, ) -> Result<(), ContextError> { - log::trace!("Setting {identifier} to type {type} at {position:?}"); + log::trace!("Setting {identifier} to type {type}."); let mut associations = self.associations.write()?; let last_position = associations .get(&identifier) - .map(|(_, last_position)| { - if last_position.1 > position.1 { - *last_position - } else { - position - } - }) + .map(|(_, last_position)| *last_position) .unwrap_or_default(); associations.insert( @@ -283,16 +276,32 @@ impl Context { identifier: &Identifier, position: Span, ) -> Result { - if let Some((_, last_position)) = self.associations.write()?.get_mut(identifier) { - *last_position = position; + let mut associations = self.associations.write()?; - log::trace!("Updating {identifier}'s last position to {position:?}"); + if let Some((_, last_position)) = associations.get_mut(identifier) { + if position.1 > last_position.1 { + log::trace!("Updating {identifier}'s last position to {position:?}"); + + *last_position = position; + } Ok(true) - } else if let Some(parent) = self.parent.read().unwrap().as_ref() { - parent.contains(identifier) } else { - Ok(false) + let ancestor_contains = if let Some(parent) = self.parent.read().unwrap().as_ref() { + parent.contains(identifier)? + } else { + false + }; + + if ancestor_contains { + Ok(true) + } else { + log::trace!("Reserving {identifier} at {position:?}"); + + associations.insert(identifier.clone(), (ContextData::Reserved, position)); + + Ok(false) + } } } @@ -327,6 +336,7 @@ pub enum ContextData { ConstructorType(StructType), VariableValue(Value), VariableType(Type), + Reserved, } #[derive(Debug, Clone)] diff --git a/dust-lang/src/dust_error.rs b/dust-lang/src/dust_error.rs index bb178a3..d6840f4 100644 --- a/dust-lang/src/dust_error.rs +++ b/dust-lang/src/dust_error.rs @@ -2,12 +2,13 @@ use annotate_snippets::{Level, Renderer, Snippet}; use std::fmt::Display; -use crate::{ast::Span, AnalysisError, LexError, ParseError, RuntimeError}; +use crate::{ast::Span, 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, @@ -26,6 +27,12 @@ pub enum DustError<'src> { }, } +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 { @@ -54,6 +61,7 @@ impl<'src> DustError<'src> { pub fn title(&self) -> &'static str { match self { + DustError::ContextError(_) => "Context error", DustError::Runtime { .. } => "Runtime error", DustError::Analysis { .. } => "Analysis error", DustError::Parse { .. } => "Parse error", @@ -63,6 +71,7 @@ impl<'src> DustError<'src> { pub fn source(&self) -> &'src str { match self { + DustError::ContextError(_) => "", DustError::Runtime { source, .. } => source, DustError::Analysis { source, .. } => source, DustError::Parse { source, .. } => source, @@ -72,6 +81,7 @@ impl<'src> DustError<'src> { pub fn error_data(&self) -> Vec<(&'static str, Span, String)> { match self { + DustError::ContextError(_) => vec![], DustError::Runtime { runtime_error, .. } => vec![( "Runtime error", runtime_error.position(), @@ -114,6 +124,7 @@ impl<'src> DustError<'src> { 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, .. diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 2944fd1..2150c6a 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -11,8 +11,8 @@ use std::{ }; use crate::{ - ast::*, core_library, Context, DustError, Identifier, LexError, Lexer, Token, TokenKind, - TokenOwned, Type, + ast::*, core_library, Context, ContextError, DustError, Identifier, LexError, Lexer, Token, + TokenKind, TokenOwned, Type, }; /// Parses the input into an abstract syntax tree. @@ -40,34 +40,27 @@ use crate::{ pub fn parse(source: &str) -> Result { let mut tree = AbstractSyntaxTree::new(); - parse_into(source, &mut tree)?; + tree.context.assign_parent(core_library().clone()); - Ok(tree) -} - -pub fn parse_into<'src>( - source: &'src str, - tree: &mut AbstractSyntaxTree, -) -> Result<(), DustError<'src>> { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); loop { - let node = parser - .parse_statement() + let statement = parser + .parse_statement(&tree.context) .map_err(|parse_error| DustError::Parse { parse_error, source, })?; - tree.statements.push_back(node); + tree.statements.push_back(statement); if let Token::Eof = parser.current_token { break; } } - Ok(()) + Ok(tree) } /// Low-level tool for parsing the input a statement at a time. @@ -99,7 +92,6 @@ pub struct Parser<'src> { current_token: Token<'src>, current_position: Span, mode: ParserMode, - context: Context, } impl<'src> Parser<'src> { @@ -111,7 +103,6 @@ impl<'src> Parser<'src> { current_token, current_position, mode: ParserMode::Normal, - context: core_library().create_child(), } } @@ -119,7 +110,7 @@ impl<'src> Parser<'src> { matches!(self.current_token, Token::Eof) } - pub fn parse_statement(&mut self) -> Result { + pub fn parse_statement(&mut self, context: &Context) -> Result { let start_position = self.current_position; if let Token::Let = self.current_token { @@ -135,7 +126,7 @@ impl<'src> Parser<'src> { false }; - let identifier = self.parse_identifier()?; + let identifier = self.parse_identifier(context)?; if let Token::Equal = self.current_token { self.next_token()?; @@ -147,7 +138,7 @@ impl<'src> Parser<'src> { }); } - let value = self.parse_expression(0)?; + let value = self.parse_expression(0, context)?; let end = if let Token::Semicolon = self.current_token { let end = self.current_position.1; @@ -174,7 +165,7 @@ impl<'src> Parser<'src> { self.next_token()?; let name = if let Token::Identifier(_) = self.current_token { - self.parse_identifier()? + self.parse_identifier(context)? } else { return Err(ParseError::ExpectedToken { expected: TokenKind::Identifier, @@ -203,10 +194,6 @@ impl<'src> Parser<'src> { if let Token::RightParenthesis = self.current_token { self.next_token()?; - if let Token::Semicolon = self.current_token { - self.next_token()?; - } - break; } @@ -223,6 +210,10 @@ impl<'src> Parser<'src> { 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 }, @@ -245,14 +236,10 @@ impl<'src> Parser<'src> { if let Token::RightCurlyBrace = self.current_token { self.next_token()?; - if let Token::Semicolon = self.current_token { - self.next_token()?; - } - break; } - let field_name = self.parse_identifier()?; + let field_name = self.parse_identifier(context)?; if let Token::Colon = self.current_token { self.next_token()?; @@ -277,6 +264,10 @@ impl<'src> Parser<'src> { 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 }, @@ -301,7 +292,7 @@ impl<'src> Parser<'src> { }); } - let expression = self.parse_expression(0)?; + let expression = self.parse_expression(0, context)?; if let Token::Semicolon = self.current_token { let position = (start_position.0, self.current_position.1); @@ -325,19 +316,23 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse_expression(&mut self, mut precedence: u8) -> Result { + 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()? + self.parse_prefix(context)? } else { - self.parse_primary()? + 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)?; + let statement = self.parse_postfix(left, context)?; precedence = self.current_token.precedence(); @@ -345,14 +340,14 @@ impl<'src> Parser<'src> { statement } else { // Replace the left-hand side with the infix operation - self.parse_infix(left)? + self.parse_infix(left, context)? }; } Ok(left) } - fn parse_prefix(&mut self) -> Result { + fn parse_prefix(&mut self, context: &Context) -> Result { log::trace!("Parsing {} as prefix operator", self.current_token); let operator_start = self.current_position.0; @@ -361,7 +356,7 @@ impl<'src> Parser<'src> { Token::Bang => { self.next_token()?; - let operand = self.parse_expression(0)?; + let operand = self.parse_expression(0, context)?; let position = (operator_start, self.current_position.1); Ok(Expression::not(operand, position)) @@ -369,7 +364,7 @@ impl<'src> Parser<'src> { Token::Minus => { self.next_token()?; - let operand = self.parse_expression(0)?; + let operand = self.parse_expression(0, context)?; let position = (operator_start, self.current_position.1); Ok(Expression::negation(operand, position)) @@ -377,7 +372,7 @@ impl<'src> Parser<'src> { Token::Star => { self.next_token()?; - let operand = self.parse_expression(0)?; + let operand = self.parse_expression(0, context)?; let position = (operator_start, self.current_position.1); Ok(Expression::dereference(operand, position)) @@ -390,14 +385,14 @@ impl<'src> Parser<'src> { } } - fn parse_primary(&mut self) -> Result { + 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()?; + let block = self.parse_block(context)?; let position = (start_position.0, block.position.1); Ok(Expression::block(block.inner, position)) @@ -422,7 +417,7 @@ impl<'src> Parser<'src> { // Do not consume the semicolon, allowing it to nullify the expression (None, break_end) - } else if let Ok(expression) = self.parse_expression(0) { + } else if let Ok(expression) = self.parse_expression(0, context) { let end = expression.position().1; (Some(expression), end) @@ -460,13 +455,15 @@ impl<'src> Parser<'src> { let identifier = Identifier::new(text); if let ParserMode::Condition = self.mode { + context.update_last_position(&identifier, start_position)?; + return Ok(Expression::identifier(identifier, start_position)); } if let Token::LeftCurlyBrace = self.current_token { self.next_token()?; - let name = Node::new(identifier, start_position); + let name = Node::new(identifier.clone(), start_position); let mut fields = Vec::new(); loop { @@ -476,7 +473,7 @@ impl<'src> Parser<'src> { break; } - let field_name = self.parse_identifier()?; + let field_name = self.parse_identifier(context)?; if let Token::Colon = self.current_token { self.next_token()?; @@ -488,7 +485,7 @@ impl<'src> Parser<'src> { }); } - let field_value = self.parse_expression(0)?; + let field_value = self.parse_expression(0, context)?; fields.push((field_name, field_value)); @@ -499,12 +496,16 @@ impl<'src> Parser<'src> { let position = (start_position.0, self.current_position.1); + context.update_last_position(&identifier, position)?; + return Ok(Expression::r#struct( StructExpression::Fields { name, fields }, position, )); } + context.update_last_position(&identifier, start_position)?; + Ok(Expression::identifier(identifier, start_position)) } Token::Integer(text) => { @@ -520,7 +521,7 @@ impl<'src> Parser<'src> { Token::If => { self.next_token()?; - let r#if = self.parse_if()?; + let r#if = self.parse_if(context)?; let position = (start_position.0, self.current_position.1); Ok(Expression::r#if(r#if, position)) @@ -531,14 +532,14 @@ impl<'src> Parser<'src> { Ok(Expression::literal(text.to_string(), start_position)) } Token::LeftCurlyBrace => { - let block_node = self.parse_block()?; + 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)?; + let node = self.parse_expression(0, context)?; if let Token::RightParenthesis = self.current_token { let position = (start_position.0, self.current_position.1); @@ -565,12 +566,12 @@ impl<'src> Parser<'src> { return Ok(Expression::list(Vec::new(), position)); } - let first_expression = self.parse_expression(0)?; + 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)?; + let repeat_operand = self.parse_expression(0, context)?; if let Token::RightSquareBrace = self.current_token { let position = (start_position.0, self.current_position.1); @@ -608,7 +609,7 @@ impl<'src> Parser<'src> { continue; } - let expression = self.parse_expression(0)?; + let expression = self.parse_expression(0, context)?; expressions.push(expression); } @@ -616,7 +617,7 @@ impl<'src> Parser<'src> { Token::Loop => { self.next_token()?; - let block = self.parse_block()?; + let block = self.parse_block(context)?; let position = (start_position.0, block.position.1); Ok(Expression::infinite_loop(block, position)) @@ -645,7 +646,7 @@ impl<'src> Parser<'src> { return Ok(Expression::map(fields, position)); } - let field_name = self.parse_identifier()?; + let field_name = self.parse_identifier(context)?; if let Token::Equal = self.current_token { self.next_token()?; @@ -657,7 +658,7 @@ impl<'src> Parser<'src> { }); } - let field_value = self.parse_expression(0)?; + let field_value = self.parse_expression(0, context)?; fields.push((field_name, field_value)); @@ -669,8 +670,8 @@ impl<'src> Parser<'src> { Token::While => { self.next_token()?; - let condition = self.parse_expression(0)?; - let block = self.parse_block()?; + 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)) @@ -695,7 +696,11 @@ impl<'src> Parser<'src> { } } - fn parse_infix(&mut self, left: Expression) -> Result { + 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() @@ -709,7 +714,7 @@ impl<'src> Parser<'src> { if let Token::Equal = &self.current_token { self.next_token()?; - let value = self.parse_expression(operator_precedence)?; + let value = self.parse_expression(operator_precedence, context)?; let position = (left_start, value.position().1); return Ok(Expression::assignment(left, value, position)); @@ -725,7 +730,7 @@ impl<'src> Parser<'src> { self.next_token()?; - let value = self.parse_expression(operator_precedence)?; + let value = self.parse_expression(operator_precedence, context)?; let position = (left_start, value.position().1); return Ok(Expression::operator( @@ -741,7 +746,7 @@ impl<'src> Parser<'src> { if let Token::DoubleDot = &self.current_token { self.next_token()?; - let end = self.parse_expression(operator_precedence)?; + let end = self.parse_expression(operator_precedence, context)?; let position = (left_start, end.position().1); return Ok(Expression::exclusive_range(left, end, position)); @@ -761,7 +766,7 @@ impl<'src> Parser<'src> { self.next_token()?; - let right = self.parse_expression(operator_precedence)?; + let right = self.parse_expression(operator_precedence, context)?; let position = (left_start, right.position().1); return Ok(Expression::operator( @@ -798,7 +803,7 @@ impl<'src> Parser<'src> { self.next_token()?; - let right = self.parse_expression(operator_precedence)?; + let right = self.parse_expression(operator_precedence, context)?; let position = (left_start, right.position().1); return Ok(Expression::operator( @@ -824,7 +829,7 @@ impl<'src> Parser<'src> { self.next_token()?; - let right = self.parse_expression(operator_precedence)?; + let right = self.parse_expression(operator_precedence, context)?; let position = (left_start, right.position().1); Ok(Expression::operator( @@ -837,7 +842,11 @@ impl<'src> Parser<'src> { )) } - fn parse_postfix(&mut self, left: Expression) -> Result { + 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 { @@ -856,7 +865,7 @@ impl<'src> Parser<'src> { Expression::tuple_access(left, index_node, position) } else { - let field = self.parse_identifier()?; + let field = self.parse_identifier(context)?; let position = (left.position().0, field.position.1); Expression::field_access(left, field, position) @@ -868,7 +877,7 @@ impl<'src> Parser<'src> { let mut arguments = Vec::new(); while self.current_token != Token::RightParenthesis { - let argument = self.parse_expression(0)?; + let argument = self.parse_expression(0, context)?; arguments.push(argument); @@ -879,16 +888,16 @@ impl<'src> Parser<'src> { } } - self.next_token()?; - 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)?; + let index = self.parse_expression(0, context)?; let operator_end = if let Token::RightSquareBrace = self.current_token { let end = self.current_position.1; @@ -922,22 +931,22 @@ impl<'src> Parser<'src> { }; if self.current_token.is_postfix() { - self.parse_postfix(expression) + self.parse_postfix(expression, context) } else { Ok(expression) } } - fn parse_if(&mut self) -> Result { + 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)?; + let condition = self.parse_expression(0, context)?; self.mode = ParserMode::Normal; - let if_block = self.parse_block()?; + let if_block = self.parse_block(context)?; if let Token::Else = self.current_token { self.next_token()?; @@ -947,7 +956,7 @@ impl<'src> Parser<'src> { if let Token::If = self.current_token { self.next_token()?; - let if_expression = self.parse_if()?; + let if_expression = self.parse_if(context)?; let position = (if_keyword_start, self.current_position.1); Ok(IfExpression::IfElse { @@ -956,7 +965,7 @@ impl<'src> Parser<'src> { r#else: ElseExpression::If(Node::new(Box::new(if_expression), position)), }) } else { - let else_block = self.parse_block()?; + let else_block = self.parse_block(context)?; Ok(IfExpression::IfElse { condition, @@ -972,13 +981,16 @@ impl<'src> Parser<'src> { } } - fn parse_identifier(&mut self) -> Result, ParseError> { + 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()?; - Ok(Node::new(Identifier::new(text), position)) + context.update_last_position(&identifier, position)?; + + Ok(Node::new(identifier, position)) } else { Err(ParseError::ExpectedToken { expected: TokenKind::Identifier, @@ -988,7 +1000,7 @@ impl<'src> Parser<'src> { } } - fn parse_block(&mut self) -> Result, ParseError> { + 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()?; @@ -1008,7 +1020,10 @@ impl<'src> Parser<'src> { }); } - let mut statements = VecDeque::new(); + let mut ast = AbstractSyntaxTree { + statements: VecDeque::new(), + context: context.create_child(), + }; loop { if let Token::RightCurlyBrace = self.current_token { @@ -1016,11 +1031,6 @@ impl<'src> Parser<'src> { self.next_token()?; - let ast = AbstractSyntaxTree { - statements, - context: self.context.create_child(), - }; - return if is_async { Ok(Node::new(BlockExpression::Async(ast), position)) } else { @@ -1028,9 +1038,9 @@ impl<'src> Parser<'src> { }; } - let statement = self.parse_statement()?; + let statement = self.parse_statement(&ast.context)?; - statements.push_back(statement); + ast.statements.push_back(statement); } } @@ -1063,6 +1073,7 @@ pub enum ParserMode { #[derive(Debug, PartialEq, Clone)] pub enum ParseError { + ContextError(ContextError), Boolean { error: ParseBoolError, position: Span, @@ -1105,6 +1116,12 @@ pub enum ParseError { }, } +impl From for ParseError { + fn from(error: ContextError) -> Self { + Self::ContextError(error) + } +} + impl From for ParseError { fn from(v: LexError) -> Self { Self::Lex(v) @@ -1115,6 +1132,7 @@ 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(), @@ -1133,6 +1151,7 @@ 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 } => { @@ -1398,7 +1417,7 @@ mod tests { Expression::literal(42, (4, 6)), Expression::literal("bar".to_string(), (8, 13)), ], - (0, 15) + (0, 14) ), Node::new(0, (15, 16)), (0, 16) diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 380223e..2305ee9 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -40,7 +40,7 @@ pub fn run(source: &str) -> Result, DustError> { let abstract_syntax_tree = parse(source)?; let mut analyzer = Analyzer::new(&abstract_syntax_tree); - analyzer.analyze(); + analyzer.analyze()?; if !analyzer.errors.is_empty() { return Err(DustError::Analysis { @@ -58,11 +58,7 @@ pub fn run(source: &str) -> Result, DustError> { /// Dust virtual machine. /// -/// **Warning**: Do not run an AbstractSyntaxTree that has not been analyzed *with the same -/// context*. Use the `run` or `run_with_context` functions to make sure the program is analyzed -/// before running it. -/// -/// See the `run_with_context` function for an example of how to use the Analyzer and the VM. +/// See the `run` function for an example of how to parse, analyze and run code. pub struct Vm; impl Vm { @@ -70,7 +66,11 @@ impl Vm { 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 { @@ -193,12 +193,6 @@ impl Vm { } }; - if collect_garbage { - context - .collect_garbage(position.1) - .map_err(|error| RuntimeError::ContextError { error, position })?; - } - result.map_err(|error| RuntimeError::Statement { error: Box::new(error), position, @@ -1020,7 +1014,7 @@ impl Vm { fn run_block( &self, block: BlockExpression, - context: &Context, + _context: &Context, collect_garbage: bool, ) -> Result { match block { @@ -1424,7 +1418,7 @@ impl Display for RuntimeError { mod tests { use std::collections::HashMap; - use crate::{AnalysisError, Struct}; + use crate::Struct; use super::*; @@ -1480,50 +1474,6 @@ mod tests { assert_eq!(run(source), Ok(Some(Value::integer(42)))); } - #[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() { - 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)))); - } - #[test] fn character() { let input = "'a'"; diff --git a/dust-lang/tests/scopes.rs b/dust-lang/tests/scopes.rs new file mode 100644 index 0000000..001b5fc --- /dev/null +++ b/dust-lang/tests/scopes.rs @@ -0,0 +1,45 @@ +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() { + 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)))); +}