Begin preparing for type expressions
This commit is contained in:
parent
54071eb8c0
commit
a0b754cc1c
@ -9,31 +9,27 @@ use crate::{
|
|||||||
Value,
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct As {
|
pub struct As {
|
||||||
expression: Expression,
|
expression: ValueExpression,
|
||||||
r#type: WithPosition<Type>,
|
r#type: WithPosition<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl As {
|
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 }
|
Self { expression, r#type }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for As {
|
impl AbstractNode for As {
|
||||||
fn expected_type(&self, _: &mut Context) -> Result<Type, ValidationError> {
|
|
||||||
Ok(self.r#type.item.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
match self.r#type.item {
|
match self.r#type.node {
|
||||||
Type::Boolean | Type::Float | Type::Integer | Type::String => {}
|
Type::Boolean | Type::Float | Type::Integer | Type::String => {}
|
||||||
_ => todo!("Create an error for this occurence."),
|
_ => todo!("Create an error for this occurence."),
|
||||||
};
|
};
|
||||||
@ -54,7 +50,7 @@ impl AbstractNode for As {
|
|||||||
ValidationError::InterpreterExpectedReturn(expression_position),
|
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) {
|
let converted = match (from_value, to_type) {
|
||||||
(ValueInner::Boolean(boolean), Type::String) => Value::string(boolean.to_string()),
|
(ValueInner::Boolean(boolean), Type::String) => Value::string(boolean.to_string()),
|
||||||
@ -65,3 +61,9 @@ impl AbstractNode for As {
|
|||||||
Ok(Action::Return(converted))
|
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,
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Assignment {
|
pub struct Assignment {
|
||||||
@ -41,15 +41,11 @@ impl Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for 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> {
|
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
let statement_type = self.statement.expected_type(context)?;
|
let statement_type = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
if let Some(WithPosition {
|
if let Some(WithPosition {
|
||||||
item: expected_type,
|
node: expected_type,
|
||||||
position: expected_position,
|
position: expected_position,
|
||||||
}) = &self.r#type
|
}) = &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 {
|
} 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)?;
|
self.statement.validate(context, manage_memory)?;
|
||||||
@ -80,13 +76,13 @@ impl AbstractNode for Assignment {
|
|||||||
|
|
||||||
match self.operator {
|
match self.operator {
|
||||||
AssignmentOperator::Assign => {
|
AssignmentOperator::Assign => {
|
||||||
context.set_value(self.identifier.item, right)?;
|
context.set_value(self.identifier.node, right)?;
|
||||||
}
|
}
|
||||||
AssignmentOperator::AddAssign => {
|
AssignmentOperator::AddAssign => {
|
||||||
let left_option = if manage_memory {
|
let left_option = if manage_memory {
|
||||||
context.use_value(&self.identifier.item)?
|
context.use_value(&self.identifier.node)?
|
||||||
} else {
|
} else {
|
||||||
context.get_value(&self.identifier.item)?
|
context.get_value(&self.identifier.node)?
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(left) = left_option {
|
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 {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableNotFound {
|
ValidationError::VariableNotFound {
|
||||||
identifier: self.identifier.item,
|
identifier: self.identifier.node,
|
||||||
position: self.identifier.position,
|
position: self.identifier.position,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@ -129,9 +125,9 @@ impl AbstractNode for Assignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::SubAssign => {
|
AssignmentOperator::SubAssign => {
|
||||||
let left_option = if manage_memory {
|
let left_option = if manage_memory {
|
||||||
context.use_value(&self.identifier.item)?
|
context.use_value(&self.identifier.node)?
|
||||||
} else {
|
} else {
|
||||||
context.get_value(&self.identifier.item)?
|
context.get_value(&self.identifier.node)?
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(left) = left_option {
|
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 {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableNotFound {
|
ValidationError::VariableNotFound {
|
||||||
identifier: self.identifier.item,
|
identifier: self.identifier.node,
|
||||||
position: self.identifier.position,
|
position: self.identifier.position,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
error::{RuntimeError, RwLockPoisonError, ValidationError},
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct AsyncBlock {
|
pub struct AsyncBlock {
|
||||||
@ -22,10 +22,6 @@ impl AsyncBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for 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> {
|
fn validate(&self, _context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.validate(_context, manage_memory)?;
|
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},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Statement, Type};
|
use super::{AbstractNode, Action, ExpectedType, Statement};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
@ -27,14 +27,6 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for 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(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{Expression, ValueNode, WithPos},
|
abstract_tree::{Type, ValueExpression, ValueNode, WithPos},
|
||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,13 +68,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn run_returns_value_of_final_statement() {
|
fn run_returns_value_of_final_statement() {
|
||||||
let block = Block::new(vec![
|
let block = Block::new(vec![
|
||||||
Statement::Expression(Expression::Value(
|
Statement::ValueExpression(ValueExpression::Value(
|
||||||
ValueNode::Integer(1).with_position((0, 0)),
|
ValueNode::Integer(1).with_position((0, 0)),
|
||||||
)),
|
)),
|
||||||
Statement::Expression(Expression::Value(
|
Statement::ValueExpression(ValueExpression::Value(
|
||||||
ValueNode::Integer(2).with_position((0, 0)),
|
ValueNode::Integer(2).with_position((0, 0)),
|
||||||
)),
|
)),
|
||||||
Statement::Expression(Expression::Value(
|
Statement::ValueExpression(ValueExpression::Value(
|
||||||
ValueNode::Integer(42).with_position((0, 0)),
|
ValueNode::Integer(42).with_position((0, 0)),
|
||||||
)),
|
)),
|
||||||
]);
|
]);
|
||||||
@ -90,10 +88,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expected_type_returns_type_of_final_statement() {
|
fn expected_type_returns_type_of_final_statement() {
|
||||||
let block = Block::new(vec![
|
let block = Block::new(vec![
|
||||||
Statement::Expression(Expression::Value(
|
Statement::ValueExpression(ValueExpression::Value(
|
||||||
ValueNode::String("42".to_string()).with_position((0, 0)),
|
ValueNode::String("42".to_string()).with_position((0, 0)),
|
||||||
)),
|
)),
|
||||||
Statement::Expression(Expression::Value(
|
Statement::ValueExpression(ValueExpression::Value(
|
||||||
ValueNode::Integer(42).with_position((0, 0)),
|
ValueNode::Integer(42).with_position((0, 0)),
|
||||||
)),
|
)),
|
||||||
]);
|
]);
|
||||||
|
@ -15,30 +15,19 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Expression, WithPosition};
|
use super::{AbstractNode, ExpectedType, ValueExpression, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum BuiltInFunctionCall {
|
pub enum BuiltInFunctionCall {
|
||||||
JsonParse(WithPosition<Type>, Expression),
|
JsonParse(WithPosition<Type>, ValueExpression),
|
||||||
Length(Expression),
|
Length(ValueExpression),
|
||||||
ReadFile(Expression),
|
ReadFile(ValueExpression),
|
||||||
ReadLine,
|
ReadLine,
|
||||||
Sleep(Expression),
|
Sleep(ValueExpression),
|
||||||
WriteLine(Expression),
|
WriteLine(ValueExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for BuiltInFunctionCall {
|
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(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
@ -64,7 +53,7 @@ impl AbstractNode for BuiltInFunctionCall {
|
|||||||
|
|
||||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
BuiltInFunctionCall::JsonParse(r#type, expression) => {
|
BuiltInFunctionCall::JsonParse(_type, expression) => {
|
||||||
let action = expression.clone().run(context, _manage_memory)?;
|
let action = expression.clone().run(context, _manage_memory)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
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,
|
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)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct FunctionCall {
|
pub struct FunctionCall {
|
||||||
function: Box<Expression>,
|
function: Box<ValueExpression>,
|
||||||
type_arguments: Vec<WithPosition<Type>>,
|
type_arguments: Vec<WithPosition<Type>>,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<ValueExpression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionCall {
|
impl FunctionCall {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
function: Expression,
|
function: ValueExpression,
|
||||||
type_arguments: Vec<WithPosition<Type>>,
|
type_arguments: Vec<WithPosition<Type>>,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<ValueExpression>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
FunctionCall {
|
FunctionCall {
|
||||||
function: Box::new(function),
|
function: Box::new(function),
|
||||||
@ -30,19 +30,6 @@ impl FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for 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> {
|
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
self.function.validate(context, manage_memory)?;
|
self.function.validate(context, manage_memory)?;
|
||||||
|
|
||||||
@ -60,13 +47,13 @@ impl AbstractNode for FunctionCall {
|
|||||||
for (type_parameter, type_argument) in
|
for (type_parameter, type_argument) in
|
||||||
parameter_types.iter().zip(self.type_arguments.iter())
|
parameter_types.iter().zip(self.type_arguments.iter())
|
||||||
{
|
{
|
||||||
if let Type::Argument(_) = type_parameter.item {
|
if let Type::Argument(_) = type_parameter.node {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
type_parameter
|
type_parameter
|
||||||
.item
|
.node
|
||||||
.check(&type_argument.item)
|
.check(&type_argument.node)
|
||||||
.map_err(|conflict| ValidationError::TypeCheck {
|
.map_err(|conflict| ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: type_argument.position,
|
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()) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let actual = expression.expected_type(context)?;
|
let actual = expression.expected_type(context)?;
|
||||||
|
|
||||||
type_parameter.item.check(&actual).map_err(|conflict| {
|
type_parameter.node.check(&actual).map_err(|conflict| {
|
||||||
ValidationError::TypeCheck {
|
ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: expression.position(),
|
actual_position: expression.position(),
|
||||||
@ -140,8 +127,8 @@ impl AbstractNode for FunctionCall {
|
|||||||
for (type_parameter, type_argument) in function
|
for (type_parameter, type_argument) in function
|
||||||
.type_parameters()
|
.type_parameters()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r#type| r#type.item.clone())
|
.map(|r#type| r#type.node.clone())
|
||||||
.zip(self.type_arguments.into_iter().map(|r#type| r#type.item))
|
.zip(self.type_arguments.into_iter().map(|r#type| r#type.node))
|
||||||
{
|
{
|
||||||
if let Type::Argument(identifier) = type_parameter {
|
if let Type::Argument(identifier) = type_parameter {
|
||||||
function_context.set_type(identifier, type_argument)?;
|
function_context.set_type(identifier, type_argument)?;
|
||||||
@ -153,3 +140,18 @@ impl AbstractNode for FunctionCall {
|
|||||||
.call(arguments, &mut function_context, clear_variables)
|
.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,
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct IfElse {
|
pub struct IfElse {
|
||||||
if_expression: Expression,
|
if_expression: ValueExpression,
|
||||||
if_block: WithPosition<Block>,
|
if_block: WithPosition<Block>,
|
||||||
else_ifs: Vec<(Expression, WithPosition<Block>)>,
|
else_ifs: Vec<(ValueExpression, WithPosition<Block>)>,
|
||||||
else_block: Option<WithPosition<Block>>,
|
else_block: Option<WithPosition<Block>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IfElse {
|
impl IfElse {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
if_expression: Expression,
|
if_expression: ValueExpression,
|
||||||
if_block: WithPosition<Block>,
|
if_block: WithPosition<Block>,
|
||||||
else_ifs: Vec<(Expression, WithPosition<Block>)>,
|
else_ifs: Vec<(ValueExpression, WithPosition<Block>)>,
|
||||||
else_block: Option<WithPosition<Block>>,
|
else_block: Option<WithPosition<Block>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -33,29 +33,25 @@ impl IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for 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> {
|
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
self.if_expression.validate(context, manage_memory)?;
|
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)?;
|
let if_expression_type = self.if_expression.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Boolean = if_expression_type {
|
if let Type::Boolean = if_expression_type {
|
||||||
if let Some(else_block) = &self.else_block {
|
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
|
expected_type
|
||||||
.check(&actual)
|
.check(&actual)
|
||||||
.map_err(|conflict| ValidationError::TypeCheck {
|
.map_err(|conflict| ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: else_block.item.last_statement().position(),
|
actual_position: else_block.node.last_statement().position(),
|
||||||
expected_position: self.if_block.item.first_statement().position(),
|
expected_position: self.if_block.node.first_statement().position(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -69,15 +65,15 @@ impl AbstractNode for IfElse {
|
|||||||
let expression_type = expression.expected_type(context)?;
|
let expression_type = expression.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Boolean = expression_type {
|
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
|
expected_type
|
||||||
.check(&actual)
|
.check(&actual)
|
||||||
.map_err(|conflict| ValidationError::TypeCheck {
|
.map_err(|conflict| ValidationError::TypeCheck {
|
||||||
conflict,
|
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(),
|
expected_position: self.if_expression.position(),
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
@ -104,7 +100,7 @@ impl AbstractNode for IfElse {
|
|||||||
|
|
||||||
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
|
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
|
||||||
if *if_boolean {
|
if *if_boolean {
|
||||||
self.if_block.item.run(context, _manage_memory)
|
self.if_block.node.run(context, _manage_memory)
|
||||||
} else {
|
} else {
|
||||||
for (expression, block) in self.else_ifs {
|
for (expression, block) in self.else_ifs {
|
||||||
let expression_position = expression.position();
|
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 let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() {
|
||||||
if *else_if_boolean {
|
if *else_if_boolean {
|
||||||
return block.item.run(context, _manage_memory);
|
return block.node.run(context, _manage_memory);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
@ -132,7 +128,7 @@ impl AbstractNode for IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(else_statement) = self.else_block {
|
if let Some(else_statement) = self.else_block {
|
||||||
else_statement.item.run(context, _manage_memory)
|
else_statement.node.run(context, _manage_memory)
|
||||||
} else {
|
} else {
|
||||||
Ok(Action::None)
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -161,8 +163,8 @@ mod tests {
|
|||||||
fn simple_if() {
|
fn simple_if() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
IfElse::new(
|
IfElse::new(
|
||||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Block::new(vec![Statement::Expression(Expression::Value(
|
Block::new(vec![Statement::ValueExpression(ValueExpression::Value(
|
||||||
ValueNode::String("foo".to_string()).with_position((0, 0))
|
ValueNode::String("foo".to_string()).with_position((0, 0))
|
||||||
))])
|
))])
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
|
@ -5,50 +5,21 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct ListIndex {
|
pub struct ListIndex {
|
||||||
left: Expression,
|
left: ValueExpression,
|
||||||
right: Expression,
|
right: ValueExpression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListIndex {
|
impl ListIndex {
|
||||||
pub fn new(left: Expression, right: Expression) -> Self {
|
pub fn new(left: ValueExpression, right: ValueExpression) -> Self {
|
||||||
Self { left, right }
|
Self { left, right }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for ListIndex {
|
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> {
|
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
self.left.validate(context, _manage_memory)?;
|
self.left.validate(context, _manage_memory)?;
|
||||||
self.right.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);
|
let found_item = list.get(index as usize);
|
||||||
|
|
||||||
if let Some(item) = found_item {
|
if let Some(item) = found_item {
|
||||||
Ok(Action::Return(item.item.clone()))
|
Ok(Action::Return(item.node.clone()))
|
||||||
} else {
|
} else {
|
||||||
Ok(Action::None)
|
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,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Expression, Type};
|
use super::{AbstractNode, Action, ExpectedType, Type, ValueExpression};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum Logic {
|
pub enum Logic {
|
||||||
Equal(Expression, Expression),
|
Equal(ValueExpression, ValueExpression),
|
||||||
NotEqual(Expression, Expression),
|
NotEqual(ValueExpression, ValueExpression),
|
||||||
Greater(Expression, Expression),
|
Greater(ValueExpression, ValueExpression),
|
||||||
Less(Expression, Expression),
|
Less(ValueExpression, ValueExpression),
|
||||||
GreaterOrEqual(Expression, Expression),
|
GreaterOrEqual(ValueExpression, ValueExpression),
|
||||||
LessOrEqual(Expression, Expression),
|
LessOrEqual(ValueExpression, ValueExpression),
|
||||||
And(Expression, Expression),
|
And(ValueExpression, ValueExpression),
|
||||||
Or(Expression, Expression),
|
Or(ValueExpression, ValueExpression),
|
||||||
Not(Expression),
|
Not(ValueExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Logic {
|
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> {
|
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Logic::Equal(left, right)
|
Logic::Equal(left, right)
|
||||||
@ -94,7 +90,7 @@ impl AbstractNode for Logic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
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 expression_position = expression.position();
|
||||||
let action = expression.run(&mut context.clone(), _manage_memory)?;
|
let action = expression.run(&mut context.clone(), _manage_memory)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
@ -108,7 +104,7 @@ impl AbstractNode for Logic {
|
|||||||
Ok(value)
|
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 expression_position = expression.position();
|
||||||
let action = expression.run(&mut context.clone(), _manage_memory)?;
|
let action = expression.run(&mut context.clone(), _manage_memory)?;
|
||||||
let value = if let Action::Return(value) = action {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::abstract_tree::{ValueNode, WithPos};
|
use crate::abstract_tree::{ValueNode, WithPos};
|
||||||
@ -205,8 +207,8 @@ mod tests {
|
|||||||
fn equal() {
|
fn equal() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Equal(
|
Logic::Equal(
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -217,8 +219,8 @@ mod tests {
|
|||||||
fn not_equal() {
|
fn not_equal() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::NotEqual(
|
Logic::NotEqual(
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -229,8 +231,8 @@ mod tests {
|
|||||||
fn greater() {
|
fn greater() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Greater(
|
Logic::Greater(
|
||||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -241,8 +243,8 @@ mod tests {
|
|||||||
fn less() {
|
fn less() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Less(
|
Logic::Less(
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
ValueExpression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -253,8 +255,8 @@ mod tests {
|
|||||||
fn greater_or_equal() {
|
fn greater_or_equal() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::GreaterOrEqual(
|
Logic::GreaterOrEqual(
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
ValueExpression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -262,8 +264,8 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::GreaterOrEqual(
|
Logic::GreaterOrEqual(
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -274,8 +276,8 @@ mod tests {
|
|||||||
fn less_or_equal() {
|
fn less_or_equal() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::LessOrEqual(
|
Logic::LessOrEqual(
|
||||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -283,8 +285,8 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::LessOrEqual(
|
Logic::LessOrEqual(
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -295,8 +297,8 @@ mod tests {
|
|||||||
fn and() {
|
fn and() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::And(
|
Logic::And(
|
||||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -307,8 +309,8 @@ mod tests {
|
|||||||
fn or() {
|
fn or() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Or(
|
Logic::Or(
|
||||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
ValueExpression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -318,7 +320,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn not() {
|
fn not() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Not(Expression::Value(
|
Logic::Not(ValueExpression::Value(
|
||||||
ValueNode::Boolean(false).with_position((0, 0))
|
ValueNode::Boolean(false).with_position((0, 0))
|
||||||
))
|
))
|
||||||
.run(&mut Context::new(None), true),
|
.run(&mut Context::new(None), true),
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Statement, Type};
|
use super::{AbstractNode, Action, Statement};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Loop {
|
pub struct Loop {
|
||||||
@ -19,10 +19,6 @@ impl Loop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Loop {
|
impl AbstractNode for Loop {
|
||||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
|
||||||
Ok(Type::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
|
@ -6,16 +6,16 @@ use crate::{
|
|||||||
value::ValueInner,
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct MapIndex {
|
pub struct MapIndex {
|
||||||
collection: Expression,
|
collection: ValueExpression,
|
||||||
index: Expression,
|
index: ValueExpression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapIndex {
|
impl MapIndex {
|
||||||
pub fn new(left: Expression, right: Expression) -> Self {
|
pub fn new(left: ValueExpression, right: ValueExpression) -> Self {
|
||||||
Self {
|
Self {
|
||||||
collection: left,
|
collection: left,
|
||||||
index: right,
|
index: right,
|
||||||
@ -24,87 +24,6 @@ impl MapIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for 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(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_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)
|
(collection.inner().as_ref(), self.index)
|
||||||
{
|
{
|
||||||
let action = map
|
let action = map
|
||||||
.get(&index.item)
|
.get(&index.node)
|
||||||
.map(|value| Action::Return(value.clone()))
|
.map(|value| Action::Return(value.clone()))
|
||||||
.unwrap_or(Action::None);
|
.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,
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum Math {
|
pub enum Math {
|
||||||
Add(Expression, Expression),
|
Add(ValueExpression, ValueExpression),
|
||||||
Subtract(Expression, Expression),
|
Subtract(ValueExpression, ValueExpression),
|
||||||
Multiply(Expression, Expression),
|
Multiply(ValueExpression, ValueExpression),
|
||||||
Divide(Expression, Expression),
|
Divide(ValueExpression, ValueExpression),
|
||||||
Modulo(Expression, Expression),
|
Modulo(ValueExpression, ValueExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Math {
|
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> {
|
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Math::Add(left, right) => {
|
Math::Add(left, right) => {
|
||||||
@ -91,8 +68,9 @@ impl AbstractNode for Math {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||||
let run_and_expect_value =
|
let run_and_expect_value = |position: SourcePosition,
|
||||||
|position: SourcePosition, expression: Expression| -> Result<Value, RuntimeError> {
|
expression: ValueExpression|
|
||||||
|
-> Result<Value, RuntimeError> {
|
||||||
let action = expression.run(&mut _context.clone(), _clear_variables)?;
|
let action = expression.run(&mut _context.clone(), _clear_variables)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
@ -313,3 +291,28 @@ impl AbstractNode for Math {
|
|||||||
Ok(Action::Return(value))
|
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 async_block;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod built_in_function_call;
|
pub mod built_in_function_call;
|
||||||
pub mod expression;
|
|
||||||
pub mod function_call;
|
pub mod function_call;
|
||||||
pub mod if_else;
|
pub mod if_else;
|
||||||
pub mod list_index;
|
pub mod list_index;
|
||||||
@ -15,6 +14,7 @@ pub mod statement;
|
|||||||
pub mod structure_definition;
|
pub mod structure_definition;
|
||||||
pub mod r#type;
|
pub mod r#type;
|
||||||
pub mod type_alias;
|
pub mod type_alias;
|
||||||
|
pub mod value_expression;
|
||||||
pub mod value_node;
|
pub mod value_node;
|
||||||
pub mod r#while;
|
pub mod r#while;
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ pub use self::{
|
|||||||
async_block::AsyncBlock,
|
async_block::AsyncBlock,
|
||||||
block::Block,
|
block::Block,
|
||||||
built_in_function_call::BuiltInFunctionCall,
|
built_in_function_call::BuiltInFunctionCall,
|
||||||
expression::Expression,
|
|
||||||
function_call::FunctionCall,
|
function_call::FunctionCall,
|
||||||
if_else::IfElse,
|
if_else::IfElse,
|
||||||
list_index::ListIndex,
|
list_index::ListIndex,
|
||||||
@ -41,7 +40,8 @@ pub use self::{
|
|||||||
r#while::While,
|
r#while::While,
|
||||||
statement::Statement,
|
statement::Statement,
|
||||||
structure_definition::StructureDefinition,
|
structure_definition::StructureDefinition,
|
||||||
type_alias::TypeAlias,
|
type_alias::TypeAssignment,
|
||||||
|
value_expression::ValueExpression,
|
||||||
value_node::ValueNode,
|
value_node::ValueNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,14 +53,14 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct WithPosition<T> {
|
pub struct WithPosition<T> {
|
||||||
pub item: T,
|
pub node: T,
|
||||||
pub position: SourcePosition,
|
pub position: SourcePosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WithPos: Sized {
|
pub trait WithPos: Sized {
|
||||||
fn with_position<T: Into<SourcePosition>>(self, span: T) -> WithPosition<Self> {
|
fn with_position<T: Into<SourcePosition>>(self, span: T) -> WithPosition<Self> {
|
||||||
WithPosition {
|
WithPosition {
|
||||||
item: self,
|
node: self,
|
||||||
position: span.into(),
|
position: span.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +188,10 @@ impl Index<usize> for AbstractTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait AbstractNode: Sized {
|
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 validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError>;
|
||||||
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError>;
|
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::{
|
use super::{
|
||||||
AbstractNode, Action, Assignment, AsyncBlock, Block, Expression, IfElse, Loop, SourcePosition,
|
AbstractNode, Action, Assignment, AsyncBlock, Block, ExpectedType, IfElse, Loop,
|
||||||
StructureDefinition, Type, TypeAlias, While, WithPosition,
|
SourcePosition, StructureDefinition, Type, TypeAssignment, ValueExpression, While,
|
||||||
|
WithPosition,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
@ -16,11 +17,11 @@ pub enum Statement {
|
|||||||
AsyncBlock(WithPosition<AsyncBlock>),
|
AsyncBlock(WithPosition<AsyncBlock>),
|
||||||
Block(WithPosition<Block>),
|
Block(WithPosition<Block>),
|
||||||
Break(WithPosition<()>),
|
Break(WithPosition<()>),
|
||||||
Expression(Expression),
|
|
||||||
IfElse(WithPosition<IfElse>),
|
IfElse(WithPosition<IfElse>),
|
||||||
Loop(WithPosition<Loop>),
|
Loop(WithPosition<Loop>),
|
||||||
StructureDefinition(WithPosition<StructureDefinition>),
|
StructureDefinition(WithPosition<StructureDefinition>),
|
||||||
TypeAlias(WithPosition<TypeAlias>),
|
TypeAssignment(WithPosition<TypeAssignment>),
|
||||||
|
ValueExpression(ValueExpression),
|
||||||
While(WithPosition<While>),
|
While(WithPosition<While>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,71 +32,56 @@ impl Statement {
|
|||||||
Statement::AsyncBlock(inner) => inner.position,
|
Statement::AsyncBlock(inner) => inner.position,
|
||||||
Statement::Block(inner) => inner.position,
|
Statement::Block(inner) => inner.position,
|
||||||
Statement::Break(inner) => inner.position,
|
Statement::Break(inner) => inner.position,
|
||||||
Statement::Expression(expression) => expression.position(),
|
Statement::ValueExpression(expression) => expression.position(),
|
||||||
Statement::IfElse(inner) => inner.position,
|
Statement::IfElse(inner) => inner.position,
|
||||||
Statement::Loop(inner) => inner.position,
|
Statement::Loop(inner) => inner.position,
|
||||||
Statement::StructureDefinition(inner) => inner.position,
|
Statement::StructureDefinition(inner) => inner.position,
|
||||||
Statement::TypeAlias(inner) => inner.position,
|
Statement::TypeAssignment(inner) => inner.position,
|
||||||
Statement::While(inner) => inner.position,
|
Statement::While(inner) => inner.position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Statement {
|
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(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.item.validate(_context, _manage_memory),
|
Statement::Assignment(assignment) => assignment.node.validate(_context, _manage_memory),
|
||||||
Statement::AsyncBlock(async_block) => {
|
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::Break(_) => Ok(()),
|
||||||
Statement::Expression(expression) => expression.validate(_context, _manage_memory),
|
Statement::ValueExpression(expression) => expression.validate(_context, _manage_memory),
|
||||||
Statement::IfElse(if_else) => if_else.item.validate(_context, _manage_memory),
|
Statement::IfElse(if_else) => if_else.node.validate(_context, _manage_memory),
|
||||||
Statement::Loop(r#loop) => r#loop.item.validate(_context, _manage_memory),
|
Statement::Loop(r#loop) => r#loop.node.validate(_context, _manage_memory),
|
||||||
Statement::StructureDefinition(structure_definition) => {
|
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::TypeAssignment(type_alias) => {
|
||||||
Statement::While(r#while) => r#while.item.validate(_context, _manage_memory),
|
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> {
|
fn run(self, context: &mut Context, manage_memory: bool) -> Result<Action, RuntimeError> {
|
||||||
let result = match self {
|
let result = match self {
|
||||||
Statement::Assignment(assignment) => assignment.item.run(context, manage_memory),
|
Statement::Assignment(assignment) => assignment.node.run(context, manage_memory),
|
||||||
Statement::AsyncBlock(async_block) => async_block.item.run(context, manage_memory),
|
Statement::AsyncBlock(async_block) => async_block.node.run(context, manage_memory),
|
||||||
Statement::Block(block) => block.item.run(context, manage_memory),
|
Statement::Block(block) => block.node.run(context, manage_memory),
|
||||||
Statement::Break(_) => Ok(Action::Break),
|
Statement::Break(_) => Ok(Action::Break),
|
||||||
Statement::Expression(expression) => expression.run(context, manage_memory),
|
Statement::ValueExpression(expression) => expression.run(context, manage_memory),
|
||||||
Statement::IfElse(if_else) => if_else.item.run(context, manage_memory),
|
Statement::IfElse(if_else) => if_else.node.run(context, manage_memory),
|
||||||
Statement::Loop(r#loop) => r#loop.item.run(context, manage_memory),
|
Statement::Loop(r#loop) => r#loop.node.run(context, manage_memory),
|
||||||
Statement::StructureDefinition(structure_definition) => {
|
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::TypeAssignment(type_alias) => type_alias.node.run(context, manage_memory),
|
||||||
Statement::While(r#while) => r#while.item.run(context, manage_memory),
|
Statement::While(r#while) => r#while.node.run(context, manage_memory),
|
||||||
};
|
};
|
||||||
|
|
||||||
if manage_memory {
|
if manage_memory {
|
||||||
@ -105,3 +91,15 @@ impl AbstractNode for Statement {
|
|||||||
result
|
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 {
|
impl AbstractNode for StructureDefinition {
|
||||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
|
||||||
Ok(Type::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
|
@ -58,27 +58,27 @@ impl Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Type::ListOf(left), Type::ListOf(right)) => {
|
(Type::ListOf(left), Type::ListOf(right)) => {
|
||||||
if let Ok(()) = left.item.check(&right.item) {
|
if let Ok(()) = left.node.check(&right.node) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Type::ListOf(list_of), Type::ListExact(list_exact)) => {
|
(Type::ListOf(list_of), Type::ListExact(list_exact)) => {
|
||||||
for r#type in list_exact {
|
for r#type in list_exact {
|
||||||
list_of.item.check(&r#type.item)?;
|
list_of.node.check(&r#type.node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
(Type::ListExact(list_exact), Type::ListOf(list_of)) => {
|
(Type::ListExact(list_exact), Type::ListOf(list_of)) => {
|
||||||
for r#type in list_exact {
|
for r#type in list_exact {
|
||||||
r#type.item.check(&list_of.item)?;
|
r#type.node.check(&list_of.node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
(Type::ListExact(left), Type::ListExact(right)) => {
|
(Type::ListExact(left), Type::ListExact(right)) => {
|
||||||
for (left, right) in left.iter().zip(right.iter()) {
|
for (left, right) in left.iter().zip(right.iter()) {
|
||||||
left.item.check(&right.item)?;
|
left.node.check(&right.node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -97,7 +97,7 @@ impl Type {
|
|||||||
for ((left_field_name, left_type), (right_field_name, right_type)) in
|
for ((left_field_name, left_type), (right_field_name, right_type)) in
|
||||||
left_fields.iter().zip(right_fields.iter())
|
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 {
|
return Err(TypeConflict {
|
||||||
actual: other.clone(),
|
actual: other.clone(),
|
||||||
@ -119,11 +119,11 @@ impl Type {
|
|||||||
return_type: right_return,
|
return_type: right_return,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
if left_return.item == right_return.item {
|
if left_return.node == right_return.node {
|
||||||
for (left_parameter, right_parameter) in
|
for (left_parameter, right_parameter) in
|
||||||
left_parameters.iter().zip(right_parameters.iter())
|
left_parameters.iter().zip(right_parameters.iter())
|
||||||
{
|
{
|
||||||
if left_parameter.item != right_parameter.item {
|
if left_parameter.node != right_parameter.node {
|
||||||
return Err(TypeConflict {
|
return Err(TypeConflict {
|
||||||
actual: other.clone(),
|
actual: other.clone(),
|
||||||
expected: self.clone(),
|
expected: self.clone(),
|
||||||
@ -145,10 +145,6 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Type {
|
impl AbstractNode for Type {
|
||||||
fn expected_type(&self, _: &mut Context) -> Result<Type, ValidationError> {
|
|
||||||
Ok(Type::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
@ -170,15 +166,15 @@ impl Display for Type {
|
|||||||
Type::Float => write!(f, "float"),
|
Type::Float => write!(f, "float"),
|
||||||
Type::Integer => write!(f, "int"),
|
Type::Integer => write!(f, "int"),
|
||||||
Type::List => write!(f, "list"),
|
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) => {
|
Type::ListExact(item_types) => {
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
|
|
||||||
for (index, item_type) in item_types.into_iter().enumerate() {
|
for (index, item_type) in item_types.into_iter().enumerate() {
|
||||||
if index == item_types.len() - 1 {
|
if index == item_types.len() - 1 {
|
||||||
write!(f, "{}", item_type.item)?;
|
write!(f, "{}", item_type.node)?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}, ", item_type.item)?;
|
write!(f, "{}, ", item_type.node)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,10 +191,10 @@ impl Display for Type {
|
|||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
|
|
||||||
for r#type in parameter_types {
|
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::Structure { name, .. } => write!(f, "{name}"),
|
||||||
Type::Argument(identifier) => write!(f, "{identifier}"),
|
Type::Argument(identifier) => write!(f, "{identifier}"),
|
||||||
|
@ -9,22 +9,18 @@ use crate::{
|
|||||||
use super::{AbstractNode, Action, Type, WithPosition};
|
use super::{AbstractNode, Action, Type, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct TypeAlias {
|
pub struct TypeAssignment {
|
||||||
identifier: WithPosition<Identifier>,
|
identifier: WithPosition<Identifier>,
|
||||||
r#type: WithPosition<Type>,
|
r#type: WithPosition<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeAlias {
|
impl TypeAssignment {
|
||||||
pub fn new(identifier: WithPosition<Identifier>, r#type: WithPosition<Type>) -> Self {
|
pub fn new(identifier: WithPosition<Identifier>, r#type: WithPosition<Type>) -> Self {
|
||||||
Self { identifier, r#type }
|
Self { identifier, r#type }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for TypeAlias {
|
impl AbstractNode for TypeAssignment {
|
||||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
|
||||||
Ok(Type::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
@ -34,7 +30,7 @@ impl AbstractNode for TypeAlias {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &mut Context, _manage_memory: bool) -> Result<Action, RuntimeError> {
|
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)
|
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,
|
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)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ValueNode {
|
pub enum ValueNode {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
List(Vec<Expression>),
|
List(Vec<ValueExpression>),
|
||||||
Map(Vec<(Identifier, Option<WithPosition<Type>>, Expression)>),
|
Map(Vec<(Identifier, Option<WithPosition<Type>>, ValueExpression)>),
|
||||||
Range(Range<i64>),
|
Range(Range<i64>),
|
||||||
String(String),
|
String(String),
|
||||||
Structure {
|
Structure {
|
||||||
name: WithPosition<Identifier>,
|
name: WithPosition<Identifier>,
|
||||||
fields: Vec<(Identifier, Expression)>,
|
fields: Vec<(Identifier, ValueExpression)>,
|
||||||
},
|
},
|
||||||
ParsedFunction {
|
ParsedFunction {
|
||||||
type_arguments: Vec<WithPosition<Type>>,
|
type_arguments: Vec<WithPosition<Type>>,
|
||||||
@ -33,66 +35,6 @@ pub enum ValueNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for 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> {
|
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
if let ValueNode::Map(map_assignments) = self {
|
if let ValueNode::Map(map_assignments) = self {
|
||||||
for (_identifier, r#type, expression) in map_assignments {
|
for (_identifier, r#type, expression) in map_assignments {
|
||||||
@ -101,7 +43,7 @@ impl AbstractNode for ValueNode {
|
|||||||
if let Some(expected_type) = r#type {
|
if let Some(expected_type) = r#type {
|
||||||
let actual_type = expression.expected_type(context)?;
|
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 {
|
ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: expression.position(),
|
actual_position: expression.position(),
|
||||||
@ -124,21 +66,21 @@ impl AbstractNode for ValueNode {
|
|||||||
let mut function_context = Context::new(Some(&context));
|
let mut function_context = Context::new(Some(&context));
|
||||||
|
|
||||||
for r#type in type_arguments {
|
for r#type in type_arguments {
|
||||||
if let Type::Argument(identifier) = &r#type.item {
|
if let Type::Argument(identifier) = &r#type.node {
|
||||||
function_context.set_type(identifier.clone(), r#type.item.clone())?;
|
function_context.set_type(identifier.clone(), r#type.node.clone())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (identifier, r#type) in parameters {
|
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
|
return_type
|
||||||
.item
|
.node
|
||||||
.check(&actual_return_type)
|
.check(&actual_return_type)
|
||||||
.map_err(|conflict| ValidationError::TypeCheck {
|
.map_err(|conflict| ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
@ -154,9 +96,9 @@ impl AbstractNode for ValueNode {
|
|||||||
fields: expressions,
|
fields: expressions,
|
||||||
} = self
|
} = self
|
||||||
{
|
{
|
||||||
if !context.contains(&name.item)? {
|
if !context.contains(&name.node)? {
|
||||||
return Err(ValidationError::VariableNotFound {
|
return Err(ValidationError::VariableNotFound {
|
||||||
identifier: name.item.clone(),
|
identifier: name.node.clone(),
|
||||||
position: name.position,
|
position: name.position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -164,12 +106,12 @@ impl AbstractNode for ValueNode {
|
|||||||
if let Some(Type::Structure {
|
if let Some(Type::Structure {
|
||||||
name: _,
|
name: _,
|
||||||
fields: types,
|
fields: types,
|
||||||
}) = context.get_type(&name.item)?
|
}) = context.get_type(&name.node)?
|
||||||
{
|
{
|
||||||
for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
|
for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
|
||||||
let actual_type = expression.expected_type(context)?;
|
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 {
|
ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: expression.position(),
|
actual_position: expression.position(),
|
||||||
@ -196,7 +138,7 @@ impl AbstractNode for ValueNode {
|
|||||||
let action = expression.run(_context, _manage_memory)?;
|
let action = expression.run(_context, _manage_memory)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
WithPosition {
|
WithPosition {
|
||||||
item: value,
|
node: value,
|
||||||
position: expression_position,
|
position: expression_position,
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Expression, Statement, Type};
|
use super::{AbstractNode, Action, Statement, ValueExpression};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct While {
|
pub struct While {
|
||||||
expression: Expression,
|
expression: ValueExpression,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl While {
|
impl While {
|
||||||
pub fn new(expression: Expression, statements: Vec<Statement>) -> Self {
|
pub fn new(expression: ValueExpression, statements: Vec<Statement>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
expression,
|
expression,
|
||||||
statements,
|
statements,
|
||||||
@ -25,10 +25,6 @@ impl While {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for While {
|
impl AbstractNode for While {
|
||||||
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> {
|
|
||||||
Ok(Type::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(
|
fn validate(
|
||||||
&self,
|
&self,
|
||||||
_context: &mut Context,
|
_context: &mut Context,
|
||||||
|
@ -403,7 +403,7 @@ impl InterpreterError {
|
|||||||
.with_message(format!("This has type {}.", actual.fg(type_color),)),
|
.with_message(format!("This has type {}.", actual.fg(type_color),)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ValidationError::ExpectedString { actual, position } => todo!(),
|
ValidationError::ExpectedString { .. } => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let report = builder.finish();
|
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() {
|
for (index, value) in list.into_iter().enumerate() {
|
||||||
if index == list.len() - 1 {
|
if index == list.len() - 1 {
|
||||||
write!(f, "{}", value.item)?;
|
write!(f, "{}", value.node)?;
|
||||||
} else {
|
} 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() {
|
for (index, r#type) in type_arguments.into_iter().enumerate() {
|
||||||
if index == type_arguments.len() - 1 {
|
if index == type_arguments.len() - 1 {
|
||||||
write!(f, "{}", r#type.item)?;
|
write!(f, "{}", r#type.node)?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{} ", r#type.item)?;
|
write!(f, "{} ", r#type.node)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,13 +151,13 @@ impl Display for Value {
|
|||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
|
|
||||||
for (identifier, r#type) in parameters {
|
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 } => {
|
ValueInner::Structure { name, fields } => {
|
||||||
write!(f, "{}\n{{", name.item)?;
|
write!(f, "{}\n{{", name.node)?;
|
||||||
|
|
||||||
for (key, value) in fields {
|
for (key, value) in fields {
|
||||||
writeln!(f, "{key} = {value},")?;
|
writeln!(f, "{key} = {value},")?;
|
||||||
@ -184,7 +184,7 @@ impl Ord for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize 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
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
@ -193,7 +193,7 @@ impl Serialize for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> 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
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
@ -227,7 +227,7 @@ impl ValueInner {
|
|||||||
let mut types = Vec::with_capacity(values.len());
|
let mut types = Vec::with_capacity(values.len());
|
||||||
|
|
||||||
for value in values {
|
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)
|
Type::ListExact(types)
|
||||||
@ -244,11 +244,11 @@ impl ValueInner {
|
|||||||
return_type: Box::new(function.return_type.clone()),
|
return_type: Box::new(function.return_type.clone()),
|
||||||
},
|
},
|
||||||
ValueInner::Structure { name, .. } => {
|
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
|
r#type
|
||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::VariableNotFound {
|
return Err(ValidationError::VariableNotFound {
|
||||||
identifier: name.item.clone(),
|
identifier: name.node.clone(),
|
||||||
position: name.position,
|
position: name.position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -342,6 +342,6 @@ impl Function {
|
|||||||
context.set_value(identifier.clone(), value)?;
|
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]
|
#[test]
|
||||||
fn callback() {
|
fn callback() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use dust_lang::{
|
use dust_lang::{
|
||||||
abstract_tree::{Block, Expression, Statement, Type, WithPos},
|
abstract_tree::{Block, Statement, Type, ValueExpression, WithPos},
|
||||||
error::{Error, TypeConflict, ValidationError},
|
error::{Error, TypeConflict, ValidationError},
|
||||||
identifier::Identifier,
|
identifier::Identifier,
|
||||||
*,
|
*,
|
||||||
@ -49,9 +49,9 @@ fn function_variable() {
|
|||||||
Vec::with_capacity(0),
|
Vec::with_capacity(0),
|
||||||
vec![(Identifier::new("x"), Type::Integer.with_position((16, 19)))],
|
vec![(Identifier::new("x"), Type::Integer.with_position((16, 19)))],
|
||||||
Type::Integer.with_position((21, 24)),
|
Type::Integer.with_position((21, 24)),
|
||||||
Block::new(vec![Statement::Expression(Expression::Identifier(
|
Block::new(vec![Statement::ValueExpression(
|
||||||
Identifier::new("x").with_position((27, 28))
|
ValueExpression::Identifier(Identifier::new("x").with_position((27, 28)))
|
||||||
))])
|
)])
|
||||||
.with_position((25, 30))
|
.with_position((25, 30))
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user