Fix function call bug

This commit is contained in:
Jeff 2024-06-24 00:38:06 -04:00
parent af20dab0d2
commit 64ce3d56e4
6 changed files with 52 additions and 109 deletions

View File

@ -42,6 +42,8 @@ impl Expression {
impl AbstractNode for Expression { impl AbstractNode for Expression {
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
log::trace!("Defining types for expression at {}", self.position());
match self { match self {
Expression::As(inner) => inner.node.define_types(_context), Expression::As(inner) => inner.node.define_types(_context),
Expression::BuiltIn(inner) => inner.node.define_types(_context), Expression::BuiltIn(inner) => inner.node.define_types(_context),
@ -56,6 +58,8 @@ impl AbstractNode for Expression {
} }
fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> {
log::trace!("Validating expression at {}", self.position());
match self { match self {
Expression::As(r#as) => r#as.node.validate(context, manage_memory), Expression::As(r#as) => r#as.node.validate(context, manage_memory),
Expression::BuiltIn(built_in_function_call) => { Expression::BuiltIn(built_in_function_call) => {
@ -89,6 +93,8 @@ impl AbstractNode for Expression {
context: &Context, context: &Context,
manage_memory: bool, manage_memory: bool,
) -> Result<Option<Evaluation>, RuntimeError> { ) -> Result<Option<Evaluation>, RuntimeError> {
log::trace!("Evaluating expression at {}", self.position());
match self { match self {
Expression::As(r#as) => r#as.node.evaluate(context, manage_memory), Expression::As(r#as) => r#as.node.evaluate(context, manage_memory),
Expression::FunctionCall(function_call) => { Expression::FunctionCall(function_call) => {

View File

@ -1,5 +1,3 @@
use std::cmp::Ordering;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -10,14 +8,11 @@ use crate::{
use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionCall { pub struct FunctionCall {
function_expression: Box<Expression>, function_expression: Box<Expression>,
type_arguments: Option<Vec<TypeConstructor>>, type_arguments: Option<Vec<TypeConstructor>>,
value_arguments: Option<Vec<Expression>>, value_arguments: Option<Vec<Expression>>,
#[serde(skip)]
context: Context,
} }
impl FunctionCall { impl FunctionCall {
@ -30,7 +25,6 @@ impl FunctionCall {
function_expression: Box::new(function_expression), function_expression: Box::new(function_expression),
type_arguments, type_arguments,
value_arguments, value_arguments,
context: Context::new(None),
} }
} }
@ -43,34 +37,9 @@ impl AbstractNode for FunctionCall {
fn define_types(&self, context: &Context) -> Result<(), ValidationError> { fn define_types(&self, context: &Context) -> Result<(), ValidationError> {
self.function_expression.define_types(context)?; self.function_expression.define_types(context)?;
let (type_parameters, value_parameters) = if let Some(expressions) = &self.value_arguments {
if let Some(r#type) = self.function_expression.expected_type(context)? { for expression in expressions {
if let Type::Function { expression.define_types(context)?;
type_parameters,
value_parameters,
..
} = r#type
{
(type_parameters, value_parameters)
} else {
return Err(ValidationError::ExpectedFunction {
actual: r#type,
position: self.function_expression.position(),
});
}
} else {
todo!("Create an error for this occurence");
};
if let (Some(type_parameters), Some(type_arguments)) =
(type_parameters, &self.type_arguments)
{
for (identifier, constructor) in
type_parameters.into_iter().zip(type_arguments.into_iter())
{
let r#type = constructor.construct(context)?;
self.context.set_type(identifier, r#type)?;
} }
} }
@ -125,12 +94,10 @@ impl AbstractNode for FunctionCall {
fn evaluate( fn evaluate(
self, self,
context: &Context, context: &Context,
clear_variables: bool, manage_memory: bool,
) -> Result<Option<Evaluation>, RuntimeError> { ) -> Result<Option<Evaluation>, RuntimeError> {
let function_position = self.function_expression.position(); let function_position = self.function_expression.position();
let evaluation = self let evaluation = self.function_expression.evaluate(context, manage_memory)?;
.function_expression
.evaluate(context, clear_variables)?;
let value = if let Some(Evaluation::Return(value)) = evaluation { let value = if let Some(Evaluation::Return(value)) = evaluation {
value value
} else { } else {
@ -149,50 +116,34 @@ impl AbstractNode for FunctionCall {
)); ));
}; };
match (function.type_parameters(), self.type_arguments) { function.populate_context_template()?;
(Some(type_parameters), Some(type_arguments)) => {
for (parameter, constructor) in
type_parameters.into_iter().zip(type_arguments.into_iter())
{
let r#type = constructor.construct(context)?;
self.context.set_type(parameter.clone(), r#type)?; let function_context = function.context_template().create_child();
}
}
_ => {}
}
if let (Some(value_parameters), Some(value_arguments)) = if let (Some(parameters), Some(arguments)) =
(function.value_parameters(), self.value_arguments) (function.value_parameters(), self.value_arguments)
{ {
for ((identifier, _), expression) in for ((identifier, _), expression) in parameters.into_iter().zip(arguments.into_iter()) {
value_parameters.into_iter().zip(value_arguments.iter()) let position = expression.position();
{ let evaluation = expression.evaluate(context, manage_memory)?;
let expression_position = expression.position();
let evaluation = expression.clone().evaluate(context, clear_variables)?;
let value = if let Some(Evaluation::Return(value)) = evaluation { let value = if let Some(Evaluation::Return(value)) = evaluation {
value value
} else { } else {
return Err(RuntimeError::ValidationFailure( return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedExpression(expression_position), ValidationError::ExpectedValue(position),
)); ));
}; };
self.context.set_value(identifier.clone(), value)?; function_context.set_value(identifier.clone(), value)?;
} }
} }
function.clone().call(&self.context, clear_variables) function.call(&function_context, manage_memory)
} }
fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> {
let return_type = if let Some(r#type) = self.function_expression.expected_type(context)? { let return_type = if let Some(r#type) = self.function_expression.expected_type(context)? {
if let Type::Function { if let Type::Function { return_type, .. } = r#type {
type_parameters,
value_parameters,
return_type,
} = r#type
{
return_type return_type
} else { } else {
return Err(ValidationError::ExpectedFunction { return Err(ValidationError::ExpectedFunction {
@ -211,37 +162,3 @@ impl AbstractNode for FunctionCall {
Ok(return_type) Ok(return_type)
} }
} }
impl Eq for FunctionCall {}
impl PartialEq for FunctionCall {
fn eq(&self, other: &Self) -> bool {
self.function_expression == other.function_expression
&& self.type_arguments == other.type_arguments
&& self.value_arguments == other.value_arguments
}
}
impl PartialOrd for FunctionCall {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FunctionCall {
fn cmp(&self, other: &Self) -> Ordering {
let function_cmp = self.function_expression.cmp(&other.function_expression);
if function_cmp.is_eq() {
let type_arg_cmp = self.type_arguments.cmp(&other.type_arguments);
if type_arg_cmp.is_eq() {
self.value_arguments.cmp(&other.value_arguments)
} else {
type_arg_cmp
}
} else {
function_cmp
}
}
}

View File

@ -20,7 +20,11 @@ pub mod type_constructor;
pub mod value_node; pub mod value_node;
pub mod r#while; pub mod r#while;
use std::{cmp::Ordering, ops::Index}; use std::{
cmp::Ordering,
fmt::{self, Display, Formatter},
ops::Index,
};
use chumsky::span::{SimpleSpan, Span}; use chumsky::span::{SimpleSpan, Span};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -77,6 +81,12 @@ impl<T> WithPos for T {}
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SourcePosition(pub usize, pub usize); pub struct SourcePosition(pub usize, pub usize);
impl Display for SourcePosition {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "({}, {})", self.0, self.1)
}
}
impl From<SimpleSpan> for SourcePosition { impl From<SimpleSpan> for SourcePosition {
fn from(span: SimpleSpan) -> Self { fn from(span: SimpleSpan) -> Self {
SourcePosition(span.start(), span.end()) SourcePosition(span.start(), span.end())

View File

@ -53,6 +53,8 @@ impl Statement {
impl AbstractNode for Statement { impl AbstractNode for Statement {
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
log::trace!("Defining types for statement at {}", self.position());
match self { match self {
Statement::Expression(expression) => expression.define_types(_context), Statement::Expression(expression) => expression.define_types(_context),
Statement::IfElse(if_else) => if_else.node.define_types(_context), Statement::IfElse(if_else) => if_else.node.define_types(_context),
@ -73,6 +75,8 @@ impl AbstractNode for Statement {
} }
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
log::trace!("Validating statement at {}", self.position());
match self { match self {
Statement::Assignment(assignment) => assignment.node.validate(_context, _manage_memory), Statement::Assignment(assignment) => assignment.node.validate(_context, _manage_memory),
Statement::AsyncBlock(async_block) => { Statement::AsyncBlock(async_block) => {
@ -93,6 +97,8 @@ impl AbstractNode for Statement {
context: &Context, context: &Context,
manage_memory: bool, manage_memory: bool,
) -> Result<Option<Evaluation>, RuntimeError> { ) -> Result<Option<Evaluation>, RuntimeError> {
log::trace!("Evaluating statement at {}", self.position());
let result = match self { let result = match self {
Statement::Assignment(assignment) => assignment.node.evaluate(context, manage_memory), Statement::Assignment(assignment) => assignment.node.evaluate(context, manage_memory),
Statement::AsyncBlock(async_block) => async_block.node.evaluate(context, manage_memory), Statement::AsyncBlock(async_block) => async_block.node.evaluate(context, manage_memory),

View File

@ -95,7 +95,7 @@ impl Context {
if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) { if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) {
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else if let Some(parent) = &data.parent { } else if let Some(parent) = &data.parent {
parent.use_value(identifier) parent.get_value(identifier)
} else { } else {
Ok(None) Ok(None)
} }
@ -149,17 +149,22 @@ impl Context {
return Ok(()); return Ok(());
} }
self.data self.data.write()?.variables.retain(
.write()? |identifier, (value_data, usage_data)| match value_data {
.variables
.retain(|_, (value_data, usage_data)| match value_data {
VariableData::Type(_) => true, VariableData::Type(_) => true,
VariableData::Value(_) => { VariableData::Value(_) => {
let usage = usage_data.inner().read().unwrap(); let usage = usage_data.inner().read().unwrap();
usage.actual < usage.expected if usage.actual < usage.expected {
true
} else {
log::trace!("Removing {identifier}.");
false
}
} }
}); },
);
*self.is_clean.write()? = true; *self.is_clean.write()? = true;

View File

@ -50,9 +50,8 @@ fn main() {
Level::Error => "ERROR".red().bold(), Level::Error => "ERROR".red().bold(),
Level::Info => "INFO".white().bold(), Level::Info => "INFO".white().bold(),
}; };
let timestamp = buffer.timestamp_seconds().to_string().dimmed();
writeln!(buffer, "[{} {}] {}", log_level, timestamp, args) writeln!(buffer, "[{}] {}", log_level, args)
}) })
.init(); .init();