Fix function call bug
This commit is contained in:
parent
af20dab0d2
commit
64ce3d56e4
@ -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) => {
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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())
|
||||||
|
@ -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),
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user