From e84e022eed1b4c81071d7eff9923af1aebfd23b9 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 4 Jul 2024 14:39:45 -0400 Subject: [PATCH] Experiment with context scopes --- dust-lang/src/abstract_tree/as.rs | 8 +- dust-lang/src/abstract_tree/assignment.rs | 26 +- dust-lang/src/abstract_tree/async_block.rs | 14 +- dust-lang/src/abstract_tree/block.rs | 14 +- .../src/abstract_tree/built_in_function.rs | 24 +- .../src/abstract_tree/enum_declaration.rs | 25 +- dust-lang/src/abstract_tree/expression.rs | 52 ++-- dust-lang/src/abstract_tree/function_call.rs | 68 ++--- dust-lang/src/abstract_tree/if_else.rs | 30 ++- dust-lang/src/abstract_tree/list_index.rs | 13 +- dust-lang/src/abstract_tree/logic.rs | 40 +-- dust-lang/src/abstract_tree/loop.rs | 8 +- dust-lang/src/abstract_tree/map_index.rs | 11 +- dust-lang/src/abstract_tree/math.rs | 29 ++- dust-lang/src/abstract_tree/mod.rs | 14 +- dust-lang/src/abstract_tree/statement.rs | 90 ++++--- .../src/abstract_tree/structure_definition.rs | 14 +- dust-lang/src/abstract_tree/type.rs | 6 +- dust-lang/src/abstract_tree/type_alias.rs | 18 +- dust-lang/src/abstract_tree/use.rs | 10 +- dust-lang/src/abstract_tree/value_node.rs | 47 ++-- dust-lang/src/abstract_tree/while.rs | 21 +- dust-lang/src/context.rs | 242 ++++-------------- dust-lang/src/identifier.rs | 30 ++- dust-lang/src/lib.rs | 4 +- dust-lang/src/parser/mod.rs | 2 +- dust-lang/src/standard_library.rs | 9 +- dust-lang/src/value.rs | 9 +- dust-shell/src/main.rs | 2 +- 29 files changed, 439 insertions(+), 441 deletions(-) diff --git a/dust-lang/src/abstract_tree/as.rs b/dust-lang/src/abstract_tree/as.rs index 8742acd..537ed93 100644 --- a/dust-lang/src/abstract_tree/as.rs +++ b/dust-lang/src/abstract_tree/as.rs @@ -12,7 +12,7 @@ use crate::{ Value, }; -use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; +use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, TypeConstructor}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct As { @@ -34,9 +34,10 @@ impl AbstractNode for As { &self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { self.expression - .define_and_validate(_context, _manage_memory)?; + .define_and_validate(_context, _manage_memory, scope)?; match self.constructor { TypeConstructor::Raw(_) => {} @@ -50,9 +51,10 @@ impl AbstractNode for As { self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let expression_position = self.expression.position(); - let evaluation = self.expression.evaluate(context, _manage_memory)?; + let evaluation = self.expression.evaluate(context, _manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs index e20452f..75a7c92 100644 --- a/dust-lang/src/abstract_tree/assignment.rs +++ b/dust-lang/src/abstract_tree/assignment.rs @@ -9,7 +9,9 @@ use crate::{ Context, Value, }; -use super::{AbstractNode, Evaluation, Statement, Type, TypeConstructor, WithPosition}; +use super::{ + AbstractNode, Evaluation, SourcePosition, Statement, Type, TypeConstructor, WithPosition, +}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Assignment { @@ -47,20 +49,21 @@ impl AbstractNode for Assignment { &self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { - if let Some(constructor) = &self.constructor { - let r#type = constructor.construct(&context)?; - - context.set_type(self.identifier.node.clone(), r#type.clone())?; + let r#type = if let Some(constructor) = &self.constructor { + constructor.construct(&context)? } else if let Some(r#type) = self.statement.expected_type(context)? { - context.set_type(self.identifier.node.clone(), r#type)?; + r#type } else { return Err(ValidationError::CannotAssignToNone( self.statement.last_evaluated_statement().position(), )); }; - self.statement.define_and_validate(context, manage_memory)?; + context.set_type(self.identifier.node.clone(), r#type, scope)?; + self.statement + .define_and_validate(context, manage_memory, scope)?; let statement_type = self.statement.expected_type(context)?; @@ -91,8 +94,9 @@ impl AbstractNode for Assignment { self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { - let evaluation = self.statement.evaluate(context, manage_memory)?; + let evaluation = self.statement.evaluate(context, manage_memory, scope)?; let right = match evaluation { Some(Evaluation::Return(value)) => value, evaluation => return Ok(evaluation), @@ -100,7 +104,7 @@ impl AbstractNode for Assignment { match self.operator { AssignmentOperator::Assign => { - context.set_value(self.identifier.node, right)?; + context.set_value(self.identifier.node, right, scope)?; } AssignmentOperator::AddAssign => { let left_option = if manage_memory { @@ -137,7 +141,7 @@ impl AbstractNode for Assignment { )) } }; - context.set_value(self.identifier.node, new_value)?; + context.set_value(self.identifier.node, new_value, scope)?; } else { return Err(RuntimeError::ValidationFailure( ValidationError::VariableNotFound { @@ -182,7 +186,7 @@ impl AbstractNode for Assignment { )) } }; - context.set_value(self.identifier.node, new_value)?; + context.set_value(self.identifier.node, new_value, scope)?; } else { return Err(RuntimeError::ValidationFailure( ValidationError::VariableNotFound { diff --git a/dust-lang/src/abstract_tree/async_block.rs b/dust-lang/src/abstract_tree/async_block.rs index 4851820..d3dcc39 100644 --- a/dust-lang/src/abstract_tree/async_block.rs +++ b/dust-lang/src/abstract_tree/async_block.rs @@ -11,7 +11,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractNode, Evaluation, Statement, Type}; +use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct AsyncBlock { @@ -29,20 +29,26 @@ impl AbstractNode for AsyncBlock { &self, _context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { for statement in &self.statements { - statement.define_and_validate(_context, manage_memory)?; + statement.define_and_validate(_context, manage_memory, scope)?; } Ok(()) } - fn evaluate(self, _context: &Context, _: bool) -> Result, RuntimeError> { + fn evaluate( + self, + _context: &Context, + _: bool, + scope: SourcePosition, + ) -> Result, RuntimeError> { let final_result = Mutex::new(Ok(None)); let statement_count = self.statements.len(); let error_option = self.statements.into_par_iter().enumerate().find_map_any( |(index, statement)| -> Option { - let result = statement.evaluate(&_context, false); + let result = statement.evaluate(&_context, false, scope); if let Err(error) = result { return Some(error); diff --git a/dust-lang/src/abstract_tree/block.rs b/dust-lang/src/abstract_tree/block.rs index 7ae11f3..ba106de 100644 --- a/dust-lang/src/abstract_tree/block.rs +++ b/dust-lang/src/abstract_tree/block.rs @@ -7,7 +7,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractNode, Evaluation, Statement, Type}; +use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Block { @@ -33,9 +33,10 @@ impl AbstractNode for Block { &self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { for statement in &self.statements { - statement.define_and_validate(_context, _manage_memory)?; + statement.define_and_validate(_context, _manage_memory, scope)?; } Ok(()) @@ -45,11 +46,12 @@ impl AbstractNode for Block { self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let mut previous = None; for statement in self.statements { - previous = statement.evaluate(_context, _manage_memory)?; + previous = statement.evaluate(_context, _manage_memory, scope)?; } Ok(previous) @@ -96,7 +98,9 @@ mod tests { ]); assert_eq!( - block.evaluate(&Context::new(None), true).unwrap(), + block + .evaluate(&Context::new(), true, SourcePosition(0, 0)) + .unwrap(), Some(Evaluation::Return(Value::integer(42))) ) } @@ -113,7 +117,7 @@ mod tests { ]); assert_eq!( - block.expected_type(&Context::new(None)), + block.expected_type(&Context::new()), Ok(Some(Type::Integer)) ) } diff --git a/dust-lang/src/abstract_tree/built_in_function.rs b/dust-lang/src/abstract_tree/built_in_function.rs index ae6200a..91b2f9e 100644 --- a/dust-lang/src/abstract_tree/built_in_function.rs +++ b/dust-lang/src/abstract_tree/built_in_function.rs @@ -85,7 +85,7 @@ impl FunctionLogic for Length { Type::Function { type_parameters: None, value_parameters: Some(vec![( - Identifier::new("list"), + Identifier::from("list"), Type::ListOf(Box::new(Type::Any)), )]), return_type: Some(Box::new(Type::Integer)), @@ -93,7 +93,7 @@ impl FunctionLogic for Length { } fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::new("input"))? { + let value = if let Some(value) = context.get_value(&Identifier::from("input"))? { value } else { return Err(RuntimeError::ValidationFailure( @@ -119,13 +119,13 @@ impl FunctionLogic for ReadFile { fn r#type() -> Type { Type::Function { type_parameters: None, - value_parameters: Some(vec![(Identifier::new("path"), Type::String)]), + value_parameters: Some(vec![(Identifier::from("path"), Type::String)]), return_type: Some(Box::new(Type::String)), } } fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::new("path"))? { + let value = if let Some(value) = context.get_value(&Identifier::from("path"))? { value } else { return Err(RuntimeError::ValidationFailure( @@ -173,13 +173,13 @@ impl FunctionLogic for Sleep { fn r#type() -> Type { Type::Function { type_parameters: None, - value_parameters: Some(vec![(Identifier::new("milliseconds"), Type::Integer)]), + value_parameters: Some(vec![(Identifier::from("milliseconds"), Type::Integer)]), return_type: None, } } fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::new("milliseconds"))? { + let value = if let Some(value) = context.get_value(&Identifier::from("milliseconds"))? { value } else { return Err(RuntimeError::ValidationFailure( @@ -207,13 +207,13 @@ impl FunctionLogic for WriteLine { fn r#type() -> Type { Type::Function { type_parameters: None, - value_parameters: Some(vec![(Identifier::new("output"), Type::String)]), + value_parameters: Some(vec![(Identifier::from("output"), Type::String)]), return_type: None, } } fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::new("output"))? { + let value = if let Some(value) = context.get_value(&Identifier::from("output"))? { value } else { return Err(RuntimeError::ValidationFailure( @@ -240,26 +240,26 @@ struct JsonParse; impl FunctionLogic for JsonParse { fn r#type() -> Type { let type_t = Type::Generic { - identifier: Identifier::new("T"), + identifier: Identifier::from("T"), concrete_type: None, }; Type::Function { type_parameters: None, - value_parameters: Some(vec![(Identifier::new("input"), type_t.clone())]), + value_parameters: Some(vec![(Identifier::from("input"), type_t.clone())]), return_type: Some(Box::new(type_t)), } } fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let target_type = if let Some(r#type) = context.get_type(&Identifier::new("T"))? { + let target_type = if let Some(r#type) = context.get_type(&Identifier::from("T"))? { r#type } else { return Err(RuntimeError::ValidationFailure( ValidationError::BuiltInFunctionFailure("T does not exist"), )); }; - let value = if let Some(value) = context.get_value(&Identifier::new("input"))? { + let value = if let Some(value) = context.get_value(&Identifier::from("input"))? { value } else { return Err(RuntimeError::ValidationFailure( diff --git a/dust-lang/src/abstract_tree/enum_declaration.rs b/dust-lang/src/abstract_tree/enum_declaration.rs index 1c367bf..9e4f43d 100644 --- a/dust-lang/src/abstract_tree/enum_declaration.rs +++ b/dust-lang/src/abstract_tree/enum_declaration.rs @@ -8,7 +8,7 @@ use crate::{ identifier::Identifier, }; -use super::{AbstractNode, Evaluation, Type, TypeConstructor, WithPosition}; +use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct EnumDeclaration { @@ -32,7 +32,12 @@ impl EnumDeclaration { } impl AbstractNode for EnumDeclaration { - fn define_and_validate(&self, context: &Context, _: bool) -> Result<(), ValidationError> { + fn define_and_validate( + &self, + context: &Context, + _: bool, + scope: SourcePosition, + ) -> Result<(), ValidationError> { let EnumDeclaration { name, type_parameters, @@ -73,13 +78,25 @@ impl AbstractNode for EnumDeclaration { type_parameters, variants: type_variants, }; + let final_node_position = if let Some(constructors) = &self.variants.last().unwrap().content + { + constructors.last().unwrap().position() + } else { + self.variants.last().unwrap().name.position + }; + let scope = SourcePosition(self.name.position.0, final_node_position.1); - context.set_type(name.node.clone(), r#type)?; + context.set_type(name.node.clone(), r#type, scope)?; Ok(()) } - fn evaluate(self, _: &Context, _: bool) -> Result, RuntimeError> { + fn evaluate( + self, + _: &Context, + _: bool, + scope: SourcePosition, + ) -> Result, RuntimeError> { Ok(None) } diff --git a/dust-lang/src/abstract_tree/expression.rs b/dust-lang/src/abstract_tree/expression.rs index b1d8c55..ce038fa 100644 --- a/dust-lang/src/abstract_tree/expression.rs +++ b/dust-lang/src/abstract_tree/expression.rs @@ -45,12 +45,15 @@ impl AbstractNode for Expression { &self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { match self { - Expression::As(r#as) => r#as.node.define_and_validate(context, manage_memory), - Expression::FunctionCall(function_call) => function_call - .node - .define_and_validate(context, manage_memory), + Expression::As(r#as) => r#as.node.define_and_validate(context, manage_memory, scope), + Expression::FunctionCall(function_call) => { + function_call + .node + .define_and_validate(context, manage_memory, scope) + } Expression::Identifier(identifier) => { let found = context.add_expected_use(&identifier.node)?; @@ -64,15 +67,25 @@ impl AbstractNode for Expression { } } Expression::MapIndex(map_index) => { - map_index.node.define_and_validate(context, manage_memory) + map_index + .node + .define_and_validate(context, manage_memory, scope) } Expression::ListIndex(list_index) => { - list_index.node.define_and_validate(context, manage_memory) + list_index + .node + .define_and_validate(context, manage_memory, scope) } - Expression::Logic(logic) => logic.node.define_and_validate(context, manage_memory), - Expression::Math(math) => math.node.define_and_validate(context, manage_memory), + Expression::Logic(logic) => { + logic + .node + .define_and_validate(context, manage_memory, scope) + } + Expression::Math(math) => math.node.define_and_validate(context, manage_memory, scope), Expression::Value(value_node) => { - value_node.node.define_and_validate(context, manage_memory) + value_node + .node + .define_and_validate(context, manage_memory, scope) } } } @@ -81,11 +94,12 @@ impl AbstractNode for Expression { self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { match self { - Expression::As(r#as) => r#as.node.evaluate(context, manage_memory), + Expression::As(r#as) => r#as.node.evaluate(context, manage_memory, scope), Expression::FunctionCall(function_call) => { - function_call.node.evaluate(context, manage_memory) + function_call.node.evaluate(context, manage_memory, scope) } Expression::Identifier(identifier) => { let value_option = if manage_memory { @@ -105,11 +119,17 @@ impl AbstractNode for Expression { )) } } - Expression::MapIndex(map_index) => map_index.node.evaluate(context, manage_memory), - Expression::ListIndex(list_index) => list_index.node.evaluate(context, manage_memory), - Expression::Logic(logic) => logic.node.evaluate(context, manage_memory), - Expression::Math(math) => math.node.evaluate(context, manage_memory), - Expression::Value(value_node) => value_node.node.evaluate(context, manage_memory), + Expression::MapIndex(map_index) => { + map_index.node.evaluate(context, manage_memory, scope) + } + Expression::ListIndex(list_index) => { + list_index.node.evaluate(context, manage_memory, scope) + } + Expression::Logic(logic) => logic.node.evaluate(context, manage_memory, scope), + Expression::Math(math) => math.node.evaluate(context, manage_memory, scope), + Expression::Value(value_node) => { + value_node.node.evaluate(context, manage_memory, scope) + } } } diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index 7da0b10..57180d8 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -11,16 +11,13 @@ use crate::{ value::ValueInner, }; -use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; +use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, TypeConstructor}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FunctionCall { function_expression: Box, type_arguments: Option>, value_arguments: Option>, - - #[serde(skip)] - context: Context, } impl FunctionCall { @@ -33,7 +30,6 @@ impl FunctionCall { function_expression: Box::new(function_expression), type_arguments, value_arguments, - context: Context::new(None), } } } @@ -41,21 +37,21 @@ impl FunctionCall { impl AbstractNode for FunctionCall { fn define_and_validate( &self, - outer_context: &Context, + context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { - self.context.set_parent(outer_context.clone())?; self.function_expression - .define_and_validate(outer_context, manage_memory)?; + .define_and_validate(context, manage_memory, scope)?; if let Some(value_arguments) = &self.value_arguments { for expression in value_arguments { - expression.define_and_validate(outer_context, manage_memory)?; + expression.define_and_validate(context, manage_memory, scope)?; } } let function_node_type = - if let Some(r#type) = self.function_expression.expected_type(outer_context)? { + if let Some(r#type) = self.function_expression.expected_type(context)? { r#type } else { return Err(ValidationError::ExpectedValueStatement( @@ -78,9 +74,9 @@ impl AbstractNode for FunctionCall { } for (identifier, constructor) in parameters.into_iter().zip(arguments.into_iter()) { - let r#type = constructor.construct(outer_context)?; + let r#type = constructor.construct(context)?; - self.context.set_type(identifier, r#type)?; + context.set_type(identifier, r#type, self.function_expression.position())?; } } @@ -89,16 +85,19 @@ impl AbstractNode for FunctionCall { for ((identifier, _), expression) in parameters.iter().zip(arguments.into_iter()) { - let r#type = - if let Some(r#type) = expression.expected_type(outer_context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - expression.position(), - )); - }; + let r#type = if let Some(r#type) = expression.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedValueStatement( + expression.position(), + )); + }; - self.context.set_type(identifier.clone(), r#type)?; + context.set_type( + identifier.clone(), + r#type, + self.function_expression.position(), + )?; } if parameters.len() != arguments.len() { @@ -134,13 +133,14 @@ impl AbstractNode for FunctionCall { fn evaluate( self, - outer_context: &Context, + context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let function_position = self.function_expression.position(); let evaluation = self .function_expression - .evaluate(outer_context, manage_memory)?; + .evaluate(context, manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -156,9 +156,9 @@ impl AbstractNode for FunctionCall { for (identifier, constructor) in type_parameters.into_iter().zip(type_arguments.into_iter()) { - let r#type = constructor.construct(outer_context)?; + let r#type = constructor.construct(context)?; - self.context.set_type(identifier.clone(), r#type)?; + context.set_type(identifier.clone(), r#type, function_position)?; } } @@ -169,7 +169,7 @@ impl AbstractNode for FunctionCall { parameters.into_iter().zip(arguments.into_iter()) { let position = expression.position(); - let evaluation = expression.evaluate(outer_context, manage_memory)?; + let evaluation = expression.evaluate(context, manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -178,11 +178,11 @@ impl AbstractNode for FunctionCall { )); }; - self.context.set_value(identifier.clone(), value)?; + context.set_value(identifier.clone(), value, function_position)?; } } - return function.clone().call(&self.context, manage_memory); + return function.clone().call(context, manage_memory, scope); } if let ValueInner::BuiltInFunction(function) = value.inner().as_ref() { @@ -208,9 +208,9 @@ impl AbstractNode for FunctionCall { for (identifier, constructor) in type_parameters.into_iter().zip(type_arguments.into_iter()) { - let r#type = constructor.construct(outer_context)?; + let r#type = constructor.construct(context)?; - self.context.set_type(identifier.clone(), r#type)?; + context.set_type(identifier.clone(), r#type, function_position)?; } } @@ -219,7 +219,7 @@ impl AbstractNode for FunctionCall { parameters.into_iter().zip(arguments.into_iter()) { let position = expression.position(); - let evaluation = expression.evaluate(outer_context, manage_memory)?; + let evaluation = expression.evaluate(context, manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -228,18 +228,18 @@ impl AbstractNode for FunctionCall { )); }; - self.context.set_value(identifier.clone(), value)?; + context.set_value(identifier.clone(), value, function_position)?; } } return function - .call(&self.context, manage_memory) + .call(context, manage_memory) .map(|option| option.map(|value| Evaluation::Return(value))); } Err(RuntimeError::ValidationFailure( ValidationError::ExpectedFunction { - actual: value.r#type(outer_context)?, + actual: value.r#type(context)?, position: function_position, }, )) diff --git a/dust-lang/src/abstract_tree/if_else.rs b/dust-lang/src/abstract_tree/if_else.rs index 4886b5d..79302cd 100644 --- a/dust-lang/src/abstract_tree/if_else.rs +++ b/dust-lang/src/abstract_tree/if_else.rs @@ -8,7 +8,7 @@ use crate::{ value::ValueInner, }; -use super::{AbstractNode, Block, Evaluation, Expression, Type, WithPosition}; +use super::{AbstractNode, Block, Evaluation, Expression, SourcePosition, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct IfElse { @@ -39,12 +39,13 @@ impl AbstractNode for IfElse { &self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { self.if_expression - .define_and_validate(context, manage_memory)?; + .define_and_validate(context, manage_memory, scope)?; self.if_block .node - .define_and_validate(context, manage_memory)?; + .define_and_validate(context, manage_memory, scope)?; let if_expression_type = if let Some(r#type) = self.if_expression.expected_type(context)? { r#type @@ -60,7 +61,9 @@ impl AbstractNode for IfElse { let expression_type = expression.expected_type(context)?; if let Some(Type::Boolean) = expression_type { - block.node.define_and_validate(context, manage_memory)?; + block + .node + .define_and_validate(context, manage_memory, scope)?; let else_if_block_type = block.node.expected_type(context)?; @@ -83,7 +86,9 @@ impl AbstractNode for IfElse { } if let Some(block) = &self.else_block { - block.node.define_and_validate(context, manage_memory)?; + block + .node + .define_and_validate(context, manage_memory, scope)?; let else_if_block_type = block.node.expected_type(context)?; @@ -105,9 +110,12 @@ impl AbstractNode for IfElse { self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let if_position = self.if_expression.position(); - let evaluation = self.if_expression.evaluate(context, _manage_memory)?; + let evaluation = self + .if_expression + .evaluate(context, _manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -118,13 +126,13 @@ impl AbstractNode for IfElse { if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() { if *if_boolean { - return self.if_block.node.evaluate(context, _manage_memory); + return self.if_block.node.evaluate(context, _manage_memory, scope); } if let Some(else_ifs) = self.else_ifs { for (expression, block) in else_ifs { let expression_position = expression.position(); - let evaluation = expression.evaluate(context, _manage_memory)?; + let evaluation = expression.evaluate(context, _manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -135,7 +143,7 @@ impl AbstractNode for IfElse { if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() { if *else_if_boolean { - return block.node.evaluate(context, _manage_memory); + return block.node.evaluate(context, _manage_memory, scope); } } else { return Err(RuntimeError::ValidationFailure( @@ -149,7 +157,7 @@ impl AbstractNode for IfElse { } if let Some(else_statement) = self.else_block { - else_statement.node.evaluate(context, _manage_memory) + else_statement.node.evaluate(context, _manage_memory, scope) } else { Ok(None) } @@ -214,7 +222,7 @@ mod tests { Some(Vec::with_capacity(0)), None ) - .evaluate(&Context::new(None), true) + .evaluate(&Context::new(), true, SourcePosition(0, 0)) .unwrap(), Some(Evaluation::Return(Value::string("foo".to_string()))) ) diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs index 03fb612..351f41d 100644 --- a/dust-lang/src/abstract_tree/list_index.rs +++ b/dust-lang/src/abstract_tree/list_index.rs @@ -7,7 +7,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractNode, Evaluation, Expression, Type, ValueNode, WithPosition}; +use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, ValueNode, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct ListIndex { @@ -29,10 +29,12 @@ impl AbstractNode for ListIndex { &self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { self.collection - .define_and_validate(context, _manage_memory)?; - self.index.define_and_validate(context, _manage_memory)?; + .define_and_validate(context, _manage_memory, scope)?; + self.index + .define_and_validate(context, _manage_memory, scope)?; let collection_type = if let Some(r#type) = self.collection.expected_type(context)? { r#type @@ -77,9 +79,10 @@ impl AbstractNode for ListIndex { self, context: &Context, _clear_variables: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let left_position = self.collection.position(); - let left_evaluation = self.collection.evaluate(context, _clear_variables)?; + let left_evaluation = self.collection.evaluate(context, _clear_variables, scope)?; let left_value = if let Some(Evaluation::Return(value)) = left_evaluation { value } else { @@ -88,7 +91,7 @@ impl AbstractNode for ListIndex { )); }; let right_position = self.index.position(); - let right_evaluation = self.index.evaluate(context, _clear_variables)?; + let right_evaluation = self.index.evaluate(context, _clear_variables, scope)?; let right_value = if let Some(Evaluation::Return(value)) = right_evaluation { value } else { diff --git a/dust-lang/src/abstract_tree/logic.rs b/dust-lang/src/abstract_tree/logic.rs index a589b1f..9d181b2 100644 --- a/dust-lang/src/abstract_tree/logic.rs +++ b/dust-lang/src/abstract_tree/logic.rs @@ -9,7 +9,7 @@ use crate::{ Value, }; -use super::{AbstractNode, Evaluation, Expression, Type}; +use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Logic { @@ -29,6 +29,7 @@ impl AbstractNode for Logic { &self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { match self { Logic::Equal(left, right) @@ -37,8 +38,8 @@ impl AbstractNode for Logic { | Logic::Less(left, right) | Logic::GreaterOrEqual(left, right) | Logic::LessOrEqual(left, right) => { - left.define_and_validate(context, _manage_memory)?; - right.define_and_validate(context, _manage_memory)?; + left.define_and_validate(context, _manage_memory, scope)?; + right.define_and_validate(context, _manage_memory, scope)?; let left_type = if let Some(r#type) = left.expected_type(context)? { r#type @@ -62,8 +63,8 @@ impl AbstractNode for Logic { Ok(()) } Logic::And(left, right) | Logic::Or(left, right) => { - left.define_and_validate(context, _manage_memory)?; - right.define_and_validate(context, _manage_memory)?; + left.define_and_validate(context, _manage_memory, scope)?; + right.define_and_validate(context, _manage_memory, scope)?; let left_type = if let Some(r#type) = left.expected_type(context)? { r#type @@ -95,7 +96,7 @@ impl AbstractNode for Logic { Ok(()) } Logic::Not(expression) => { - expression.define_and_validate(context, _manage_memory)?; + expression.define_and_validate(context, _manage_memory, scope)?; let expression_type = if let Some(r#type) = expression.expected_type(context)? { r#type @@ -121,10 +122,11 @@ impl AbstractNode for Logic { self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let run_and_expect_value = |expression: Expression| -> Result { let expression_position = expression.position(); - let evaluation = expression.evaluate(&mut context.clone(), _manage_memory)?; + let evaluation = expression.evaluate(&mut context.clone(), _manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -138,7 +140,7 @@ impl AbstractNode for Logic { let run_and_expect_boolean = |expression: Expression| -> Result { let expression_position = expression.position(); - let evaluation = expression.evaluate(&mut context.clone(), _manage_memory)?; + let evaluation = expression.evaluate(&mut context.clone(), _manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -256,7 +258,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -268,7 +270,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -280,7 +282,7 @@ mod tests { Expression::Value(ValueNode::Integer(43).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -292,7 +294,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -304,7 +306,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(41).with_position((0, 0))) ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ); @@ -313,7 +315,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ); } @@ -325,7 +327,7 @@ mod tests { Expression::Value(ValueNode::Integer(41).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ); @@ -334,7 +336,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ); } @@ -346,7 +348,7 @@ mod tests { Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -358,7 +360,7 @@ mod tests { Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), Expression::Value(ValueNode::Boolean(false).with_position((0, 0))), ) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -369,7 +371,7 @@ mod tests { Logic::Not(Expression::Value( ValueNode::Boolean(false).with_position((0, 0)) )) - .evaluate(&mut Context::new(None), true), + .evaluate(&mut Context::new(), true, SourcePosition(0, 0)), Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } diff --git a/dust-lang/src/abstract_tree/loop.rs b/dust-lang/src/abstract_tree/loop.rs index 8091b95..c972a94 100644 --- a/dust-lang/src/abstract_tree/loop.rs +++ b/dust-lang/src/abstract_tree/loop.rs @@ -7,7 +7,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractNode, Evaluation, Statement, Type}; +use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Loop { @@ -29,9 +29,10 @@ impl AbstractNode for Loop { &self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { for statement in &self.statements { - statement.define_and_validate(_context, false)?; + statement.define_and_validate(_context, false, scope)?; } Ok(()) @@ -41,10 +42,11 @@ impl AbstractNode for Loop { self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { loop { for statement in &self.statements { - let run = statement.clone().evaluate(_context, false)?; + let run = statement.clone().evaluate(_context, false, scope)?; if let Some(Evaluation::Break) = run { return Ok(run); diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index 8546f1c..ca99b98 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -8,7 +8,7 @@ use crate::{ value::ValueInner, }; -use super::{AbstractNode, Evaluation, Expression, Type, ValueNode, WithPosition}; +use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, ValueNode, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct MapIndex { @@ -30,9 +30,10 @@ impl AbstractNode for MapIndex { &self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { self.collection - .define_and_validate(context, _manage_memory)?; + .define_and_validate(context, _manage_memory, scope)?; let collection_type = if let Some(r#type) = self.collection.expected_type(context)? { r#type @@ -56,7 +57,8 @@ impl AbstractNode for MapIndex { if let Expression::Identifier(_) = &self.index { Ok(()) } else { - self.index.define_and_validate(context, _manage_memory) + self.index + .define_and_validate(context, _manage_memory, scope) } } @@ -64,9 +66,10 @@ impl AbstractNode for MapIndex { self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let collection_position = self.collection.position(); - let evaluation = self.collection.evaluate(context, _manage_memory)?; + let evaluation = self.collection.evaluate(context, _manage_memory, scope)?; let collection = if let Some(Evaluation::Return(value)) = evaluation { value } else { diff --git a/dust-lang/src/abstract_tree/math.rs b/dust-lang/src/abstract_tree/math.rs index df43a17..7033024 100644 --- a/dust-lang/src/abstract_tree/math.rs +++ b/dust-lang/src/abstract_tree/math.rs @@ -25,6 +25,7 @@ impl AbstractNode for Math { &self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { match self { Math::Add(left, right) => { @@ -86,22 +87,24 @@ impl AbstractNode for Math { fn evaluate( self, _context: &Context, - _clear_variables: bool, + _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { - let run_and_expect_value = - |position: SourcePosition, expression: Expression| -> Result { - let evaluation = expression.evaluate(&mut _context.clone(), _clear_variables)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - }; - - Ok(value) + let run_and_expect_value = |position: SourcePosition, + expression: Expression| + -> Result { + let evaluation = expression.evaluate(&mut _context.clone(), _manage_memory, scope)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedValueStatement(position), + )); }; + Ok(value) + }; + let value = match self { Math::Add(left, right) => { let left_position = left.position(); diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index ac58748..80d5c8c 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -126,9 +126,11 @@ impl AbstractTree { manage_memory: bool, ) -> Result, Vec> { let mut errors = Vec::new(); + let global_scope = SourcePosition(0, usize::MAX); for statement in &self.0 { - let validation_result = statement.define_and_validate(context, manage_memory); + let validation_result = + statement.define_and_validate(context, manage_memory, global_scope); if let Err(error) = validation_result { errors.push(DustError::Validation { @@ -146,7 +148,7 @@ impl AbstractTree { for statement in self.0 { let position = statement.position(); - let run = statement.evaluate(context, manage_memory); + let run = statement.evaluate(context, manage_memory, global_scope); match run { Ok(evaluation) => match evaluation { @@ -180,9 +182,10 @@ impl AbstractNode for AbstractTree { &self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { for statement in &self.0 { - statement.define_and_validate(context, manage_memory)?; + statement.define_and_validate(context, manage_memory, scope)?; } Ok(()) @@ -192,11 +195,12 @@ impl AbstractNode for AbstractTree { self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let mut previous = None; for statement in self.0 { - previous = statement.evaluate(context, manage_memory)?; + previous = statement.evaluate(context, manage_memory, scope)?; } Ok(previous) @@ -212,12 +216,14 @@ pub trait AbstractNode { &self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError>; fn evaluate( self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError>; fn expected_type(&self, context: &Context) -> Result, ValidationError>; diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs index f55ae43..d148145 100644 --- a/dust-lang/src/abstract_tree/statement.rs +++ b/dust-lang/src/abstract_tree/statement.rs @@ -62,35 +62,60 @@ impl AbstractNode for Statement { &self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { log::trace!("Validating statement at {}", self.position()); match self { - Statement::Assignment(assignment) => assignment - .node - .define_and_validate(_context, _manage_memory), - Statement::AsyncBlock(async_block) => async_block - .node - .define_and_validate(_context, _manage_memory), - Statement::Block(block) => block.node.define_and_validate(_context, _manage_memory), + Statement::Assignment(assignment) => { + assignment + .node + .define_and_validate(_context, _manage_memory, scope) + } + Statement::AsyncBlock(async_block) => { + async_block + .node + .define_and_validate(_context, _manage_memory, scope) + } + Statement::Block(block) => { + block + .node + .define_and_validate(_context, _manage_memory, scope) + } Statement::EnumDeclaration(enum_declaration) => enum_declaration .node - .define_and_validate(_context, _manage_memory), + .define_and_validate(_context, _manage_memory, scope), Statement::Expression(expression) => { - expression.define_and_validate(_context, _manage_memory) + expression.define_and_validate(_context, _manage_memory, scope) } Statement::IfElse(if_else) => { - if_else.node.define_and_validate(_context, _manage_memory) + if_else + .node + .define_and_validate(_context, _manage_memory, scope) + } + Statement::Loop(r#loop) => { + r#loop + .node + .define_and_validate(_context, _manage_memory, scope) } - Statement::Loop(r#loop) => r#loop.node.define_and_validate(_context, _manage_memory), Statement::StructureDefinition(struct_definition) => struct_definition .node - .define_and_validate(_context, _manage_memory), - Statement::TypeAlias(type_alias) => type_alias - .node - .define_and_validate(_context, _manage_memory), - Statement::While(r#while) => r#while.node.define_and_validate(_context, _manage_memory), - Statement::Use(r#use) => r#use.node.define_and_validate(_context, _manage_memory), + .define_and_validate(_context, _manage_memory, scope), + Statement::TypeAlias(type_alias) => { + type_alias + .node + .define_and_validate(_context, _manage_memory, scope) + } + Statement::While(r#while) => { + r#while + .node + .define_and_validate(_context, _manage_memory, scope) + } + Statement::Use(r#use) => { + r#use + .node + .define_and_validate(_context, _manage_memory, scope) + } Statement::Break(_) | Statement::Null(_) => Ok(()), } } @@ -99,27 +124,34 @@ impl AbstractNode for Statement { self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { log::trace!("Evaluating statement at {}", self.position()); let result = match self { - Statement::Assignment(assignment) => assignment.node.evaluate(context, manage_memory), - Statement::AsyncBlock(async_block) => async_block.node.evaluate(context, manage_memory), - Statement::Block(block) => block.node.evaluate(context, manage_memory), + Statement::Assignment(assignment) => { + assignment.node.evaluate(context, manage_memory, scope) + } + Statement::AsyncBlock(async_block) => { + async_block.node.evaluate(context, manage_memory, scope) + } + Statement::Block(block) => block.node.evaluate(context, manage_memory, scope), Statement::Break(_) => Ok(Some(Evaluation::Break)), - Statement::Expression(expression) => expression.evaluate(context, manage_memory), - Statement::IfElse(if_else) => if_else.node.evaluate(context, manage_memory), - Statement::Loop(r#loop) => r#loop.node.evaluate(context, manage_memory), + Statement::Expression(expression) => expression.evaluate(context, manage_memory, scope), + Statement::IfElse(if_else) => if_else.node.evaluate(context, manage_memory, scope), + Statement::Loop(r#loop) => r#loop.node.evaluate(context, manage_memory, scope), Statement::Null(_) => Ok(None), - Statement::StructureDefinition(structure_definition) => { - structure_definition.node.evaluate(context, manage_memory) + Statement::StructureDefinition(structure_definition) => structure_definition + .node + .evaluate(context, manage_memory, scope), + Statement::TypeAlias(type_alias) => { + type_alias.node.evaluate(context, manage_memory, scope) } - Statement::TypeAlias(type_alias) => type_alias.node.evaluate(context, manage_memory), Statement::EnumDeclaration(type_alias) => { - type_alias.node.evaluate(context, manage_memory) + type_alias.node.evaluate(context, manage_memory, scope) } - Statement::While(r#while) => r#while.node.evaluate(context, manage_memory), - Statement::Use(r#use) => r#use.node.evaluate(context, manage_memory), + Statement::While(r#while) => r#while.node.evaluate(context, manage_memory, scope), + Statement::Use(r#use) => r#use.node.evaluate(context, manage_memory, scope), }; if manage_memory { diff --git a/dust-lang/src/abstract_tree/structure_definition.rs b/dust-lang/src/abstract_tree/structure_definition.rs index 4040c6a..7927bc8 100644 --- a/dust-lang/src/abstract_tree/structure_definition.rs +++ b/dust-lang/src/abstract_tree/structure_definition.rs @@ -8,7 +8,7 @@ use crate::{ identifier::Identifier, }; -use super::{AbstractNode, Evaluation, Type, TypeConstructor}; +use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct StructureDefinition { @@ -23,7 +23,12 @@ impl StructureDefinition { } impl AbstractNode for StructureDefinition { - fn define_and_validate(&self, context: &Context, _: bool) -> Result<(), ValidationError> { + fn define_and_validate( + &self, + context: &Context, + _: bool, + scope: SourcePosition, + ) -> Result<(), ValidationError> { let mut fields = Vec::with_capacity(self.fields.len()); for (identifier, constructor) in &self.fields { @@ -37,7 +42,7 @@ impl AbstractNode for StructureDefinition { fields, }; - context.set_type(self.name.clone(), struct_type)?; + context.set_type(self.name.clone(), struct_type, scope)?; Ok(()) } @@ -46,6 +51,7 @@ impl AbstractNode for StructureDefinition { self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let mut fields = Vec::with_capacity(self.fields.len()); @@ -60,7 +66,7 @@ impl AbstractNode for StructureDefinition { fields, }; - context.set_type(self.name, struct_type)?; + context.set_type(self.name, struct_type, scope)?; Ok(None) } diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index c963a68..65c479c 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -325,9 +325,9 @@ mod tests { let mut map = BTreeMap::new(); - map.insert(Identifier::new("x"), Type::Integer); - map.insert(Identifier::new("y"), Type::String); - map.insert(Identifier::new("z"), Type::Map(map.clone())); + map.insert(Identifier::from("x"), Type::Integer); + map.insert(Identifier::from("y"), Type::String); + map.insert(Identifier::from("z"), Type::Map(map.clone())); assert_eq!(Type::Map(map.clone()).check(&Type::Map(map)), Ok(())); assert_eq!(Type::Range.check(&Type::Range), Ok(())); diff --git a/dust-lang/src/abstract_tree/type_alias.rs b/dust-lang/src/abstract_tree/type_alias.rs index dd183eb..7ec05be 100644 --- a/dust-lang/src/abstract_tree/type_alias.rs +++ b/dust-lang/src/abstract_tree/type_alias.rs @@ -8,7 +8,7 @@ use crate::{ identifier::Identifier, }; -use super::{AbstractNode, Evaluation, Type, TypeConstructor, WithPosition}; +use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct TypeAlias { @@ -26,15 +26,25 @@ impl TypeAlias { } impl AbstractNode for TypeAlias { - fn define_and_validate(&self, context: &Context, _: bool) -> Result<(), ValidationError> { + fn define_and_validate( + &self, + context: &Context, + _: bool, + scope: SourcePosition, + ) -> Result<(), ValidationError> { let r#type = self.constructor.construct(&context)?; - context.set_type(self.identifier.node.clone(), r#type)?; + context.set_type(self.identifier.node.clone(), r#type, scope)?; Ok(()) } - fn evaluate(self, _: &Context, _: bool) -> Result, RuntimeError> { + fn evaluate( + self, + _: &Context, + _: bool, + _: SourcePosition, + ) -> Result, RuntimeError> { Ok(None) } diff --git a/dust-lang/src/abstract_tree/use.rs b/dust-lang/src/abstract_tree/use.rs index 6a536e1..e8ac7fb 100644 --- a/dust-lang/src/abstract_tree/use.rs +++ b/dust-lang/src/abstract_tree/use.rs @@ -17,7 +17,7 @@ use crate::{ Type, }; -use super::{AbstractNode, AbstractTree, Evaluation}; +use super::{AbstractNode, AbstractTree, Evaluation, SourcePosition}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Use { @@ -41,6 +41,7 @@ impl AbstractNode for Use { &self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { let abstract_tree = match self.path.as_str() { "std.fs" => std_fs_compiled().clone(), @@ -59,7 +60,7 @@ impl AbstractNode for Use { *self.abstract_tree.write()? = Some(abstract_tree); if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() { - abstract_tree.define_and_validate(context, manage_memory) + abstract_tree.define_and_validate(context, manage_memory, scope) } else { Err(ValidationError::Uninitialized) } @@ -69,9 +70,12 @@ impl AbstractNode for Use { self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() { - abstract_tree.clone().evaluate(context, manage_memory) + abstract_tree + .clone() + .evaluate(context, manage_memory, scope) } else { Err(RuntimeError::ValidationFailure( ValidationError::Uninitialized, diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index b4f8f0f..b8f62ba 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -15,8 +15,8 @@ use crate::{ }; use super::{ - AbstractNode, Block, BuiltInFunction, Evaluation, Expression, Type, TypeConstructor, WithPos, - WithPosition, + AbstractNode, Block, BuiltInFunction, Evaluation, Expression, SourcePosition, Type, + TypeConstructor, WithPos, WithPosition, }; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -53,7 +53,6 @@ impl ValueNode { value_parameters, return_type, body, - validation_context: Context::new(None), }) } } @@ -63,6 +62,7 @@ impl AbstractNode for ValueNode { &self, context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { if let ValueNode::List(list) = self { let mut items = list.into_iter(); @@ -76,7 +76,7 @@ impl AbstractNode for ValueNode { }; for item in items { - item.define_and_validate(context, _manage_memory)?; + item.define_and_validate(context, _manage_memory, scope)?; let item_type = if let Some(r#type) = item.expected_type(context)? { r#type @@ -102,7 +102,7 @@ impl AbstractNode for ValueNode { { if let Some(expressions) = content { for expression in expressions { - expression.define_and_validate(context, _manage_memory)?; + expression.define_and_validate(context, _manage_memory, scope)?; } } @@ -127,7 +127,7 @@ impl AbstractNode for ValueNode { if let ValueNode::Map(map_assignments) = self { for (_identifier, constructor_option, expression) in map_assignments { - expression.define_and_validate(context, _manage_memory)?; + expression.define_and_validate(context, _manage_memory, scope)?; if let Some(constructor) = constructor_option { let actual_type = if let Some(r#type) = expression.expected_type(context)? { @@ -155,45 +155,38 @@ impl AbstractNode for ValueNode { if let ValueNode::Function(FunctionNode { return_type, body, - validation_context, type_parameters, value_parameters, }) = self { - let outer_context = context; - - validation_context.set_parent(outer_context.clone())?; - if let Some(type_parameters) = type_parameters { for identifier in type_parameters { - validation_context.set_type( + context.set_type( identifier.clone(), Type::Generic { identifier: identifier.clone(), concrete_type: None, }, + body.position, )?; } } if let Some(value_parameters) = value_parameters { for (identifier, type_constructor) in value_parameters { - let r#type = type_constructor.clone().construct(outer_context)?; + let r#type = type_constructor.clone().construct(context)?; - validation_context.set_type(identifier.clone(), r#type)?; + context.set_type(identifier.clone(), r#type, body.position)?; } } body.node - .define_and_validate(&validation_context, _manage_memory)?; + .define_and_validate(context, _manage_memory, scope)?; let ((expected_return, expected_position), actual_return) = - match (return_type, body.node.expected_type(&validation_context)?) { + match (return_type, body.node.expected_type(context)?) { (Some(constructor), Some(r#type)) => ( - ( - constructor.construct(validation_context)?, - constructor.position(), - ), + (constructor.construct(context)?, constructor.position()), r#type, ), (None, Some(_)) => { @@ -238,7 +231,7 @@ impl AbstractNode for ValueNode { }) = context.get_type(&name.node)? { for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) { - expression.define_and_validate(context, _manage_memory)?; + expression.define_and_validate(context, _manage_memory, scope)?; let actual_type = if let Some(r#type) = expression.expected_type(context)? { r#type @@ -266,6 +259,7 @@ impl AbstractNode for ValueNode { self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let value = match self { ValueNode::Boolean(boolean) => Value::boolean(boolean), @@ -279,7 +273,7 @@ impl AbstractNode for ValueNode { for expression in expressions { let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory)?; + let evaluation = expression.evaluate(context, manage_memory, scope)?; if let Some(Evaluation::Return(value)) = evaluation { values.push(value); @@ -303,7 +297,7 @@ impl AbstractNode for ValueNode { for expression in expression_list { let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory)?; + let evaluation = expression.evaluate(context, manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -322,7 +316,7 @@ impl AbstractNode for ValueNode { for (identifier, _type, expression) in property_list { let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory)?; + let evaluation = expression.evaluate(context, manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -375,7 +369,7 @@ impl AbstractNode for ValueNode { for (identifier, expression) in expressions { let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory)?; + let evaluation = expression.evaluate(context, manage_memory, scope)?; let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { @@ -703,7 +697,6 @@ impl Display for ValueNode { value_parameters, return_type, body, - validation_context: _, }) => { write!(f, "fn ")?; @@ -743,8 +736,6 @@ pub struct FunctionNode { value_parameters: Option>, return_type: Option, body: WithPosition, - #[serde(skip)] - validation_context: Context, } impl PartialEq for FunctionNode { diff --git a/dust-lang/src/abstract_tree/while.rs b/dust-lang/src/abstract_tree/while.rs index 8186445..bacca7f 100644 --- a/dust-lang/src/abstract_tree/while.rs +++ b/dust-lang/src/abstract_tree/while.rs @@ -9,7 +9,7 @@ use crate::{ Value, }; -use super::{AbstractNode, Evaluation, Expression, Statement, Type}; +use super::{AbstractNode, Evaluation, Expression, SourcePosition, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct While { @@ -31,11 +31,13 @@ impl AbstractNode for While { &self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result<(), ValidationError> { - self.expression.define_and_validate(_context, false)?; + self.expression + .define_and_validate(_context, false, scope)?; for statement in &self.statements { - statement.define_and_validate(_context, false)?; + statement.define_and_validate(_context, false, scope)?; } Ok(()) @@ -45,13 +47,14 @@ impl AbstractNode for While { self, _context: &Context, _manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { let get_boolean = || -> Result { let expression_position = self.expression.position(); - let evaluation = self - .expression - .clone() - .evaluate(&mut _context.clone(), false)?; + let evaluation = + self.expression + .clone() + .evaluate(&mut _context.clone(), false, scope)?; if let Some(Evaluation::Return(value)) = evaluation { Ok(value) @@ -64,7 +67,9 @@ impl AbstractNode for While { while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() { for statement in &self.statements { - let evaluation = statement.clone().evaluate(&mut _context.clone(), false)?; + let evaluation = statement + .clone() + .evaluate(&mut _context.clone(), false, scope)?; if let Some(Evaluation::Break) = evaluation { return Ok(evaluation); diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index f96c951..595e3e7 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -5,7 +5,7 @@ use std::{ }; use crate::{ - abstract_tree::Type, + abstract_tree::{SourcePosition, Type}, error::{PoisonError, ValidationError}, identifier::Identifier, standard_library::core_context, @@ -15,132 +15,63 @@ use crate::{ #[derive(Clone, Debug)] pub struct Context { - data: Arc>, + variables: Arc>>, is_clean: Arc>, } -#[derive(Clone, Debug)] -struct ContextData { - variables: HashMap, - parent: Option, -} - impl Context { - pub fn new(parent: Option) -> Self { + pub fn new() -> Self { Context { - data: Arc::new(RwLock::new(ContextData { - variables: HashMap::new(), - parent, - })), + variables: Arc::new(RwLock::new(HashMap::new())), is_clean: Arc::new(RwLock::new(true)), } } - pub fn new_with_std_core(parent: Option) -> Result { + pub fn new_with_std_core() -> Result { let new = Context::with_variables_from(core_context())?; - if let Some(context) = parent { - new.set_parent(context)?; - } - Ok(new) } pub fn with_variables_from(other: &Context) -> Result { - let variables = other.data.read()?.variables.clone(); + let variables = other.variables.read()?.clone(); Ok(Context { - data: Arc::new(RwLock::new(ContextData { - variables, - parent: None, - })), + variables: Arc::new(RwLock::new(variables)), is_clean: Arc::new(RwLock::new(true)), }) } - pub fn create_child(&self) -> Context { - Context::new(Some(self.clone())) - } - - pub fn set_parent(&self, parent: Context) -> Result<(), PoisonError> { - self.data.write()?.parent = Some(parent); - - Ok(()) - } - - pub fn contains(&self, identifier: &Identifier) -> Result { + pub fn contains( + &self, + identifier: &Identifier, + scope: SourcePosition, + ) -> Result { log::trace!("Checking that {identifier} exists"); - let data = self.data.read()?; + let variables = self.variables.read()?; - if let Some(_) = data.variables.get(identifier) { - Ok(true) - } else if let Some(parent) = &data.parent { - parent.contains_inheritable(identifier) - } else { - Ok(false) - } - } - - fn contains_inheritable(&self, identifier: &Identifier) -> Result { - let data = self.data.read()?; - - if let Some((variable_data, _)) = data.variables.get(identifier) { - match variable_data { - VariableData::Type(Type::Enum { .. }) - | VariableData::Type(Type::Function { .. }) - | VariableData::Type(Type::Structure { .. }) => return Ok(true), - VariableData::Value(value) => match value.inner().as_ref() { - ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => return Ok(true), - _ => {} - }, - _ => {} + if let Some((_, _, variable_scope)) = variables.get(identifier) { + if scope.0 >= variable_scope.0 && scope.1 <= variable_scope.1 { + return Ok(true); } } - if let Some(parent) = &data.parent { - parent.contains_inheritable(identifier) - } else { - Ok(false) - } + Ok(false) } pub fn get_type(&self, identifier: &Identifier) -> Result, ValidationError> { log::trace!("Getting {identifier}'s type"); - let data = self.data.read()?; + let variables = self.variables.read()?; - if let Some((data, _)) = data.variables.get(identifier) { + if let Some((data, _, _)) = variables.get(identifier) { let r#type = match data { VariableData::Type(r#type) => r#type.clone(), VariableData::Value(value) => value.r#type(self)?, }; Ok(Some(r#type.clone())) - } else if let Some(parent) = &data.parent { - parent.get_inheritable_type(identifier) - } else { - Ok(None) - } - } - - fn get_inheritable_type( - &self, - identifier: &Identifier, - ) -> Result, ValidationError> { - let data = self.data.read()?; - - if let Some(r#type) = self.get_type(identifier)? { - match r#type { - Type::Enum { .. } | Type::Function { .. } | Type::Structure { .. } => { - return Ok(Some(r#type)) - } - _ => {} - } - } - - if let Some(parent) = &data.parent { - parent.get_inheritable_type(identifier) } else { Ok(None) } @@ -149,37 +80,13 @@ impl Context { pub fn use_value(&self, identifier: &Identifier) -> Result, PoisonError> { log::trace!("Using {identifier}'s value"); - let data = self.data.read()?; + let variables = self.variables.read()?; - if let Some((VariableData::Value(value), usage_data)) = data.variables.get(identifier) { + if let Some((VariableData::Value(value), usage_data, _)) = variables.get(identifier) { usage_data.inner().write()?.actual += 1; *self.is_clean.write()? = false; return Ok(Some(value.clone())); - } else if let Some(parent) = &data.parent { - parent.use_inheritable_value(identifier) - } else { - Ok(None) - } - } - - fn use_inheritable_value(&self, identifier: &Identifier) -> Result, PoisonError> { - let data = self.data.read()?; - - if let Some((VariableData::Value(value), usage_data)) = data.variables.get(identifier) { - match value.inner().as_ref() { - ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => { - usage_data.inner().write()?.actual += 1; - *self.is_clean.write()? = false; - - return Ok(Some(value.clone())); - } - _ => {} - } - } - - if let Some(parent) = &data.parent { - parent.use_inheritable_value(identifier) } else { Ok(None) } @@ -188,62 +95,49 @@ impl Context { pub fn get_value(&self, identifier: &Identifier) -> Result, PoisonError> { log::trace!("Getting {identifier}'s value"); - let data = self.data.read()?; + let variables = self.variables.read()?; - if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) { + if let Some((VariableData::Value(value), _, _)) = variables.get(identifier) { Ok(Some(value.clone())) - } else if let Some(parent) = &data.parent { - parent.get_inheritable_value(identifier) } else { Ok(None) } } - fn get_inheritable_value(&self, identifier: &Identifier) -> Result, PoisonError> { - if let Some(value) = self.get_value(identifier)? { - match value.inner().as_ref() { - ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => return Ok(Some(value)), - _ => {} - } - } - - let data = self.data.read()?; - - if let Some(parent) = &data.parent { - parent.get_inheritable_value(identifier) - } else { - Ok(None) - } - } - - pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> { + pub fn set_type( + &self, + identifier: Identifier, + r#type: Type, + scope: SourcePosition, + ) -> Result<(), PoisonError> { log::debug!("Setting {identifier} to type {}", r#type); - let mut data = self.data.write()?; - let usage_data = data - .variables + let mut variables = self.variables.write()?; + let (usage_data, scope) = variables .remove(&identifier) - .map(|(_, usage_data)| usage_data) - .unwrap_or_else(|| UsageData::new()); + .map(|(_, old_usage_data, old_scope)| (old_usage_data, old_scope)) + .unwrap_or_else(|| (UsageData::new(), scope)); - data.variables - .insert(identifier, (VariableData::Type(r#type), usage_data)); + variables.insert(identifier, (VariableData::Type(r#type), usage_data, scope)); Ok(()) } - pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> { + pub fn set_value( + &self, + identifier: Identifier, + value: Value, + scope: SourcePosition, + ) -> Result<(), PoisonError> { log::debug!("Setting {identifier} to value {value}"); - let mut data = self.data.write()?; - let usage_data = data - .variables + let mut variables = self.variables.write()?; + let (usage_data, scope) = variables .remove(&identifier) - .map(|(_, usage_data)| usage_data) - .unwrap_or_else(|| UsageData::new()); + .map(|(_, old_usage_data, old_scope)| (old_usage_data, old_scope)) + .unwrap_or_else(|| (UsageData::new(), scope)); - data.variables - .insert(identifier, (VariableData::Value(value), usage_data)); + variables.insert(identifier, (VariableData::Value(value), usage_data, scope)); Ok(()) } @@ -251,48 +145,12 @@ impl Context { pub fn add_expected_use(&self, identifier: &Identifier) -> Result { log::trace!("Adding expected use for variable {identifier}"); - let data = self.data.read()?; + let variables = self.variables.read()?; - if let Some((_, usage_data)) = data.variables.get(identifier) { + if let Some((_, usage_data, _)) = variables.get(identifier) { usage_data.inner().write()?.expected += 1; return Ok(true); - } else if let Some(parent) = &data.parent { - parent.add_expected_use_for_inheritable(identifier) - } else { - Ok(false) - } - } - - fn add_expected_use_for_inheritable( - &self, - identifier: &Identifier, - ) -> Result { - let data = self.data.read()?; - - if let Some((variable_data, usage_data)) = data.variables.get(identifier) { - match variable_data { - VariableData::Type(Type::Enum { .. }) - | VariableData::Type(Type::Function { .. }) - | VariableData::Type(Type::Structure { .. }) => { - usage_data.inner().write()?.expected += 1; - - return Ok(true); - } - VariableData::Value(value) => match value.inner().as_ref() { - ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => { - usage_data.inner().write()?.expected += 1; - - return Ok(true); - } - _ => {} - }, - _ => {} - } - } - - if let Some(parent) = &data.parent { - parent.add_expected_use_for_inheritable(identifier) } else { Ok(false) } @@ -303,8 +161,8 @@ impl Context { return Ok(()); } - self.data.write()?.variables.retain( - |identifier, (value_data, usage_data)| match value_data { + self.variables.write()?.retain( + |identifier, (value_data, usage_data, _)| match value_data { VariableData::Type(_) => true, VariableData::Value(_) => { let usage = usage_data.inner().read().unwrap(); @@ -332,7 +190,7 @@ impl Context { impl Default for Context { fn default() -> Self { - Context::new(None) + Context::new() } } diff --git a/dust-lang/src/identifier.rs b/dust-lang/src/identifier.rs index 9362c20..afa6a5d 100644 --- a/dust-lang/src/identifier.rs +++ b/dust-lang/src/identifier.rs @@ -1,40 +1,46 @@ use std::{ collections::HashMap, fmt::{self, Display, Formatter}, + hash::{Hash, Hasher}, sync::{Arc, OnceLock, RwLock}, }; use serde::{de::Visitor, Deserialize, Serialize}; +use crate::abstract_tree::SourcePosition; + static IDENTIFIER_CACHE: OnceLock>> = OnceLock::new(); fn identifier_cache<'a>() -> &'a RwLock> { IDENTIFIER_CACHE.get_or_init(|| RwLock::new(HashMap::new())) } -#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct Identifier(Arc); impl Identifier { - pub fn new(text: &str) -> Self { + pub fn new(text: &str, scope: Option) -> Self { let cache = identifier_cache(); - if let Some(identifier) = cache.read().unwrap().get(text) { - return identifier.clone(); + if let Some(identifier) = cache.read().unwrap().get(text).cloned() { + return identifier; } - let identifier = Identifier(Arc::new(text.to_string())); + let new = Identifier(Arc::new(text.to_string())); - cache - .write() - .unwrap() - .insert(text.to_string(), identifier.clone()); + cache.write().unwrap().insert(text.to_string(), new.clone()); - identifier + new } pub fn as_str(&self) -> &str { - self.0.as_str() + &self.0.as_str() + } +} + +impl From<&str> for Identifier { + fn from(text: &str) -> Self { + Identifier::new(text, None) } } @@ -82,7 +88,7 @@ impl<'de> Visitor<'de> for IdentifierVisitor { where E: serde::de::Error, { - Ok(Identifier::new(v)) + Ok(Identifier::new(v, None)) } fn visit_borrowed_str(self, v: &'de str) -> Result diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 23afc87..149d16f 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -24,7 +24,7 @@ use lexer::{lex, Token}; use parser::{parse, parser}; pub fn interpret(source_id: &str, source: &str) -> Result, InterpreterError> { - let interpreter = Interpreter::new(Context::new(None)); + let interpreter = Interpreter::new(Context::new()); interpreter.run(Arc::from(source_id), Arc::from(source)) } @@ -448,7 +448,7 @@ mod tests { #[test] fn load_standard_library() { - let context = Context::new(None); + let context = Context::new(); for abstract_tree in std_full_compiled() { abstract_tree.run(&context, true).unwrap(); diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index 4608082..5351879 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -42,7 +42,7 @@ pub fn parser<'src>( Token::Comment(_) => {} }; let identifier = select! { - Token::Identifier(text) => Identifier::new(text), + Token::Identifier(text) => Identifier::from(text), }; let positioned_identifier = identifier diff --git a/dust-lang/src/standard_library.rs b/dust-lang/src/standard_library.rs index f3cd903..0a7ead4 100644 --- a/dust-lang/src/standard_library.rs +++ b/dust-lang/src/standard_library.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, OnceLock}; use crate::{ - abstract_tree::{AbstractNode, AbstractTree}, + abstract_tree::{AbstractNode, AbstractTree, SourcePosition}, context::Context, lexer::lex, parser, @@ -28,14 +28,15 @@ static CORE_CONTEXT: OnceLock = OnceLock::new(); pub fn core_context<'a>() -> &'a Context { CORE_CONTEXT.get_or_init(|| { - let context = Context::new(None); + let context = Context::new(); let std_core = std_core_compiled().clone(); + let global_scope = SourcePosition(0, usize::MAX); std_core - .define_and_validate(&context, true) + .define_and_validate(&context, true, global_scope) .expect("Failed to validate std.core"); std_core - .evaluate(&context, true) + .evaluate(&context, true, global_scope) .expect("Failed to evaluate std.core"); context diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index f8d6abe..fe4cba7 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -14,7 +14,9 @@ use serde::{ }; use crate::{ - abstract_tree::{AbstractNode, Block, BuiltInFunction, Evaluation, Type, WithPosition}, + abstract_tree::{ + AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, WithPosition, + }, context::Context, error::{RuntimeError, ValidationError}, identifier::Identifier, @@ -778,7 +780,10 @@ impl Function { self, context: &Context, manage_memory: bool, + scope: SourcePosition, ) -> Result, RuntimeError> { - self.body.evaluate(context, manage_memory) + self.body + .define_and_validate(context, manage_memory, scope)?; + self.body.evaluate(context, manage_memory, scope) } } diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index cac54fd..7b27866 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -56,7 +56,7 @@ fn main() { .init(); let args = Args::parse(); - let context = Context::new_with_std_core(None).unwrap(); + let context = Context::new_with_std_core().unwrap(); let interpreter = Interpreter::new(context.clone()); let (source_id, source): (Arc, Arc) = if let Some(path) = args.path {