Implement function purity
This commit is contained in:
parent
f89e94cc33
commit
e6acb8cbb9
@ -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> {
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()),
|
||||||
|
@ -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()?)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user