Implement function purity

This commit is contained in:
Jeff 2024-01-06 11:17:08 -05:00
parent f89e94cc33
commit e6acb8cbb9
5 changed files with 66 additions and 21 deletions

View File

@ -120,14 +120,7 @@ impl AbstractTree for FunctionCall {
context.set(name.to_string(), value.clone(), None)?; context.set(name.to_string(), value.clone(), None)?;
} }
value value.as_function()?.call(name, &arguments, source, context)
.as_function()
.map_err(|error| {
println!("{name:?}");
error
})?
.call(name, &arguments, source, context)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<Type> {

View File

@ -14,6 +14,7 @@ pub struct FunctionNode {
body: Block, body: Block,
r#type: Type, r#type: Type,
syntax_position: SyntaxPosition, syntax_position: SyntaxPosition,
context: Map,
} }
impl FunctionNode { impl FunctionNode {
@ -22,12 +23,14 @@ impl FunctionNode {
body: Block, body: Block,
r#type: Type, r#type: Type,
syntax_position: SyntaxPosition, syntax_position: SyntaxPosition,
context: Map,
) -> Self { ) -> Self {
Self { Self {
parameters, parameters,
body, body,
r#type, r#type,
syntax_position, syntax_position,
context,
} }
} }
@ -61,23 +64,24 @@ impl FunctionNode {
outer_context: &Map, outer_context: &Map,
) -> Result<Value> { ) -> Result<Value> {
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter()); let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
let function_context = Map::clone_from(outer_context)?;
self.context.clone_complex_values_from(outer_context)?;
for (identifier, value) in parameter_argument_pairs { for (identifier, value) in parameter_argument_pairs {
let key = identifier.inner().clone(); let key = identifier.inner().clone();
function_context.set(key, value.clone(), None)?; self.context.set(key, value.clone(), None)?;
} }
if let Some(name) = name { if let Some(name) = name {
function_context.set( self.context.set(
name, name,
Value::Function(Function::ContextDefined(self.clone())), Value::Function(Function::ContextDefined(self.clone())),
None, None,
)?; )?;
} }
let return_value = self.body.run(source, &function_context)?; let return_value = self.body.run(source, &self.context)?;
Ok(return_value) Ok(return_value)
} }
@ -107,7 +111,9 @@ impl AbstractTree for FunctionNode {
} }
} }
let function_context = Map::clone_from(context)?; let function_context = Map::new();
function_context.clone_complex_values_from(context)?;
for (parameter_name, parameter_type) in parameters.iter().zip(parameter_types.iter()) { for (parameter_name, parameter_type) in parameters.iter().zip(parameter_types.iter()) {
function_context.set( function_context.set(
@ -126,14 +132,22 @@ impl AbstractTree for FunctionNode {
let r#type = Type::function(parameter_types, return_type.take_inner()); let r#type = Type::function(parameter_types, return_type.take_inner());
let syntax_position = node.range().into(); let syntax_position = node.range().into();
Ok(FunctionNode::new(parameters, body, r#type, syntax_position)) Ok(FunctionNode::new(
parameters,
body,
r#type,
syntax_position,
function_context,
))
} }
fn check_type(&self, source: &str, context: &Map) -> Result<()> { fn check_type(&self, source: &str, _context: &Map) -> Result<()> {
self.return_type() self.return_type()
.check(&self.body.expected_type(context)?) .check(&self.body.expected_type(&self.context)?)
.map_err(|error| error.at_source_position(source, self.syntax_position))?; .map_err(|error| error.at_source_position(source, self.syntax_position))?;
self.body.check_type(source, &self.context)?;
Ok(()) Ok(())
} }

View File

@ -39,19 +39,25 @@ impl AbstractTree for Identifier {
fn run(&self, _source: &str, context: &Map) -> Result<Value> { fn run(&self, _source: &str, context: &Map) -> Result<Value> {
if let Some((value, _)) = context.variables()?.get(&self.0) { if let Some((value, _)) = context.variables()?.get(&self.0) {
if !value.is_none() { Ok(value.clone())
return Ok(value.clone()); } else {
Err(Error::VariableIdentifierNotFound(self.0.clone()))
} }
} }
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
if let Some(_) = context.variables()?.get(&self.0) {
Ok(())
} else {
Err(Error::VariableIdentifierNotFound(self.0.clone())) Err(Error::VariableIdentifierNotFound(self.0.clone()))
} }
}
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<Type> {
if let Some((_value, r#type)) = context.variables()?.get(&self.0) { if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
Ok(r#type.clone()) Ok(r#type.clone())
} else { } else {
Ok(Type::None) Err(Error::VariableIdentifierNotFound(self.0.clone()))
} }
} }
} }

View File

@ -188,6 +188,27 @@ impl AbstractTree for ValueNode {
Ok(value_node) Ok(value_node)
} }
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
match self {
ValueNode::Boolean(_) => todo!(),
ValueNode::Float(_) => todo!(),
ValueNode::Function(function) => {
if let Function::ContextDefined(function_node) = function {
function_node.check_type(_source, _context)?;
}
}
ValueNode::Integer(_) => todo!(),
ValueNode::String(_) => todo!(),
ValueNode::List(_) => todo!(),
ValueNode::Option(_) => todo!(),
ValueNode::Map(_) => todo!(),
ValueNode::BuiltInValue(_) => todo!(),
ValueNode::Structure(_) => todo!(),
}
Ok(())
}
fn run(&self, source: &str, context: &Map) -> Result<Value> { fn run(&self, source: &str, context: &Map) -> Result<Value> {
let value = match self { let value = match self {
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()), ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),

View File

@ -45,6 +45,17 @@ impl Map {
}) })
} }
pub fn clone_complex_values_from(&self, other: &Self) -> Result<()> {
for (key, (value, r#type)) in other.variables()?.iter() {
if value.is_function() {
self.variables_mut()?
.insert(key.clone(), (value.clone(), r#type.clone()));
}
}
Ok(())
}
pub fn variables(&self) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>> { pub fn variables(&self) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>> {
Ok(self.variables.read()?) Ok(self.variables.read()?)
} }