Fix function contexts and recursion

This commit is contained in:
Jeff 2024-02-16 13:23:58 -05:00
parent 7eecb7b070
commit d2e0de0483
5 changed files with 71 additions and 52 deletions

View File

@ -13,9 +13,6 @@ pub struct FunctionCall {
function_expression: FunctionExpression,
arguments: Vec<Expression>,
syntax_position: SourcePosition,
#[serde(skip)]
context: Context,
}
impl FunctionCall {
@ -24,13 +21,11 @@ impl FunctionCall {
function_expression: FunctionExpression,
arguments: Vec<Expression>,
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)
}
}
}

View File

@ -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<Identifier>,
body: Block,
r#type: Type,
syntax_position: SourcePosition,
) -> Self {
FunctionNode {
parameters,
body,
r#type,
syntax_position,
}
}
pub fn parameters(&self) -> &Vec<Identifier> {
&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<Value, RuntimeError> {
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<Value, RuntimeError> {
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
self.context.inherit_from(context)?;
let self_as_value = Value::Function(Function::ContextDefined(self.clone()));
Ok(self_as_value)

View File

@ -59,8 +59,12 @@ impl AbstractTree for Identifier {
Ok(Identifier::new(text))
}
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
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<Type, ValidationError> {

View File

@ -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, "}}")
}
}

View File

@ -96,7 +96,7 @@ fn function_context_captures_structure_definitions() {
assert_eq!(
interpret(
"
User = struct {
struct User {
name <str>
}