1
0

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, function_expression: FunctionExpression,
arguments: Vec<Expression>, arguments: Vec<Expression>,
syntax_position: SourcePosition, syntax_position: SourcePosition,
#[serde(skip)]
context: Context,
} }
impl FunctionCall { impl FunctionCall {
@ -24,13 +21,11 @@ impl FunctionCall {
function_expression: FunctionExpression, function_expression: FunctionExpression,
arguments: Vec<Expression>, arguments: Vec<Expression>,
syntax_position: SourcePosition, syntax_position: SourcePosition,
context: Context,
) -> Self { ) -> Self {
Self { Self {
function_expression, function_expression,
arguments, arguments,
syntax_position, syntax_position,
context,
} }
} }
} }
@ -58,7 +53,6 @@ impl AbstractTree for FunctionCall {
function_expression, function_expression,
arguments, arguments,
syntax_position: node.range().into(), syntax_position: node.range().into(),
context: Context::new(),
}) })
} }
@ -143,7 +137,6 @@ impl AbstractTree for FunctionCall {
let value = match &self.function_expression { let value = match &self.function_expression {
FunctionExpression::Identifier(identifier) => { FunctionExpression::Identifier(identifier) => {
if let Some(value) = context.get_value(identifier)? { if let Some(value) = context.get_value(identifier)? {
self.context.set_value(identifier.clone(), value.clone())?;
value.clone() value.clone()
} else { } else {
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone())); return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
@ -167,19 +160,25 @@ impl AbstractTree for FunctionCall {
arguments.push(value); arguments.push(value);
} }
built_in_function.call(&arguments, source, &self.context) built_in_function.call(&arguments, source, context)
} }
Function::ContextDefined(function_node) => { Function::ContextDefined(function_node) => {
let call_context = Context::with_variables_from(function_node.context())?;
call_context.inherit_from(context)?;
let parameter_expression_pairs = let parameter_expression_pairs =
function_node.parameters().iter().zip(self.arguments.iter()); function_node.parameters().iter().zip(self.arguments.iter());
for (identifier, expression) in parameter_expression_pairs { for (identifier, expression) in parameter_expression_pairs {
let value = expression.run(source, context)?; 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, body: Block,
r#type: Type, r#type: Type,
syntax_position: SourcePosition, syntax_position: SourcePosition,
#[serde(skip)]
context: Context,
} }
impl FunctionNode { 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> { pub fn parameters(&self) -> &Vec<Identifier> {
&self.parameters &self.parameters
} }
@ -47,6 +36,10 @@ impl FunctionNode {
&self.syntax_position &self.syntax_position
} }
pub fn context(&self) -> &Context {
&self.context
}
pub fn return_type(&self) -> &Type { pub fn return_type(&self) -> &Type {
match &self.r#type { match &self.r#type {
Type::Function { Type::Function {
@ -56,12 +49,6 @@ impl FunctionNode {
_ => &Type::None, _ => &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 { 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_node = node.child(child_count - 2).unwrap();
let return_type = TypeSpecification::from_syntax(return_type_node, source, context)?; 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_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 r#type = Type::function(parameter_types, return_type.take_inner());
let syntax_position = node.range().into(); let syntax_position = node.range().into();
@ -102,6 +91,7 @@ impl AbstractTree for FunctionNode {
body, body,
r#type, r#type,
syntax_position, syntax_position,
context: function_context,
}) })
} }
@ -109,19 +99,19 @@ impl AbstractTree for FunctionNode {
Ok(self.r#type().clone()) 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 { if let Type::Function {
parameter_types, parameter_types,
return_type, return_type,
} = &self.r#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()) { 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) { if !return_type.accepts(&actual) {
return Err(ValidationError::TypeCheck { 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(()) Ok(())
} else { } 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())); let self_as_value = Value::Function(Function::ContextDefined(self.clone()));
Ok(self_as_value) Ok(self_as_value)

View File

@ -59,8 +59,12 @@ impl AbstractTree for Identifier {
Ok(Identifier::new(text)) Ok(Identifier::new(text))
} }
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> { fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
Ok(()) if let Some(_) = context.get_type(self)? {
Ok(())
} else {
Err(ValidationError::VariableIdentifierNotFound(self.clone()))
}
} }
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {

View File

@ -30,6 +30,7 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::BTreeMap, collections::BTreeMap,
fmt::Display,
sync::{Arc, RwLock, RwLockReadGuard}, 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 /// In the case of the conflict, the inherited value will override the previous
/// value. /// value.
@ -96,11 +97,19 @@ impl Context {
let mut self_variables = self.inner.write()?; let mut self_variables = self.inner.write()?;
for (identifier, value_data) in other.inner.read()?.iter() { 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 { if let ValueData::TypeHint { inner } = value_data {
continue; if inner.is_function() {
} else { self_variables.insert(identifier.clone(), value_data.clone());
}
}
if let ValueData::TypeDefinition(_) = value_data {
self_variables.insert(identifier.clone(), value_data.clone()); self_variables.insert(identifier.clone(), value_data.clone());
} }
} }
@ -120,7 +129,6 @@ impl Context {
} }
for built_in_value in all_built_in_values() { 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() { if built_in_value.name() == identifier.inner().as_ref() {
return Ok(Some(built_in_value.get().clone())); return Ok(Some(built_in_value.get().clone()));
} }
@ -176,6 +184,8 @@ impl Context {
/// Set a value to a key. /// Set a value to a key.
pub fn set_value(&self, key: Identifier, value: Value) -> Result<(), RwLockError> { pub fn set_value(&self, key: Identifier, value: Value) -> Result<(), RwLockError> {
log::info!("Setting value: {key} = {value}");
self.inner.write()?.insert( self.inner.write()?.insert(
key, key,
ValueData::Value { ValueData::Value {
@ -192,6 +202,8 @@ impl Context {
/// This allows the interpreter to check a value's type before the value /// This allows the interpreter to check a value's type before the value
/// actually exists by predicting what the abstract tree will produce. /// actually exists by predicting what the abstract tree will produce.
pub fn set_type(&self, key: Identifier, r#type: Type) -> Result<(), RwLockError> { pub fn set_type(&self, key: Identifier, r#type: Type) -> Result<(), RwLockError> {
log::info!("Setting type: {key} <{}>", r#type);
self.inner self.inner
.write()? .write()?
.insert(key, ValueData::TypeHint { inner: r#type }); .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

@ -5,9 +5,9 @@ fn function_call() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
foobar = (message <str>) <str> { message } foobar = (message <str>) <str> { message }
foobar('Hiya') foobar('Hiya')
", ",
), ),
Ok(Value::string("Hiya".to_string())) Ok(Value::string("Hiya".to_string()))
); );
@ -18,9 +18,9 @@ fn call_empty_function() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
foobar = (message <str>) <none> {} foobar = (message <str>) <none> {}
foobar('Hiya') foobar('Hiya')
", ",
), ),
Ok(Value::none()) Ok(Value::none())
); );
@ -96,7 +96,7 @@ fn function_context_captures_structure_definitions() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
User = struct { struct User {
name <str> name <str>
} }