Begin preparing for type expressions

This commit is contained in:
Jeff 2024-06-16 03:12:04 -04:00
parent 54071eb8c0
commit a0b754cc1c
26 changed files with 835 additions and 818 deletions

View File

@ -9,31 +9,27 @@ use crate::{
Value,
};
use super::{AbstractNode, Action, Expression, Type, WithPosition};
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct As {
expression: Expression,
expression: ValueExpression,
r#type: WithPosition<Type>,
}
impl As {
pub fn new(expression: Expression, r#type: WithPosition<Type>) -> Self {
pub fn new(expression: ValueExpression, r#type: WithPosition<Type>) -> Self {
Self { expression, r#type }
}
}
impl AbstractNode for As {
fn expected_type(&self, _: &mut Context) -> Result<Type, ValidationError> {
Ok(self.r#type.item.clone())
}
fn validate(
&self,
_context: &mut Context,
_manage_memory: bool,
) -> Result<(), ValidationError> {
match self.r#type.item {
match self.r#type.node {
Type::Boolean | Type::Float | Type::Integer | Type::String => {}
_ => todo!("Create an error for this occurence."),
};
@ -54,7 +50,7 @@ impl AbstractNode for As {
ValidationError::InterpreterExpectedReturn(expression_position),
));
};
let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), self.r#type.item);
let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), self.r#type.node);
let converted = match (from_value, to_type) {
(ValueInner::Boolean(boolean), Type::String) => Value::string(boolean.to_string()),
@ -65,3 +61,9 @@ impl AbstractNode for As {
Ok(Action::Return(converted))
}
}
impl ExpectedType for As {
fn expected_type(&self, _: &mut Context) -> Result<Type, ValidationError> {
Ok(self.r#type.node.clone())
}
}

View File

@ -7,7 +7,7 @@ use crate::{
Context, Value,
};
use super::{AbstractNode, Action, Statement, Type, WithPosition};
use super::{AbstractNode, Action, ExpectedType, Statement, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Assignment {
@ -41,15 +41,11 @@ impl Assignment {
}
impl AbstractNode for Assignment {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::None)
}
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
let statement_type = self.statement.expected_type(context)?;
if let Some(WithPosition {
item: expected_type,
node: expected_type,
position: expected_position,
}) = &self.r#type
{
@ -61,9 +57,9 @@ impl AbstractNode for Assignment {
}
})?;
context.set_type(self.identifier.item.clone(), expected_type.clone())?;
context.set_type(self.identifier.node.clone(), expected_type.clone())?;
} else {
context.set_type(self.identifier.item.clone(), statement_type)?;
context.set_type(self.identifier.node.clone(), statement_type)?;
}
self.statement.validate(context, manage_memory)?;
@ -80,13 +76,13 @@ impl AbstractNode for Assignment {
match self.operator {
AssignmentOperator::Assign => {
context.set_value(self.identifier.item, right)?;
context.set_value(self.identifier.node, right)?;
}
AssignmentOperator::AddAssign => {
let left_option = if manage_memory {
context.use_value(&self.identifier.item)?
context.use_value(&self.identifier.node)?
} else {
context.get_value(&self.identifier.item)?
context.get_value(&self.identifier.node)?
};
if let Some(left) = left_option {
@ -117,11 +113,11 @@ impl AbstractNode for Assignment {
))
}
};
context.set_value(self.identifier.item, new_value)?;
context.set_value(self.identifier.node, new_value)?;
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound {
identifier: self.identifier.item,
identifier: self.identifier.node,
position: self.identifier.position,
},
));
@ -129,9 +125,9 @@ impl AbstractNode for Assignment {
}
AssignmentOperator::SubAssign => {
let left_option = if manage_memory {
context.use_value(&self.identifier.item)?
context.use_value(&self.identifier.node)?
} else {
context.get_value(&self.identifier.item)?
context.get_value(&self.identifier.node)?
};
if let Some(left) = left_option {
@ -162,11 +158,11 @@ impl AbstractNode for Assignment {
))
}
};
context.set_value(self.identifier.item, new_value)?;
context.set_value(self.identifier.node, new_value)?;
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound {
identifier: self.identifier.item,
identifier: self.identifier.node,
position: self.identifier.position,
},
));

View File

