From d2e0de048357f21c356449368b77077facc0b265 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 16 Feb 2024 13:23:58 -0500 Subject: [PATCH] Fix function contexts and recursion --- src/abstract_tree/function_call.rs | 19 ++++++------ src/abstract_tree/function_node.rs | 46 ++++++++++++------------------ src/abstract_tree/identifier.rs | 8 ++++-- src/context.rs | 36 +++++++++++++++++++---- tests/functions.rs | 14 ++++----- 5 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index b26bb4e..f0d5dc2 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -13,9 +13,6 @@ pub struct FunctionCall { function_expression: FunctionExpression, arguments: Vec, syntax_position: SourcePosition, - - #[serde(skip)] - context: Context, } impl FunctionCall { @@ -24,13 +21,11 @@ impl FunctionCall { function_expression: FunctionExpression, arguments: Vec, syntax_position: SourcePosition, - context: Context, ) -> Self { Self { function_expression, arguments, syntax_position, - context, } } } @@ -58,7 +53,6 @@ impl AbstractTree for FunctionCall { function_expression, arguments, syntax_position: node.range().into(), - context: Context::new(), }) } @@ -143,7 +137,6 @@ impl AbstractTree for FunctionCall { let value = match &self.function_expression { FunctionExpression::Identifier(identifier) => { if let Some(value) = context.get_value(identifier)? { - self.context.set_value(identifier.clone(), value.clone())?; value.clone() } else { return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone())); @@ -167,19 +160,25 @@ impl AbstractTree for FunctionCall { arguments.push(value); } - built_in_function.call(&arguments, source, &self.context) + built_in_function.call(&arguments, source, context) } Function::ContextDefined(function_node) => { + let call_context = Context::with_variables_from(function_node.context())?; + + call_context.inherit_from(context)?; + let parameter_expression_pairs = function_node.parameters().iter().zip(self.arguments.iter()); for (identifier, expression) in parameter_expression_pairs { let value = expression.run(source, context)?; - self.context.set_value(identifier.clone(), value)?; + call_context.set_value(identifier.clone(), value)?; } - function_node.call(source, &self.context) + println!("{}", call_context); + + function_node.body().run(source, &call_context) } } } diff --git a/src/abstract_tree/function_node.rs b/src/abstract_tree/function_node.rs index a9199ba..f836204 100644 --- a/src/abstract_tree/function_node.rs +++ b/src/abstract_tree/function_node.rs @@ -14,23 +14,12 @@ pub struct FunctionNode { body: Block, r#type: Type, syntax_position: SourcePosition, + + #[serde(skip)] + context: Context, } impl FunctionNode { - pub fn new( - parameters: Vec, - body: Block, - r#type: Type, - syntax_position: SourcePosition, - ) -> Self { - FunctionNode { - parameters, - body, - r#type, - syntax_position, - } - } - pub fn parameters(&self) -> &Vec { &self.parameters } @@ -47,6 +36,10 @@ impl FunctionNode { &self.syntax_position } + pub fn context(&self) -> &Context { + &self.context + } + pub fn return_type(&self) -> &Type { match &self.r#type { Type::Function { @@ -56,12 +49,6 @@ impl FunctionNode { _ => &Type::None, } } - - pub fn call(&self, source: &str, context: &Context) -> Result { - let return_value = self.body.run(source, context)?; - - Ok(return_value) - } } impl AbstractTree for FunctionNode { @@ -91,8 +78,10 @@ impl AbstractTree for FunctionNode { let return_type_node = node.child(child_count - 2).unwrap(); let return_type = TypeSpecification::from_syntax(return_type_node, source, context)?; + let function_context = Context::with_variables_from(context)?; + let body_node = node.child(child_count - 1).unwrap(); - let body = Block::from_syntax(body_node, source, &context)?; + let body = Block::from_syntax(body_node, source, &function_context)?; let r#type = Type::function(parameter_types, return_type.take_inner()); let syntax_position = node.range().into(); @@ -102,6 +91,7 @@ impl AbstractTree for FunctionNode { body, r#type, syntax_position, + context: function_context, }) } @@ -109,19 +99,19 @@ impl AbstractTree for FunctionNode { Ok(self.r#type().clone()) } - fn validate(&self, source: &str, _context: &Context) -> Result<(), ValidationError> { + fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> { if let Type::Function { parameter_types, return_type, } = &self.r#type { - let validation_context = Context::new(); + self.context.inherit_from(context)?; for (parameter, r#type) in self.parameters.iter().zip(parameter_types.iter()) { - validation_context.set_type(parameter.clone(), r#type.clone())?; + self.context.set_type(parameter.clone(), r#type.clone())?; } - let actual = self.body.expected_type(&validation_context)?; + let actual = self.body.expected_type(&self.context)?; if !return_type.accepts(&actual) { return Err(ValidationError::TypeCheck { @@ -131,7 +121,7 @@ impl AbstractTree for FunctionNode { }); } - self.body.validate(source, &validation_context)?; + self.body.validate(source, &self.context)?; Ok(()) } else { @@ -142,7 +132,9 @@ impl AbstractTree for FunctionNode { } } - fn run(&self, _source: &str, _context: &Context) -> Result { + fn run(&self, _source: &str, context: &Context) -> Result { + self.context.inherit_from(context)?; + let self_as_value = Value::Function(Function::ContextDefined(self.clone())); Ok(self_as_value) diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index ac091a2..0cf5a3e 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -59,8 +59,12 @@ impl AbstractTree for Identifier { Ok(Identifier::new(text)) } - fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> { - Ok(()) + fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> { + if let Some(_) = context.get_type(self)? { + Ok(()) + } else { + Err(ValidationError::VariableIdentifierNotFound(self.clone())) + } } fn expected_type(&self, context: &Context) -> Result { diff --git a/src/context.rs b/src/context.rs index 9612383..14f98af 100644 --- a/src/context.rs +++ b/src/context.rs @@ -30,6 +30,7 @@ use std::{ cmp::Ordering, collections::BTreeMap, + fmt::Display, sync::{Arc, RwLock, RwLockReadGuard}, }; @@ -73,7 +74,7 @@ impl Context { }) } - /// Modify a context to take on all of the key-value pairs of another. + /// Modify a context to take the functions and type definitions of another. /// /// In the case of the conflict, the inherited value will override the previous /// value. @@ -96,11 +97,19 @@ impl Context { let mut self_variables = self.inner.write()?; for (identifier, value_data) in other.inner.read()?.iter() { - let existing_data = self_variables.get(identifier); + if let ValueData::Value { inner, .. } = value_data { + if inner.is_function() { + self_variables.insert(identifier.clone(), value_data.clone()); + } + } - if let Some(ValueData::Value { .. }) = existing_data { - continue; - } else { + if let ValueData::TypeHint { inner } = value_data { + if inner.is_function() { + self_variables.insert(identifier.clone(), value_data.clone()); + } + } + + if let ValueData::TypeDefinition(_) = value_data { self_variables.insert(identifier.clone(), value_data.clone()); } } @@ -120,7 +129,6 @@ impl Context { } for built_in_value in all_built_in_values() { - println!("{} {}", built_in_value.name(), identifier.inner()); if built_in_value.name() == identifier.inner().as_ref() { return Ok(Some(built_in_value.get().clone())); } @@ -176,6 +184,8 @@ impl Context { /// Set a value to a key. pub fn set_value(&self, key: Identifier, value: Value) -> Result<(), RwLockError> { + log::info!("Setting value: {key} = {value}"); + self.inner.write()?.insert( key, ValueData::Value { @@ -192,6 +202,8 @@ impl Context { /// This allows the interpreter to check a value's type before the value /// actually exists by predicting what the abstract tree will produce. pub fn set_type(&self, key: Identifier, r#type: Type) -> Result<(), RwLockError> { + log::info!("Setting type: {key} <{}>", r#type); + self.inner .write()? .insert(key, ValueData::TypeHint { inner: r#type }); @@ -339,3 +351,15 @@ impl Ord for ValueData { } } } + +impl Display for Context { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{{")?; + + for (identifier, value_data) in self.inner.read().unwrap().iter() { + writeln!(f, "{identifier} {value_data:?}")?; + } + + writeln!(f, "}}") + } +} diff --git a/tests/functions.rs b/tests/functions.rs index 3befcf6..f261c82 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -5,9 +5,9 @@ fn function_call() { assert_eq!( interpret( " - foobar = (message ) { message } - foobar('Hiya') - ", + foobar = (message ) { message } + foobar('Hiya') + ", ), Ok(Value::string("Hiya".to_string())) ); @@ -18,9 +18,9 @@ fn call_empty_function() { assert_eq!( interpret( " - foobar = (message ) {} - foobar('Hiya') - ", + foobar = (message ) {} + foobar('Hiya') + ", ), Ok(Value::none()) ); @@ -96,7 +96,7 @@ fn function_context_captures_structure_definitions() { assert_eq!( interpret( " - User = struct { + struct User { name }