Fix function contexts and recursion
This commit is contained in:
parent
7eecb7b070
commit
d2e0de0483
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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> {
|
||||
|
@ -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, "}}")
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ fn function_context_captures_structure_definitions() {
|
||||
assert_eq!(
|
||||
interpret(
|
||||
"
|
||||
User = struct {
|
||||
struct User {
|
||||
name <str>
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user