@ -8,7 +8,7 @@ use crate::{
error::{RuntimeError, RwLockPoisonError, ValidationError},
};
use super::{AbstractNode, Action, Statement, Type};
use super::{AbstractNode, Action, ExpectedType, Statement, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct AsyncBlock {
@ -22,10 +22,6 @@ impl AsyncBlock {
}
impl AbstractNode for AsyncBlock {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
self.statements.last().unwrap().expected_type(_context)
}
fn validate(&self, _context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
for statement in &self.statements {
statement.validate(_context, manage_memory)?;
@ -65,3 +61,9 @@ impl AbstractNode for AsyncBlock {
)
}
}
impl ExpectedType for AsyncBlock {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
self.statements.first().unwrap().expected_type(_context)
}
}

View File

@ -5,7 +5,7 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractNode, Action, Statement, Type};
use super::{AbstractNode, Action, ExpectedType, Statement};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Block {
@ -27,14 +27,6 @@ impl Block {
}
impl AbstractNode for Block {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
if let Some(statement) = self.statements.last() {
statement.expected_type(_context)
} else {
Ok(Type::None)
}
}
fn validate(
&self,
_context: &mut Context,
@ -58,10 +50,16 @@ impl AbstractNode for Block {
}
}
impl ExpectedType for Block {
fn expected_type(&self, _context: &mut Context) -> Result<super::Type, ValidationError> {
self.last_statement().expected_type(_context)
}
}
#[cfg(test)]
mod tests {
use crate::{
abstract_tree::{Expression, ValueNode, WithPos},
abstract_tree::{Type, ValueExpression, ValueNode, WithPos},
Value,
};
@ -70,13 +68,13 @@ mod tests {
#[test]
fn run_returns_value_of_final_statement() {
let block = Block::new(vec![
Statement::Expression(Expression::Value(
Statement::ValueExpression(ValueExpression::Value(
ValueNode::Integer(1).with_position((0, 0)),
)),
Statement::Expression(Expression::Value(
Statement::ValueExpression(ValueExpression::Value(
ValueNode::Integer(2).with_position((0, 0)),
)),
Statement::Expression(Expression::Value(
Statement::ValueExpression(ValueExpression::Value(
ValueNode::Integer(42).with_position((0, 0)),
)),
]);
@ -90,10 +88,10 @@ mod tests {
#[test]
fn expected_type_returns_type_of_final_statement() {
let block = Block::new(vec![
Statement::Expression(Expression::Value(
Statement::ValueExpression(ValueExpression::Value(
ValueNode::String("42".to_string()).with_position((0, 0)),
)),
Statement::Expression(Expression::Value(
Statement::ValueExpression(ValueExpression::Value(
ValueNode::Integer(42).with_position((0, 0)),
)),
]);

View File

@ -15,30 +15,19 @@ use crate::{
Value,
};
use super::{AbstractNode, Expression, WithPosition};
use super::{AbstractNode, ExpectedType, ValueExpression, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BuiltInFunctionCall {
JsonParse(WithPosition<Type>, Expression),
Length(Expression),
ReadFile(Expression),
JsonParse(WithPosition<Type>, ValueExpression),
Length(ValueExpression),
ReadFile(ValueExpression),
ReadLine,
Sleep(Expression),
WriteLine(Expression),
Sleep(ValueExpression),
WriteLine(ValueExpression),
}
impl AbstractNode for BuiltInFunctionCall {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
match self {
BuiltInFunctionCall::JsonParse(r#type, _) => Ok(r#type.item.clone()),
BuiltInFunctionCall::Length(_) => Ok(Type::Integer),
BuiltInFunctionCall::ReadFile(_) => Ok(Type::String),
BuiltInFunctionCall::ReadLine => Ok(Type::String),
BuiltInFunctionCall::Sleep(_) => Ok(Type::None),
BuiltInFunctionCall::WriteLine(_) => Ok(Type::None),
}
}
fn validate(
&self,
_context: &mut Context,
@ -64,7 +53,7 @@ impl AbstractNode for BuiltInFunctionCall {
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
match self {
BuiltInFunctionCall::JsonParse(r#type, expression) => {
BuiltInFunctionCall::JsonParse(_type, expression) => {
let action = expression.clone().run(context, _manage_memory)?;
let value = if let Action::Return(value) = action {
value
@ -169,3 +158,16 @@ impl AbstractNode for BuiltInFunctionCall {
}
}
}
impl ExpectedType for BuiltInFunctionCall {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
match self {
BuiltInFunctionCall::JsonParse(r#type, _) => Ok(r#type.node.clone()),
BuiltInFunctionCall::Length(_) => Ok(Type::Integer),
BuiltInFunctionCall::ReadFile(_) => Ok(Type::String),
BuiltInFunctionCall::ReadLine => Ok(Type::String),
BuiltInFunctionCall::Sleep(_) => Ok(Type::None),
BuiltInFunctionCall::WriteLine(_) => Ok(Type::None),
}
}
}

View File

@ -1,136 +0,0 @@
use serde::{Deserialize, Serialize};
use crate::{
context::Context,
error::{RuntimeError, ValidationError},
identifier::Identifier,
};
use super::{
AbstractNode, Action, As, BuiltInFunctionCall, FunctionCall, ListIndex, Logic, MapIndex, Math,
SourcePosition, Type, ValueNode, WithPosition,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Expression {
As(WithPosition<Box<As>>),
BuiltInFunctionCall(WithPosition<Box<BuiltInFunctionCall>>),
FunctionCall(WithPosition<FunctionCall>),
Identifier(WithPosition<Identifier>),
MapIndex(WithPosition<Box<MapIndex>>),
ListIndex(WithPosition<Box<ListIndex>>),
Logic(WithPosition<Box<Logic>>),
Math(WithPosition<Box<Math>>),
Value(WithPosition<ValueNode>),
}
impl Expression {
pub fn position(&self) -> SourcePosition {
match self {
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 Expression {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
match self {
Expression::As(r#as) => r#as.item.expected_type(_context),
Expression::FunctionCall(function_call) => function_call.item.expected_type(_context),
Expression::Identifier(identifier) => {
if let Some(r#type) = _context.get_type(&identifier.item)? {
Ok(r#type)
} else {
Err(ValidationError::VariableNotFound {
identifier: identifier.item.clone(),
position: identifier.position,
})
}
}
Expression::MapIndex(map_index) => map_index.item.expected_type(_context),
Expression::ListIndex(list_index) => list_index.item.expected_type(_context),
Expression::Logic(logic) => logic.item.expected_type(_context),
Expression::Math(math) => math.item.expected_type(_context),
Expression::Value(value_node) => value_node.item.expected_type(_context),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.item.expected_type(_context)
}
}
}
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
match self {
Expression::As(r#as) => r#as.item.validate(context, manage_memory),
Expression::FunctionCall(function_call) => {
function_call.item.validate(context, manage_memory)
}
Expression::Identifier(identifier) => {
let found = if manage_memory {
context.add_expected_use(&identifier.item)?
} else {
context.contains(&identifier.item)?
};
if found {
Ok(())
} else {
Err(ValidationError::VariableNotFound {
identifier: identifier.item.clone(),
position: identifier.position,
})
}
}
Expression::MapIndex(map_index) => map_index.item.validate(context, manage_memory),
Expression::ListIndex(list_index) => list_index.item.validate(context, manage_memory),
Expression::Logic(logic) => logic.item.validate(context, manage_memory),
Expression::Math(math) => math.item.validate(context, manage_memory),
Expression::Value(value_node) => value_node.item.validate(context, manage_memory),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.item.validate(context, manage_memory)
}
}
}
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError> {
match self {
Expression::As(r#as) => r#as.item.run(context, manage_memory),
Expression::FunctionCall(function_call) => {
function_call.item.run(context, manage_memory)
}
Expression::Identifier(identifier) => {
let value_option = if manage_memory {
context.use_value(&identifier.item)?
} else {
context.get_value(&identifier.item)?
};
if let Some(value) = value_option {
Ok(Action::Return(value))
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound {
identifier: identifier.item.clone(),
position: identifier.position,
},
))
}
}
Expression::MapIndex(map_index) => map_index.item.run(context, manage_memory),
Expression::ListIndex(list_index) => list_index.item.run(context, manage_memory),
Expression::Logic(logic) => logic.item.run(context, manage_memory),
Expression::Math(math) => math.item.run(context, manage_memory),
Expression::Value(value_node) => value_node.item.run(context, manage_memory),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.item.run(context, manage_memory)
}
}
}
}

View File

@ -6,20 +6,20 @@ use crate::{
value::ValueInner,
};
use super::{AbstractNode, Action, Expression, Type, WithPosition};
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, WithPosition};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionCall {
function: Box<Expression>,
function: Box<ValueExpression>,
type_arguments: Vec<WithPosition<Type>>,
arguments: Vec<Expression>,
arguments: Vec<ValueExpression>,
}
impl FunctionCall {
pub fn new(
function: Expression,
function: ValueExpression,
type_arguments: Vec<WithPosition<Type>>,
arguments: Vec<Expression>,
arguments: Vec<ValueExpression>,
) -> Self {
FunctionCall {
function: Box::new(function),
@ -30,19 +30,6 @@ impl FunctionCall {
}
impl AbstractNode for FunctionCall {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
let function_node_type = self.function.expected_type(_context)?;
if let Type::Function { return_type, .. } = function_node_type {
Ok(return_type.item)
} else {
Err(ValidationError::ExpectedFunction {
actual: function_node_type,
position: self.function.position(),
})
}
}
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
self.function.validate(context, manage_memory)?;
@ -60,13 +47,13 @@ impl AbstractNode for FunctionCall {
for (type_parameter, type_argument) in
parameter_types.iter().zip(self.type_arguments.iter())
{
if let Type::Argument(_) = type_parameter.item {
if let Type::Argument(_) = type_parameter.node {
continue;
}
type_parameter
.item
.check(&type_argument.item)
.node
.check(&type_argument.node)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
actual_position: type_argument.position,
@ -75,13 +62,13 @@ impl AbstractNode for FunctionCall {
}
for (type_parameter, expression) in parameter_types.iter().zip(self.arguments.iter()) {
if let Type::Argument(_) = type_parameter.item {
if let Type::Argument(_) = type_parameter.node {
continue;
}
let actual = expression.expected_type(context)?;
type_parameter.item.check(&actual).map_err(|conflict| {
type_parameter.node.check(&actual).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: expression.position(),
@ -140,8 +127,8 @@ impl AbstractNode for FunctionCall {
for (type_parameter, type_argument) in function
.type_parameters()
.iter()
.map(|r#type| r#type.item.clone())
.zip(self.type_arguments.into_iter().map(|r#type| r#type.item))
.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)?;
@ -153,3 +140,18 @@ impl AbstractNode for FunctionCall {
.call(arguments, &mut function_context, clear_variables)
}
}
impl ExpectedType for FunctionCall {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
let function_node_type = self.function.expected_type(_context)?;
if let Type::Function { return_type, .. } = function_node_type {
Ok(return_type.node)
} else {
Err(ValidationError::ExpectedFunction {
actual: function_node_type,
position: self.function.position(),
})
}
}
}

View File

@ -6,21 +6,21 @@ use crate::{
value::ValueInner,
};
use super::{AbstractNode, Action, Block, Expression, Type, WithPosition};
use super::{AbstractNode, Action, Block, ExpectedType, Type, ValueExpression, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct IfElse {
if_expression: Expression,
if_expression: ValueExpression,
if_block: WithPosition<Block>,
else_ifs: Vec<(Expression, WithPosition<Block>)>,
else_ifs: Vec<(ValueExpression, WithPosition<Block>)>,
else_block: Option<WithPosition<Block>>,
}
impl IfElse {
pub fn new(
if_expression: Expression,
if_expression: ValueExpression,
if_block: WithPosition<Block>,
else_ifs: Vec<(Expression, WithPosition<Block>)>,
else_ifs: Vec<(ValueExpression, WithPosition<Block>)>,
else_block: Option<WithPosition<Block>>,
) -> Self {
Self {
@ -33,29 +33,25 @@ impl IfElse {
}
impl AbstractNode for IfElse {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
self.if_block.item.expected_type(_context)
}
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
self.if_expression.validate(context, manage_memory)?;
self.if_block.item.validate(context, manage_memory)?;
self.if_block.node.validate(context, manage_memory)?;
let expected_type = self.if_block.item.expected_type(context)?;
let expected_type = self.if_block.node.expected_type(context)?;
let if_expression_type = self.if_expression.expected_type(context)?;
if let Type::Boolean = if_expression_type {
if let Some(else_block) = &self.else_block {
else_block.item.validate(context, manage_memory)?;
else_block.node.validate(context, manage_memory)?;
let actual = else_block.item.expected_type(context)?;
let actual = else_block.node.expected_type(context)?;
expected_type
.check(&actual)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
actual_position: else_block.item.last_statement().position(),
expected_position: self.if_block.item.first_statement().position(),
actual_position: else_block.node.last_statement().position(),
expected_position: self.if_block.node.first_statement().position(),
})?;
}
} else {
@ -69,15 +65,15 @@ impl AbstractNode for IfElse {
let expression_type = expression.expected_type(context)?;
if let Type::Boolean = expression_type {
block.item.validate(context, manage_memory)?;
block.node.validate(context, manage_memory)?;
let actual = block.item.expected_type(context)?;
let actual = block.node.expected_type(context)?;
expected_type
.check(&actual)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
actual_position: self.if_block.item.last_statement().position(),
actual_position: self.if_block.node.last_statement().position(),
expected_position: self.if_expression.position(),
})?;
} else {
@ -104,7 +100,7 @@ impl AbstractNode for IfElse {
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
if *if_boolean {
self.if_block.item.run(context, _manage_memory)
self.if_block.node.run(context, _manage_memory)
} else {
for (expression, block) in self.else_ifs {
let expression_position = expression.position();
@ -119,7 +115,7 @@ impl AbstractNode for IfElse {
if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() {
if *else_if_boolean {
return block.item.run(context, _manage_memory);
return block.node.run(context, _manage_memory);
}
} else {
return Err(RuntimeError::ValidationFailure(
@ -132,7 +128,7 @@ impl AbstractNode for IfElse {
}
if let Some(else_statement) = self.else_block {
else_statement.item.run(context, _manage_memory)
else_statement.node.run(context, _manage_memory)
} else {
Ok(Action::None)
}
@ -148,6 +144,12 @@ impl AbstractNode for IfElse {
}
}
impl ExpectedType for IfElse {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
self.if_block.node.expected_type(_context)
}
}
#[cfg(test)]
mod tests {
use crate::{
@ -161,8 +163,8 @@ mod tests {
fn simple_if() {
assert_eq!(
IfElse::new(
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
Block::new(vec![Statement::Expression(Expression::Value(
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
Block::new(vec![Statement::ValueExpression(ValueExpression::Value(
ValueNode::String("foo".to_string()).with_position((0, 0))
))])
.with_position((0, 0)),

View File

@ -5,50 +5,21 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractNode, Action, Expression, Type, ValueNode, WithPosition};
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, ValueNode, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ListIndex {
left: Expression,
right: Expression,
left: ValueExpression,
right: ValueExpression,
}
impl ListIndex {
pub fn new(left: Expression, right: Expression) -> Self {
pub fn new(left: ValueExpression, right: ValueExpression) -> Self {
Self { left, right }
}
}
impl AbstractNode for ListIndex {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
let left_type = self.left.expected_type(_context)?;
if let (
Expression::Value(WithPosition {
item: ValueNode::List(expression_list),
..
}),
Expression::Value(WithPosition {
item: ValueNode::Integer(index),
..
}),
) = (&self.left, &self.right)
{
let expression = if let Some(expression) = expression_list.get(*index as usize) {
expression
} else {
return Ok(Type::None);
};
expression.expected_type(_context)
} else {
Err(ValidationError::CannotIndex {
r#type: left_type,
position: self.left.position(),
})
}
}
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
self.left.validate(context, _manage_memory)?;
self.right.validate(context, _manage_memory)?;
@ -103,7 +74,7 @@ impl AbstractNode for ListIndex {
let found_item = list.get(index as usize);
if let Some(item) = found_item {
Ok(Action::Return(item.item.clone()))
Ok(Action::Return(item.node.clone()))
} else {
Ok(Action::None)
}
@ -119,3 +90,34 @@ 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)?;
if let (
ValueExpression::Value(WithPosition {
node: ValueNode::List(expression_list),
..
}),
ValueExpression::Value(WithPosition {
node: ValueNode::Integer(index),
..
}),
) = (&self.left, &self.right)
{
let expression = if let Some(expression) = expression_list.get(*index as usize) {
expression
} else {
return Ok(Type::None);
};
expression.expected_type(_context)
} else {
Err(ValidationError::CannotIndex {
r#type: left_type,
position: self.left.position(),
})
}
}
}

View File

@ -7,26 +7,22 @@ use crate::{
Value,
};
use super::{AbstractNode, Action, Expression, Type};
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Logic {
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),
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),
}
impl AbstractNode for Logic {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::Boolean)
}
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
match self {
Logic::Equal(left, right)
@ -94,7 +90,7 @@ impl AbstractNode for Logic {
}
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
let run_and_expect_value = |expression: Expression| -> Result<Value, RuntimeError> {
let run_and_expect_value = |expression: ValueExpression| -> 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 {
@ -108,7 +104,7 @@ impl AbstractNode for Logic {
Ok(value)
};
let run_and_expect_boolean = |expression: Expression| -> Result<bool, RuntimeError> {
let run_and_expect_boolean = |expression: ValueExpression| -> 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 {
@ -195,6 +191,12 @@ impl AbstractNode for Logic {
}
}
impl ExpectedType for Logic {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::Boolean)
}
}
#[cfg(test)]
mod tests {
use crate::abstract_tree::{ValueNode, WithPos};
@ -205,8 +207,8 @@ mod tests {
fn equal() {
assert_eq!(
Logic::Equal(
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0)))
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -217,8 +219,8 @@ mod tests {
fn not_equal() {
assert_eq!(
Logic::NotEqual(
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0)))
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -229,8 +231,8 @@ mod tests {
fn greater() {
assert_eq!(
Logic::Greater(
Expression::Value(ValueNode::Integer(43).with_position((0, 0))),
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0)))
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -241,8 +243,8 @@ mod tests {
fn less() {
assert_eq!(
Logic::Less(
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0)))
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -253,8 +255,8 @@ mod tests {
fn greater_or_equal() {
assert_eq!(
Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(41).with_position((0, 0)))
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(41).with_position((0, 0)))
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -262,8 +264,8 @@ mod tests {
assert_eq!(
Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -274,8 +276,8 @@ mod tests {
fn less_or_equal() {
assert_eq!(
Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(41).with_position((0, 0))),
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(41).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -283,8 +285,8 @@ mod tests {
assert_eq!(
Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -295,8 +297,8 @@ mod tests {
fn and() {
assert_eq!(
Logic::And(
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -307,8 +309,8 @@ mod tests {
fn or() {
assert_eq!(
Logic::Or(
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
Expression::Value(ValueNode::Boolean(false).with_position((0, 0))),
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
ValueExpression::Value(ValueNode::Boolean(false).with_position((0, 0))),
)
.run(&mut Context::new(None), true),
Ok(Action::Return(Value::boolean(true)))
@ -318,7 +320,7 @@ mod tests {
#[test]
fn not() {
assert_eq!(
Logic::Not(Expression::Value(
Logic::Not(ValueExpression::Value(
ValueNode::Boolean(false).with_position((0, 0))
))
.run(&mut Context::new(None), true),

View File

@ -5,7 +5,7 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractNode, Action, Statement, Type};
use super::{AbstractNode, Action, Statement};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Loop {
@ -19,10 +19,6 @@ impl Loop {
}
impl AbstractNode for Loop {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::None)
}
fn validate(
&self,
_context: &mut Context,

View File

@ -6,16 +6,16 @@ use crate::{
value::ValueInner,
};
use super::{AbstractNode, Action, Expression, Type, ValueNode, WithPosition};
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression, ValueNode, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct MapIndex {
collection: Expression,
index: Expression,
collection: ValueExpression,
index: ValueExpression,
}
impl MapIndex {
pub fn new(left: Expression, right: Expression) -> Self {
pub fn new(left: ValueExpression, right: ValueExpression) -> Self {
Self {
collection: left,
index: right,
@ -24,87 +24,6 @@ impl MapIndex {
}
impl AbstractNode for MapIndex {
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
if let (Expression::Identifier(collection), Expression::Identifier(index)) =
(&self.collection, &self.index)
{
let collection = if let Some(collection) = context.get_value(&collection.item)? {
collection
} else {
return Err(ValidationError::VariableNotFound {
identifier: collection.item.clone(),
position: collection.position,
});
};
if let ValueInner::Map(map) = collection.inner().as_ref() {
return if let Some(value) = map.get(&index.item) {
Ok(value.r#type(context)?)
} else {
Err(ValidationError::PropertyNotFound {
identifier: index.item.clone(),
position: index.position,
})
};
};
}
if let (
Expression::Value(WithPosition {
item: ValueNode::Map(properties),
..
}),
Expression::Identifier(index),
) = (&self.collection, &self.index)
{
return if let Some(type_result) =
properties
.iter()
.find_map(|(property, type_option, expression)| {
if property == &index.item {
if let Some(r#type) = type_option {
Some(r#type.item.expected_type(context))
} else {
Some(expression.expected_type(context))
}
} else {
None
}
})
{
type_result
} else {
Ok(Type::None)
};
}
if let (
Expression::Value(WithPosition {
item: ValueNode::Structure { fields, .. },
..
}),
Expression::Identifier(index),
) = (&self.collection, &self.index)
{
return if let Some(type_result) = fields.iter().find_map(|(property, expression)| {
if property == &index.item {
Some(expression.expected_type(context))
} else {
None
}
}) {
type_result
} else {
Ok(Type::None)
};
}
Err(ValidationError::CannotIndex {
r#type: self.collection.expected_type(context)?,
position: self.collection.position(),
})
}
fn validate(
&self,
_context: &mut Context,
@ -124,11 +43,11 @@ impl AbstractNode for MapIndex {
));
};
if let (ValueInner::Map(map), Expression::Identifier(index)) =
if let (ValueInner::Map(map), ValueExpression::Identifier(index)) =
(collection.inner().as_ref(), self.index)
{
let action = map
.get(&index.item)
.get(&index.node)
.map(|value| Action::Return(value.clone()))
.unwrap_or(Action::None);
@ -143,3 +62,78 @@ 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)) =
(&self.collection, &self.index)
{
let collection = if let Some(collection) = context.get_value(&collection.node)? {
collection
} else {
return Err(ValidationError::VariableNotFound {
identifier: collection.node.clone(),
position: collection.position,
});
};
if let ValueInner::Map(map) = collection.inner().as_ref() {
return if let Some(value) = map.get(&index.node) {
Ok(value.r#type(context)?)
} else {
Err(ValidationError::PropertyNotFound {
identifier: index.node.clone(),
position: index.position,
})
};
};
}
if let (
ValueExpression::Value(WithPosition {
node: ValueNode::Map(properties),
..
}),
ValueExpression::Identifier(index),
) = (&self.collection, &self.index)
{
for (property, type_option, expression) in properties {
if property == &index.node {
return if let Some(r#type) = type_option {
Ok(r#type.node.clone())
} else {
Ok(expression.expected_type(context)?)
};
}
}
return Ok(Type::None);
}
if let (
ValueExpression::Value(WithPosition {
node: ValueNode::Structure { fields, .. },
..
}),
ValueExpression::Identifier(index),
) = (&self.collection, &self.index)
{
return if let Some(type_result) = fields.iter().find_map(|(property, expression)| {
if property == &index.node {
Some(expression.expected_type(context))
} else {
None
}
}) {
type_result
} else {
Ok(Type::None)
};
}
Err(ValidationError::CannotIndex {
r#type: self.collection.expected_type(context)?,
position: self.collection.position(),
})
}
}

View File

@ -7,41 +7,18 @@ use crate::{
Value,
};
use super::{AbstractNode, Action, Expression, SourcePosition, Type};
use super::{AbstractNode, Action, ExpectedType, SourcePosition, Type, ValueExpression};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Math {
Add(Expression, Expression),
Subtract(Expression, Expression),
Multiply(Expression, Expression),
Divide(Expression, Expression),
Modulo(Expression, Expression),
Add(ValueExpression, ValueExpression),
Subtract(ValueExpression, ValueExpression),
Multiply(ValueExpression, ValueExpression),
Divide(ValueExpression, ValueExpression),
Modulo(ValueExpression, ValueExpression),
}
impl AbstractNode for Math {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
match self {
Math::Add(left, right)
| Math::Subtract(left, right)
| Math::Multiply(left, right)
| Math::Divide(left, right)
| Math::Modulo(left, right) => {
let left_type = left.expected_type(_context)?;
let right_type = right.expected_type(_context)?;
if let Type::Float = left_type {
return Ok(Type::Float);
}
if let Type::Float = right_type {
return Ok(Type::Float);
}
Ok(left_type)
}
}
}
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
match self {
Math::Add(left, right) => {
@ -91,8 +68,9 @@ impl AbstractNode for Math {
}
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
let run_and_expect_value =
|position: SourcePosition, expression: Expression| -> Result<Value, 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
@ -313,3 +291,28 @@ impl AbstractNode for Math {
Ok(Action::Return(value))
}
}
impl ExpectedType for Math {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
match self {
Math::Add(left, right)
| Math::Subtract(left, right)
| Math::Multiply(left, right)
| Math::Divide(left, right)
| Math::Modulo(left, right) => {
let left_type = left.expected_type(_context)?;
let right_type = right.expected_type(_context)?;
if let Type::Float = left_type {
return Ok(Type::Float);
}
if let Type::Float = right_type {
return Ok(Type::Float);
}
Ok(left_type)
}
}
}
}

View File

@ -3,7 +3,6 @@ pub mod assignment;
pub mod async_block;
pub mod block;
pub mod built_in_function_call;
pub mod expression;
pub mod function_call;
pub mod if_else;
pub mod list_index;
@ -15,6 +14,7 @@ pub mod statement;
pub mod structure_definition;
pub mod r#type;
pub mod type_alias;
pub mod value_expression;
pub mod value_node;
pub mod r#while;
@ -28,7 +28,6 @@ pub use self::{
async_block::AsyncBlock,
block::Block,
built_in_function_call::BuiltInFunctionCall,
expression::Expression,
function_call::FunctionCall,
if_else::IfElse,
list_index::ListIndex,
@ -41,7 +40,8 @@ pub use self::{
r#while::While,
statement::Statement,
structure_definition::StructureDefinition,
type_alias::TypeAlias,
type_alias::TypeAssignment,
value_expression::ValueExpression,
value_node::ValueNode,
};
@ -53,14 +53,14 @@ use crate::{
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct WithPosition<T> {
pub item: T,
pub node: T,
pub position: SourcePosition,
}
pub trait WithPos: Sized {
fn with_position<T: Into<SourcePosition>>(self, span: T) -> WithPosition<Self> {
WithPosition {
item: self,
node: self,
position: span.into(),
}
}
@ -188,7 +188,10 @@ impl Index<usize> for AbstractTree {
}
pub trait AbstractNode: Sized {
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError>;
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError>;
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError>;
}
pub trait ExpectedType {
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError>;
}

View File

@ -6,8 +6,9 @@ use crate::{
};
use super::{
AbstractNode, Action, Assignment, AsyncBlock, Block, Expression, IfElse, Loop, SourcePosition,
StructureDefinition, Type, TypeAlias, While, WithPosition,
AbstractNode, Action, Assignment, AsyncBlock, Block, ExpectedType, IfElse, Loop,
SourcePosition, StructureDefinition, Type, TypeAssignment, ValueExpression, While,
WithPosition,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -16,11 +17,11 @@ pub enum Statement {
AsyncBlock(WithPosition<AsyncBlock>),
Block(WithPosition<Block>),
Break(WithPosition<()>),
Expression(Expression),
IfElse(WithPosition<IfElse>),
Loop(WithPosition<Loop>),
StructureDefinition(WithPosition<StructureDefinition>),
TypeAlias(WithPosition<TypeAlias>),
TypeAssignment(WithPosition<TypeAssignment>),
ValueExpression(ValueExpression),
While(WithPosition<While>),
}
@ -31,71 +32,56 @@ impl Statement {
Statement::AsyncBlock(inner) => inner.position,
Statement::Block(inner) => inner.position,
Statement::Break(inner) => inner.position,
Statement::Expression(expression) => expression.position(),
Statement::ValueExpression(expression) => expression.position(),
Statement::IfElse(inner) => inner.position,
Statement::Loop(inner) => inner.position,
Statement::StructureDefinition(inner) => inner.position,
Statement::TypeAlias(inner) => inner.position,
Statement::TypeAssignment(inner) => inner.position,
Statement::While(inner) => inner.position,
}
}
}
impl AbstractNode for Statement {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
match self {
Statement::Assignment(assignment) => assignment.item.expected_type(_context),
Statement::AsyncBlock(async_block) => async_block.item.expected_type(_context),
Statement::Block(block) => block.item.expected_type(_context),
Statement::Break(_) => Ok(Type::None),
Statement::Expression(expression) => expression.expected_type(_context),
Statement::IfElse(if_else) => if_else.item.expected_type(_context),
Statement::Loop(r#loop) => r#loop.item.expected_type(_context),
Statement::While(r#while) => r#while.item.expected_type(_context),
Statement::TypeAlias(type_alias) => type_alias.item.expected_type(_context),
Statement::StructureDefinition(structure_definition) => {
structure_definition.item.expected_type(_context)
}
}
}
fn validate(
&self,
_context: &mut Context,
_manage_memory: bool,
) -> Result<(), ValidationError> {
match self {
Statement::Assignment(assignment) => assignment.item.validate(_context, _manage_memory),
Statement::Assignment(assignment) => assignment.node.validate(_context, _manage_memory),
Statement::AsyncBlock(async_block) => {
async_block.item.validate(_context, _manage_memory)
async_block.node.validate(_context, _manage_memory)
}
Statement::Block(block) => block.item.validate(_context, _manage_memory),
Statement::Block(block) => block.node.validate(_context, _manage_memory),
Statement::Break(_) => Ok(()),
Statement::Expression(expression) => expression.validate(_context, _manage_memory),
Statement::IfElse(if_else) => if_else.item.validate(_context, _manage_memory),
Statement::Loop(r#loop) => r#loop.item.validate(_context, _manage_memory),
Statement::ValueExpression(expression) => expression.validate(_context, _manage_memory),
Statement::IfElse(if_else) => if_else.node.validate(_context, _manage_memory),
Statement::Loop(r#loop) => r#loop.node.validate(_context, _manage_memory),
Statement::StructureDefinition(structure_definition) => {
structure_definition.item.validate(_context, _manage_memory)
structure_definition.node.validate(_context, _manage_memory)
}
Statement::TypeAlias(type_alias) => type_alias.item.validate(_context, _manage_memory),
Statement::While(r#while) => r#while.item.validate(_context, _manage_memory),
Statement::TypeAssignment(type_alias) => {
type_alias.node.validate(_context, _manage_memory)
}
Statement::While(r#while) => r#while.node.validate(_context, _manage_memory),
}
}
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError> {
let result = match self {
Statement::Assignment(assignment) => assignment.item.run(context, manage_memory),
Statement::AsyncBlock(async_block) => async_block.item.run(context, manage_memory),
Statement::Block(block) => block.item.run(context, manage_memory),
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::Expression(expression) => expression.run(context, manage_memory),
Statement::IfElse(if_else) => if_else.item.run(context, manage_memory),
Statement::Loop(r#loop) => r#loop.item.run(context, manage_memory),
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::StructureDefinition(structure_definition) => {
structure_definition.item.run(context, manage_memory)
structure_definition.node.run(context, manage_memory)
}
Statement::TypeAlias(type_alias) => type_alias.item.run(context, manage_memory),
Statement::While(r#while) => r#while.item.run(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),
};
if manage_memory {
@ -105,3 +91,15 @@ impl AbstractNode for Statement {
result
}
}
impl ExpectedType for Statement {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
match self {
Statement::ValueExpression(expression) => expression.expected_type(_context),
Statement::IfElse(if_else) => if_else.node.expected_type(_context),
Statement::Block(block) => block.node.expected_type(_context),
Statement::AsyncBlock(async_block) => async_block.node.expected_type(_context),
_ => Ok(Type::None),
}
}
}

View File

@ -21,10 +21,6 @@ impl StructureDefinition {
}
impl AbstractNode for StructureDefinition {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::None)
}
fn validate(
&self,
_context: &mut Context,

View File

@ -58,27 +58,27 @@ impl Type {
}
}
(Type::ListOf(left), Type::ListOf(right)) => {
if let Ok(()) = left.item.check(&right.item) {
if let Ok(()) = left.node.check(&right.node) {
return Ok(());
}
}
(Type::ListOf(list_of), Type::ListExact(list_exact)) => {
for r#type in list_exact {
list_of.item.check(&r#type.item)?;
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.item.check(&list_of.item)?;
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.item.check(&right.item)?;
left.node.check(&right.node)?;
}
return Ok(());
@ -97,7 +97,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.item != right_type.item
if left_field_name != right_field_name || left_type.node != right_type.node
{
return Err(TypeConflict {
actual: other.clone(),
@ -119,11 +119,11 @@ impl Type {
return_type: right_return,
},
) => {
if left_return.item == right_return.item {
if left_return.node == right_return.node {
for (left_parameter, right_parameter) in
left_parameters.iter().zip(right_parameters.iter())
{
if left_parameter.item != right_parameter.item {
if left_parameter.node != right_parameter.node {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
@ -145,10 +145,6 @@ impl Type {
}
impl AbstractNode for Type {
fn expected_type(&self, _: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::None)
}
fn validate(
&self,
_context: &mut Context,
@ -170,15 +166,15 @@ impl Display for Type {
Type::Float => write!(f, "float"),
Type::Integer => write!(f, "int"),
Type::List => write!(f, "list"),
Type::ListOf(item_type) => write!(f, "list({})", item_type.item),
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.item)?;
write!(f, "{}", item_type.node)?;
} else {
write!(f, "{}, ", item_type.item)?;
write!(f, "{}, ", item_type.node)?;
}
}
@ -195,10 +191,10 @@ impl Display for Type {
write!(f, "(")?;
for r#type in parameter_types {
write!(f, "{} ", r#type.item)?;
write!(f, "{} ", r#type.node)?;
}
write!(f, ") : {}", return_type.item)
write!(f, ") : {}", return_type.node)
}
Type::Structure { name, .. } => write!(f, "{name}"),
Type::Argument(identifier) => write!(f, "{identifier}"),

View File

@ -9,22 +9,18 @@ use crate::{
use super::{AbstractNode, Action, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TypeAlias {
pub struct TypeAssignment {
identifier: WithPosition<Identifier>,
r#type: WithPosition<Type>,
}
impl TypeAlias {
impl TypeAssignment {
pub fn new(identifier: WithPosition<Identifier>, r#type: WithPosition<Type>) -> Self {
Self { identifier, r#type }
}
}
impl AbstractNode for TypeAlias {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::None)
}
impl AbstractNode for TypeAssignment {
fn validate(
&self,
_context: &mut Context,
@ -34,7 +30,7 @@ impl AbstractNode for TypeAlias {
}
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
context.set_type(self.identifier.item, self.r#type.item)?;
context.set_type(self.identifier.node, self.r#type.node)?;
Ok(Action::None)
}

View File

@ -0,0 +1,142 @@
use serde::{Deserialize, Serialize};
use crate::{
context::Context,
error::{RuntimeError, ValidationError},
identifier::Identifier,
};
use super::{
AbstractNode, Action, As, BuiltInFunctionCall, ExpectedType, FunctionCall, ListIndex, Logic,
MapIndex, Math, SourcePosition, Type, ValueNode, WithPosition,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum ValueExpression {
As(WithPosition<Box<As>>),
BuiltInFunctionCall(WithPosition<Box<BuiltInFunctionCall>>),
FunctionCall(WithPosition<FunctionCall>),
Identifier(WithPosition<Identifier>),
MapIndex(WithPosition<Box<MapIndex>>),
ListIndex(WithPosition<Box<ListIndex>>),
Logic(WithPosition<Box<Logic>>),
Math(WithPosition<Box<Math>>),
Value(WithPosition<ValueNode>),
}
impl ValueExpression {
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,
}
}
}
impl AbstractNode for ValueExpression {
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) => {
function_call.node.validate(context, manage_memory)
}
ValueExpression::Identifier(identifier) => {
let found = if manage_memory {
context.add_expected_use(&identifier.node)?
} else {
context.contains(&identifier.node)?
};
if found {
Ok(())
} else {
Err(ValidationError::VariableNotFound {
identifier: identifier.node.clone(),
position: identifier.position,
})
}
}
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) => {
built_in_function_call.node.validate(context, manage_memory)
}
}
}
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, 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)
}
ValueExpression::Identifier(identifier) => {
let value_option = if manage_memory {
context.use_value(&identifier.node)?
} else {
context.get_value(&identifier.node)?
};
if let Some(value) = value_option {
Ok(Action::Return(value))
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound {
identifier: identifier.node.clone(),
position: identifier.position,
},
))
}
}
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)
}
}
}
}
impl ExpectedType for ValueExpression {
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) => {
if let Some(r#type) = _context.get_type(&identifier.node)? {
Ok(r#type)
} else {
Err(ValidationError::VariableNotFound {
identifier: identifier.node.clone(),
position: identifier.position,
})
}
}
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) => {
built_in_function_call.node.expected_type(_context)
}
}
}
}

View File

@ -9,20 +9,22 @@ use crate::{
Value,
};
use super::{AbstractNode, Action, Block, Expression, Type, WithPos, WithPosition};
use super::{
AbstractNode, Action, Block, ExpectedType, Type, ValueExpression, WithPos, WithPosition,
};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ValueNode {
Boolean(bool),
Float(f64),
Integer(i64),
List(Vec<Expression>),
Map(Vec<(Identifier, Option<WithPosition<Type>>, Expression)>),
List(Vec<ValueExpression>),
Map(Vec<(Identifier, Option<WithPosition<Type>>, ValueExpression)>),
Range(Range<i64>),
String(String),
Structure {
name: WithPosition<Identifier>,
fields: Vec<(Identifier, Expression)>,
fields: Vec<(Identifier, ValueExpression)>,
},
ParsedFunction {
type_arguments: Vec<WithPosition<Type>>,
@ -33,66 +35,6 @@ pub enum ValueNode {
}
impl AbstractNode for ValueNode {
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
let r#type = match self {
ValueNode::Boolean(_) => Type::Boolean,
ValueNode::Float(_) => Type::Float,
ValueNode::Integer(_) => Type::Integer,
ValueNode::List(items) => {
let mut item_types = Vec::with_capacity(items.len());
for expression in items {
item_types.push(
expression
.expected_type(context)?
.with_position(expression.position()),
);
}
Type::ListExact(item_types)
}
ValueNode::Map(_) => Type::Map,
ValueNode::Range(_) => Type::Range,
ValueNode::String(_) => Type::String,
ValueNode::ParsedFunction {
parameters,
return_type,
..
} => Type::Function {
parameter_types: parameters
.iter()
.map(|(_, r#type)| r#type.clone())
.collect(),
return_type: Box::new(return_type.clone()),
},
ValueNode::Structure {
name,
fields: expressions,
} => {
let mut types = Vec::with_capacity(expressions.len());
for (identifier, expression) in expressions {
let r#type = expression.expected_type(context)?;
types.push((
identifier.clone(),
WithPosition {
item: r#type,
position: expression.position(),
},
));
}
Type::Structure {
name: name.item.clone(),
fields: types,
}
}
};
Ok(r#type)
}
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 {
@ -101,7 +43,7 @@ impl AbstractNode for ValueNode {
if let Some(expected_type) = r#type {
let actual_type = expression.expected_type(context)?;
expected_type.item.check(&actual_type).map_err(|conflict| {
expected_type.node.check(&actual_type).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: expression.position(),
@ -124,21 +66,21 @@ impl AbstractNode for ValueNode {
let mut function_context = Context::new(Some(&context));
for r#type in type_arguments {
if let Type::Argument(identifier) = &r#type.item {
function_context.set_type(identifier.clone(), r#type.item.clone())?;
if let Type::Argument(identifier) = &r#type.node {
function_context.set_type(identifier.clone(), r#type.node.clone())?;
}
}
for (identifier, r#type) in parameters {
function_context.set_type(identifier.clone(), r#type.item.clone())?;
function_context.set_type(identifier.clone(), r#type.node.clone())?;
}
body.item.validate(&mut function_context, _manage_memory)?;
body.node.validate(&mut function_context, _manage_memory)?;
let actual_return_type = body.item.expected_type(&mut function_context)?;
let actual_return_type = body.node.expected_type(&mut function_context)?;
return_type
.item
.node
.check(&actual_return_type)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
@ -154,9 +96,9 @@ impl AbstractNode for ValueNode {
fields: expressions,
} = self
{
if !context.contains(&name.item)? {
if !context.contains(&name.node)? {
return Err(ValidationError::VariableNotFound {
identifier: name.item.clone(),
identifier: name.node.clone(),
position: name.position,
});
}
@ -164,12 +106,12 @@ impl AbstractNode for ValueNode {
if let Some(Type::Structure {
name: _,
fields: types,
}) = context.get_type(&name.item)?
}) = context.get_type(&name.node)?
{
for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
let actual_type = expression.expected_type(context)?;
expected_type.item.check(&actual_type).map_err(|conflict| {
expected_type.node.check(&actual_type).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: expression.position(),
@ -196,7 +138,7 @@ impl AbstractNode for ValueNode {
let action = expression.run(_context, _manage_memory)?;
let value = if let Action::Return(value) = action {
WithPosition {
item: value,
node: value,
position: expression_position,
}
} else {
@ -357,3 +299,65 @@ impl Ord for ValueNode {
}
}
}
impl ExpectedType for ValueNode {
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
let r#type = match self {
ValueNode::Boolean(_) => Type::Boolean,
ValueNode::Float(_) => Type::Float,
ValueNode::Integer(_) => Type::Integer,
ValueNode::List(items) => {
let mut item_types = Vec::with_capacity(items.len());
for expression in items {
item_types.push(
expression
.expected_type(context)?
.with_position(expression.position()),
);
}
Type::ListExact(item_types)
}
ValueNode::Map(_) => Type::Map,
ValueNode::Range(_) => Type::Range,
ValueNode::String(_) => Type::String,
ValueNode::ParsedFunction {
parameters,
return_type,
..
} => Type::Function {
parameter_types: parameters
.iter()
.map(|(_, r#type)| r#type.clone())
.collect(),
return_type: Box::new(return_type.clone()),
},
ValueNode::Structure {
name,
fields: expressions,
} => {
let mut types = Vec::with_capacity(expressions.len());
for (identifier, expression) in expressions {
let r#type = expression.expected_type(context)?;
types.push((
identifier.clone(),
WithPosition {
node: r#type,
position: expression.position(),
},
));
}
Type::Structure {
name: name.node.clone(),
fields: types,
}
}
};
Ok(r#type)
}
}

View File

@ -7,16 +7,16 @@ use crate::{
Value,
};
use super::{AbstractNode, Action, Expression, Statement, Type};
use super::{AbstractNode, Action, Statement, ValueExpression};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct While {
expression: Expression,
expression: ValueExpression,
statements: Vec<Statement>,
}
impl While {
pub fn new(expression: Expression, statements: Vec<Statement>) -> Self {
pub fn new(expression: ValueExpression, statements: Vec<Statement>) -> Self {
Self {
expression,
statements,
@ -25,10 +25,6 @@ impl While {
}
impl AbstractNode for While {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
Ok(Type::None)
}
fn validate(
&self,
_context: &mut Context,

View File

@ -403,7 +403,7 @@ impl InterpreterError {
.with_message(format!("This has type {}.", actual.fg(type_color),)),
)
}
ValidationError::ExpectedString { actual, position } => todo!(),
ValidationError::ExpectedString { .. } => todo!(),
}
}
let report = builder.finish();

File diff suppressed because it is too large Load Diff

View File

@ -109,9 +109,9 @@ impl Display for Value {
for (index, value) in list.into_iter().enumerate() {
if index == list.len() - 1 {
write!(f, "{}", value.item)?;
write!(f, "{}", value.node)?;
} else {
write!(f, "{}, ", value.item)?;
write!(f, "{}, ", value.node)?;
}
}
@ -139,9 +139,9 @@ impl Display for Value {
for (index, r#type) in type_arguments.into_iter().enumerate() {
if index == type_arguments.len() - 1 {
write!(f, "{}", r#type.item)?;
write!(f, "{}", r#type.node)?;
} else {
write!(f, "{} ", r#type.item)?;
write!(f, "{} ", r#type.node)?;
}
}
@ -151,13 +151,13 @@ impl Display for Value {
write!(f, "(")?;
for (identifier, r#type) in parameters {
write!(f, "{identifier}: {}", r#type.item)?;
write!(f, "{identifier}: {}", r#type.node)?;
}
write!(f, "): {} {:?}", return_type.item, body.item)
write!(f, "): {} {:?}", return_type.node, body.node)
}
ValueInner::Structure { name, fields } => {
write!(f, "{}\n{{", name.item)?;
write!(f, "{}\n{{", name.node)?;
for (key, value) in fields {
writeln!(f, "{key} = {value},")?;
@ -184,7 +184,7 @@ impl Ord for Value {
}
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
@ -193,7 +193,7 @@ impl Serialize for Value {
}
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
@ -227,7 +227,7 @@ impl ValueInner {
let mut types = Vec::with_capacity(values.len());
for value in values {
types.push(value.item.r#type(context)?.with_position(value.position));
types.push(value.node.r#type(context)?.with_position(value.position));
}
Type::ListExact(types)
@ -244,11 +244,11 @@ impl ValueInner {
return_type: Box::new(function.return_type.clone()),
},
ValueInner::Structure { name, .. } => {
if let Some(r#type) = context.get_type(&name.item)? {
if let Some(r#type) = context.get_type(&name.node)? {
r#type
} else {
return Err(ValidationError::VariableNotFound {
identifier: name.item.clone(),
identifier: name.node.clone(),
position: name.position,
});
}
@ -342,6 +342,6 @@ impl Function {
context.set_value(identifier.clone(), value)?;
}
self.body.item.run(context, clear_variables)
self.body.node.run(context, clear_variables)
}
}

View File

@ -28,20 +28,6 @@ fn function_call() {
);
}
#[test]
fn call_empty_function() {
assert_eq!(
interpret(
"test",
"
foobar = fn (message : str) none {}
foobar('Hiya')
",
),
Ok(None)
);
}
#[test]
fn callback() {
assert_eq!(

View File

@ -1,5 +1,5 @@
use dust_lang::{
abstract_tree::{Block, Expression, Statement, Type, WithPos},
abstract_tree::{Block, Statement, Type, ValueExpression, WithPos},
error::{Error, TypeConflict, ValidationError},
identifier::Identifier,
*,
@ -49,9 +49,9 @@ fn function_variable() {
Vec::with_capacity(0),
vec![(Identifier::new("x"), Type::Integer.with_position((16, 19)))],
Type::Integer.with_position((21, 24)),
Block::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("x").with_position((27, 28))
))])
Block::new(vec![Statement::ValueExpression(
ValueExpression::Identifier(Identifier::new("x").with_position((27, 28)))
)])
.with_position((25, 30))
)))
);