Begin preparing for type expressions
This commit is contained in:
parent
54071eb8c0
commit
a0b754cc1c
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
));
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)),
|
||||
)),
|
||||
]);
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)),
|
||||
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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}"),
|
||||
|
@ -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)
|
||||
}
|
||||
|
142
dust-lang/src/abstract_tree/value_expression.rs
Normal file
142
dust-lang/src/abstract_tree/value_expression.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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!(
|
||||
|
@ -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))
|
||||
)))
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user