Add type constructor
This commit is contained in:
parent
a0b754cc1c
commit
e448c9dd4c
@ -9,17 +9,22 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, WithPosition};
|
||||
use super::{
|
||||
AbstractNode, Evaluation, ExpectedType, Expression, Type, TypeConstructor, WithPosition,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct As {
|
||||
expression: ValueExpression,
|
||||
r#type: WithPosition<Type>,
|
||||
expression: Expression,
|
||||
constructor: WithPosition<TypeConstructor>,
|
||||
}
|
||||
|
||||
impl As {
|
||||
pub fn new(expression: ValueExpression, r#type: WithPosition<Type>) -> Self {
|
||||
Self { expression, r#type }
|
||||
pub fn new(expression: Expression, constructor: WithPosition<TypeConstructor>) -> Self {
|
||||
Self {
|
||||
expression,
|
||||
constructor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,28 +34,35 @@ impl AbstractNode for As {
|
||||
_context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<(), ValidationError> {
|
||||
match self.r#type.node {
|
||||
Type::Boolean | Type::Float | Type::Integer | Type::String => {}
|
||||
match self.constructor.node {
|
||||
TypeConstructor::Type(_) => {}
|
||||
_ => todo!("Create an error for this occurence."),
|
||||
};
|
||||
|
||||
match self.expression.expected_type(_context)? {
|
||||
Type::Boolean | Type::Float | Type::Integer | Type::String => Ok(()),
|
||||
Type::Boolean | Type::Float | Type::Integer | Type::String => {}
|
||||
_ => todo!("Create an error for this occurence."),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let expression_position = self.expression.position();
|
||||
let action = self.expression.run(_context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = self.expression.evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||
));
|
||||
};
|
||||
let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), self.r#type.node);
|
||||
let r#type = self.constructor.node.construct(&context)?;
|
||||
let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), r#type);
|
||||
|
||||
let converted = match (from_value, to_type) {
|
||||
(ValueInner::Boolean(boolean), Type::String) => Value::string(boolean.to_string()),
|
||||
@ -58,12 +70,12 @@ impl AbstractNode for As {
|
||||
_ => todo!("Create an error for this occurence."),
|
||||
};
|
||||
|
||||
Ok(Action::Return(converted))
|
||||
Ok(Evaluation::Return(converted))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpectedType for As {
|
||||
fn expected_type(&self, _: &mut Context) -> Result<Type, ValidationError> {
|
||||
Ok(self.r#type.node.clone())
|
||||
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
|
||||
self.constructor.node.clone().construct(&context)
|
||||
}
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ use crate::{
|
||||
Context, Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Statement, Type, WithPosition};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Statement, TypeConstructor, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Assignment {
|
||||
identifier: WithPosition<Identifier>,
|
||||
r#type: Option<WithPosition<Type>>,
|
||||
constructor: Option<WithPosition<TypeConstructor>>,
|
||||
operator: AssignmentOperator,
|
||||
statement: Box<Statement>,
|
||||
}
|
||||
@ -27,13 +27,13 @@ pub enum AssignmentOperator {
|
||||
impl Assignment {
|
||||
pub fn new(
|
||||
identifier: WithPosition<Identifier>,
|
||||
r#type: Option<WithPosition<Type>>,
|
||||
constructor: Option<WithPosition<TypeConstructor>>,
|
||||
operator: AssignmentOperator,
|
||||
statement: Statement,
|
||||
) -> Self {
|
||||
Self {
|
||||
identifier,
|
||||
r#type,
|
||||
constructor,
|
||||
operator,
|
||||
statement: Box::new(statement),
|
||||
}
|
||||
@ -45,19 +45,21 @@ impl AbstractNode for Assignment {
|
||||
let statement_type = self.statement.expected_type(context)?;
|
||||
|
||||
if let Some(WithPosition {
|
||||
node: expected_type,
|
||||
node: constructor,
|
||||
position: expected_position,
|
||||
}) = &self.r#type
|
||||
}) = &self.constructor
|
||||
{
|
||||
expected_type.check(&statement_type).map_err(|conflict| {
|
||||
ValidationError::TypeCheck {
|
||||
let r#type = constructor.clone().construct(&context)?;
|
||||
|
||||
r#type
|
||||
.check(&statement_type)
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: self.statement.position(),
|
||||
expected_position: expected_position.clone(),
|
||||
}
|
||||
})?;
|
||||
expected_position: Some(expected_position.clone()),
|
||||
})?;
|
||||
|
||||
context.set_type(self.identifier.node.clone(), expected_type.clone())?;
|
||||
context.set_type(self.identifier.node.clone(), r#type.clone())?;
|
||||
} else {
|
||||
context.set_type(self.identifier.node.clone(), statement_type)?;
|
||||
}
|
||||
@ -67,10 +69,14 @@ impl AbstractNode for Assignment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
let action = self.statement.run(context, manage_memory)?;
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let action = self.statement.evaluate(context, manage_memory)?;
|
||||
let right = match action {
|
||||
Action::Return(value) => value,
|
||||
Evaluation::Return(value) => value,
|
||||
r#break => return Ok(r#break),
|
||||
};
|
||||
|
||||
@ -170,6 +176,6 @@ impl AbstractNode for Assignment {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Action::None)
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
error::{RuntimeError, RwLockPoisonError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Statement, Type};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Statement, Type};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct AsyncBlock {
|
||||
@ -30,15 +30,19 @@ impl AbstractNode for AsyncBlock {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
_context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let statement_count = self.statements.len();
|
||||
let final_result = RwLock::new(Ok(Action::None));
|
||||
let final_result = RwLock::new(Ok(Evaluation::None));
|
||||
|
||||
self.statements
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.find_map_first(|(index, statement)| {
|
||||
let result = statement.run(&mut _context.clone(), false);
|
||||
let result = statement.evaluate(&mut _context.clone(), false);
|
||||
|
||||
if index == statement_count - 1 {
|
||||
let get_write_lock = final_result.write();
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Statement};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Statement, Type};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Block {
|
||||
@ -39,11 +39,15 @@ impl AbstractNode for Block {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
let mut previous = Action::None;
|
||||
fn evaluate(
|
||||
self,
|
||||
_context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let mut previous = Evaluation::None;
|
||||
|
||||
for statement in self.statements {
|
||||
previous = statement.run(_context, _manage_memory)?;
|
||||
previous = statement.evaluate(_context, _manage_memory)?;
|
||||
}
|
||||
|
||||
Ok(previous)
|
||||
@ -51,7 +55,7 @@ impl AbstractNode for Block {
|
||||
}
|
||||
|
||||
impl ExpectedType for Block {
|
||||
fn expected_type(&self, _context: &mut Context) -> Result<super::Type, ValidationError> {
|
||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
||||
self.last_statement().expected_type(_context)
|
||||
}
|
||||
}
|
||||
@ -59,7 +63,7 @@ impl ExpectedType for Block {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{Type, ValueExpression, ValueNode, WithPos},
|
||||
abstract_tree::{Expression, ValueNode, WithPos},
|
||||
Value,
|
||||
};
|
||||
|
||||
@ -68,30 +72,30 @@ mod tests {
|
||||
#[test]
|
||||
fn run_returns_value_of_final_statement() {
|
||||
let block = Block::new(vec![
|
||||
Statement::ValueExpression(ValueExpression::Value(
|
||||
Statement::ValueExpression(Expression::Value(
|
||||
ValueNode::Integer(1).with_position((0, 0)),
|
||||
)),
|
||||
Statement::ValueExpression(ValueExpression::Value(
|
||||
Statement::ValueExpression(Expression::Value(
|
||||
ValueNode::Integer(2).with_position((0, 0)),
|
||||
)),
|
||||
Statement::ValueExpression(ValueExpression::Value(
|
||||
Statement::ValueExpression(Expression::Value(
|
||||
ValueNode::Integer(42).with_position((0, 0)),
|
||||
)),
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
block.run(&mut Context::new(None), true).unwrap(),
|
||||
Action::Return(Value::integer(42))
|
||||
block.evaluate(&mut Context::new(None), true).unwrap(),
|
||||
Evaluation::Return(Value::integer(42))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expected_type_returns_type_of_final_statement() {
|
||||
let block = Block::new(vec![
|
||||
Statement::ValueExpression(ValueExpression::Value(
|
||||
Statement::ValueExpression(Expression::Value(
|
||||
ValueNode::String("42".to_string()).with_position((0, 0)),
|
||||
)),
|
||||
Statement::ValueExpression(ValueExpression::Value(
|
||||
Statement::ValueExpression(Expression::Value(
|
||||
ValueNode::Integer(42).with_position((0, 0)),
|
||||
)),
|
||||
]);
|
||||
|
@ -8,23 +8,22 @@ use std::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{Action, Type},
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
value::ValueInner,
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, ExpectedType, ValueExpression, WithPosition};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Expression, Type, TypeConstructor};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum BuiltInFunctionCall {
|
||||
JsonParse(WithPosition<Type>, ValueExpression),
|
||||
Length(ValueExpression),
|
||||
ReadFile(ValueExpression),
|
||||
JsonParse(TypeConstructor, Expression),
|
||||
Length(Expression),
|
||||
ReadFile(Expression),
|
||||
ReadLine,
|
||||
Sleep(ValueExpression),
|
||||
WriteLine(ValueExpression),
|
||||
Sleep(Expression),
|
||||
WriteLine(Expression),
|
||||
}
|
||||
|
||||
impl AbstractNode for BuiltInFunctionCall {
|
||||
@ -51,11 +50,15 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
match self {
|
||||
BuiltInFunctionCall::JsonParse(_type, expression) => {
|
||||
let action = expression.clone().run(context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.clone().evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -66,7 +69,7 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
if let ValueInner::String(string) = value.inner().as_ref() {
|
||||
let deserialized = serde_json::from_str(string)?;
|
||||
|
||||
Ok(Action::Return(deserialized))
|
||||
Ok(Evaluation::Return(deserialized))
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedString {
|
||||
@ -77,8 +80,8 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
}
|
||||
}
|
||||
BuiltInFunctionCall::Length(expression) => {
|
||||
let action = expression.clone().run(context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.clone().evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -91,11 +94,11 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
0
|
||||
};
|
||||
|
||||
Ok(Action::Return(Value::integer(length)))
|
||||
Ok(Evaluation::Return(Value::integer(length)))
|
||||
}
|
||||
BuiltInFunctionCall::ReadFile(expression) => {
|
||||
let action = expression.clone().run(context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.clone().evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -108,20 +111,20 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
String::with_capacity(0)
|
||||
};
|
||||
|
||||
Ok(Action::Return(Value::string(file_contents)))
|
||||
Ok(Evaluation::Return(Value::string(file_contents)))
|
||||
}
|
||||
BuiltInFunctionCall::ReadLine => {
|
||||
let mut buffer = String::new();
|
||||
|
||||
stdin().read_line(&mut buffer)?;
|
||||
|
||||
Ok(Action::Return(Value::string(
|
||||
Ok(Evaluation::Return(Value::string(
|
||||
buffer.strip_suffix('\n').unwrap_or(&buffer),
|
||||
)))
|
||||
}
|
||||
BuiltInFunctionCall::Sleep(expression) => {
|
||||
let action = expression.clone().run(context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.clone().evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -133,11 +136,11 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
thread::sleep(Duration::from_millis(*milliseconds as u64));
|
||||
}
|
||||
|
||||
Ok(Action::None)
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
BuiltInFunctionCall::WriteLine(expression) => {
|
||||
let action = expression.clone().run(context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.clone().evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -153,16 +156,16 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
stdout.flush()?;
|
||||
}
|
||||
|
||||
Ok(Action::None)
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpectedType for BuiltInFunctionCall {
|
||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
||||
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
|
||||
match self {
|
||||
BuiltInFunctionCall::JsonParse(r#type, _) => Ok(r#type.node.clone()),
|
||||
BuiltInFunctionCall::JsonParse(r#type, _) => Ok(r#type.clone().construct(&context)?),
|
||||
BuiltInFunctionCall::Length(_) => Ok(Type::Integer),
|
||||
BuiltInFunctionCall::ReadFile(_) => Ok(Type::String),
|
||||
BuiltInFunctionCall::ReadLine => Ok(Type::String),
|
||||
|
@ -6,25 +6,27 @@ use crate::{
|
||||
value::ValueInner,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, WithPosition};
|
||||
use super::{
|
||||
AbstractNode, Evaluation, ExpectedType, Expression, Type, TypeConstructor, WithPosition,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct FunctionCall {
|
||||
function: Box<ValueExpression>,
|
||||
type_arguments: Vec<WithPosition<Type>>,
|
||||
arguments: Vec<ValueExpression>,
|
||||
function: Box<Expression>,
|
||||
type_arguments: Option<Vec<WithPosition<TypeConstructor>>>,
|
||||
value_arguments: Vec<Expression>,
|
||||
}
|
||||
|
||||
impl FunctionCall {
|
||||
pub fn new(
|
||||
function: ValueExpression,
|
||||
type_arguments: Vec<WithPosition<Type>>,
|
||||
arguments: Vec<ValueExpression>,
|
||||
function: Expression,
|
||||
type_arguments: Option<Vec<WithPosition<TypeConstructor>>>,
|
||||
value_arguments: Vec<Expression>,
|
||||
) -> Self {
|
||||
FunctionCall {
|
||||
function: Box::new(function),
|
||||
type_arguments,
|
||||
arguments,
|
||||
value_arguments,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -33,48 +35,28 @@ impl AbstractNode for FunctionCall {
|
||||
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||
self.function.validate(context, manage_memory)?;
|
||||
|
||||
for expression in &self.arguments {
|
||||
for expression in &self.value_arguments {
|
||||
expression.validate(context, manage_memory)?;
|
||||
}
|
||||
|
||||
let function_node_type = self.function.expected_type(context)?;
|
||||
|
||||
if let Type::Function {
|
||||
parameter_types,
|
||||
type_parameters,
|
||||
value_parameters: _,
|
||||
return_type: _,
|
||||
} = function_node_type
|
||||
{
|
||||
for (type_parameter, type_argument) in
|
||||
parameter_types.iter().zip(self.type_arguments.iter())
|
||||
{
|
||||
if let Type::Argument(_) = type_parameter.node {
|
||||
continue;
|
||||
}
|
||||
|
||||
type_parameter
|
||||
.node
|
||||
.check(&type_argument.node)
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: type_argument.position,
|
||||
expected_position: type_parameter.position,
|
||||
})?;
|
||||
}
|
||||
|
||||
for (type_parameter, expression) in parameter_types.iter().zip(self.arguments.iter()) {
|
||||
if let Type::Argument(_) = type_parameter.node {
|
||||
continue;
|
||||
}
|
||||
|
||||
let actual = expression.expected_type(context)?;
|
||||
|
||||
type_parameter.node.check(&actual).map_err(|conflict| {
|
||||
ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: expression.position(),
|
||||
expected_position: type_parameter.position,
|
||||
match (type_parameters, &self.type_arguments) {
|
||||
(Some(type_parameters), Some(type_arguments)) => {
|
||||
if type_parameters.len() != type_arguments.len() {
|
||||
return Err(ValidationError::WrongTypeArgumentCount {
|
||||
actual: type_parameters.len(),
|
||||
expected: type_arguments.len(),
|
||||
});
|
||||
}
|
||||
})?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -86,10 +68,14 @@ impl AbstractNode for FunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
clear_variables: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let function_position = self.function.position();
|
||||
let action = self.function.run(context, clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = self.function.evaluate(context, clear_variables)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -97,7 +83,7 @@ impl AbstractNode for FunctionCall {
|
||||
));
|
||||
};
|
||||
let function = if let ValueInner::Function(function) = value.inner().as_ref() {
|
||||
function
|
||||
function.clone()
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedFunction {
|
||||
@ -106,12 +92,12 @@ impl AbstractNode for FunctionCall {
|
||||
},
|
||||
));
|
||||
};
|
||||
let mut arguments = Vec::with_capacity(self.arguments.len());
|
||||
let mut arguments = Vec::with_capacity(self.value_arguments.len());
|
||||
|
||||
for expression in self.arguments {
|
||||
for expression in self.value_arguments {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(context, clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.evaluate(context, clear_variables)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -124,15 +110,17 @@ impl AbstractNode for FunctionCall {
|
||||
|
||||
let mut function_context = Context::new(Some(&context));
|
||||
|
||||
for (type_parameter, type_argument) in function
|
||||
.type_parameters()
|
||||
.iter()
|
||||
.map(|r#type| r#type.node.clone())
|
||||
.zip(self.type_arguments.into_iter().map(|r#type| r#type.node))
|
||||
{
|
||||
if let Type::Argument(identifier) = type_parameter {
|
||||
function_context.set_type(identifier, type_argument)?;
|
||||
match (function.type_parameters(), self.type_arguments) {
|
||||
(Some(type_parameters), Some(type_arguments)) => {
|
||||
for (parameter, constructor) in
|
||||
type_parameters.into_iter().zip(type_arguments.into_iter())
|
||||
{
|
||||
let r#type = constructor.node.construct(context)?;
|
||||
|
||||
function_context.set_type(parameter.clone(), r#type)?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
function
|
||||
@ -146,7 +134,7 @@ impl ExpectedType for FunctionCall {
|
||||
let function_node_type = self.function.expected_type(_context)?;
|
||||
|
||||
if let Type::Function { return_type, .. } = function_node_type {
|
||||
Ok(return_type.node)
|
||||
Ok(*return_type)
|
||||
} else {
|
||||
Err(ValidationError::ExpectedFunction {
|
||||
actual: function_node_type,
|
||||
|
@ -6,21 +6,21 @@ use crate::{
|
||||
value::ValueInner,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Block, ExpectedType, Type, ValueExpression, WithPosition};
|
||||
use super::{AbstractNode, Block, Evaluation, ExpectedType, Expression, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct IfElse {
|
||||
if_expression: ValueExpression,
|
||||
if_expression: Expression,
|
||||
if_block: WithPosition<Block>,
|
||||
else_ifs: Vec<(ValueExpression, WithPosition<Block>)>,
|
||||
else_ifs: Vec<(Expression, WithPosition<Block>)>,
|
||||
else_block: Option<WithPosition<Block>>,
|
||||
}
|
||||
|
||||
impl IfElse {
|
||||
pub fn new(
|
||||
if_expression: ValueExpression,
|
||||
if_expression: Expression,
|
||||
if_block: WithPosition<Block>,
|
||||
else_ifs: Vec<(ValueExpression, WithPosition<Block>)>,
|
||||
else_ifs: Vec<(Expression, WithPosition<Block>)>,
|
||||
else_block: Option<WithPosition<Block>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -51,7 +51,7 @@ impl AbstractNode for IfElse {
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: else_block.node.last_statement().position(),
|
||||
expected_position: self.if_block.node.first_statement().position(),
|
||||
expected_position: Some(self.if_block.node.first_statement().position()),
|
||||
})?;
|
||||
}
|
||||
} else {
|
||||
@ -74,7 +74,7 @@ impl AbstractNode for IfElse {
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: self.if_block.node.last_statement().position(),
|
||||
expected_position: self.if_expression.position(),
|
||||
expected_position: Some(self.if_expression.position()),
|
||||
})?;
|
||||
} else {
|
||||
return Err(ValidationError::ExpectedBoolean {
|
||||
@ -87,10 +87,14 @@ impl AbstractNode for IfElse {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let if_position = self.if_expression.position();
|
||||
let action = self.if_expression.run(context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = self.if_expression.evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -100,12 +104,12 @@ impl AbstractNode for IfElse {
|
||||
|
||||
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
|
||||
if *if_boolean {
|
||||
self.if_block.node.run(context, _manage_memory)
|
||||
self.if_block.node.evaluate(context, _manage_memory)
|
||||
} else {
|
||||
for (expression, block) in self.else_ifs {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -115,7 +119,7 @@ impl AbstractNode for IfElse {
|
||||
|
||||
if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() {
|
||||
if *else_if_boolean {
|
||||
return block.node.run(context, _manage_memory);
|
||||
return block.node.evaluate(context, _manage_memory);
|
||||
}
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -128,9 +132,9 @@ impl AbstractNode for IfElse {
|
||||
}
|
||||
|
||||
if let Some(else_statement) = self.else_block {
|
||||
else_statement.node.run(context, _manage_memory)
|
||||
else_statement.node.evaluate(context, _manage_memory)
|
||||
} else {
|
||||
Ok(Action::None)
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -163,17 +167,17 @@ mod tests {
|
||||
fn simple_if() {
|
||||
assert_eq!(
|
||||
IfElse::new(
|
||||
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
Block::new(vec![Statement::ValueExpression(ValueExpression::Value(
|
||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
Block::new(vec![Statement::ValueExpression(Expression::Value(
|
||||
ValueNode::String("foo".to_string()).with_position((0, 0))
|
||||
))])
|
||||
.with_position((0, 0)),
|
||||
Vec::with_capacity(0),
|
||||
None
|
||||
)
|
||||
.run(&mut Context::new(None), true)
|
||||
.evaluate(&mut Context::new(None), true)
|
||||
.unwrap(),
|
||||
Action::Return(Value::string("foo".to_string()))
|
||||
Evaluation::Return(Value::string("foo".to_string()))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -5,64 +5,72 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, ValueNode, WithPosition};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Expression, Type, ValueNode, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct ListIndex {
|
||||
left: ValueExpression,
|
||||
right: ValueExpression,
|
||||
collection: Expression,
|
||||
index: Expression,
|
||||
}
|
||||
|
||||
impl ListIndex {
|
||||
pub fn new(left: ValueExpression, right: ValueExpression) -> Self {
|
||||
Self { left, right }
|
||||
pub fn new(left: Expression, right: Expression) -> Self {
|
||||
Self {
|
||||
collection: left,
|
||||
index: right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractNode for ListIndex {
|
||||
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||
self.left.validate(context, _manage_memory)?;
|
||||
self.right.validate(context, _manage_memory)?;
|
||||
self.collection.validate(context, _manage_memory)?;
|
||||
self.index.validate(context, _manage_memory)?;
|
||||
|
||||
let left_type = self.left.expected_type(context)?;
|
||||
let collection_type = self.collection.expected_type(context)?;
|
||||
let index_type = self.index.expected_type(context)?;
|
||||
|
||||
match left_type {
|
||||
Type::List => todo!(),
|
||||
Type::ListOf(_) => todo!(),
|
||||
Type::ListExact(_) => {
|
||||
let right_type = self.right.expected_type(context)?;
|
||||
|
||||
if let Type::Integer = right_type {
|
||||
match collection_type {
|
||||
Type::List {
|
||||
length: _,
|
||||
item_type: _,
|
||||
} => {
|
||||
if index_type == Type::Integer {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ValidationError::CannotIndexWith {
|
||||
collection_type: left_type,
|
||||
collection_position: self.left.position(),
|
||||
index_type: right_type,
|
||||
index_position: self.right.position(),
|
||||
collection_type,
|
||||
collection_position: self.collection.position(),
|
||||
index_type,
|
||||
index_position: self.index.position(),
|
||||
})
|
||||
}
|
||||
}
|
||||
Type::ListOf(_) => todo!(),
|
||||
_ => Err(ValidationError::CannotIndex {
|
||||
r#type: left_type,
|
||||
position: self.left.position(),
|
||||
r#type: collection_type,
|
||||
position: self.collection.position(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let left_position = self.left.position();
|
||||
let left_action = self.left.run(context, _clear_variables)?;
|
||||
let left_value = if let Action::Return(value) = left_action {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_clear_variables: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let left_position = self.collection.position();
|
||||
let left_action = self.collection.evaluate(context, _clear_variables)?;
|
||||
let left_value = if let Evaluation::Return(value) = left_action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::InterpreterExpectedReturn(left_position),
|
||||
));
|
||||
};
|
||||
let right_position = self.right.position();
|
||||
let right_action = self.right.run(context, _clear_variables)?;
|
||||
let right_value = if let Action::Return(value) = right_action {
|
||||
let right_position = self.index.position();
|
||||
let right_action = self.index.evaluate(context, _clear_variables)?;
|
||||
let right_value = if let Evaluation::Return(value) = right_action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -74,9 +82,9 @@ impl AbstractNode for ListIndex {
|
||||
let found_item = list.get(index as usize);
|
||||
|
||||
if let Some(item) = found_item {
|
||||
Ok(Action::Return(item.node.clone()))
|
||||
Ok(Evaluation::Return(item.node.clone()))
|
||||
} else {
|
||||
Ok(Action::None)
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
@ -93,18 +101,18 @@ impl AbstractNode for ListIndex {
|
||||
|
||||
impl ExpectedType for ListIndex {
|
||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
||||
let left_type = self.left.expected_type(_context)?;
|
||||
let left_type = self.collection.expected_type(_context)?;
|
||||
|
||||
if let (
|
||||
ValueExpression::Value(WithPosition {
|
||||
Expression::Value(WithPosition {
|
||||
node: ValueNode::List(expression_list),
|
||||
..
|
||||
}),
|
||||
ValueExpression::Value(WithPosition {
|
||||
Expression::Value(WithPosition {
|
||||
node: ValueNode::Integer(index),
|
||||
..
|
||||
}),
|
||||
) = (&self.left, &self.right)
|
||||
) = (&self.collection, &self.index)
|
||||
{
|
||||
let expression = if let Some(expression) = expression_list.get(*index as usize) {
|
||||
expression
|
||||
@ -116,7 +124,7 @@ impl ExpectedType for ListIndex {
|
||||
} else {
|
||||
Err(ValidationError::CannotIndex {
|
||||
r#type: left_type,
|
||||
position: self.left.position(),
|
||||
position: self.collection.position(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -7,19 +7,19 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Expression, Type};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum Logic {
|
||||
Equal(ValueExpression, ValueExpression),
|
||||
NotEqual(ValueExpression, ValueExpression),
|
||||
Greater(ValueExpression, ValueExpression),
|
||||
Less(ValueExpression, ValueExpression),
|
||||
GreaterOrEqual(ValueExpression, ValueExpression),
|
||||
LessOrEqual(ValueExpression, ValueExpression),
|
||||
And(ValueExpression, ValueExpression),
|
||||
Or(ValueExpression, ValueExpression),
|
||||
Not(ValueExpression),
|
||||
Equal(Expression, Expression),
|
||||
NotEqual(Expression, Expression),
|
||||
Greater(Expression, Expression),
|
||||
Less(Expression, Expression),
|
||||
GreaterOrEqual(Expression, Expression),
|
||||
LessOrEqual(Expression, Expression),
|
||||
And(Expression, Expression),
|
||||
Or(Expression, Expression),
|
||||
Not(Expression),
|
||||
}
|
||||
|
||||
impl AbstractNode for Logic {
|
||||
@ -42,7 +42,7 @@ impl AbstractNode for Logic {
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: left.position(),
|
||||
expected_position: right.position(),
|
||||
expected_position: Some(right.position()),
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
@ -89,11 +89,15 @@ impl AbstractNode for Logic {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
let run_and_expect_value = |expression: ValueExpression| -> Result<Value, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let run_and_expect_value = |expression: Expression| -> Result<Value, RuntimeError> {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(&mut context.clone(), _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.evaluate(&mut context.clone(), _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -104,10 +108,10 @@ impl AbstractNode for Logic {
|
||||
Ok(value)
|
||||
};
|
||||
|
||||
let run_and_expect_boolean = |expression: ValueExpression| -> Result<bool, RuntimeError> {
|
||||
let run_and_expect_boolean = |expression: Expression| -> Result<bool, RuntimeError> {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(&mut context.clone(), _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.evaluate(&mut context.clone(), _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -187,7 +191,7 @@ impl AbstractNode for Logic {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Action::Return(Value::boolean(boolean)))
|
||||
Ok(Evaluation::Return(Value::boolean(boolean)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,11 +211,11 @@ mod tests {
|
||||
fn equal() {
|
||||
assert_eq!(
|
||||
Logic::Equal(
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
|
||||
@ -219,11 +223,11 @@ mod tests {
|
||||
fn not_equal() {
|
||||
assert_eq!(
|
||||
Logic::NotEqual(
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
|
||||
@ -231,11 +235,11 @@ mod tests {
|
||||
fn greater() {
|
||||
assert_eq!(
|
||||
Logic::Greater(
|
||||
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
|
||||
@ -243,11 +247,11 @@ mod tests {
|
||||
fn less() {
|
||||
assert_eq!(
|
||||
Logic::Less(
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
|
||||
@ -255,20 +259,20 @@ mod tests {
|
||||
fn greater_or_equal() {
|
||||
assert_eq!(
|
||||
Logic::GreaterOrEqual(
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Logic::GreaterOrEqual(
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
);
|
||||
}
|
||||
|
||||
@ -276,20 +280,20 @@ mod tests {
|
||||
fn less_or_equal() {
|
||||
assert_eq!(
|
||||
Logic::LessOrEqual(
|
||||
ValueExpression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Logic::LessOrEqual(
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
);
|
||||
}
|
||||
|
||||
@ -297,11 +301,11 @@ mod tests {
|
||||
fn and() {
|
||||
assert_eq!(
|
||||
Logic::And(
|
||||
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
|
||||
@ -309,22 +313,22 @@ mod tests {
|
||||
fn or() {
|
||||
assert_eq!(
|
||||
Logic::Or(
|
||||
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
ValueExpression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
||||
)
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not() {
|
||||
assert_eq!(
|
||||
Logic::Not(ValueExpression::Value(
|
||||
Logic::Not(Expression::Value(
|
||||
ValueNode::Boolean(false).with_position((0, 0))
|
||||
))
|
||||
.run(&mut Context::new(None), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
.evaluate(&mut Context::new(None), true),
|
||||
Ok(Evaluation::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Statement};
|
||||
use super::{AbstractNode, Evaluation, Statement};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Loop {
|
||||
@ -31,15 +31,19 @@ impl AbstractNode for Loop {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
_context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
loop {
|
||||
for statement in &self.statements {
|
||||
let action = statement.clone().run(_context, false)?;
|
||||
let action = statement.clone().evaluate(_context, false)?;
|
||||
|
||||
match action {
|
||||
Action::Return(_) => {}
|
||||
Action::None => {}
|
||||
Action::Break => return Ok(Action::Break),
|
||||
Evaluation::Return(_) => {}
|
||||
Evaluation::None => {}
|
||||
Evaluation::Break => return Ok(Evaluation::Break),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,16 +6,16 @@ use crate::{
|
||||
value::ValueInner,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, ValueNode, WithPosition};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Expression, Type, ValueNode, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct MapIndex {
|
||||
collection: ValueExpression,
|
||||
index: ValueExpression,
|
||||
collection: Expression,
|
||||
index: Expression,
|
||||
}
|
||||
|
||||
impl MapIndex {
|
||||
pub fn new(left: ValueExpression, right: ValueExpression) -> Self {
|
||||
pub fn new(left: Expression, right: Expression) -> Self {
|
||||
Self {
|
||||
collection: left,
|
||||
index: right,
|
||||
@ -32,10 +32,14 @@ impl AbstractNode for MapIndex {
|
||||
self.collection.validate(_context, _manage_memory)
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let collection_position = self.collection.position();
|
||||
let action = self.collection.run(context, _manage_memory)?;
|
||||
let collection = if let Action::Return(value) = action {
|
||||
let action = self.collection.evaluate(context, _manage_memory)?;
|
||||
let collection = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -43,13 +47,13 @@ impl AbstractNode for MapIndex {
|
||||
));
|
||||
};
|
||||
|
||||
if let (ValueInner::Map(map), ValueExpression::Identifier(index)) =
|
||||
if let (ValueInner::Map(map), Expression::Identifier(index)) =
|
||||
(collection.inner().as_ref(), self.index)
|
||||
{
|
||||
let action = map
|
||||
.get(&index.node)
|
||||
.map(|value| Action::Return(value.clone()))
|
||||
.unwrap_or(Action::None);
|
||||
.map(|value| Evaluation::Return(value.clone()))
|
||||
.unwrap_or(Evaluation::None);
|
||||
|
||||
Ok(action)
|
||||
} else {
|
||||
@ -65,7 +69,7 @@ impl AbstractNode for MapIndex {
|
||||
|
||||
impl ExpectedType for MapIndex {
|
||||
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
|
||||
if let (ValueExpression::Identifier(collection), ValueExpression::Identifier(index)) =
|
||||
if let (Expression::Identifier(collection), Expression::Identifier(index)) =
|
||||
(&self.collection, &self.index)
|
||||
{
|
||||
let collection = if let Some(collection) = context.get_value(&collection.node)? {
|
||||
@ -90,17 +94,19 @@ impl ExpectedType for MapIndex {
|
||||
}
|
||||
|
||||
if let (
|
||||
ValueExpression::Value(WithPosition {
|
||||
Expression::Value(WithPosition {
|
||||
node: ValueNode::Map(properties),
|
||||
..
|
||||
}),
|
||||
ValueExpression::Identifier(index),
|
||||
Expression::Identifier(index),
|
||||
) = (&self.collection, &self.index)
|
||||
{
|
||||
for (property, type_option, expression) in properties {
|
||||
for (property, constructor_option, expression) in properties {
|
||||
if property == &index.node {
|
||||
return if let Some(r#type) = type_option {
|
||||
Ok(r#type.node.clone())
|
||||
return if let Some(constructor) = constructor_option {
|
||||
let r#type = constructor.node.clone().construct(&context)?;
|
||||
|
||||
Ok(r#type)
|
||||
} else {
|
||||
Ok(expression.expected_type(context)?)
|
||||
};
|
||||
@ -111,15 +117,15 @@ impl ExpectedType for MapIndex {
|
||||
}
|
||||
|
||||
if let (
|
||||
ValueExpression::Value(WithPosition {
|
||||
Expression::Value(WithPosition {
|
||||
node: ValueNode::Structure { fields, .. },
|
||||
..
|
||||
}),
|
||||
ValueExpression::Identifier(index),
|
||||
Expression::Identifier(index),
|
||||
) = (&self.collection, &self.index)
|
||||
{
|
||||
return if let Some(type_result) = fields.iter().find_map(|(property, expression)| {
|
||||
if property == &index.node {
|
||||
if property.node == index.node {
|
||||
Some(expression.expected_type(context))
|
||||
} else {
|
||||
None
|
||||
|
@ -7,15 +7,15 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, ExpectedType, SourcePosition, Type, ValueExpression};
|
||||
use super::{AbstractNode, Evaluation, ExpectedType, Expression, SourcePosition, Type};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum Math {
|
||||
Add(ValueExpression, ValueExpression),
|
||||
Subtract(ValueExpression, ValueExpression),
|
||||
Multiply(ValueExpression, ValueExpression),
|
||||
Divide(ValueExpression, ValueExpression),
|
||||
Modulo(ValueExpression, ValueExpression),
|
||||
Add(Expression, Expression),
|
||||
Subtract(Expression, Expression),
|
||||
Multiply(Expression, Expression),
|
||||
Divide(Expression, Expression),
|
||||
Modulo(Expression, Expression),
|
||||
}
|
||||
|
||||
impl AbstractNode for Math {
|
||||
@ -67,21 +67,24 @@ impl AbstractNode for Math {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let run_and_expect_value = |position: SourcePosition,
|
||||
expression: ValueExpression|
|
||||
-> Result<Value, RuntimeError> {
|
||||
let action = expression.run(&mut _context.clone(), _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::InterpreterExpectedReturn(position),
|
||||
));
|
||||
};
|
||||
fn evaluate(
|
||||
self,
|
||||
_context: &mut Context,
|
||||
_clear_variables: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let run_and_expect_value =
|
||||
|position: SourcePosition, expression: Expression| -> Result<Value, RuntimeError> {
|
||||
let action = expression.evaluate(&mut _context.clone(), _clear_variables)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::InterpreterExpectedReturn(position),
|
||||
));
|
||||
};
|
||||
|
||||
Ok(value)
|
||||
};
|
||||
Ok(value)
|
||||
};
|
||||
|
||||
let value = match self {
|
||||
Math::Add(left, right) => {
|
||||
@ -288,7 +291,7 @@ impl AbstractNode for Math {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Action::Return(value))
|
||||
Ok(Evaluation::Return(value))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ pub mod statement;
|
||||
pub mod structure_definition;
|
||||
pub mod r#type;
|
||||
pub mod type_alias;
|
||||
pub mod type_constructor;
|
||||
pub mod value_expression;
|
||||
pub mod value_node;
|
||||
pub mod r#while;
|
||||
@ -41,7 +42,8 @@ pub use self::{
|
||||
statement::Statement,
|
||||
structure_definition::StructureDefinition,
|
||||
type_alias::TypeAssignment,
|
||||
value_expression::ValueExpression,
|
||||
type_constructor::TypeConstructor,
|
||||
value_expression::Expression,
|
||||
value_node::ValueNode,
|
||||
};
|
||||
|
||||
@ -84,7 +86,7 @@ impl From<(usize, usize)> for SourcePosition {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Action {
|
||||
pub enum Evaluation {
|
||||
Return(Value),
|
||||
Break,
|
||||
None,
|
||||
@ -114,12 +116,12 @@ impl AbstractTree {
|
||||
|
||||
for statement in valid_statements {
|
||||
let position = statement.position();
|
||||
let run = statement.run(context, manage_memory);
|
||||
let run = statement.evaluate(context, manage_memory);
|
||||
|
||||
match run {
|
||||
Ok(action) => match action {
|
||||
Action::Return(value) => previous_value = Some(value),
|
||||
Action::None => previous_value = None,
|
||||
Evaluation::Return(value) => previous_value = Some(value),
|
||||
Evaluation::None => previous_value = None,
|
||||
_ => {}
|
||||
},
|
||||
Err(runtime_error) => {
|
||||
@ -153,7 +155,7 @@ impl AbstractTree {
|
||||
} else if errors.is_empty() {
|
||||
if let Statement::StructureDefinition(_) = statement {
|
||||
let position = statement.position();
|
||||
let run = statement.run(context, true);
|
||||
let run = statement.evaluate(context, true);
|
||||
|
||||
if let Err(runtime_error) = run {
|
||||
errors.push(Error::Runtime {
|
||||
@ -189,7 +191,11 @@ impl Index<usize> for AbstractTree {
|
||||
|
||||
pub trait AbstractNode: Sized {
|
||||
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError>;
|
||||
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError>;
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError>;
|
||||
}
|
||||
|
||||
pub trait ExpectedType {
|
||||
|
@ -6,9 +6,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
AbstractNode, Action, Assignment, AsyncBlock, Block, ExpectedType, IfElse, Loop,
|
||||
SourcePosition, StructureDefinition, Type, TypeAssignment, ValueExpression, While,
|
||||
WithPosition,
|
||||
AbstractNode, Assignment, AsyncBlock, Block, Evaluation, ExpectedType, Expression, IfElse,
|
||||
Loop, SourcePosition, StructureDefinition, Type, TypeAssignment, While, WithPosition,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
@ -21,7 +20,7 @@ pub enum Statement {
|
||||
Loop(WithPosition<Loop>),
|
||||
StructureDefinition(WithPosition<StructureDefinition>),
|
||||
TypeAssignment(WithPosition<TypeAssignment>),
|
||||
ValueExpression(ValueExpression),
|
||||
ValueExpression(Expression),
|
||||
While(WithPosition<While>),
|
||||
}
|
||||
|
||||
@ -68,20 +67,26 @@ impl AbstractNode for Statement {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let result = match self {
|
||||
Statement::Assignment(assignment) => assignment.node.run(context, manage_memory),
|
||||
Statement::AsyncBlock(async_block) => async_block.node.run(context, manage_memory),
|
||||
Statement::Block(block) => block.node.run(context, manage_memory),
|
||||
Statement::Break(_) => Ok(Action::Break),
|
||||
Statement::ValueExpression(expression) => expression.run(context, manage_memory),
|
||||
Statement::IfElse(if_else) => if_else.node.run(context, manage_memory),
|
||||
Statement::Loop(r#loop) => r#loop.node.run(context, manage_memory),
|
||||
Statement::Assignment(assignment) => assignment.node.evaluate(context, manage_memory),
|
||||
Statement::AsyncBlock(async_block) => async_block.node.evaluate(context, manage_memory),
|
||||
Statement::Block(block) => block.node.evaluate(context, manage_memory),
|
||||
Statement::Break(_) => Ok(Evaluation::Break),
|
||||
Statement::ValueExpression(expression) => expression.evaluate(context, manage_memory),
|
||||
Statement::IfElse(if_else) => if_else.node.evaluate(context, manage_memory),
|
||||
Statement::Loop(r#loop) => r#loop.node.evaluate(context, manage_memory),
|
||||
Statement::StructureDefinition(structure_definition) => {
|
||||
structure_definition.node.run(context, manage_memory)
|
||||
structure_definition.node.evaluate(context, manage_memory)
|
||||
}
|
||||
Statement::TypeAssignment(type_alias) => type_alias.node.run(context, manage_memory),
|
||||
Statement::While(r#while) => r#while.node.run(context, manage_memory),
|
||||
Statement::TypeAssignment(type_alias) => {
|
||||
type_alias.node.evaluate(context, manage_memory)
|
||||
}
|
||||
Statement::While(r#while) => r#while.node.evaluate(context, manage_memory),
|
||||
};
|
||||
|
||||
if manage_memory {
|
||||
|
@ -6,16 +6,16 @@ use crate::{
|
||||
identifier::Identifier,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Type, WithPosition};
|
||||
use super::{AbstractNode, Evaluation, Type, TypeConstructor, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct StructureDefinition {
|
||||
name: Identifier,
|
||||
fields: Vec<(Identifier, WithPosition<Type>)>,
|
||||
fields: Vec<(Identifier, WithPosition<TypeConstructor>)>,
|
||||
}
|
||||
|
||||
impl StructureDefinition {
|
||||
pub fn new(name: Identifier, fields: Vec<(Identifier, WithPosition<Type>)>) -> Self {
|
||||
pub fn new(name: Identifier, fields: Vec<(Identifier, WithPosition<TypeConstructor>)>) -> Self {
|
||||
Self { name, fields }
|
||||
}
|
||||
}
|
||||
@ -29,14 +29,26 @@ impl AbstractNode for StructureDefinition {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let mut fields = Vec::with_capacity(self.fields.len());
|
||||
|
||||
for (identifier, constructor) in self.fields {
|
||||
let r#type = constructor.node.construct(&context)?;
|
||||
|
||||
fields.push((identifier, r#type));
|
||||
}
|
||||
|
||||
let struct_type = Type::Structure {
|
||||
name: self.name.clone(),
|
||||
fields: self.fields,
|
||||
fields,
|
||||
};
|
||||
|
||||
context.set_type(self.name, struct_type)?;
|
||||
|
||||
Ok(Action::None)
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
}
|
||||
|
@ -9,29 +9,31 @@ use crate::{
|
||||
identifier::Identifier,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, WithPosition};
|
||||
use super::{AbstractNode, Evaluation};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Argument(Identifier),
|
||||
Boolean,
|
||||
Float,
|
||||
Function {
|
||||
parameter_types: Vec<WithPosition<Type>>,
|
||||
return_type: Box<WithPosition<Type>>,
|
||||
type_parameters: Option<Vec<Identifier>>,
|
||||
value_parameters: Vec<(Identifier, Type)>,
|
||||
return_type: Box<Type>,
|
||||
},
|
||||
Integer,
|
||||
List,
|
||||
ListOf(Box<WithPosition<Type>>),
|
||||
ListExact(Vec<WithPosition<Type>>),
|
||||
List {
|
||||
length: usize,
|
||||
item_type: Box<Type>,
|
||||
},
|
||||
ListOf(Box<Type>),
|
||||
Map,
|
||||
None,
|
||||
Range,
|
||||
String,
|
||||
Structure {
|
||||
name: Identifier,
|
||||
fields: Vec<(Identifier, WithPosition<Type>)>,
|
||||
fields: Vec<(Identifier, Type)>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -43,46 +45,15 @@ impl Type {
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
| (Type::Float, Type::Float)
|
||||
| (Type::Integer, Type::Integer)
|
||||
| (Type::List, Type::List)
|
||||
| (Type::List, Type::ListOf(_))
|
||||
| (Type::List, Type::ListExact(_))
|
||||
| (Type::ListOf(_), Type::List)
|
||||
| (Type::ListExact(_), Type::List)
|
||||
| (Type::Map, Type::Map)
|
||||
| (Type::None, Type::None)
|
||||
| (Type::Range, Type::Range)
|
||||
| (Type::String, Type::String) => return Ok(()),
|
||||
(Type::Argument(left), Type::Argument(right)) => {
|
||||
if left == right {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
(Type::ListOf(left), Type::ListOf(right)) => {
|
||||
if let Ok(()) = left.node.check(&right.node) {
|
||||
if let Ok(()) = left.check(&right) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
(Type::ListOf(list_of), Type::ListExact(list_exact)) => {
|
||||
for r#type in list_exact {
|
||||
list_of.node.check(&r#type.node)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
(Type::ListExact(list_exact), Type::ListOf(list_of)) => {
|
||||
for r#type in list_exact {
|
||||
r#type.node.check(&list_of.node)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
(Type::ListExact(left), Type::ListExact(right)) => {
|
||||
for (left, right) in left.iter().zip(right.iter()) {
|
||||
left.node.check(&right.node)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
(
|
||||
Type::Structure {
|
||||
name: left_name,
|
||||
@ -97,8 +68,7 @@ impl Type {
|
||||
for ((left_field_name, left_type), (right_field_name, right_type)) in
|
||||
left_fields.iter().zip(right_fields.iter())
|
||||
{
|
||||
if left_field_name != right_field_name || left_type.node != right_type.node
|
||||
{
|
||||
if left_field_name != right_field_name || left_type != right_type {
|
||||
return Err(TypeConflict {
|
||||
actual: other.clone(),
|
||||
expected: self.clone(),
|
||||
@ -111,19 +81,33 @@ impl Type {
|
||||
}
|
||||
(
|
||||
Type::Function {
|
||||
parameter_types: left_parameters,
|
||||
type_parameters: left_type_parameters,
|
||||
value_parameters: left_value_parameters,
|
||||
return_type: left_return,
|
||||
},
|
||||
Type::Function {
|
||||
parameter_types: right_parameters,
|
||||
type_parameters: right_type_parameters,
|
||||
value_parameters: right_value_parameters,
|
||||
return_type: right_return,
|
||||
},
|
||||
) => {
|
||||
if left_return.node == right_return.node {
|
||||
for (left_parameter, right_parameter) in
|
||||
left_parameters.iter().zip(right_parameters.iter())
|
||||
if left_return == right_return {
|
||||
for (left_parameter, right_parameter) in left_type_parameters
|
||||
.iter()
|
||||
.zip(right_type_parameters.iter())
|
||||
{
|
||||
if left_parameter.node != right_parameter.node {
|
||||
if left_parameter != right_parameter {
|
||||
return Err(TypeConflict {
|
||||
actual: other.clone(),
|
||||
expected: self.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
for (left_parameter, right_parameter) in left_value_parameters
|
||||
.iter()
|
||||
.zip(right_value_parameters.iter())
|
||||
{
|
||||
if left_parameter != right_parameter {
|
||||
return Err(TypeConflict {
|
||||
actual: other.clone(),
|
||||
expected: self.clone(),
|
||||
@ -153,8 +137,12 @@ impl AbstractNode for Type {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
Ok(Action::None)
|
||||
fn evaluate(
|
||||
self,
|
||||
_context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,47 +153,40 @@ impl Display for Type {
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Integer => write!(f, "int"),
|
||||
Type::List => write!(f, "list"),
|
||||
Type::ListOf(item_type) => write!(f, "list({})", item_type.node),
|
||||
Type::ListExact(item_types) => {
|
||||
write!(f, "[")?;
|
||||
|
||||
for (index, item_type) in item_types.into_iter().enumerate() {
|
||||
if index == item_types.len() - 1 {
|
||||
write!(f, "{}", item_type.node)?;
|
||||
} else {
|
||||
write!(f, "{}, ", item_type.node)?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
}
|
||||
Type::List { length, item_type } => write!(f, "[{length}; {}]", item_type),
|
||||
Type::ListOf(item_type) => write!(f, "list({})", item_type),
|
||||
Type::Map => write!(f, "map"),
|
||||
Type::None => write!(f, "none"),
|
||||
Type::Range => write!(f, "range"),
|
||||
Type::String => write!(f, "str"),
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
type_parameters,
|
||||
value_parameters,
|
||||
return_type,
|
||||
} => {
|
||||
write!(f, "(")?;
|
||||
|
||||
for r#type in parameter_types {
|
||||
write!(f, "{} ", r#type.node)?;
|
||||
if let Some(type_parameters) = type_parameters {
|
||||
for identifier in type_parameters {
|
||||
write!(f, "{} ", identifier)?;
|
||||
}
|
||||
|
||||
write!(f, ")(")?;
|
||||
}
|
||||
|
||||
write!(f, ") : {}", return_type.node)
|
||||
for (identifier, r#type) in value_parameters {
|
||||
write!(f, "{identifier}: {type}")?;
|
||||
}
|
||||
|
||||
write!(f, ") : {}", return_type)
|
||||
}
|
||||
Type::Structure { name, .. } => write!(f, "{name}"),
|
||||
Type::Argument(identifier) => write!(f, "{identifier}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::abstract_tree::WithPos;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@ -214,18 +195,22 @@ mod tests {
|
||||
assert_eq!(Type::Boolean.check(&Type::Boolean), Ok(()));
|
||||
assert_eq!(Type::Float.check(&Type::Float), Ok(()));
|
||||
assert_eq!(Type::Integer.check(&Type::Integer), Ok(()));
|
||||
assert_eq!(Type::List.check(&Type::List), Ok(()));
|
||||
assert_eq!(
|
||||
Type::ListOf(Box::new(Type::Integer.with_position((0, 0))))
|
||||
.check(&Type::ListOf(Box::new(Type::Integer.with_position((0, 0))))),
|
||||
Type::List {
|
||||
length: 4,
|
||||
item_type: Box::new(Type::Boolean),
|
||||
}
|
||||
.check(&Type::List {
|
||||
length: 4,
|
||||
item_type: Box::new(Type::Boolean),
|
||||
}),
|
||||
Ok(())
|
||||
);
|
||||
assert_eq!(
|
||||
Type::ListOf(Box::new(Type::Integer)).check(&Type::ListOf(Box::new(Type::Integer))),
|
||||
Ok(())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Type::ListExact(vec![Type::Float.with_position((0, 0))])
|
||||
.check(&Type::ListExact(vec![Type::Float.with_position((0, 0))])),
|
||||
Ok(())
|
||||
);
|
||||
assert_eq!(Type::Map.check(&Type::Map), Ok(()));
|
||||
assert_eq!(Type::None.check(&Type::None), Ok(()));
|
||||
assert_eq!(Type::Range.check(&Type::Range), Ok(()));
|
||||
@ -257,9 +242,11 @@ mod tests {
|
||||
Type::Boolean,
|
||||
Type::Float,
|
||||
Type::Integer,
|
||||
Type::List,
|
||||
Type::ListOf(Box::new(Type::Boolean.with_position((0, 0)))),
|
||||
Type::ListExact(vec![Type::Integer.with_position((0, 0))]),
|
||||
Type::List {
|
||||
length: 10,
|
||||
item_type: Box::new(Type::Integer),
|
||||
},
|
||||
Type::ListOf(Box::new(Type::Boolean)),
|
||||
Type::Map,
|
||||
Type::None,
|
||||
Type::Range,
|
||||
@ -283,18 +270,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn check_list_types() {
|
||||
let list = Type::List;
|
||||
let list_exact = Type::ListExact(vec![
|
||||
Type::Integer.with_position((0, 0)),
|
||||
Type::Integer.with_position((0, 0)),
|
||||
]);
|
||||
let list_of = Type::ListOf(Box::new(Type::Integer.with_position((0, 0))));
|
||||
let list = Type::List {
|
||||
length: 42,
|
||||
item_type: Box::new(Type::Integer),
|
||||
};
|
||||
let list_of = Type::ListOf(Box::new(Type::Integer));
|
||||
|
||||
assert_eq!(list.check(&list_exact), Ok(()));
|
||||
assert_eq!(list.check(&list_of), Ok(()));
|
||||
assert_eq!(list_exact.check(&list), Ok(()));
|
||||
assert_eq!(list_exact.check(&list_of), Ok(()));
|
||||
assert_eq!(list_of.check(&list), Ok(()));
|
||||
assert_eq!(list_of.check(&list_exact), Ok(()));
|
||||
}
|
||||
}
|
||||
|
@ -6,17 +6,23 @@ use crate::{
|
||||
identifier::Identifier,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Type, WithPosition};
|
||||
use super::{AbstractNode, Evaluation, TypeConstructor, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct TypeAssignment {
|
||||
identifier: WithPosition<Identifier>,
|
||||
r#type: WithPosition<Type>,
|
||||
constructor: WithPosition<TypeConstructor>,
|
||||
}
|
||||
|
||||
impl TypeAssignment {
|
||||
pub fn new(identifier: WithPosition<Identifier>, r#type: WithPosition<Type>) -> Self {
|
||||
Self { identifier, r#type }
|
||||
pub fn new(
|
||||
identifier: WithPosition<Identifier>,
|
||||
constructor: WithPosition<TypeConstructor>,
|
||||
) -> Self {
|
||||
Self {
|
||||
identifier,
|
||||
constructor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,9 +35,15 @@ impl AbstractNode for TypeAssignment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
context.set_type(self.identifier.node, self.r#type.node)?;
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let r#type = self.constructor.node.construct(&context)?;
|
||||
|
||||
Ok(Action::None)
|
||||
context.set_type(self.identifier.node, r#type)?;
|
||||
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
}
|
||||
|
78
dust-lang/src/abstract_tree/type_constructor.rs
Normal file
78
dust-lang/src/abstract_tree/type_constructor.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{context::Context, error::ValidationError, identifier::Identifier};
|
||||
|
||||
use super::{ExpectedType, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum TypeConstructor {
|
||||
Function {
|
||||
type_parameters: Option<Vec<WithPosition<Identifier>>>,
|
||||
value_parameters: Vec<(WithPosition<Identifier>, Box<WithPosition<TypeConstructor>>)>,
|
||||
return_type: Box<WithPosition<TypeConstructor>>,
|
||||
},
|
||||
Identifier(WithPosition<Identifier>),
|
||||
List {
|
||||
length: usize,
|
||||
item_type: Box<WithPosition<TypeConstructor>>,
|
||||
},
|
||||
ListOf(WithPosition<Box<TypeConstructor>>),
|
||||
Type(Type),
|
||||
}
|
||||
|
||||
impl TypeConstructor {
|
||||
pub fn validate(
|
||||
&self,
|
||||
_context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<(), ValidationError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn construct(self, context: &Context) -> Result<Type, ValidationError> {
|
||||
match self {
|
||||
TypeConstructor::Function {
|
||||
type_parameters: _,
|
||||
value_parameters: _,
|
||||
return_type: _,
|
||||
} => todo!(),
|
||||
TypeConstructor::Identifier(WithPosition {
|
||||
node: identifier,
|
||||
position,
|
||||
}) => {
|
||||
if let Some(r#type) = context.get_type(&identifier)? {
|
||||
Ok(r#type)
|
||||
} else {
|
||||
Err(ValidationError::VariableNotFound {
|
||||
identifier,
|
||||
position,
|
||||
})
|
||||
}
|
||||
}
|
||||
TypeConstructor::List { length, item_type } => {
|
||||
let constructed_type = item_type.node.construct(context)?;
|
||||
|
||||
Ok(Type::List {
|
||||
length,
|
||||
item_type: Box::new(constructed_type),
|
||||
})
|
||||
}
|
||||
TypeConstructor::Type(r#type) => Ok(r#type),
|
||||
TypeConstructor::ListOf(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpectedType for TypeConstructor {
|
||||
fn expected_type(&self, _: &mut Context) -> Result<Type, ValidationError> {
|
||||
Ok(Type::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TypeConstructor {
|
||||
fn fmt(&self, _: &mut Formatter) -> fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -7,12 +7,12 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
AbstractNode, Action, As, BuiltInFunctionCall, ExpectedType, FunctionCall, ListIndex, Logic,
|
||||
MapIndex, Math, SourcePosition, Type, ValueNode, WithPosition,
|
||||
AbstractNode, As, BuiltInFunctionCall, Evaluation, ExpectedType, FunctionCall, ListIndex,
|
||||
Logic, MapIndex, Math, SourcePosition, Type, ValueNode, WithPosition,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum ValueExpression {
|
||||
pub enum Expression {
|
||||
As(WithPosition<Box<As>>),
|
||||
BuiltInFunctionCall(WithPosition<Box<BuiltInFunctionCall>>),
|
||||
FunctionCall(WithPosition<FunctionCall>),
|
||||
@ -24,30 +24,30 @@ pub enum ValueExpression {
|
||||
Value(WithPosition<ValueNode>),
|
||||
}
|
||||
|
||||
impl ValueExpression {
|
||||
impl Expression {
|
||||
pub fn position(&self) -> SourcePosition {
|
||||
match self {
|
||||
ValueExpression::As(inner) => inner.position,
|
||||
ValueExpression::FunctionCall(inner) => inner.position,
|
||||
ValueExpression::Identifier(inner) => inner.position,
|
||||
ValueExpression::MapIndex(inner) => inner.position,
|
||||
ValueExpression::ListIndex(inner) => inner.position,
|
||||
ValueExpression::Logic(inner) => inner.position,
|
||||
ValueExpression::Math(inner) => inner.position,
|
||||
ValueExpression::Value(inner) => inner.position,
|
||||
ValueExpression::BuiltInFunctionCall(inner) => inner.position,
|
||||
Expression::As(inner) => inner.position,
|
||||
Expression::FunctionCall(inner) => inner.position,
|
||||
Expression::Identifier(inner) => inner.position,
|
||||
Expression::MapIndex(inner) => inner.position,
|
||||
Expression::ListIndex(inner) => inner.position,
|
||||
Expression::Logic(inner) => inner.position,
|
||||
Expression::Math(inner) => inner.position,
|
||||
Expression::Value(inner) => inner.position,
|
||||
Expression::BuiltInFunctionCall(inner) => inner.position,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractNode for ValueExpression {
|
||||
impl AbstractNode for Expression {
|
||||
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||
match self {
|
||||
ValueExpression::As(r#as) => r#as.node.validate(context, manage_memory),
|
||||
ValueExpression::FunctionCall(function_call) => {
|
||||
Expression::As(r#as) => r#as.node.validate(context, manage_memory),
|
||||
Expression::FunctionCall(function_call) => {
|
||||
function_call.node.validate(context, manage_memory)
|
||||
}
|
||||
ValueExpression::Identifier(identifier) => {
|
||||
Expression::Identifier(identifier) => {
|
||||
let found = if manage_memory {
|
||||
context.add_expected_use(&identifier.node)?
|
||||
} else {
|
||||
@ -63,26 +63,28 @@ impl AbstractNode for ValueExpression {
|
||||
})
|
||||
}
|
||||
}
|
||||
ValueExpression::MapIndex(map_index) => map_index.node.validate(context, manage_memory),
|
||||
ValueExpression::ListIndex(list_index) => {
|
||||
list_index.node.validate(context, manage_memory)
|
||||
}
|
||||
ValueExpression::Logic(logic) => logic.node.validate(context, manage_memory),
|
||||
ValueExpression::Math(math) => math.node.validate(context, manage_memory),
|
||||
ValueExpression::Value(value_node) => value_node.node.validate(context, manage_memory),
|
||||
ValueExpression::BuiltInFunctionCall(built_in_function_call) => {
|
||||
Expression::MapIndex(map_index) => map_index.node.validate(context, manage_memory),
|
||||
Expression::ListIndex(list_index) => list_index.node.validate(context, manage_memory),
|
||||
Expression::Logic(logic) => logic.node.validate(context, manage_memory),
|
||||
Expression::Math(math) => math.node.validate(context, manage_memory),
|
||||
Expression::Value(value_node) => value_node.node.validate(context, manage_memory),
|
||||
Expression::BuiltInFunctionCall(built_in_function_call) => {
|
||||
built_in_function_call.node.validate(context, manage_memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
match self {
|
||||
ValueExpression::As(r#as) => r#as.node.run(context, manage_memory),
|
||||
ValueExpression::FunctionCall(function_call) => {
|
||||
function_call.node.run(context, manage_memory)
|
||||
Expression::As(r#as) => r#as.node.evaluate(context, manage_memory),
|
||||
Expression::FunctionCall(function_call) => {
|
||||
function_call.node.evaluate(context, manage_memory)
|
||||
}
|
||||
ValueExpression::Identifier(identifier) => {
|
||||
Expression::Identifier(identifier) => {
|
||||
let value_option = if manage_memory {
|
||||
context.use_value(&identifier.node)?
|
||||
} else {
|
||||
@ -90,7 +92,7 @@ impl AbstractNode for ValueExpression {
|
||||
};
|
||||
|
||||
if let Some(value) = value_option {
|
||||
Ok(Action::Return(value))
|
||||
Ok(Evaluation::Return(value))
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableNotFound {
|
||||
@ -100,26 +102,24 @@ impl AbstractNode for ValueExpression {
|
||||
))
|
||||
}
|
||||
}
|
||||
ValueExpression::MapIndex(map_index) => map_index.node.run(context, manage_memory),
|
||||
ValueExpression::ListIndex(list_index) => list_index.node.run(context, manage_memory),
|
||||
ValueExpression::Logic(logic) => logic.node.run(context, manage_memory),
|
||||
ValueExpression::Math(math) => math.node.run(context, manage_memory),
|
||||
ValueExpression::Value(value_node) => value_node.node.run(context, manage_memory),
|
||||
ValueExpression::BuiltInFunctionCall(built_in_function_call) => {
|
||||
built_in_function_call.node.run(context, manage_memory)
|
||||
Expression::MapIndex(map_index) => map_index.node.evaluate(context, manage_memory),
|
||||
Expression::ListIndex(list_index) => list_index.node.evaluate(context, manage_memory),
|
||||
Expression::Logic(logic) => logic.node.evaluate(context, manage_memory),
|
||||
Expression::Math(math) => math.node.evaluate(context, manage_memory),
|
||||
Expression::Value(value_node) => value_node.node.evaluate(context, manage_memory),
|
||||
Expression::BuiltInFunctionCall(built_in_function_call) => {
|
||||
built_in_function_call.node.evaluate(context, manage_memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpectedType for ValueExpression {
|
||||
impl ExpectedType for Expression {
|
||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
||||
match self {
|
||||
ValueExpression::As(r#as) => r#as.node.expected_type(_context),
|
||||
ValueExpression::FunctionCall(function_call) => {
|
||||
function_call.node.expected_type(_context)
|
||||
}
|
||||
ValueExpression::Identifier(identifier) => {
|
||||
Expression::As(r#as) => r#as.node.expected_type(_context),
|
||||
Expression::FunctionCall(function_call) => function_call.node.expected_type(_context),
|
||||
Expression::Identifier(identifier) => {
|
||||
if let Some(r#type) = _context.get_type(&identifier.node)? {
|
||||
Ok(r#type)
|
||||
} else {
|
||||
@ -129,12 +129,12 @@ impl ExpectedType for ValueExpression {
|
||||
})
|
||||
}
|
||||
}
|
||||
ValueExpression::MapIndex(map_index) => map_index.node.expected_type(_context),
|
||||
ValueExpression::ListIndex(list_index) => list_index.node.expected_type(_context),
|
||||
ValueExpression::Logic(logic) => logic.node.expected_type(_context),
|
||||
ValueExpression::Math(math) => math.node.expected_type(_context),
|
||||
ValueExpression::Value(value_node) => value_node.node.expected_type(_context),
|
||||
ValueExpression::BuiltInFunctionCall(built_in_function_call) => {
|
||||
Expression::MapIndex(map_index) => map_index.node.expected_type(_context),
|
||||
Expression::ListIndex(list_index) => list_index.node.expected_type(_context),
|
||||
Expression::Logic(logic) => logic.node.expected_type(_context),
|
||||
Expression::Math(math) => math.node.expected_type(_context),
|
||||
Expression::Value(value_node) => value_node.node.expected_type(_context),
|
||||
Expression::BuiltInFunctionCall(built_in_function_call) => {
|
||||
built_in_function_call.node.expected_type(_context)
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
AbstractNode, Action, Block, ExpectedType, Type, ValueExpression, WithPos, WithPosition,
|
||||
AbstractNode, Block, Evaluation, ExpectedType, Expression, Type, TypeConstructor, WithPosition,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -18,18 +18,24 @@ pub enum ValueNode {
|
||||
Boolean(bool),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
List(Vec<ValueExpression>),
|
||||
Map(Vec<(Identifier, Option<WithPosition<Type>>, ValueExpression)>),
|
||||
List(Vec<Expression>),
|
||||
Map(
|
||||
Vec<(
|
||||
Identifier,
|
||||
Option<WithPosition<TypeConstructor>>,
|
||||
Expression,
|
||||
)>,
|
||||
),
|
||||
Range(Range<i64>),
|
||||
String(String),
|
||||
Structure {
|
||||
name: WithPosition<Identifier>,
|
||||
fields: Vec<(Identifier, ValueExpression)>,
|
||||
fields: Vec<(WithPosition<Identifier>, Expression)>,
|
||||
},
|
||||
ParsedFunction {
|
||||
type_arguments: Vec<WithPosition<Type>>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
type_parameters: Option<Vec<WithPosition<Identifier>>>,
|
||||
value_parameters: Vec<(Identifier, WithPosition<TypeConstructor>)>,
|
||||
return_type: WithPosition<TypeConstructor>,
|
||||
body: WithPosition<Block>,
|
||||
},
|
||||
}
|
||||
@ -37,17 +43,18 @@ pub enum ValueNode {
|
||||
impl AbstractNode for ValueNode {
|
||||
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||
if let ValueNode::Map(map_assignments) = self {
|
||||
for (_identifier, r#type, expression) in map_assignments {
|
||||
for (_identifier, constructor_option, expression) in map_assignments {
|
||||
expression.validate(context, _manage_memory)?;
|
||||
|
||||
if let Some(expected_type) = r#type {
|
||||
if let Some(constructor) = constructor_option {
|
||||
let actual_type = expression.expected_type(context)?;
|
||||
let exprected_type = constructor.node.clone().construct(&context)?;
|
||||
|
||||
expected_type.node.check(&actual_type).map_err(|conflict| {
|
||||
exprected_type.check(&actual_type).map_err(|conflict| {
|
||||
ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: expression.position(),
|
||||
expected_position: expected_type.position,
|
||||
expected_position: Some(constructor.position),
|
||||
}
|
||||
})?;
|
||||
}
|
||||
@ -57,22 +64,18 @@ impl AbstractNode for ValueNode {
|
||||
}
|
||||
|
||||
if let ValueNode::ParsedFunction {
|
||||
type_arguments,
|
||||
parameters,
|
||||
type_parameters: _,
|
||||
value_parameters,
|
||||
return_type,
|
||||
body,
|
||||
} = self
|
||||
{
|
||||
let mut function_context = Context::new(Some(&context));
|
||||
|
||||
for r#type in type_arguments {
|
||||
if let Type::Argument(identifier) = &r#type.node {
|
||||
function_context.set_type(identifier.clone(), r#type.node.clone())?;
|
||||
}
|
||||
}
|
||||
for (identifier, type_constructor) in value_parameters {
|
||||
let r#type = type_constructor.node.clone().construct(&function_context)?;
|
||||
|
||||
for (identifier, r#type) in parameters {
|
||||
function_context.set_type(identifier.clone(), r#type.node.clone())?;
|
||||
function_context.set_type(identifier.clone(), r#type)?;
|
||||
}
|
||||
|
||||
body.node.validate(&mut function_context, _manage_memory)?;
|
||||
@ -81,11 +84,13 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
return_type
|
||||
.node
|
||||
.clone()
|
||||
.construct(&function_context)?
|
||||
.check(&actual_return_type)
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: body.position,
|
||||
expected_position: return_type.position,
|
||||
expected_position: Some(return_type.position),
|
||||
})?;
|
||||
|
||||
return Ok(());
|
||||
@ -111,11 +116,11 @@ impl AbstractNode for ValueNode {
|
||||
for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
|
||||
let actual_type = expression.expected_type(context)?;
|
||||
|
||||
expected_type.node.check(&actual_type).map_err(|conflict| {
|
||||
expected_type.check(&actual_type).map_err(|conflict| {
|
||||
ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: expression.position(),
|
||||
expected_position: expected_type.position,
|
||||
expected_position: None,
|
||||
}
|
||||
})?
|
||||
}
|
||||
@ -125,7 +130,11 @@ impl AbstractNode for ValueNode {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let value = match self {
|
||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
||||
ValueNode::Float(float) => Value::float(float),
|
||||
@ -135,8 +144,8 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
for expression in expression_list {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(_context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
WithPosition {
|
||||
node: value,
|
||||
position: expression_position,
|
||||
@ -157,8 +166,8 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
for (identifier, _type, expression) in property_list {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(_context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -174,11 +183,29 @@ impl AbstractNode for ValueNode {
|
||||
ValueNode::Range(range) => Value::range(range),
|
||||
ValueNode::String(string) => Value::string(string),
|
||||
ValueNode::ParsedFunction {
|
||||
type_arguments,
|
||||
parameters,
|
||||
type_parameters,
|
||||
value_parameters: constructors,
|
||||
return_type,
|
||||
body,
|
||||
} => Value::function(type_arguments, parameters, return_type, body),
|
||||
} => {
|
||||
let type_parameters = type_parameters.map(|parameter_list| {
|
||||
parameter_list
|
||||
.into_iter()
|
||||
.map(|parameter| parameter.node)
|
||||
.collect()
|
||||
});
|
||||
let mut value_parameters = Vec::with_capacity(constructors.len());
|
||||
|
||||
for (identifier, constructor) in constructors {
|
||||
let r#type = constructor.node.construct(&context)?;
|
||||
|
||||
value_parameters.push((identifier, r#type));
|
||||
}
|
||||
|
||||
let return_type = return_type.node.construct(&context)?;
|
||||
|
||||
Value::function(type_parameters, value_parameters, return_type, body.node)
|
||||
}
|
||||
ValueNode::Structure {
|
||||
name,
|
||||
fields: expressions,
|
||||
@ -187,8 +214,8 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
for (identifier, expression) in expressions {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(_context, _manage_memory)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
let action = expression.evaluate(context, _manage_memory)?;
|
||||
let value = if let Evaluation::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -196,14 +223,14 @@ impl AbstractNode for ValueNode {
|
||||
));
|
||||
};
|
||||
|
||||
fields.push((identifier, value));
|
||||
fields.push((identifier.node, value));
|
||||
}
|
||||
|
||||
Value::structure(name, fields)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Action::Return(value))
|
||||
Ok(Evaluation::Return(value))
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,14 +271,14 @@ impl Ord for ValueNode {
|
||||
(String(_), _) => Ordering::Greater,
|
||||
(
|
||||
ParsedFunction {
|
||||
type_arguments: left_type_arguments,
|
||||
parameters: left_parameters,
|
||||
type_parameters: left_type_arguments,
|
||||
value_parameters: left_parameters,
|
||||
return_type: left_return,
|
||||
body: left_body,
|
||||
},
|
||||
ParsedFunction {
|
||||
type_arguments: right_type_arguments,
|
||||
parameters: right_parameters,
|
||||
type_parameters: right_type_arguments,
|
||||
value_parameters: right_parameters,
|
||||
return_type: right_return,
|
||||
body: right_body,
|
||||
},
|
||||
@ -307,32 +334,44 @@ impl ExpectedType for ValueNode {
|
||||
ValueNode::Float(_) => Type::Float,
|
||||
ValueNode::Integer(_) => Type::Integer,
|
||||
ValueNode::List(items) => {
|
||||
let mut item_types = Vec::with_capacity(items.len());
|
||||
let item_type = items.first().unwrap().expected_type(context)?;
|
||||
|
||||
for expression in items {
|
||||
item_types.push(
|
||||
expression
|
||||
.expected_type(context)?
|
||||
.with_position(expression.position()),
|
||||
);
|
||||
Type::List {
|
||||
length: items.len(),
|
||||
item_type: Box::new(item_type),
|
||||
}
|
||||
|
||||
Type::ListExact(item_types)
|
||||
}
|
||||
ValueNode::Map(_) => Type::Map,
|
||||
ValueNode::Range(_) => Type::Range,
|
||||
ValueNode::String(_) => Type::String,
|
||||
ValueNode::ParsedFunction {
|
||||
parameters,
|
||||
type_parameters,
|
||||
value_parameters,
|
||||
return_type,
|
||||
..
|
||||
} => Type::Function {
|
||||
parameter_types: parameters
|
||||
.iter()
|
||||
.map(|(_, r#type)| r#type.clone())
|
||||
.collect(),
|
||||
return_type: Box::new(return_type.clone()),
|
||||
},
|
||||
} => {
|
||||
let mut value_parameter_types = Vec::with_capacity(value_parameters.len());
|
||||
|
||||
for (identifier, type_constructor) in value_parameters {
|
||||
let r#type = type_constructor.node.clone().construct(&context)?;
|
||||
|
||||
value_parameter_types.push((identifier.clone(), r#type));
|
||||
}
|
||||
|
||||
let type_parameters = type_parameters.clone().map(|parameters| {
|
||||
parameters
|
||||
.iter()
|
||||
.map(|identifier| identifier.node.clone())
|
||||
.collect()
|
||||
});
|
||||
let return_type = return_type.node.clone().construct(&context)?;
|
||||
|
||||
Type::Function {
|
||||
type_parameters,
|
||||
value_parameters: value_parameter_types,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
ValueNode::Structure {
|
||||
name,
|
||||
fields: expressions,
|
||||
@ -353,7 +392,10 @@ impl ExpectedType for ValueNode {
|
||||
|
||||
Type::Structure {
|
||||
name: name.node.clone(),
|
||||
fields: types,
|
||||
fields: types
|
||||
.into_iter()
|
||||
.map(|(identifier, r#type)| (identifier.node, r#type.node))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -7,16 +7,16 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Statement, ValueExpression};
|
||||
use super::{AbstractNode, Evaluation, Expression, Statement};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct While {
|
||||
expression: ValueExpression,
|
||||
expression: Expression,
|
||||
statements: Vec<Statement>,
|
||||
}
|
||||
|
||||
impl While {
|
||||
pub fn new(expression: ValueExpression, statements: Vec<Statement>) -> Self {
|
||||
pub fn new(expression: Expression, statements: Vec<Statement>) -> Self {
|
||||
Self {
|
||||
expression,
|
||||
statements,
|
||||
@ -39,12 +39,19 @@ impl AbstractNode for While {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||
fn evaluate(
|
||||
self,
|
||||
_context: &mut Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
let get_boolean = || -> Result<Value, RuntimeError> {
|
||||
let expression_position = self.expression.position();
|
||||
let action = self.expression.clone().run(&mut _context.clone(), false)?;
|
||||
let action = self
|
||||
.expression
|
||||
.clone()
|
||||
.evaluate(&mut _context.clone(), false)?;
|
||||
|
||||
if let Action::Return(value) = action {
|
||||
if let Evaluation::Return(value) = action {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
@ -55,16 +62,16 @@ impl AbstractNode for While {
|
||||
|
||||
while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() {
|
||||
for statement in &self.statements {
|
||||
let action = statement.clone().run(&mut _context.clone(), false)?;
|
||||
let action = statement.clone().evaluate(&mut _context.clone(), false)?;
|
||||
|
||||
match action {
|
||||
Action::Return(_) => {}
|
||||
Action::None => {}
|
||||
Action::Break => return Ok(Action::Break),
|
||||
Evaluation::Return(_) => {}
|
||||
Evaluation::None => {}
|
||||
Evaluation::Break => return Ok(Evaluation::Break),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Action::None)
|
||||
Ok(Evaluation::None)
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Context<'a> {
|
||||
variables: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageData)>>>,
|
||||
variables: Arc<RwLock<BTreeMap<Identifier, (VariableData, UsageData)>>>,
|
||||
parent: Option<&'a Context<'a>>,
|
||||
is_clean: Arc<RwLock<bool>>,
|
||||
}
|
||||
@ -28,7 +28,7 @@ impl<'a> Context<'a> {
|
||||
|
||||
pub fn inner(
|
||||
&self,
|
||||
) -> Result<RwLockReadGuard<BTreeMap<Identifier, (ValueData, UsageData)>>, RwLockPoisonError>
|
||||
) -> Result<RwLockReadGuard<BTreeMap<Identifier, (VariableData, UsageData)>>, RwLockPoisonError>
|
||||
{
|
||||
Ok(self.variables.read()?)
|
||||
}
|
||||
@ -50,8 +50,8 @@ impl<'a> Context<'a> {
|
||||
log::trace!("Getting {identifier}'s type.");
|
||||
|
||||
let r#type = match value_data {
|
||||
ValueData::Type(r#type) => r#type.clone(),
|
||||
ValueData::Value(value) => value.r#type(self)?,
|
||||
VariableData::Type(r#type) => r#type.clone(),
|
||||
VariableData::Value(value) => value.r#type(self)?,
|
||||
};
|
||||
|
||||
Ok(Some(r#type.clone()))
|
||||
@ -63,7 +63,8 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
||||
if let Some((ValueData::Value(value), usage_data)) = self.variables.read()?.get(identifier)
|
||||
if let Some((VariableData::Value(value), usage_data)) =
|
||||
self.variables.read()?.get(identifier)
|
||||
{
|
||||
log::trace!("Using {identifier}'s value.");
|
||||
|
||||
@ -79,7 +80,7 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
||||
if let Some((ValueData::Value(value), _)) = self.variables.read()?.get(identifier) {
|
||||
if let Some((VariableData::Value(value), _)) = self.variables.read()?.get(identifier) {
|
||||
log::trace!("Getting {identifier}'s value.");
|
||||
|
||||
Ok(Some(value.clone()))
|
||||
@ -93,7 +94,7 @@ impl<'a> Context<'a> {
|
||||
pub fn get_data(
|
||||
&self,
|
||||
identifier: &Identifier,
|
||||
) -> Result<Option<(ValueData, UsageData)>, RwLockPoisonError> {
|
||||
) -> Result<Option<(VariableData, UsageData)>, RwLockPoisonError> {
|
||||
if let Some(full_data) = self.variables.read()?.get(identifier) {
|
||||
log::trace!("Getting {identifier}'s value.");
|
||||
|
||||
@ -110,7 +111,7 @@ impl<'a> Context<'a> {
|
||||
|
||||
self.variables
|
||||
.write()?
|
||||
.insert(identifier, (ValueData::Type(r#type), UsageData::new()));
|
||||
.insert(identifier, (VariableData::Type(r#type), UsageData::new()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -128,9 +129,9 @@ impl<'a> Context<'a> {
|
||||
.map(|(_, usage_data)| usage_data);
|
||||
|
||||
if let Some(usage_data) = old_usage_data {
|
||||
variables.insert(identifier, (ValueData::Value(value), usage_data));
|
||||
variables.insert(identifier, (VariableData::Value(value), usage_data));
|
||||
} else {
|
||||
variables.insert(identifier, (ValueData::Value(value), UsageData::new()));
|
||||
variables.insert(identifier, (VariableData::Value(value), UsageData::new()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -144,7 +145,7 @@ impl<'a> Context<'a> {
|
||||
self.variables
|
||||
.write()?
|
||||
.retain(|identifier, (value_data, usage_data)| {
|
||||
if let ValueData::Value(_) = value_data {
|
||||
if let VariableData::Value(_) = value_data {
|
||||
let usage = usage_data.inner().read().unwrap();
|
||||
|
||||
if usage.actual < usage.expected {
|
||||
@ -196,7 +197,7 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ValueData {
|
||||
pub enum VariableData {
|
||||
Type(Type),
|
||||
Value(Value),
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::{io, sync::PoisonError};
|
||||
use chumsky::{prelude::Rich, span::Span};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{SourcePosition, Type},
|
||||
abstract_tree::{r#type::Type, SourcePosition, TypeConstructor},
|
||||
identifier::Identifier,
|
||||
lexer::Token,
|
||||
};
|
||||
@ -141,11 +141,15 @@ pub enum ValidationError {
|
||||
actual_position: SourcePosition,
|
||||
|
||||
/// The position of the item that gave the "expected" type.
|
||||
expected_position: SourcePosition,
|
||||
expected_position: Option<SourcePosition>,
|
||||
},
|
||||
WrongTypeArgumentCount {
|
||||
expected: usize,
|
||||
actual: usize,
|
||||
},
|
||||
WrongArguments {
|
||||
expected: Vec<Type>,
|
||||
actual: Vec<Type>,
|
||||
expected: Vec<TypeConstructor>,
|
||||
actual: Vec<TypeConstructor>,
|
||||
},
|
||||
VariableNotFound {
|
||||
identifier: Identifier,
|
||||
|
@ -325,21 +325,23 @@ impl InterpreterError {
|
||||
} => {
|
||||
let TypeConflict { actual, expected } = conflict;
|
||||
|
||||
builder.add_labels([
|
||||
Label::new((
|
||||
self.source_id.clone(),
|
||||
expected_position.0..expected_position.1,
|
||||
))
|
||||
.with_message(format!(
|
||||
"Type {} established here.",
|
||||
expected.fg(type_color)
|
||||
)),
|
||||
if let Some(position) = expected_position {
|
||||
builder.add_label(
|
||||
Label::new((self.source_id.clone(), position.0..position.1))
|
||||
.with_message(format!(
|
||||
"Type {} established here.",
|
||||
expected.fg(type_color)
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
builder.add_label(
|
||||
Label::new((
|
||||
self.source_id.clone(),
|
||||
actual_position.0..actual_position.1,
|
||||
))
|
||||
.with_message(format!("Got type {} here.", actual.fg(type_color))),
|
||||
]);
|
||||
);
|
||||
}
|
||||
ValidationError::VariableNotFound {
|
||||
identifier,
|
||||
@ -390,6 +392,7 @@ impl InterpreterError {
|
||||
ValidationError::ExpectedValue(_) => todo!(),
|
||||
ValidationError::PropertyNotFound { .. } => todo!(),
|
||||
ValidationError::WrongArguments { .. } => todo!(),
|
||||
ValidationError::WrongTypeArgumentCount { .. } => todo!(),
|
||||
ValidationError::ExpectedIntegerFloatOrString { actual, position } => {
|
||||
builder = builder.with_message(format!(
|
||||
"Expected an {}, {} or {}.",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ use std::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{AbstractNode, Action, Block, Type, WithPos, WithPosition},
|
||||
abstract_tree::{AbstractNode, Block, Evaluation, Type, WithPosition},
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
identifier::Identifier,
|
||||
@ -52,14 +52,14 @@ impl Value {
|
||||
}
|
||||
|
||||
pub fn function(
|
||||
type_arguments: Vec<WithPosition<Type>>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
type_parameters: Option<Vec<Identifier>>,
|
||||
value_parameters: Vec<(Identifier, Type)>,
|
||||
return_type: Type,
|
||||
body: Block,
|
||||
) -> Self {
|
||||
Value(Arc::new(ValueInner::Function(Function {
|
||||
type_parameters: type_arguments,
|
||||
parameters,
|
||||
type_parameters,
|
||||
value_parameters,
|
||||
return_type,
|
||||
body,
|
||||
})))
|
||||
@ -129,19 +129,19 @@ impl Display for Value {
|
||||
ValueInner::Range(_) => todo!(),
|
||||
ValueInner::String(string) => write!(f, "{string}"),
|
||||
ValueInner::Function(Function {
|
||||
type_parameters: type_arguments,
|
||||
parameters,
|
||||
type_parameters,
|
||||
value_parameters: parameters,
|
||||
return_type,
|
||||
body,
|
||||
}) => {
|
||||
if !type_arguments.is_empty() {
|
||||
if let Some(type_parameters) = type_parameters {
|
||||
write!(f, "(")?;
|
||||
|
||||
for (index, r#type) in type_arguments.into_iter().enumerate() {
|
||||
if index == type_arguments.len() - 1 {
|
||||
write!(f, "{}", r#type.node)?;
|
||||
for (index, r#type) in type_parameters.into_iter().enumerate() {
|
||||
if index == type_parameters.len() - 1 {
|
||||
write!(f, "{}", r#type)?;
|
||||
} else {
|
||||
write!(f, "{} ", r#type.node)?;
|
||||
write!(f, "{} ", r#type)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,10 +151,10 @@ impl Display for Value {
|
||||
write!(f, "(")?;
|
||||
|
||||
for (identifier, r#type) in parameters {
|
||||
write!(f, "{identifier}: {}", r#type.node)?;
|
||||
write!(f, "{identifier}: {}", r#type)?;
|
||||
}
|
||||
|
||||
write!(f, "): {} {:?}", return_type.node, body.node)
|
||||
write!(f, "): {} {:?}", return_type, body)
|
||||
}
|
||||
ValueInner::Structure { name, fields } => {
|
||||
write!(f, "{}\n{{", name.node)?;
|
||||
@ -224,23 +224,19 @@ impl ValueInner {
|
||||
ValueInner::Float(_) => Type::Float,
|
||||
ValueInner::Integer(_) => Type::Integer,
|
||||
ValueInner::List(values) => {
|
||||
let mut types = Vec::with_capacity(values.len());
|
||||
let item_type = values.first().unwrap().node.r#type(context)?;
|
||||
|
||||
for value in values {
|
||||
types.push(value.node.r#type(context)?.with_position(value.position));
|
||||
Type::List {
|
||||
length: values.len(),
|
||||
item_type: Box::new(item_type),
|
||||
}
|
||||
|
||||
Type::ListExact(types)
|
||||
}
|
||||
ValueInner::Map(_) => Type::Map,
|
||||
ValueInner::Range(_) => Type::Range,
|
||||
ValueInner::String(_) => Type::String,
|
||||
ValueInner::Function(function) => Type::Function {
|
||||
parameter_types: function
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|(_, r#type)| r#type.clone())
|
||||
.collect(),
|
||||
type_parameters: None,
|
||||
value_parameters: function.value_parameters.clone(),
|
||||
return_type: Box::new(function.return_type.clone()),
|
||||
},
|
||||
ValueInner::Structure { name, .. } => {
|
||||
@ -321,14 +317,14 @@ impl Ord for ValueInner {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Function {
|
||||
type_parameters: Vec<WithPosition<Type>>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
type_parameters: Option<Vec<Identifier>>,
|
||||
value_parameters: Vec<(Identifier, Type)>,
|
||||
return_type: Type,
|
||||
body: Block,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn type_parameters(&self) -> &Vec<WithPosition<Type>> {
|
||||
pub fn type_parameters(&self) -> &Option<Vec<Identifier>> {
|
||||
&self.type_parameters
|
||||
}
|
||||
|
||||
@ -337,11 +333,12 @@ impl Function {
|
||||
arguments: Vec<Value>,
|
||||
context: &mut Context,
|
||||
clear_variables: bool,
|
||||
) -> Result<Action, RuntimeError> {
|
||||
for ((identifier, _), value) in self.parameters.into_iter().zip(arguments.into_iter()) {
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
for ((identifier, _), value) in self.value_parameters.into_iter().zip(arguments.into_iter())
|
||||
{
|
||||
context.set_value(identifier.clone(), value)?;
|
||||
}
|
||||
|
||||
self.body.node.run(context, clear_variables)
|
||||
self.body.evaluate(context, clear_variables)
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ fn field_type_error() {
|
||||
expected: Type::Integer
|
||||
},
|
||||
actual_position: (128, 134).into(),
|
||||
expected_position: (56, 59).into()
|
||||
expected_position: Some((56, 59).into()),
|
||||
},
|
||||
position: (96, 153).into()
|
||||
}]
|
||||
|
@ -148,7 +148,7 @@ fn map_type_errors() {
|
||||
expected: Type::Boolean
|
||||
},
|
||||
actual_position: (15, 20).into(),
|
||||
expected_position: (8, 12).into(),
|
||||
expected_position: Some((8, 12).into()),
|
||||
},
|
||||
position: (0, 22).into()
|
||||
}]
|
||||
|
@ -1,5 +1,5 @@
|
||||
use dust_lang::{
|
||||
abstract_tree::{Block, Statement, Type, ValueExpression, WithPos},
|
||||
abstract_tree::{Block, Expression, Statement, Type, WithPos},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
identifier::Identifier,
|
||||
*,
|
||||
@ -34,7 +34,7 @@ fn set_variable_with_type_error() {
|
||||
expected: Type::String
|
||||
},
|
||||
actual_position: (14, 18).into(),
|
||||
expected_position: (8, 11).into()
|
||||
expected_position: Some((8, 11).into())
|
||||
},
|
||||
position: (0, 18).into()
|
||||
}]
|
||||
@ -46,13 +46,12 @@ fn function_variable() {
|
||||
assert_eq!(
|
||||
interpret("test", "foobar = fn (x: int) int { x }; foobar"),
|
||||
Ok(Some(Value::function(
|
||||
Vec::with_capacity(0),
|
||||
vec![(Identifier::new("x"), Type::Integer.with_position((16, 19)))],
|
||||
Type::Integer.with_position((21, 24)),
|
||||
Block::new(vec![Statement::ValueExpression(
|
||||
ValueExpression::Identifier(Identifier::new("x").with_position((27, 28)))
|
||||
)])
|
||||
.with_position((25, 30))
|
||||
Some(Vec::with_capacity(0)),
|
||||
vec![(Identifier::new("x"), Type::Integer)],
|
||||
Type::Integer,
|
||||
Block::new(vec![Statement::ValueExpression(Expression::Identifier(
|
||||
Identifier::new("x").with_position((27, 28))
|
||||
))])
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user