Pass function tests; Fix recursion
This commit is contained in:
parent
d4a5424ad5
commit
a52eadc5ad
@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, AssignmentOperator, Format, Identifier, SourcePosition, Statement, SyntaxNode,
|
AbstractTree, AssignmentOperator, Format, Function, Identifier, SourcePosition, Statement,
|
||||||
Type, TypeSpecification, Value,
|
SyntaxNode, Type, TypeSpecification, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Variable assignment, including add-assign and subtract-assign operations.
|
/// Variable assignment, including add-assign and subtract-assign operations.
|
||||||
@ -149,6 +149,12 @@ impl AbstractTree for Assignment {
|
|||||||
AssignmentOperator::Equal => right,
|
AssignmentOperator::Equal => right,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Value::Function(Function::ContextDefined(function_node)) = &new_value {
|
||||||
|
function_node
|
||||||
|
.context()
|
||||||
|
.set_value(self.identifier.clone(), new_value.clone())?;
|
||||||
|
}
|
||||||
|
|
||||||
context.set_value(self.identifier.clone(), new_value)?;
|
context.set_value(self.identifier.clone(), new_value)?;
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
|
@ -94,6 +94,8 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||||
|
self.function_expression.validate(_source, context)?;
|
||||||
|
|
||||||
let function_expression_type = self.function_expression.expected_type(context)?;
|
let function_expression_type = self.function_expression.expected_type(context)?;
|
||||||
|
|
||||||
let parameter_types = if let Type::Function {
|
let parameter_types = if let Type::Function {
|
||||||
@ -117,6 +119,8 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (index, expression) in self.arguments.iter().enumerate() {
|
for (index, expression) in self.arguments.iter().enumerate() {
|
||||||
|
expression.validate(_source, context)?;
|
||||||
|
|
||||||
if let Some(expected) = parameter_types.get(index) {
|
if let Some(expected) = parameter_types.get(index) {
|
||||||
let actual = expression.expected_type(context)?;
|
let actual = expression.expected_type(context)?;
|
||||||
|
|
||||||
@ -178,8 +182,6 @@ impl AbstractTree for FunctionCall {
|
|||||||
call_context.set_value(identifier.clone(), value)?;
|
call_context.set_value(identifier.clone(), value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", call_context);
|
|
||||||
|
|
||||||
function_node.body().run(source, &call_context)
|
function_node.body().run(source, &call_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,8 @@ impl AbstractTree for IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(block) = &self.else_block {
|
if let Some(block) = &self.else_block {
|
||||||
|
block.validate(_source, context)?;
|
||||||
|
|
||||||
let actual = block.expected_type(context)?;
|
let actual = block.expected_type(context)?;
|
||||||
|
|
||||||
if !expected.accepts(&actual) {
|
if !expected.accepts(&actual) {
|
||||||
|
@ -91,8 +91,11 @@ impl Context {
|
|||||||
pub fn with_variables_from(other: &Context) -> Result<Context, RwLockError> {
|
pub fn with_variables_from(other: &Context) -> Result<Context, RwLockError> {
|
||||||
let mut new_variables = BTreeMap::new();
|
let mut new_variables = BTreeMap::new();
|
||||||
|
|
||||||
for (identifier, value_data) in other.inner.read()?.iter() {
|
for (identifier, (value_data, counter)) in other.inner.read()?.iter() {
|
||||||
new_variables.insert(identifier.clone(), value_data.clone());
|
let (allowances, _runtime_uses) = counter.get_counts()?;
|
||||||
|
let new_counter = UsageCounter::with_counts(allowances, 0);
|
||||||
|
|
||||||
|
new_variables.insert(identifier.clone(), (value_data.clone(), new_counter));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Context {
|
Ok(Context {
|
||||||
@ -123,30 +126,20 @@ impl Context {
|
|||||||
pub fn inherit_from(&self, other: &Context) -> Result<(), RwLockError> {
|
pub fn inherit_from(&self, other: &Context) -> Result<(), RwLockError> {
|
||||||
let mut self_variables = self.inner.write()?;
|
let mut self_variables = self.inner.write()?;
|
||||||
|
|
||||||
for (identifier, (value_data, _counter)) in other.inner.read()?.iter() {
|
for (identifier, (value_data, counter)) in other.inner.read()?.iter() {
|
||||||
|
let (allowances, _runtime_uses) = counter.get_counts()?;
|
||||||
|
let new_counter = UsageCounter::with_counts(allowances, 0);
|
||||||
|
|
||||||
if let ValueData::Value(value) = value_data {
|
if let ValueData::Value(value) = value_data {
|
||||||
if value.is_function() {
|
if value.is_function() {
|
||||||
self_variables.insert(
|
self_variables.insert(identifier.clone(), (value_data.clone(), new_counter));
|
||||||
identifier.clone(),
|
|
||||||
(value_data.clone(), UsageCounter::new()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
} else if let ValueData::TypeHint(r#type) = value_data {
|
||||||
|
|
||||||
if let ValueData::TypeHint(r#type) = value_data {
|
|
||||||
if r#type.is_function() {
|
if r#type.is_function() {
|
||||||
self_variables.insert(
|
self_variables.insert(identifier.clone(), (value_data.clone(), new_counter));
|
||||||
identifier.clone(),
|
|
||||||
(value_data.clone(), UsageCounter::new()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
} else if let ValueData::TypeDefinition(_) = value_data {
|
||||||
|
self_variables.insert(identifier.clone(), (value_data.clone(), new_counter));
|
||||||
if let ValueData::TypeDefinition(_) = value_data {
|
|
||||||
self_variables.insert(
|
|
||||||
identifier.clone(),
|
|
||||||
(value_data.clone(), UsageCounter::new()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,13 @@ impl UsageCounter {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_counts(allowances: usize, runtime_uses: usize) -> UsageCounter {
|
||||||
|
UsageCounter(Arc::new(RwLock::new(UsageCounterInner {
|
||||||
|
allowances,
|
||||||
|
runtime_uses,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_counts(&self) -> Result<(usize, usize), RwLockError> {
|
pub fn get_counts(&self) -> Result<(usize, usize), RwLockError> {
|
||||||
let inner = self.0.read()?;
|
let inner = self.0.read()?;
|
||||||
Ok((inner.allowances, inner.runtime_uses))
|
Ok((inner.allowances, inner.runtime_uses))
|
||||||
|
@ -115,6 +115,8 @@ fn function_context_captures_structure_definitions() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recursion() {
|
fn recursion() {
|
||||||
|
env_logger::builder().is_test(true).try_init().unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
"
|
"
|
||||||
|
Loading…
Reference in New Issue
Block a user