From dd72faf7c8b75aee98ad383a83ff148eb7441657 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 6 Jul 2024 02:41:43 -0400 Subject: [PATCH] Continue experimenting with context and scopes --- dust-lang/src/abstract_tree/function_call.rs | 47 +++++++----- dust-lang/src/abstract_tree/use.rs | 6 +- dust-lang/src/abstract_tree/value_node.rs | 2 +- dust-lang/src/context.rs | 47 +++++++++++- dust-lang/src/identifier.rs | 10 +-- dust-lang/src/value.rs | 78 +++++++++++++++++--- examples/fizzbuzz.ds | 2 + examples/hello_world.ds | 2 + 8 files changed, 154 insertions(+), 40 deletions(-) diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index 57180d8..ccfd944 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -150,27 +150,28 @@ impl AbstractNode for FunctionCall { }; if let ValueInner::Function(function) = value.inner().as_ref() { - if let (Some(type_parameters), Some(type_arguments)) = - (function.type_parameters(), self.type_arguments) - { - for (identifier, constructor) in - type_parameters.into_iter().zip(type_arguments.into_iter()) - { - let r#type = constructor.construct(context)?; + let type_arguments = if let Some(type_arguments) = self.type_arguments { + let mut types = Vec::with_capacity(type_arguments.len()); - context.set_type(identifier.clone(), r#type, function_position)?; + for constructor in type_arguments { + types.push(constructor.construct(context)?) } - } - if let (Some(parameters), Some(arguments)) = - (function.value_parameters(), self.value_arguments) - { - for ((identifier, _), expression) in - parameters.into_iter().zip(arguments.into_iter()) - { + Some(types) + } else { + None + }; + let value_arguments = if let Some(value_arguments) = self.value_arguments { + let mut values = Vec::with_capacity(value_arguments.len()); + + for expression in value_arguments { let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { + let evaluation = (expression.evaluate(context, manage_memory, scope)?).ok_or( + RuntimeError::ValidationFailure(ValidationError::ExpectedValueStatement( + position, + )), + )?; + let value = if let Evaluation::Return(value) = evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -178,11 +179,17 @@ impl AbstractNode for FunctionCall { )); }; - context.set_value(identifier.clone(), value, function_position)?; + values.push(value); } - } - return function.clone().call(context, manage_memory, scope); + Some(values) + } else { + None + }; + + return function + .clone() + .call(Some(context), type_arguments, value_arguments); } if let ValueInner::BuiltInFunction(function) = value.inner().as_ref() { diff --git a/dust-lang/src/abstract_tree/use.rs b/dust-lang/src/abstract_tree/use.rs index e8ac7fb..426d3e5 100644 --- a/dust-lang/src/abstract_tree/use.rs +++ b/dust-lang/src/abstract_tree/use.rs @@ -1,5 +1,5 @@ use std::{ - fmt::Display, + fmt::{self, Display, Formatter}, fs::read_to_string, path::Path, sync::{Arc, RwLock}, @@ -93,8 +93,8 @@ impl AbstractNode for Use { } impl Display for Use { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "use {}", self.path) } } diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index b8f62ba..afb20d5 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -218,7 +218,7 @@ impl AbstractNode for ValueNode { fields: expressions, } = self { - if !context.contains(&name.node)? { + if !context.contains(&name.node, scope)? { return Err(ValidationError::VariableNotFound { identifier: name.node.clone(), position: name.position, diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 595e3e7..59150c7 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -1,20 +1,24 @@ use std::{ + cmp::Ordering, collections::HashMap, fmt::Debug, sync::{Arc, RwLock}, }; +use log::trace; +use rand::random; + use crate::{ abstract_tree::{SourcePosition, Type}, error::{PoisonError, ValidationError}, identifier::Identifier, standard_library::core_context, - value::ValueInner, Value, }; #[derive(Clone, Debug)] pub struct Context { + id: u32, variables: Arc>>, is_clean: Arc>, } @@ -22,6 +26,7 @@ pub struct Context { impl Context { pub fn new() -> Self { Context { + id: random(), variables: Arc::new(RwLock::new(HashMap::new())), is_clean: Arc::new(RwLock::new(true)), } @@ -37,11 +42,29 @@ impl Context { let variables = other.variables.read()?.clone(); Ok(Context { + id: random(), variables: Arc::new(RwLock::new(variables)), is_clean: Arc::new(RwLock::new(true)), }) } + pub fn inherit_variables_from(&self, other: &Context) -> Result<(), PoisonError> { + let (get_self_variables, get_other_variables) = + (self.variables.try_write(), other.variables.try_read()); + + if let (Ok(mut self_variables), Ok(other_variables)) = + (get_self_variables, get_other_variables) + { + self_variables.extend(other_variables.iter().map(|(identifier, data)| { + trace!("Inheriting {identifier}"); + + (identifier.clone(), data.clone()) + })); + } + + Ok(()) + } + pub fn contains( &self, identifier: &Identifier, @@ -55,6 +78,8 @@ impl Context { if scope.0 >= variable_scope.0 && scope.1 <= variable_scope.1 { return Ok(true); } + } else { + trace!("Denying access to {identifier}, out of scope") } Ok(false) @@ -194,6 +219,26 @@ impl Default for Context { } } +impl Eq for Context {} + +impl PartialEq for Context { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl PartialOrd for Context { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Context { + fn cmp(&self, other: &Self) -> Ordering { + self.id.cmp(&other.id) + } +} + #[derive(Clone, Debug, PartialEq)] pub enum VariableData { Type(Type), diff --git a/dust-lang/src/identifier.rs b/dust-lang/src/identifier.rs index afa6a5d..2ad0539 100644 --- a/dust-lang/src/identifier.rs +++ b/dust-lang/src/identifier.rs @@ -1,14 +1,12 @@ use std::{ collections::HashMap, fmt::{self, Display, Formatter}, - hash::{Hash, Hasher}, + hash::Hash, 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> { @@ -19,7 +17,7 @@ fn identifier_cache<'a>() -> &'a RwLock> { pub struct Identifier(Arc); impl Identifier { - pub fn new(text: &str, scope: Option) -> Self { + pub fn new(text: &str) -> Self { let cache = identifier_cache(); if let Some(identifier) = cache.read().unwrap().get(text).cloned() { @@ -40,7 +38,7 @@ impl Identifier { impl From<&str> for Identifier { fn from(text: &str) -> Self { - Identifier::new(text, None) + Identifier::new(text) } } @@ -88,7 +86,7 @@ impl<'de> Visitor<'de> for IdentifierVisitor { where E: serde::de::Error, { - Ok(Identifier::new(v, None)) + Ok(Identifier::new(v)) } fn visit_borrowed_str(self, v: &'de str) -> Result diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index fe4cba7..9520b79 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -7,6 +7,7 @@ use std::{ }; use chumsky::container::Container; +use log::{debug, trace}; use serde::{ de::Visitor, ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple}, @@ -15,7 +16,8 @@ use serde::{ use crate::{ abstract_tree::{ - AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, WithPosition, + AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, TypeConstructor, + WithPosition, }, context::Context, error::{RuntimeError, ValidationError}, @@ -80,12 +82,12 @@ impl Value { return_type: Option, body: Block, ) -> Self { - Value(Arc::new(ValueInner::Function(Function { + Value(Arc::new(ValueInner::Function(Function::new( type_parameters, value_parameters, return_type, body, - }))) + )))) } pub fn structure(name: WithPosition, fields: Vec<(Identifier, Value)>) -> Self { @@ -741,12 +743,13 @@ impl Ord for ValueInner { } } -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Clone, Debug)] pub struct Function { type_parameters: Option>, value_parameters: Option>, return_type: Option, body: Block, + context: Context, } impl Function { @@ -761,6 +764,7 @@ impl Function { value_parameters, return_type, body, + context: Context::new(), } } @@ -778,12 +782,68 @@ impl Function { pub fn call( self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, + outer_context: Option<&Context>, + type_arguments: Option>, + value_arguments: Option>, ) -> Result, RuntimeError> { + trace!("Setting function call variables"); + + if let Some(outer_context) = outer_context { + if &self.context == outer_context { + log::debug!("Recursion detected"); + } + + self.context.inherit_variables_from(outer_context)?; + } + + if let (Some(type_parameters), Some(type_arguments)) = + (self.type_parameters, type_arguments) + { + for (identifier, r#type) in type_parameters.into_iter().zip(type_arguments.into_iter()) + { + self.context + .set_type(identifier.clone(), r#type, SourcePosition(0, usize::MAX))?; + } + } + + if let (Some(value_parameters), Some(value_arguments)) = + (self.value_parameters, value_arguments) + { + for ((identifier, _), value) in value_parameters + .into_iter() + .zip(value_arguments.into_iter()) + { + self.context + .set_value(identifier.clone(), value, SourcePosition(0, usize::MAX))?; + } + } + + debug!("Calling function"); + self.body - .define_and_validate(context, manage_memory, scope)?; - self.body.evaluate(context, manage_memory, scope) + .evaluate(&self.context, false, SourcePosition(0, usize::MAX)) + } +} + +impl Eq for Function {} + +impl PartialEq for Function { + fn eq(&self, other: &Self) -> bool { + self.type_parameters == other.type_parameters + && self.value_parameters == other.value_parameters + && self.return_type == other.return_type + && self.body == other.body + } +} + +impl PartialOrd for Function { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Function { + fn cmp(&self, other: &Self) -> Ordering { + todo!() } } diff --git a/examples/fizzbuzz.ds b/examples/fizzbuzz.ds index 7c4a956..2fd54c0 100644 --- a/examples/fizzbuzz.ds +++ b/examples/fizzbuzz.ds @@ -1,3 +1,5 @@ +use std.io + count = 1 while count <= 15 { diff --git a/examples/hello_world.ds b/examples/hello_world.ds index a61968b..3bab54d 100644 --- a/examples/hello_world.ds +++ b/examples/hello_world.ds @@ -1,3 +1,5 @@ +use std.io + io.write_line("Hello, world!") io.write_line("Enter your name...")