Overhaul AST
This commit is contained in:
parent
4b460c0e68
commit
e50b231958
@ -1,17 +1,18 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
value::ValueInner,
|
value::ValueInner,
|
||||||
Context, Value,
|
Context, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Identifier, Statement, Type, WithPosition};
|
use super::{AbstractNode, Action, Statement, Type, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Assignment {
|
pub struct Assignment {
|
||||||
identifier: WithPosition<Identifier>,
|
identifier: WithPosition<Identifier>,
|
||||||
r#type: Option<WithPosition<Type>>,
|
r#type: Option<WithPosition<Type>>,
|
||||||
operator: AssignmentOperator,
|
operator: AssignmentOperator,
|
||||||
statement: Box<WithPosition<Statement>>,
|
statement: Box<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -26,7 +27,7 @@ impl Assignment {
|
|||||||
identifier: WithPosition<Identifier>,
|
identifier: WithPosition<Identifier>,
|
||||||
r#type: Option<WithPosition<Type>>,
|
r#type: Option<WithPosition<Type>>,
|
||||||
operator: AssignmentOperator,
|
operator: AssignmentOperator,
|
||||||
statement: WithPosition<Statement>,
|
statement: Statement,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
identifier,
|
identifier,
|
||||||
@ -43,7 +44,7 @@ impl AbstractNode for Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
let statement_type = self.statement.node.expected_type(context)?;
|
let statement_type = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
if let Some(WithPosition {
|
if let Some(WithPosition {
|
||||||
node: expected_type,
|
node: expected_type,
|
||||||
@ -53,7 +54,7 @@ impl AbstractNode for Assignment {
|
|||||||
expected_type.check(&statement_type).map_err(|conflict| {
|
expected_type.check(&statement_type).map_err(|conflict| {
|
||||||
ValidationError::TypeCheck {
|
ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: self.statement.position,
|
actual_position: self.statement.position(),
|
||||||
expected_position: expected_position.clone(),
|
expected_position: expected_position.clone(),
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
@ -63,14 +64,13 @@ impl AbstractNode for Assignment {
|
|||||||
context.set_type(self.identifier.node.clone(), statement_type)?;
|
context.set_type(self.identifier.node.clone(), statement_type)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.identifier.node.validate(context)?;
|
self.statement.validate(context)?;
|
||||||
self.statement.node.validate(context)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let action = self.statement.node.run(context)?;
|
let action = self.statement.run(context)?;
|
||||||
let right = match action {
|
let right = match action {
|
||||||
Action::Return(value) => value,
|
Action::Return(value) => value,
|
||||||
r#break => return Ok(r#break),
|
r#break => return Ok(r#break),
|
||||||
@ -112,7 +112,10 @@ impl AbstractNode for Assignment {
|
|||||||
context.set_value(self.identifier.node, new_value)?;
|
context.set_value(self.identifier.node, new_value)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableNotFound(self.identifier.node),
|
ValidationError::VariableNotFound {
|
||||||
|
identifier: self.identifier.node,
|
||||||
|
position: self.identifier.position,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +151,10 @@ impl AbstractNode for Assignment {
|
|||||||
context.set_value(self.identifier.node, new_value)?;
|
context.set_value(self.identifier.node, new_value)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableNotFound(self.identifier.node),
|
ValidationError::VariableNotFound {
|
||||||
|
identifier: self.identifier.node,
|
||||||
|
position: self.identifier.position,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +181,9 @@ mod tests {
|
|||||||
Identifier::new("foobar").with_position((0, 0)),
|
Identifier::new("foobar").with_position((0, 0)),
|
||||||
None,
|
None,
|
||||||
AssignmentOperator::Assign,
|
AssignmentOperator::Assign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)),
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(42).with_position((0, 0)),
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
.run(&context)
|
.run(&context)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -198,7 +206,9 @@ mod tests {
|
|||||||
Identifier::new("foobar").with_position((0, 0)),
|
Identifier::new("foobar").with_position((0, 0)),
|
||||||
None,
|
None,
|
||||||
AssignmentOperator::AddAssign,
|
AssignmentOperator::AddAssign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(41))).with_position((0, 0)),
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(41).with_position((0, 0)),
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
.run(&context)
|
.run(&context)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -221,7 +231,9 @@ mod tests {
|
|||||||
Identifier::new("foobar").with_position((0, 0)),
|
Identifier::new("foobar").with_position((0, 0)),
|
||||||
None,
|
None,
|
||||||
AssignmentOperator::SubAssign,
|
AssignmentOperator::SubAssign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(1))).with_position((0, 0)),
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(1).with_position((0, 0)),
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
.run(&context)
|
.run(&context)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -241,7 +253,9 @@ mod tests {
|
|||||||
position: (0, 0).into(),
|
position: (0, 0).into(),
|
||||||
}),
|
}),
|
||||||
AssignmentOperator::Assign,
|
AssignmentOperator::Assign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)),
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(42).with_position((0, 0)),
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
.validate(&Context::new());
|
.validate(&Context::new());
|
||||||
|
|
||||||
|
@ -7,27 +7,27 @@ use crate::{
|
|||||||
error::{RuntimeError, RwLockPoisonError, ValidationError},
|
error::{RuntimeError, RwLockPoisonError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Statement, Type, WithPosition};
|
use super::{AbstractNode, Action, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct AsyncBlock {
|
pub struct AsyncBlock {
|
||||||
statements: Vec<WithPosition<Statement>>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncBlock {
|
impl AsyncBlock {
|
||||||
pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
|
pub fn new(statements: Vec<Statement>) -> Self {
|
||||||
Self { statements }
|
Self { statements }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for AsyncBlock {
|
impl AbstractNode for AsyncBlock {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
self.statements.last().unwrap().node.expected_type(_context)
|
self.statements.last().unwrap().expected_type(_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.node.validate(_context)?;
|
statement.validate(_context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -41,7 +41,7 @@ impl AbstractNode for AsyncBlock {
|
|||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map_first(|(index, statement)| {
|
.find_map_first(|(index, statement)| {
|
||||||
let result = statement.node.run(_context);
|
let result = statement.run(_context);
|
||||||
|
|
||||||
if index == statement_count - 1 {
|
if index == statement_count - 1 {
|
||||||
let get_write_lock = final_result.write();
|
let get_write_lock = final_result.write();
|
||||||
|
@ -3,19 +3,19 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Statement, Type, WithPosition};
|
use super::{AbstractNode, Action, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
statements: Vec<WithPosition<Statement>>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
|
pub fn new(statements: Vec<Statement>) -> Self {
|
||||||
Self { statements }
|
Self { statements }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_statement(&self) -> &WithPosition<Statement> {
|
pub fn last_statement(&self) -> &Statement {
|
||||||
self.statements.last().unwrap()
|
self.statements.last().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,7 +23,7 @@ impl Block {
|
|||||||
impl AbstractNode for Block {
|
impl AbstractNode for Block {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
if let Some(statement) = self.statements.last() {
|
if let Some(statement) = self.statements.last() {
|
||||||
statement.node.expected_type(_context)
|
statement.expected_type(_context)
|
||||||
} else {
|
} else {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ impl AbstractNode for Block {
|
|||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.node.validate(_context)?;
|
statement.validate(_context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -41,7 +41,7 @@ impl AbstractNode for Block {
|
|||||||
let mut previous = Action::None;
|
let mut previous = Action::None;
|
||||||
|
|
||||||
for statement in self.statements {
|
for statement in self.statements {
|
||||||
previous = statement.node.run(_context)?;
|
previous = statement.run(_context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(previous)
|
Ok(previous)
|
||||||
@ -60,9 +60,15 @@ 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(ValueNode::Integer(1))).with_position((0, 0)),
|
Statement::Expression(Expression::Value(
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(2))).with_position((0, 0)),
|
ValueNode::Integer(1).with_position((0, 0)),
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)),
|
)),
|
||||||
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(2).with_position((0, 0)),
|
||||||
|
)),
|
||||||
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(42).with_position((0, 0)),
|
||||||
|
)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -74,9 +80,12 @@ 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(ValueNode::String("42".to_string())))
|
Statement::Expression(Expression::Value(
|
||||||
.with_position((0, 0)),
|
ValueNode::String("42".to_string()).with_position((0, 0)),
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)),
|
)),
|
||||||
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(42).with_position((0, 0)),
|
||||||
|
)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))
|
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))
|
||||||
|
@ -1,58 +1,102 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AbstractNode, Action, FunctionCall, Identifier, ListIndex, Logic, MapIndex, Math, Type,
|
AbstractNode, Action, FunctionCall, ListIndex, Logic, MapIndex, Math, SourcePosition, Type,
|
||||||
ValueNode,
|
ValueNode, WithPosition,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(WithPosition<FunctionCall>),
|
||||||
Identifier(Identifier),
|
Identifier(WithPosition<Identifier>),
|
||||||
MapIndex(Box<MapIndex>),
|
MapIndex(WithPosition<Box<MapIndex>>),
|
||||||
ListIndex(Box<ListIndex>),
|
ListIndex(WithPosition<Box<ListIndex>>),
|
||||||
Logic(Box<Logic>),
|
Logic(WithPosition<Box<Logic>>),
|
||||||
Math(Box<Math>),
|
Math(WithPosition<Box<Math>>),
|
||||||
Value(ValueNode),
|
Value(WithPosition<ValueNode>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
pub fn position(&self) -> SourcePosition {
|
||||||
|
match self {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Expression {
|
impl AbstractNode for Expression {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::FunctionCall(function_call) => function_call.expected_type(_context),
|
Expression::FunctionCall(function_call) => function_call.node.expected_type(_context),
|
||||||
Expression::Identifier(identifier) => identifier.expected_type(_context),
|
Expression::Identifier(identifier) => {
|
||||||
Expression::MapIndex(map_index) => map_index.expected_type(_context),
|
if let Some(r#type) = _context.get_type(&identifier.node)? {
|
||||||
Expression::ListIndex(list_index) => list_index.expected_type(_context),
|
Ok(r#type)
|
||||||
Expression::Logic(logic) => logic.expected_type(_context),
|
} else {
|
||||||
Expression::Math(math) => math.expected_type(_context),
|
Err(ValidationError::VariableNotFound {
|
||||||
Expression::Value(value_node) => value_node.expected_type(_context),
|
identifier: identifier.node.clone(),
|
||||||
|
position: identifier.position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::MapIndex(map_index) => map_index.node.expected_type(_context),
|
||||||
|
Expression::ListIndex(list_index) => list_index.node.expected_type(_context),
|
||||||
|
Expression::Logic(logic) => logic.node.expected_type(_context),
|
||||||
|
Expression::Math(math) => math.node.expected_type(_context),
|
||||||
|
Expression::Value(value_node) => value_node.node.expected_type(_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::FunctionCall(function_call) => function_call.validate(_context),
|
Expression::FunctionCall(function_call) => function_call.node.validate(context),
|
||||||
Expression::Identifier(identifier) => identifier.validate(_context),
|
Expression::Identifier(identifier) => {
|
||||||
Expression::MapIndex(map_index) => map_index.validate(_context),
|
if context.contains(&identifier.node)? {
|
||||||
Expression::ListIndex(list_index) => list_index.validate(_context),
|
Ok(())
|
||||||
Expression::Logic(logic) => logic.validate(_context),
|
} else {
|
||||||
Expression::Math(math) => math.validate(_context),
|
Err(ValidationError::VariableNotFound {
|
||||||
Expression::Value(value_node) => value_node.validate(_context),
|
identifier: identifier.node.clone(),
|
||||||
|
position: identifier.position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::MapIndex(map_index) => map_index.node.validate(context),
|
||||||
|
Expression::ListIndex(list_index) => list_index.node.validate(context),
|
||||||
|
Expression::Logic(logic) => logic.node.validate(context),
|
||||||
|
Expression::Math(math) => math.node.validate(context),
|
||||||
|
Expression::Value(value_node) => value_node.node.validate(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::FunctionCall(function_call) => function_call.run(_context),
|
Expression::FunctionCall(function_call) => function_call.node.run(_context),
|
||||||
Expression::Identifier(identifier) => identifier.run(_context),
|
Expression::Identifier(identifier) => {
|
||||||
Expression::MapIndex(map_index) => map_index.run(_context),
|
if let Some(value) = _context.get_value(&identifier.node)? {
|
||||||
Expression::ListIndex(list_index) => list_index.run(_context),
|
Ok(Action::Return(value))
|
||||||
Expression::Logic(logic) => logic.run(_context),
|
} else {
|
||||||
Expression::Math(math) => math.run(_context),
|
Err(RuntimeError::ValidationFailure(
|
||||||
Expression::Value(value_node) => value_node.run(_context),
|
ValidationError::VariableNotFound {
|
||||||
|
identifier: identifier.node.clone(),
|
||||||
|
position: identifier.position,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::MapIndex(map_index) => map_index.node.run(_context),
|
||||||
|
Expression::ListIndex(list_index) => list_index.node.run(_context),
|
||||||
|
Expression::Logic(logic) => logic.node.run(_context),
|
||||||
|
Expression::Math(math) => math.node.run(_context),
|
||||||
|
Expression::Value(value_node) => value_node.node.run(_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,16 @@ use super::{AbstractNode, Action, Expression, Type, WithPosition};
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct FunctionCall {
|
pub struct FunctionCall {
|
||||||
function: Box<WithPosition<Expression>>,
|
function: Box<Expression>,
|
||||||
type_arguments: Vec<WithPosition<Type>>,
|
type_arguments: Vec<WithPosition<Type>>,
|
||||||
arguments: Vec<WithPosition<Expression>>,
|
arguments: Vec<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionCall {
|
impl FunctionCall {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
function: WithPosition<Expression>,
|
function: Expression,
|
||||||
type_arguments: Vec<WithPosition<Type>>,
|
type_arguments: Vec<WithPosition<Type>>,
|
||||||
arguments: Vec<WithPosition<Expression>>,
|
arguments: Vec<Expression>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
FunctionCall {
|
FunctionCall {
|
||||||
function: Box::new(function),
|
function: Box::new(function),
|
||||||
@ -29,24 +29,24 @@ impl FunctionCall {
|
|||||||
|
|
||||||
impl AbstractNode for FunctionCall {
|
impl AbstractNode for FunctionCall {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
let function_node_type = self.function.node.expected_type(_context)?;
|
let function_node_type = self.function.expected_type(_context)?;
|
||||||
|
|
||||||
if let Type::Function { return_type, .. } = function_node_type {
|
if let Type::Function { return_type, .. } = function_node_type {
|
||||||
Ok(return_type.node)
|
Ok(return_type.node)
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedFunction {
|
Err(ValidationError::ExpectedFunction {
|
||||||
actual: function_node_type,
|
actual: function_node_type,
|
||||||
position: self.function.position,
|
position: self.function.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
for expression in &self.arguments {
|
for expression in &self.arguments {
|
||||||
expression.node.validate(context)?;
|
expression.validate(context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_node_type = self.function.node.expected_type(context)?;
|
let function_node_type = self.function.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Function {
|
if let Type::Function {
|
||||||
parameter_types,
|
parameter_types,
|
||||||
@ -67,12 +67,12 @@ 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()) {
|
||||||
let actual = expression.node.expected_type(context)?;
|
let actual = expression.expected_type(context)?;
|
||||||
|
|
||||||
type_parameter.node.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(),
|
||||||
expected_position: type_parameter.position,
|
expected_position: type_parameter.position,
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
@ -82,18 +82,19 @@ impl AbstractNode for FunctionCall {
|
|||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedFunction {
|
Err(ValidationError::ExpectedFunction {
|
||||||
actual: function_node_type,
|
actual: function_node_type,
|
||||||
position: self.function.position,
|
position: self.function.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let action = self.function.node.run(context)?;
|
let function_position = self.function.position();
|
||||||
|
let action = self.function.run(context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(self.function.position),
|
ValidationError::InterpreterExpectedReturn(function_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let function = if let ValueInner::Function(function) = value.inner().as_ref() {
|
let function = if let ValueInner::Function(function) = value.inner().as_ref() {
|
||||||
@ -102,19 +103,20 @@ impl AbstractNode for FunctionCall {
|
|||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedFunction {
|
ValidationError::ExpectedFunction {
|
||||||
actual: value.r#type(context)?,
|
actual: value.r#type(context)?,
|
||||||
position: self.function.position,
|
position: function_position,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let mut arguments = Vec::with_capacity(self.arguments.len());
|
let mut arguments = Vec::with_capacity(self.arguments.len());
|
||||||
|
|
||||||
for expression in self.arguments {
|
for expression in self.arguments {
|
||||||
let action = expression.node.run(context)?;
|
let expression_position = expression.position();
|
||||||
|
let action = expression.run(context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(expression.position),
|
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fmt::{self, Display, Formatter},
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
context::Context,
|
|
||||||
error::{RuntimeError, ValidationError},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Type};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
|
||||||
pub struct Identifier(Arc<String>);
|
|
||||||
|
|
||||||
impl Identifier {
|
|
||||||
pub fn new<T: ToString>(string: T) -> Self {
|
|
||||||
Identifier(Arc::new(string.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
self.0.as_str()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AbstractNode for Identifier {
|
|
||||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
|
||||||
if let Some(r#type) = context.get_type(self)? {
|
|
||||||
Ok(r#type)
|
|
||||||
} else {
|
|
||||||
Err(ValidationError::VariableNotFound(self.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
|
||||||
if context.contains(self)? {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(ValidationError::VariableNotFound(self.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
|
||||||
let return_action = context.get_value(&self)?.map(|value| Action::Return(value));
|
|
||||||
|
|
||||||
if let Some(action) = return_action {
|
|
||||||
Ok(action)
|
|
||||||
} else {
|
|
||||||
Err(RuntimeError::ValidationFailure(
|
|
||||||
ValidationError::VariableNotFound(self.clone()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Identifier {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,24 +4,27 @@ use crate::{
|
|||||||
value::ValueInner,
|
value::ValueInner,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Block, Expression, Type, WithPosition};
|
use super::{AbstractNode, Action, Block, Expression, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct IfElse {
|
pub struct IfElse {
|
||||||
if_expression: WithPosition<Expression>,
|
if_expression: Expression,
|
||||||
if_block: Block,
|
if_block: Block,
|
||||||
|
else_ifs: Option<Vec<(Expression, Block)>>,
|
||||||
else_block: Option<Block>,
|
else_block: Option<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IfElse {
|
impl IfElse {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
if_expression: WithPosition<Expression>,
|
if_expression: Expression,
|
||||||
if_block: Block,
|
if_block: Block,
|
||||||
|
else_ifs: Option<Vec<(Expression, Block)>>,
|
||||||
else_block: Option<Block>,
|
else_block: Option<Block>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
if_expression,
|
if_expression,
|
||||||
if_block,
|
if_block,
|
||||||
|
else_ifs,
|
||||||
else_block,
|
else_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,10 +36,10 @@ impl AbstractNode for IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
self.if_expression.node.validate(context)?;
|
self.if_expression.validate(context)?;
|
||||||
self.if_block.validate(context)?;
|
self.if_block.validate(context)?;
|
||||||
|
|
||||||
let if_expression_type = self.if_expression.node.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 {
|
||||||
@ -49,8 +52,8 @@ impl AbstractNode for IfElse {
|
|||||||
.check(&actual)
|
.check(&actual)
|
||||||
.map_err(|conflict| ValidationError::TypeCheck {
|
.map_err(|conflict| ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: self.if_block.last_statement().position,
|
actual_position: self.if_block.last_statement().position(),
|
||||||
expected_position: self.if_expression.position,
|
expected_position: self.if_expression.position(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,18 +61,19 @@ impl AbstractNode for IfElse {
|
|||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedBoolean {
|
Err(ValidationError::ExpectedBoolean {
|
||||||
actual: if_expression_type,
|
actual: if_expression_type,
|
||||||
position: self.if_expression.position,
|
position: self.if_expression.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let action = self.if_expression.node.run(context)?;
|
let if_position = self.if_expression.position();
|
||||||
|
let action = self.if_expression.run(context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(self.if_expression.position),
|
ValidationError::InterpreterExpectedReturn(if_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,7 +89,7 @@ impl AbstractNode for IfElse {
|
|||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedBoolean {
|
ValidationError::ExpectedBoolean {
|
||||||
actual: value.r#type(context)?,
|
actual: value.r#type(context)?,
|
||||||
position: self.if_expression.position,
|
position: if_position,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -105,11 +109,11 @@ 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)),
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Block::new(vec![Statement::Expression(Expression::Value(
|
Block::new(vec![Statement::Expression(Expression::Value(
|
||||||
ValueNode::String("foo".to_string())
|
ValueNode::String("foo".to_string()).with_position((0, 0))
|
||||||
))
|
))]),
|
||||||
.with_position((0, 0))]),
|
None,
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
.run(&Context::new())
|
.run(&Context::new())
|
||||||
@ -117,24 +121,4 @@ mod tests {
|
|||||||
Action::Return(Value::string("foo".to_string()))
|
Action::Return(Value::string("foo".to_string()))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn simple_if_else() {
|
|
||||||
assert_eq!(
|
|
||||||
IfElse::new(
|
|
||||||
Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),
|
|
||||||
Block::new(vec![Statement::Expression(Expression::Value(
|
|
||||||
ValueNode::String("foo".to_string())
|
|
||||||
))
|
|
||||||
.with_position((0, 0))]),
|
|
||||||
Some(Block::new(vec![Statement::Expression(Expression::Value(
|
|
||||||
ValueNode::String("bar".to_string())
|
|
||||||
))
|
|
||||||
.with_position((0, 0))]))
|
|
||||||
)
|
|
||||||
.run(&Context::new())
|
|
||||||
.unwrap(),
|
|
||||||
Action::Return(Value::string("bar".to_string()))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,24 +7,30 @@ use super::{AbstractNode, Action, Expression, Type, ValueNode, WithPosition};
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct ListIndex {
|
pub struct ListIndex {
|
||||||
left: WithPosition<Expression>,
|
left: Expression,
|
||||||
right: WithPosition<Expression>,
|
right: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListIndex {
|
impl ListIndex {
|
||||||
pub fn new(left: WithPosition<Expression>, right: WithPosition<Expression>) -> Self {
|
pub fn new(left: Expression, right: Expression) -> Self {
|
||||||
Self { left, right }
|
Self { left, right }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for ListIndex {
|
impl AbstractNode for ListIndex {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
let left_type = self.left.node.expected_type(_context)?;
|
let left_type = self.left.expected_type(_context)?;
|
||||||
|
|
||||||
if let (
|
if let (
|
||||||
Expression::Value(ValueNode::List(expression_list)),
|
Expression::Value(WithPosition {
|
||||||
Expression::Value(ValueNode::Integer(index)),
|
node: ValueNode::List(expression_list),
|
||||||
) = (&self.left.node, &self.right.node)
|
..
|
||||||
|
}),
|
||||||
|
Expression::Value(WithPosition {
|
||||||
|
node: ValueNode::Integer(index),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
) = (&self.left, &self.right)
|
||||||
{
|
{
|
||||||
let expression = if let Some(expression) = expression_list.get(*index as usize) {
|
let expression = if let Some(expression) = expression_list.get(*index as usize) {
|
||||||
expression
|
expression
|
||||||
@ -32,57 +38,59 @@ impl AbstractNode for ListIndex {
|
|||||||
return Ok(Type::None);
|
return Ok(Type::None);
|
||||||
};
|
};
|
||||||
|
|
||||||
expression.node.expected_type(_context)
|
expression.expected_type(_context)
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::CannotIndex {
|
Err(ValidationError::CannotIndex {
|
||||||
r#type: left_type,
|
r#type: left_type,
|
||||||
position: self.left.position,
|
position: self.left.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
let left_type = self.left.node.expected_type(context)?;
|
let left_type = self.left.expected_type(context)?;
|
||||||
|
|
||||||
match left_type {
|
match left_type {
|
||||||
Type::List => todo!(),
|
Type::List => todo!(),
|
||||||
Type::ListOf(_) => todo!(),
|
Type::ListOf(_) => todo!(),
|
||||||
Type::ListExact(_) => {
|
Type::ListExact(_) => {
|
||||||
let right_type = self.right.node.expected_type(context)?;
|
let right_type = self.right.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Integer = right_type {
|
if let Type::Integer = right_type {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::CannotIndexWith {
|
Err(ValidationError::CannotIndexWith {
|
||||||
collection_type: left_type,
|
collection_type: left_type,
|
||||||
collection_position: self.left.position,
|
collection_position: self.left.position(),
|
||||||
index_type: right_type,
|
index_type: right_type,
|
||||||
index_position: self.right.position,
|
index_position: self.right.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(ValidationError::CannotIndex {
|
_ => Err(ValidationError::CannotIndex {
|
||||||
r#type: left_type,
|
r#type: left_type,
|
||||||
position: self.left.position,
|
position: self.left.position(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let left_action = self.left.node.run(context)?;
|
let left_position = self.left.position();
|
||||||
|
let left_action = self.left.run(context)?;
|
||||||
let left_value = if let Action::Return(value) = left_action {
|
let left_value = if let Action::Return(value) = left_action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(self.left.position),
|
ValidationError::InterpreterExpectedReturn(left_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let right_action = self.right.node.run(context)?;
|
let right_position = self.right.position();
|
||||||
|
let right_action = self.right.run(context)?;
|
||||||
let right_value = if let Action::Return(value) = right_action {
|
let right_value = if let Action::Return(value) = right_action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(self.left.position),
|
ValidationError::InterpreterExpectedReturn(right_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,9 +106,9 @@ impl AbstractNode for ListIndex {
|
|||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::CannotIndexWith {
|
ValidationError::CannotIndexWith {
|
||||||
collection_type: left_value.r#type(context)?,
|
collection_type: left_value.r#type(context)?,
|
||||||
collection_position: self.left.position,
|
collection_position: left_position,
|
||||||
index_type: right_value.r#type(context)?,
|
index_type: right_value.r#type(context)?,
|
||||||
index_position: self.right.position,
|
index_position: right_position,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -5,19 +5,19 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Expression, Type, WithPosition};
|
use super::{AbstractNode, Action, Expression, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Logic {
|
pub enum Logic {
|
||||||
Equal(WithPosition<Expression>, WithPosition<Expression>),
|
Equal(Expression, Expression),
|
||||||
NotEqual(WithPosition<Expression>, WithPosition<Expression>),
|
NotEqual(Expression, Expression),
|
||||||
Greater(WithPosition<Expression>, WithPosition<Expression>),
|
Greater(Expression, Expression),
|
||||||
Less(WithPosition<Expression>, WithPosition<Expression>),
|
Less(Expression, Expression),
|
||||||
GreaterOrEqual(WithPosition<Expression>, WithPosition<Expression>),
|
GreaterOrEqual(Expression, Expression),
|
||||||
LessOrEqual(WithPosition<Expression>, WithPosition<Expression>),
|
LessOrEqual(Expression, Expression),
|
||||||
And(WithPosition<Expression>, WithPosition<Expression>),
|
And(Expression, Expression),
|
||||||
Or(WithPosition<Expression>, WithPosition<Expression>),
|
Or(Expression, Expression),
|
||||||
Not(WithPosition<Expression>),
|
Not(Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Logic {
|
impl AbstractNode for Logic {
|
||||||
@ -33,28 +33,28 @@ impl AbstractNode for Logic {
|
|||||||
| Logic::Less(left, right)
|
| Logic::Less(left, right)
|
||||||
| Logic::GreaterOrEqual(left, right)
|
| Logic::GreaterOrEqual(left, right)
|
||||||
| Logic::LessOrEqual(left, right) => {
|
| Logic::LessOrEqual(left, right) => {
|
||||||
let left_type = left.node.expected_type(context)?;
|
let left_type = left.expected_type(context)?;
|
||||||
let right_type = right.node.expected_type(context)?;
|
let right_type = right.expected_type(context)?;
|
||||||
|
|
||||||
left_type
|
left_type
|
||||||
.check(&right_type)
|
.check(&right_type)
|
||||||
.map_err(|conflict| ValidationError::TypeCheck {
|
.map_err(|conflict| ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position: left.position,
|
actual_position: left.position(),
|
||||||
expected_position: right.position,
|
expected_position: right.position(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Logic::And(left, right) | Logic::Or(left, right) => {
|
Logic::And(left, right) | Logic::Or(left, right) => {
|
||||||
let left_type = left.node.expected_type(context)?;
|
let left_type = left.expected_type(context)?;
|
||||||
let right_type = right.node.expected_type(context)?;
|
let right_type = right.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Boolean = left_type {
|
if let Type::Boolean = left_type {
|
||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::ExpectedBoolean {
|
return Err(ValidationError::ExpectedBoolean {
|
||||||
actual: left_type,
|
actual: left_type,
|
||||||
position: left.position,
|
position: left.position(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,21 +62,21 @@ impl AbstractNode for Logic {
|
|||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::ExpectedBoolean {
|
return Err(ValidationError::ExpectedBoolean {
|
||||||
actual: right_type,
|
actual: right_type,
|
||||||
position: right.position,
|
position: right.position(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Logic::Not(expression) => {
|
Logic::Not(expression) => {
|
||||||
let expression_type = expression.node.expected_type(context)?;
|
let expression_type = expression.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Boolean = expression_type {
|
if let Type::Boolean = expression_type {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedBoolean {
|
Err(ValidationError::ExpectedBoolean {
|
||||||
actual: expression_type,
|
actual: expression_type,
|
||||||
position: expression.position,
|
position: expression.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,28 +84,28 @@ impl AbstractNode for Logic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let run_and_expect_value =
|
let run_and_expect_value = |expression: Expression| -> Result<Value, RuntimeError> {
|
||||||
|expression: WithPosition<Expression>| -> Result<Value, RuntimeError> {
|
let expression_position = expression.position();
|
||||||
let action = expression.node.run(context)?;
|
let action = expression.run(context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(expression.position),
|
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
};
|
};
|
||||||
|
|
||||||
let run_and_expect_boolean =
|
let run_and_expect_boolean = |expression: Expression| -> Result<bool, RuntimeError> {
|
||||||
|expression: WithPosition<Expression>| -> Result<bool, RuntimeError> {
|
let expression_position = expression.position();
|
||||||
let action = expression.node.run(context)?;
|
let action = expression.run(context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(expression.position),
|
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ impl AbstractNode for Logic {
|
|||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedBoolean {
|
ValidationError::ExpectedBoolean {
|
||||||
actual: value.r#type(context)?,
|
actual: value.r#type(context)?,
|
||||||
position: expression.position,
|
position: expression_position,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -195,8 +195,8 @@ mod tests {
|
|||||||
fn equal() {
|
fn equal() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Equal(
|
Logic::Equal(
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -207,8 +207,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)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(43)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -219,8 +219,8 @@ mod tests {
|
|||||||
fn greater() {
|
fn greater() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Greater(
|
Logic::Greater(
|
||||||
Expression::Value(ValueNode::Integer(43)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -231,8 +231,8 @@ mod tests {
|
|||||||
fn less() {
|
fn less() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Less(
|
Logic::Less(
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(43)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -243,8 +243,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)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(41)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -252,8 +252,8 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::GreaterOrEqual(
|
Logic::GreaterOrEqual(
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -264,8 +264,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)),
|
Expression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -273,8 +273,8 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::LessOrEqual(
|
Logic::LessOrEqual(
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -285,8 +285,8 @@ mod tests {
|
|||||||
fn and() {
|
fn and() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::And(
|
Logic::And(
|
||||||
Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)),
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)),
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -297,8 +297,8 @@ mod tests {
|
|||||||
fn or() {
|
fn or() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Or(
|
Logic::Or(
|
||||||
Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)),
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),
|
Expression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
@ -308,7 +308,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn not() {
|
fn not() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Logic::Not(Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),)
|
Logic::Not(Expression::Value(
|
||||||
|
ValueNode::Boolean(false).with_position((0, 0))
|
||||||
|
))
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::boolean(true)))
|
Ok(Action::Return(Value::boolean(true)))
|
||||||
)
|
)
|
||||||
|
@ -5,15 +5,15 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Statement, Type, WithPosition};
|
use super::{AbstractNode, Action, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Loop {
|
pub struct Loop {
|
||||||
statements: Vec<WithPosition<Statement>>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Loop {
|
impl Loop {
|
||||||
pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
|
pub fn new(statements: Vec<Statement>) -> Self {
|
||||||
Self { statements }
|
Self { statements }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ impl AbstractNode for Loop {
|
|||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.node.validate(_context)?;
|
statement.validate(_context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -34,7 +34,7 @@ impl AbstractNode for Loop {
|
|||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
loop {
|
loop {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
let action = statement.node.clone().run(_context)?;
|
let action = statement.clone().run(_context)?;
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
Action::Return(_) => {}
|
Action::Return(_) => {}
|
||||||
@ -70,9 +70,9 @@ impl Ord for Loop {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{
|
abstract_tree::{
|
||||||
Assignment, AssignmentOperator, Block, Expression, Identifier, IfElse, Logic,
|
Assignment, AssignmentOperator, Block, Expression, IfElse, Logic, ValueNode, WithPos,
|
||||||
ValueNode, WithPos,
|
|
||||||
},
|
},
|
||||||
|
identifier::Identifier,
|
||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_loop() {
|
fn basic_loop() {
|
||||||
let action = Loop::new(vec![Statement::Break.with_position((0, 0))])
|
let action = Loop::new(vec![Statement::Break(().with_position((0, 0)))])
|
||||||
.run(&Context::new())
|
.run(&Context::new())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -90,34 +90,48 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn complex_loop() {
|
fn complex_loop() {
|
||||||
let action = Block::new(vec![
|
let action = Block::new(vec![
|
||||||
Statement::Assignment(Assignment::new(
|
Statement::Assignment(
|
||||||
|
Assignment::new(
|
||||||
Identifier::new("i").with_position((0, 0)),
|
Identifier::new("i").with_position((0, 0)),
|
||||||
None,
|
None,
|
||||||
AssignmentOperator::Assign,
|
AssignmentOperator::Assign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(1).with_position((0, 0)),
|
||||||
|
)),
|
||||||
|
)
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
|
),
|
||||||
|
Statement::Loop(
|
||||||
|
Loop::new(vec![Statement::IfElse(
|
||||||
|
IfElse::new(
|
||||||
|
Expression::Logic(
|
||||||
|
Box::new(Logic::Greater(
|
||||||
|
Expression::Identifier(Identifier::new("i").with_position((0, 0))),
|
||||||
|
Expression::Value(ValueNode::Integer(2).with_position((0, 0))),
|
||||||
))
|
))
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
Statement::Loop(Loop::new(vec![Statement::IfElse(IfElse::new(
|
),
|
||||||
Expression::Logic(Box::new(Logic::Greater(
|
Block::new(vec![Statement::Break(().with_position((0, 0)))]),
|
||||||
Expression::Identifier(Identifier::new("i")).with_position((0, 0)),
|
None,
|
||||||
Expression::Value(ValueNode::Integer(2)).with_position((0, 0)),
|
Some(Block::new(vec![Statement::Assignment(
|
||||||
)))
|
Assignment::new(
|
||||||
.with_position((0, 0)),
|
|
||||||
Block::new(vec![Statement::Break.with_position((0, 0))]),
|
|
||||||
Some(Block::new(vec![Statement::Assignment(Assignment::new(
|
|
||||||
Identifier::new("i").with_position((0, 0)),
|
Identifier::new("i").with_position((0, 0)),
|
||||||
None,
|
None,
|
||||||
AssignmentOperator::AddAssign,
|
AssignmentOperator::AddAssign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(1).with_position((0, 0)),
|
||||||
|
)),
|
||||||
|
)
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
))
|
)])),
|
||||||
.with_position((0, 0))])),
|
)
|
||||||
))
|
|
||||||
.with_position((0, 0))]))
|
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
Statement::Expression(Expression::Identifier(Identifier::new("i")))
|
)])
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
|
),
|
||||||
|
Statement::Expression(Expression::Identifier(
|
||||||
|
Identifier::new("i").with_position((0, 0)),
|
||||||
|
)),
|
||||||
])
|
])
|
||||||
.run(&Context::new())
|
.run(&Context::new())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -8,12 +8,12 @@ use super::{AbstractNode, Action, Expression, Type, ValueNode, WithPosition};
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct MapIndex {
|
pub struct MapIndex {
|
||||||
left: WithPosition<Expression>,
|
left: Expression,
|
||||||
right: WithPosition<Expression>,
|
right: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapIndex {
|
impl MapIndex {
|
||||||
pub fn new(left: WithPosition<Expression>, right: WithPosition<Expression>) -> Self {
|
pub fn new(left: Expression, right: Expression) -> Self {
|
||||||
Self { left, right }
|
Self { left, right }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,40 +23,47 @@ impl AbstractNode for MapIndex {
|
|||||||
if let (
|
if let (
|
||||||
Expression::Identifier(collection_identifier),
|
Expression::Identifier(collection_identifier),
|
||||||
Expression::Identifier(index_identifier),
|
Expression::Identifier(index_identifier),
|
||||||
) = (&self.left.node, &self.right.node)
|
) = (&self.left, &self.right)
|
||||||
{
|
{
|
||||||
let collection = if let Some(collection) = context.get_value(collection_identifier)? {
|
let collection =
|
||||||
|
if let Some(collection) = context.get_value(&collection_identifier.node)? {
|
||||||
collection
|
collection
|
||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::VariableNotFound(
|
return Err(ValidationError::VariableNotFound {
|
||||||
collection_identifier.clone(),
|
identifier: collection_identifier.node.clone(),
|
||||||
));
|
position: collection_identifier.position,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if let ValueInner::Map(map) = collection.inner().as_ref() {
|
if let ValueInner::Map(map) = collection.inner().as_ref() {
|
||||||
return if let Some(value) = map.get(index_identifier) {
|
return if let Some(value) = map.get(&index_identifier.node) {
|
||||||
Ok(value.r#type(context)?)
|
Ok(value.r#type(context)?)
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::PropertyNotFound {
|
Err(ValidationError::PropertyNotFound {
|
||||||
identifier: index_identifier.clone(),
|
identifier: index_identifier.node.clone(),
|
||||||
position: self.right.position,
|
position: self.right.position(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Expression::Value(ValueNode::Map(properties)), Expression::Identifier(identifier)) =
|
if let (
|
||||||
(&self.left.node, &self.right.node)
|
Expression::Value(WithPosition {
|
||||||
|
node: ValueNode::Map(properties),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
Expression::Identifier(identifier),
|
||||||
|
) = (&self.left, &self.right)
|
||||||
{
|
{
|
||||||
return if let Some(type_result) =
|
return if let Some(type_result) =
|
||||||
properties
|
properties
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|(property, type_option, expression)| {
|
.find_map(|(property, type_option, expression)| {
|
||||||
if property == identifier {
|
if property == &identifier.node {
|
||||||
if let Some(r#type) = type_option {
|
if let Some(r#type) = type_option {
|
||||||
Some(r#type.node.expected_type(context))
|
Some(r#type.node.expected_type(context))
|
||||||
} else {
|
} else {
|
||||||
Some(expression.node.expected_type(context))
|
Some(expression.expected_type(context))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -70,13 +77,16 @@ impl AbstractNode for MapIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let (
|
if let (
|
||||||
Expression::Value(ValueNode::Structure { fields, .. }),
|
Expression::Value(WithPosition {
|
||||||
|
node: ValueNode::Structure { fields, .. },
|
||||||
|
..
|
||||||
|
}),
|
||||||
Expression::Identifier(identifier),
|
Expression::Identifier(identifier),
|
||||||
) = (&self.left.node, &self.right.node)
|
) = (&self.left, &self.right)
|
||||||
{
|
{
|
||||||
return if let Some(type_result) = fields.iter().find_map(|(property, expression)| {
|
return if let Some(type_result) = fields.iter().find_map(|(property, expression)| {
|
||||||
if property == identifier {
|
if property == &identifier.node {
|
||||||
Some(expression.node.expected_type(context))
|
Some(expression.expected_type(context))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -88,49 +98,55 @@ impl AbstractNode for MapIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Err(ValidationError::CannotIndexWith {
|
Err(ValidationError::CannotIndexWith {
|
||||||
collection_type: self.left.node.expected_type(context)?,
|
collection_type: self.left.expected_type(context)?,
|
||||||
collection_position: self.left.position,
|
collection_position: self.left.position(),
|
||||||
index_type: self.right.node.expected_type(context)?,
|
index_type: self.right.expected_type(context)?,
|
||||||
index_position: self.right.position,
|
index_position: self.right.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
let left_type = self.left.node.expected_type(context)?;
|
let left_type = self.left.expected_type(context)?;
|
||||||
|
|
||||||
if let (Expression::Value(ValueNode::Map(_)), Expression::Identifier(_)) =
|
if let (
|
||||||
(&self.left.node, &self.right.node)
|
Expression::Value(WithPosition {
|
||||||
|
node: ValueNode::Map(_),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
Expression::Identifier(_),
|
||||||
|
) = (&self.left, &self.right)
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if let (Expression::Identifier(_), Expression::Identifier(_)) =
|
} else if let (Expression::Identifier(_), Expression::Identifier(_)) =
|
||||||
(&self.left.node, &self.right.node)
|
(&self.left, &self.right)
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::CannotIndexWith {
|
Err(ValidationError::CannotIndexWith {
|
||||||
collection_type: left_type,
|
collection_type: left_type,
|
||||||
collection_position: self.left.position,
|
collection_position: self.left.position(),
|
||||||
index_type: self.right.node.expected_type(context)?,
|
index_type: self.right.expected_type(context)?,
|
||||||
index_position: self.right.position,
|
index_position: self.right.position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let action = self.left.node.run(context)?;
|
let collection_position = self.left.position();
|
||||||
|
let action = self.left.run(context)?;
|
||||||
let collection = if let Action::Return(value) = action {
|
let collection = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(self.left.position),
|
ValidationError::InterpreterExpectedReturn(collection_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
if let (ValueInner::Map(map), Expression::Identifier(identifier)) =
|
if let (ValueInner::Map(map), Expression::Identifier(identifier)) =
|
||||||
(collection.inner().as_ref(), &self.right.node)
|
(collection.inner().as_ref(), &self.right)
|
||||||
{
|
{
|
||||||
let action = map
|
let action = map
|
||||||
.get(identifier)
|
.get(&identifier.node)
|
||||||
.map(|value| Action::Return(value.clone()))
|
.map(|value| Action::Return(value.clone()))
|
||||||
.unwrap_or(Action::None);
|
.unwrap_or(Action::None);
|
||||||
|
|
||||||
@ -139,9 +155,9 @@ impl AbstractNode for MapIndex {
|
|||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::CannotIndexWith {
|
ValidationError::CannotIndexWith {
|
||||||
collection_type: collection.r#type(context)?,
|
collection_type: collection.r#type(context)?,
|
||||||
collection_position: self.left.position,
|
collection_position,
|
||||||
index_type: self.right.node.expected_type(context)?,
|
index_type: self.right.expected_type(context)?,
|
||||||
index_position: self.right.position,
|
index_position: self.right.position(),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,15 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Expression, SourcePosition, Type, WithPosition};
|
use super::{AbstractNode, Action, Expression, SourcePosition, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Math {
|
pub enum Math {
|
||||||
Add(WithPosition<Expression>, WithPosition<Expression>),
|
Add(Expression, Expression),
|
||||||
Subtract(WithPosition<Expression>, WithPosition<Expression>),
|
Subtract(Expression, Expression),
|
||||||
Multiply(WithPosition<Expression>, WithPosition<Expression>),
|
Multiply(Expression, Expression),
|
||||||
Divide(WithPosition<Expression>, WithPosition<Expression>),
|
Divide(Expression, Expression),
|
||||||
Modulo(WithPosition<Expression>, WithPosition<Expression>),
|
Modulo(Expression, Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for Math {
|
impl AbstractNode for Math {
|
||||||
@ -24,8 +24,8 @@ impl AbstractNode for Math {
|
|||||||
| Math::Multiply(left, right)
|
| Math::Multiply(left, right)
|
||||||
| Math::Divide(left, right)
|
| Math::Divide(left, right)
|
||||||
| Math::Modulo(left, right) => {
|
| Math::Modulo(left, right) => {
|
||||||
let left_type = left.node.expected_type(_context)?;
|
let left_type = left.expected_type(_context)?;
|
||||||
let right_type = right.node.expected_type(_context)?;
|
let right_type = right.expected_type(_context)?;
|
||||||
|
|
||||||
if let Type::Float = left_type {
|
if let Type::Float = left_type {
|
||||||
return Ok(Type::Float);
|
return Ok(Type::Float);
|
||||||
@ -43,22 +43,25 @@ impl AbstractNode for Math {
|
|||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Math::Add(left, right) => {
|
Math::Add(left, right) => {
|
||||||
let left_type = left.node.expected_type(context)?;
|
let left_position = left.position();
|
||||||
let right_type = right.node.expected_type(context)?;
|
let left_type = left.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Integer | Type::Float | Type::String = left_type {
|
if let Type::Integer | Type::Float | Type::String = left_type {
|
||||||
|
let right_position = right.position();
|
||||||
|
let right_type = right.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Integer | Type::Float | Type::String = right_type {
|
if let Type::Integer | Type::Float | Type::String = right_type {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedIntegerFloatOrString {
|
Err(ValidationError::ExpectedIntegerFloatOrString {
|
||||||
actual: right_type,
|
actual: right_type,
|
||||||
position: right.position,
|
position: right_position,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedIntegerFloatOrString {
|
Err(ValidationError::ExpectedIntegerFloatOrString {
|
||||||
actual: left_type,
|
actual: left_type,
|
||||||
position: left.position,
|
position: left_position,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,17 +69,20 @@ impl AbstractNode for Math {
|
|||||||
| Math::Multiply(left, right)
|
| Math::Multiply(left, right)
|
||||||
| Math::Divide(left, right)
|
| Math::Divide(left, right)
|
||||||
| Math::Modulo(left, right) => {
|
| Math::Modulo(left, right) => {
|
||||||
let left_type = left.node.expected_type(context)?;
|
let left_position = left.position();
|
||||||
let right_type = right.node.expected_type(context)?;
|
let left_type = left.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Integer | Type::Float = left_type {
|
if let Type::Integer | Type::Float = left_type {
|
||||||
|
let right_position = right.position();
|
||||||
|
let right_type = right.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Integer | Type::Float = right_type {
|
if let Type::Integer | Type::Float = right_type {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedIntegerOrFloat(right.position))
|
Err(ValidationError::ExpectedIntegerOrFloat(right_position))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::ExpectedIntegerOrFloat(left.position))
|
Err(ValidationError::ExpectedIntegerOrFloat(left_position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +90,7 @@ impl AbstractNode for Math {
|
|||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let run_and_expect_value =
|
let run_and_expect_value =
|
||||||
|expression: Expression, position: SourcePosition| -> Result<Value, RuntimeError> {
|
|position: SourcePosition, expression: Expression| -> Result<Value, RuntimeError> {
|
||||||
let action = expression.run(_context)?;
|
let action = expression.run(_context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
@ -99,8 +105,10 @@ impl AbstractNode for Math {
|
|||||||
|
|
||||||
let value = match self {
|
let value = match self {
|
||||||
Math::Add(left, right) => {
|
Math::Add(left, right) => {
|
||||||
let left_value = run_and_expect_value(left.node, left.position)?;
|
let left_position = left.position();
|
||||||
let right_value = run_and_expect_value(right.node, right.position)?;
|
let left_value = run_and_expect_value(left_position, left)?;
|
||||||
|
let right_position = right.position();
|
||||||
|
let right_value = run_and_expect_value(right_position, right)?;
|
||||||
|
|
||||||
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
||||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||||
@ -132,19 +140,21 @@ impl AbstractNode for Math {
|
|||||||
}
|
}
|
||||||
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(right.position),
|
ValidationError::ExpectedIntegerOrFloat(right_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(left.position),
|
ValidationError::ExpectedIntegerOrFloat(left_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Math::Subtract(left, right) => {
|
Math::Subtract(left, right) => {
|
||||||
let left_value = run_and_expect_value(left.node, left.position)?;
|
let left_position = left.position();
|
||||||
let right_value = run_and_expect_value(right.node, right.position)?;
|
let left_value = run_and_expect_value(left_position, left)?;
|
||||||
|
let right_position = right.position();
|
||||||
|
let right_value = run_and_expect_value(right_position, right)?;
|
||||||
|
|
||||||
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
||||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||||
@ -169,19 +179,21 @@ impl AbstractNode for Math {
|
|||||||
}
|
}
|
||||||
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(right.position),
|
ValidationError::ExpectedIntegerOrFloat(right_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(left.position),
|
ValidationError::ExpectedIntegerOrFloat(left_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Math::Multiply(left, right) => {
|
Math::Multiply(left, right) => {
|
||||||
let left_value = run_and_expect_value(left.node, left.position)?;
|
let left_position = left.position();
|
||||||
let right_value = run_and_expect_value(right.node, right.position)?;
|
let left_value = run_and_expect_value(left_position, left)?;
|
||||||
|
let right_position = right.position();
|
||||||
|
let right_value = run_and_expect_value(right_position, right)?;
|
||||||
|
|
||||||
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
||||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||||
@ -206,19 +218,21 @@ impl AbstractNode for Math {
|
|||||||
}
|
}
|
||||||
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(right.position).into(),
|
ValidationError::ExpectedIntegerOrFloat(right_position).into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(left.position),
|
ValidationError::ExpectedIntegerOrFloat(left_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Math::Divide(left, right) => {
|
Math::Divide(left, right) => {
|
||||||
let left_value = run_and_expect_value(left.node, left.position)?;
|
let left_position = left.position();
|
||||||
let right_value = run_and_expect_value(right.node, right.position)?;
|
let left_value = run_and_expect_value(left_position, left)?;
|
||||||
|
let right_position = right.position();
|
||||||
|
let right_value = run_and_expect_value(right_position, right)?;
|
||||||
|
|
||||||
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
||||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||||
@ -243,19 +257,21 @@ impl AbstractNode for Math {
|
|||||||
}
|
}
|
||||||
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(right.position).into(),
|
ValidationError::ExpectedIntegerOrFloat(right_position).into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(left.position),
|
ValidationError::ExpectedIntegerOrFloat(left_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Math::Modulo(left, right) => {
|
Math::Modulo(left, right) => {
|
||||||
let left_value = run_and_expect_value(left.node, left.position)?;
|
let left_position = left.position();
|
||||||
let right_value = run_and_expect_value(right.node, right.position)?;
|
let left_value = run_and_expect_value(left_position, left)?;
|
||||||
|
let right_position = right.position();
|
||||||
|
let right_value = run_and_expect_value(right_position, right)?;
|
||||||
|
|
||||||
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
|
||||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||||
@ -280,12 +296,12 @@ impl AbstractNode for Math {
|
|||||||
}
|
}
|
||||||
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(right.position).into(),
|
ValidationError::ExpectedIntegerOrFloat(right_position).into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedIntegerOrFloat(left.position),
|
ValidationError::ExpectedIntegerOrFloat(left_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ pub mod async_block;
|
|||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod function_call;
|
pub mod function_call;
|
||||||
pub mod identifier;
|
|
||||||
pub mod if_else;
|
pub mod if_else;
|
||||||
pub mod list_index;
|
pub mod list_index;
|
||||||
pub mod logic;
|
pub mod logic;
|
||||||
@ -26,7 +25,6 @@ pub use self::{
|
|||||||
block::Block,
|
block::Block,
|
||||||
expression::Expression,
|
expression::Expression,
|
||||||
function_call::FunctionCall,
|
function_call::FunctionCall,
|
||||||
identifier::Identifier,
|
|
||||||
if_else::IfElse,
|
if_else::IfElse,
|
||||||
list_index::ListIndex,
|
list_index::ListIndex,
|
||||||
logic::Logic,
|
logic::Logic,
|
||||||
@ -85,11 +83,11 @@ pub enum Action {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AbstractTree(Vec<WithPosition<Statement>>);
|
pub struct AbstractTree(Vec<Statement>);
|
||||||
|
|
||||||
impl AbstractTree {
|
impl AbstractTree {
|
||||||
pub fn new(mut statements: Vec<WithPosition<Statement>>) -> Self {
|
pub fn new(mut statements: Vec<Statement>) -> Self {
|
||||||
statements.sort_by(|left, right| match (&left.node, &right.node) {
|
statements.sort_by(|left, right| match (&left, &right) {
|
||||||
(Statement::StructureDefinition(_), _) => Ordering::Less,
|
(Statement::StructureDefinition(_), _) => Ordering::Less,
|
||||||
(_, Statement::StructureDefinition(_)) => Ordering::Greater,
|
(_, Statement::StructureDefinition(_)) => Ordering::Greater,
|
||||||
(_, _) => Ordering::Equal,
|
(_, _) => Ordering::Equal,
|
||||||
@ -103,7 +101,8 @@ impl AbstractTree {
|
|||||||
let mut previous_value = None;
|
let mut previous_value = None;
|
||||||
|
|
||||||
for statement in valid_statements {
|
for statement in valid_statements {
|
||||||
let run = statement.node.run(context);
|
let position = statement.position();
|
||||||
|
let run = statement.run(context);
|
||||||
|
|
||||||
match run {
|
match run {
|
||||||
Ok(action) => match action {
|
Ok(action) => match action {
|
||||||
@ -113,7 +112,7 @@ impl AbstractTree {
|
|||||||
Err(runtime_error) => {
|
Err(runtime_error) => {
|
||||||
return Err(vec![Error::Runtime {
|
return Err(vec![Error::Runtime {
|
||||||
error: runtime_error,
|
error: runtime_error,
|
||||||
position: statement.position,
|
position,
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,29 +121,27 @@ impl AbstractTree {
|
|||||||
Ok(previous_value)
|
Ok(previous_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_type_definitions(
|
fn run_type_definitions(self, context: &Context) -> Result<Vec<Statement>, Vec<Error>> {
|
||||||
self,
|
|
||||||
context: &Context,
|
|
||||||
) -> Result<Vec<WithPosition<Statement>>, Vec<Error>> {
|
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
let mut valid_statements = Vec::new();
|
let mut valid_statements = Vec::new();
|
||||||
|
|
||||||
for statement in self.0 {
|
for statement in self.0 {
|
||||||
let validation = statement.node.validate(context);
|
let validation = statement.validate(context);
|
||||||
|
|
||||||
if let Err(validation_error) = validation {
|
if let Err(validation_error) = validation {
|
||||||
errors.push(Error::Validation {
|
errors.push(Error::Validation {
|
||||||
error: validation_error,
|
error: validation_error,
|
||||||
position: statement.position,
|
position: statement.position(),
|
||||||
})
|
})
|
||||||
} else if errors.is_empty() {
|
} else if errors.is_empty() {
|
||||||
if let Statement::StructureDefinition(_) = statement.node {
|
if let Statement::StructureDefinition(_) = statement {
|
||||||
let run = statement.node.run(context);
|
let position = statement.position();
|
||||||
|
let run = statement.run(context);
|
||||||
|
|
||||||
if let Err(runtime_error) = run {
|
if let Err(runtime_error) = run {
|
||||||
errors.push(Error::Runtime {
|
errors.push(Error::Runtime {
|
||||||
error: runtime_error,
|
error: runtime_error,
|
||||||
position: statement.position,
|
position,
|
||||||
});
|
});
|
||||||
|
|
||||||
return Err(errors);
|
return Err(errors);
|
||||||
@ -164,7 +161,7 @@ impl AbstractTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for AbstractTree {
|
impl Index<usize> for AbstractTree {
|
||||||
type Output = WithPosition<Statement>;
|
type Output = Statement;
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
&self.0[index]
|
&self.0[index]
|
||||||
|
@ -4,28 +4,35 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AbstractNode, Action, Assignment, AsyncBlock, Block, Expression, IfElse, Loop,
|
AbstractNode, Action, Assignment, AsyncBlock, Block, Expression, IfElse, Loop, SourcePosition,
|
||||||
StructureDefinition, Type, While,
|
StructureDefinition, Type, While, WithPosition,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Assignment(Assignment),
|
Assignment(WithPosition<Assignment>),
|
||||||
AsyncBlock(AsyncBlock),
|
AsyncBlock(WithPosition<AsyncBlock>),
|
||||||
Block(Block),
|
Block(WithPosition<Block>),
|
||||||
Break,
|
Break(WithPosition<()>),
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
IfElse(IfElse),
|
IfElse(WithPosition<IfElse>),
|
||||||
Loop(Loop),
|
Loop(WithPosition<Loop>),
|
||||||
StructureDefinition(StructureDefinition),
|
StructureDefinition(WithPosition<StructureDefinition>),
|
||||||
While(While),
|
While(WithPosition<While>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
pub fn kind(&self) -> u8 {
|
pub fn position(&self) -> SourcePosition {
|
||||||
match self {
|
match self {
|
||||||
Statement::StructureDefinition(_) => 0,
|
Statement::Assignment(inner) => inner.position,
|
||||||
_ => 1,
|
Statement::AsyncBlock(inner) => inner.position,
|
||||||
|
Statement::Block(inner) => inner.position,
|
||||||
|
Statement::Break(inner) => inner.position,
|
||||||
|
Statement::Expression(expression) => expression.position(),
|
||||||
|
Statement::IfElse(inner) => inner.position,
|
||||||
|
Statement::Loop(inner) => inner.position,
|
||||||
|
Statement::StructureDefinition(inner) => inner.position,
|
||||||
|
Statement::While(inner) => inner.position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,48 +40,48 @@ impl Statement {
|
|||||||
impl AbstractNode for Statement {
|
impl AbstractNode for Statement {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.expected_type(_context),
|
Statement::Assignment(assignment) => assignment.node.expected_type(_context),
|
||||||
Statement::AsyncBlock(async_block) => async_block.expected_type(_context),
|
Statement::AsyncBlock(async_block) => async_block.node.expected_type(_context),
|
||||||
Statement::Block(block) => block.expected_type(_context),
|
Statement::Block(block) => block.node.expected_type(_context),
|
||||||
Statement::Break => Ok(Type::None),
|
Statement::Break(_) => Ok(Type::None),
|
||||||
Statement::Expression(expression) => expression.expected_type(_context),
|
Statement::Expression(expression) => expression.expected_type(_context),
|
||||||
Statement::IfElse(if_else) => if_else.expected_type(_context),
|
Statement::IfElse(if_else) => if_else.node.expected_type(_context),
|
||||||
Statement::Loop(r#loop) => r#loop.expected_type(_context),
|
Statement::Loop(r#loop) => r#loop.node.expected_type(_context),
|
||||||
Statement::While(r#while) => r#while.expected_type(_context),
|
Statement::While(r#while) => r#while.node.expected_type(_context),
|
||||||
Statement::StructureDefinition(structure_definition) => {
|
Statement::StructureDefinition(structure_definition) => {
|
||||||
structure_definition.expected_type(_context)
|
structure_definition.node.expected_type(_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.validate(_context),
|
Statement::Assignment(assignment) => assignment.node.validate(_context),
|
||||||
Statement::AsyncBlock(async_block) => async_block.validate(_context),
|
Statement::AsyncBlock(async_block) => async_block.node.validate(_context),
|
||||||
Statement::Block(block) => block.validate(_context),
|
Statement::Block(block) => block.node.validate(_context),
|
||||||
Statement::Break => Ok(()),
|
Statement::Break(_) => Ok(()),
|
||||||
Statement::Expression(expression) => expression.validate(_context),
|
Statement::Expression(expression) => expression.validate(_context),
|
||||||
Statement::IfElse(if_else) => if_else.validate(_context),
|
Statement::IfElse(if_else) => if_else.node.validate(_context),
|
||||||
Statement::Loop(r#loop) => r#loop.validate(_context),
|
Statement::Loop(r#loop) => r#loop.node.validate(_context),
|
||||||
Statement::While(r#while) => r#while.validate(_context),
|
Statement::While(r#while) => r#while.node.validate(_context),
|
||||||
Statement::StructureDefinition(structure_definition) => {
|
Statement::StructureDefinition(structure_definition) => {
|
||||||
structure_definition.validate(_context)
|
structure_definition.node.validate(_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.run(_context),
|
Statement::Assignment(assignment) => assignment.node.run(_context),
|
||||||
Statement::AsyncBlock(async_block) => async_block.run(_context),
|
Statement::AsyncBlock(async_block) => async_block.node.run(_context),
|
||||||
Statement::Block(block) => block.run(_context),
|
Statement::Block(block) => block.node.run(_context),
|
||||||
Statement::Break => Ok(Action::Break),
|
Statement::Break(_) => Ok(Action::Break),
|
||||||
Statement::Expression(expression) => expression.run(_context),
|
Statement::Expression(expression) => expression.run(_context),
|
||||||
Statement::IfElse(if_else) => if_else.run(_context),
|
Statement::IfElse(if_else) => if_else.node.run(_context),
|
||||||
Statement::Loop(r#loop) => r#loop.run(_context),
|
Statement::Loop(r#loop) => r#loop.node.run(_context),
|
||||||
Statement::While(r#while) => r#while.run(_context),
|
Statement::While(r#while) => r#while.node.run(_context),
|
||||||
Statement::StructureDefinition(structure_definition) => {
|
Statement::StructureDefinition(structure_definition) => {
|
||||||
structure_definition.run(_context)
|
structure_definition.node.run(_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Identifier, Type, WithPosition};
|
use super::{AbstractNode, Action, Type, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct StructureDefinition {
|
pub struct StructureDefinition {
|
||||||
|
@ -3,9 +3,9 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use clap::error::Result;
|
use clap::error::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::Identifier,
|
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, TypeConflict, ValidationError},
|
error::{RuntimeError, TypeConflict, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, WithPosition};
|
use super::{AbstractNode, Action, WithPosition};
|
||||||
|
@ -4,10 +4,11 @@ use crate::{
|
|||||||
built_in_functions::BuiltInFunction,
|
built_in_functions::BuiltInFunction,
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPos, WithPosition};
|
use super::{AbstractNode, Action, Block, Expression, Type, WithPos, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ValueNode {
|
pub enum ValueNode {
|
||||||
@ -15,19 +16,13 @@ pub enum ValueNode {
|
|||||||
BuiltInFunction(BuiltInFunction),
|
BuiltInFunction(BuiltInFunction),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
List(Vec<WithPosition<Expression>>),
|
List(Vec<Expression>),
|
||||||
Map(
|
Map(Vec<(Identifier, Option<WithPosition<Type>>, Expression)>),
|
||||||
Vec<(
|
|
||||||
Identifier,
|
|
||||||
Option<WithPosition<Type>>,
|
|
||||||
WithPosition<Expression>,
|
|
||||||
)>,
|
|
||||||
),
|
|
||||||
Range(Range<i64>),
|
Range(Range<i64>),
|
||||||
String(String),
|
String(String),
|
||||||
Structure {
|
Structure {
|
||||||
name: Identifier,
|
name: WithPosition<Identifier>,
|
||||||
fields: Vec<(Identifier, WithPosition<Expression>)>,
|
fields: Vec<(Identifier, Expression)>,
|
||||||
},
|
},
|
||||||
ParsedFunction {
|
ParsedFunction {
|
||||||
type_arguments: Vec<WithPosition<Type>>,
|
type_arguments: Vec<WithPosition<Type>>,
|
||||||
@ -49,9 +44,8 @@ impl AbstractNode for ValueNode {
|
|||||||
for expression in items {
|
for expression in items {
|
||||||
item_types.push(
|
item_types.push(
|
||||||
expression
|
expression
|
||||||
.node
|
|
||||||
.expected_type(context)?
|
.expected_type(context)?
|
||||||
.with_position(expression.position),
|
.with_position(expression.position()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,19 +72,19 @@ impl AbstractNode for ValueNode {
|
|||||||
let mut types = Vec::with_capacity(expressions.len());
|
let mut types = Vec::with_capacity(expressions.len());
|
||||||
|
|
||||||
for (identifier, expression) in expressions {
|
for (identifier, expression) in expressions {
|
||||||
let r#type = expression.node.expected_type(context)?;
|
let r#type = expression.expected_type(context)?;
|
||||||
|
|
||||||
types.push((
|
types.push((
|
||||||
identifier.clone(),
|
identifier.clone(),
|
||||||
WithPosition {
|
WithPosition {
|
||||||
node: r#type,
|
node: r#type,
|
||||||
position: expression.position,
|
position: expression.position(),
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Structure {
|
Type::Structure {
|
||||||
name: name.clone(),
|
name: name.node.clone(),
|
||||||
fields: types,
|
fields: types,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,12 +98,12 @@ impl AbstractNode for ValueNode {
|
|||||||
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 {
|
||||||
if let Some(expected_type) = r#type {
|
if let Some(expected_type) = r#type {
|
||||||
let actual_type = expression.node.expected_type(context)?;
|
let actual_type = expression.expected_type(context)?;
|
||||||
|
|
||||||
expected_type.node.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(),
|
||||||
expected_position: expected_type.position,
|
expected_position: expected_type.position,
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
@ -161,18 +155,18 @@ impl AbstractNode for ValueNode {
|
|||||||
fields: expressions,
|
fields: expressions,
|
||||||
} = self
|
} = self
|
||||||
{
|
{
|
||||||
if let Type::Structure {
|
if let Some(Type::Structure {
|
||||||
name: _,
|
name: _,
|
||||||
fields: types,
|
fields: types,
|
||||||
} = name.expected_type(context)?
|
}) = 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.node.expected_type(context)?;
|
let actual_type = expression.expected_type(context)?;
|
||||||
|
|
||||||
expected_type.node.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(),
|
||||||
expected_position: expected_type.position,
|
expected_position: expected_type.position,
|
||||||
}
|
}
|
||||||
})?
|
})?
|
||||||
@ -192,15 +186,16 @@ impl AbstractNode for ValueNode {
|
|||||||
let mut value_list = Vec::with_capacity(expression_list.len());
|
let mut value_list = Vec::with_capacity(expression_list.len());
|
||||||
|
|
||||||
for expression in expression_list {
|
for expression in expression_list {
|
||||||
let action = expression.node.run(_context)?;
|
let expression_position = expression.position();
|
||||||
|
let action = expression.run(_context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
WithPosition {
|
WithPosition {
|
||||||
node: value,
|
node: value,
|
||||||
position: expression.position,
|
position: expression_position,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(expression.position),
|
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -213,12 +208,13 @@ impl AbstractNode for ValueNode {
|
|||||||
let mut property_map = BTreeMap::new();
|
let mut property_map = BTreeMap::new();
|
||||||
|
|
||||||
for (identifier, _type, expression) in property_list {
|
for (identifier, _type, expression) in property_list {
|
||||||
let action = expression.node.run(_context)?;
|
let expression_position = expression.position();
|
||||||
|
let action = expression.run(_context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(expression.position),
|
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -242,12 +238,13 @@ impl AbstractNode for ValueNode {
|
|||||||
let mut fields = Vec::with_capacity(expressions.len());
|
let mut fields = Vec::with_capacity(expressions.len());
|
||||||
|
|
||||||
for (identifier, expression) in expressions {
|
for (identifier, expression) in expressions {
|
||||||
let action = expression.node.run(_context)?;
|
let expression_position = expression.position();
|
||||||
|
let action = expression.run(_context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(expression.position),
|
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,19 +5,16 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Action, Expression, Statement, Type, WithPosition};
|
use super::{AbstractNode, Action, Expression, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct While {
|
pub struct While {
|
||||||
expression: WithPosition<Expression>,
|
expression: Expression,
|
||||||
statements: Vec<WithPosition<Statement>>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl While {
|
impl While {
|
||||||
pub fn new(
|
pub fn new(expression: Expression, statements: Vec<Statement>) -> Self {
|
||||||
expression: WithPosition<Expression>,
|
|
||||||
statements: Vec<WithPosition<Statement>>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
expression,
|
expression,
|
||||||
statements,
|
statements,
|
||||||
@ -31,10 +28,10 @@ impl AbstractNode for While {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
self.expression.node.validate(_context)?;
|
self.expression.validate(_context)?;
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.node.validate(_context)?;
|
statement.validate(_context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -42,13 +39,14 @@ impl AbstractNode for While {
|
|||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let get_boolean = || -> Result<Value, RuntimeError> {
|
let get_boolean = || -> Result<Value, RuntimeError> {
|
||||||
let action = self.expression.node.run(_context)?;
|
let expression_position = self.expression.position();
|
||||||
|
let action = self.expression.run(_context)?;
|
||||||
|
|
||||||
if let Action::Return(value) = action {
|
if let Action::Return(value) = action {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::InterpreterExpectedReturn(self.expression.position),
|
ValidationError::InterpreterExpectedReturn(expression_position),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -56,7 +54,7 @@ impl AbstractNode for While {
|
|||||||
if let ValueInner::Boolean(boolean) = get_boolean()?.inner().as_ref() {
|
if let ValueInner::Boolean(boolean) = get_boolean()?.inner().as_ref() {
|
||||||
while *boolean {
|
while *boolean {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
let action = statement.node.clone().run(_context)?;
|
let action = statement.clone().run(_context)?;
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
Action::Return(_) => {}
|
Action::Return(_) => {}
|
||||||
@ -73,42 +71,57 @@ impl AbstractNode for While {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::abstract_tree::{
|
use crate::{
|
||||||
Assignment, AssignmentOperator, Block, Identifier, Logic, ValueNode, WithPos,
|
abstract_tree::{Assignment, AssignmentOperator, Block, Logic, ValueNode, WithPos},
|
||||||
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_while_loop() {
|
fn simple_while_loop() {
|
||||||
let action = Statement::Block(Block::new(vec![
|
let action = Statement::Block(
|
||||||
Statement::Assignment(Assignment::new(
|
Block::new(vec![
|
||||||
|
Statement::Assignment(
|
||||||
|
Assignment::new(
|
||||||
Identifier::new("i").with_position((0, 0)),
|
Identifier::new("i").with_position((0, 0)),
|
||||||
None,
|
None,
|
||||||
AssignmentOperator::Assign,
|
AssignmentOperator::Assign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(3)))
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(3).with_position((0, 0)),
|
||||||
|
)),
|
||||||
|
)
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
|
),
|
||||||
|
Statement::While(
|
||||||
|
While::new(
|
||||||
|
Expression::Logic(
|
||||||
|
Box::new(Logic::Less(
|
||||||
|
Expression::Identifier(Identifier::new("i").with_position((0, 0))),
|
||||||
|
Expression::Value(ValueNode::Integer(3).with_position((0, 0))),
|
||||||
))
|
))
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
Statement::While(While {
|
),
|
||||||
expression: Expression::Logic(Box::new(Logic::Less(
|
vec![Statement::Assignment(
|
||||||
Expression::Identifier(Identifier::new("i")).with_position((0, 0)),
|
Assignment::new(
|
||||||
Expression::Value(ValueNode::Integer(3)).with_position((0, 0)),
|
|
||||||
)))
|
|
||||||
.with_position((0, 0)),
|
|
||||||
statements: vec![Statement::Assignment(Assignment::new(
|
|
||||||
Identifier::new("i").with_position((0, 0)),
|
Identifier::new("i").with_position((0, 0)),
|
||||||
None,
|
None,
|
||||||
AssignmentOperator::AddAssign,
|
AssignmentOperator::AddAssign,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::Integer(1).with_position((0, 0)),
|
||||||
|
)),
|
||||||
|
)
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
))
|
)],
|
||||||
.with_position((0, 0))],
|
)
|
||||||
})
|
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
Statement::Expression(Expression::Identifier(Identifier::new("i")))
|
),
|
||||||
|
Statement::Expression(Expression::Identifier(
|
||||||
|
Identifier::new("i").with_position((0, 0)),
|
||||||
|
)),
|
||||||
|
])
|
||||||
.with_position((0, 0)),
|
.with_position((0, 0)),
|
||||||
]))
|
)
|
||||||
.run(&Context::new())
|
.run(&Context::new())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -4,8 +4,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{Identifier, Type},
|
abstract_tree::Type,
|
||||||
error::{RwLockPoisonError, ValidationError},
|
error::{RwLockPoisonError, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ use std::{io, sync::PoisonError};
|
|||||||
use chumsky::{prelude::Rich, span::Span};
|
use chumsky::{prelude::Rich, span::Span};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{Identifier, SourcePosition, Type},
|
abstract_tree::{SourcePosition, Type},
|
||||||
|
identifier::Identifier,
|
||||||
lexer::Token,
|
lexer::Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,7 +136,10 @@ pub enum ValidationError {
|
|||||||
expected: Vec<Type>,
|
expected: Vec<Type>,
|
||||||
actual: Vec<Type>,
|
actual: Vec<Type>,
|
||||||
},
|
},
|
||||||
VariableNotFound(Identifier),
|
VariableNotFound {
|
||||||
|
identifier: Identifier,
|
||||||
|
position: SourcePosition,
|
||||||
|
},
|
||||||
PropertyNotFound {
|
PropertyNotFound {
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: SourcePosition,
|
position: SourcePosition,
|
||||||
|
23
dust-lang/src/identifier.rs
Normal file
23
dust-lang/src/identifier.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use std::{
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct Identifier(Arc<String>);
|
||||||
|
|
||||||
|
impl Identifier {
|
||||||
|
pub fn new<T: ToString>(string: T) -> Self {
|
||||||
|
Identifier(Arc::new(string.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Identifier {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ pub mod abstract_tree;
|
|||||||
pub mod built_in_functions;
|
pub mod built_in_functions;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod identifier;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
@ -120,7 +121,7 @@ impl InterpreterError {
|
|||||||
let mut reports = Vec::new();
|
let mut reports = Vec::new();
|
||||||
|
|
||||||
for error in self.errors {
|
for error in self.errors {
|
||||||
let (mut builder, validation_error, error_position) = match error {
|
let (mut builder, validation_error) = match error {
|
||||||
Error::Lex {
|
Error::Lex {
|
||||||
expected,
|
expected,
|
||||||
span,
|
span,
|
||||||
@ -145,7 +146,6 @@ impl InterpreterError {
|
|||||||
.with_color(Color::Red),
|
.with_color(Color::Red),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
span.into(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Error::Parse {
|
Error::Parse {
|
||||||
@ -172,7 +172,6 @@ impl InterpreterError {
|
|||||||
.with_color(Color::Red),
|
.with_color(Color::Red),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
span.into(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Error::Validation { error, position } => (
|
Error::Validation { error, position } => (
|
||||||
@ -184,7 +183,6 @@ impl InterpreterError {
|
|||||||
.with_message("The syntax is valid but this code would cause an error.")
|
.with_message("The syntax is valid but this code would cause an error.")
|
||||||
.with_note("This error was detected by the interpreter before running the code."),
|
.with_note("This error was detected by the interpreter before running the code."),
|
||||||
Some(error),
|
Some(error),
|
||||||
position,
|
|
||||||
),
|
),
|
||||||
Error::Runtime { error, position } => (
|
Error::Runtime { error, position } => (
|
||||||
Report::build(
|
Report::build(
|
||||||
@ -207,7 +205,6 @@ impl InterpreterError {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
position,
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -260,12 +257,16 @@ impl InterpreterError {
|
|||||||
.with_message(format!("Got type {} here.", actual.fg(type_color))),
|
.with_message(format!("Got type {} here.", actual.fg(type_color))),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
ValidationError::VariableNotFound(identifier) => builder.add_label(
|
ValidationError::VariableNotFound {
|
||||||
Label::new((self.source_id.clone(), error_position.0..error_position.1))
|
identifier,
|
||||||
.with_message(format!(
|
position,
|
||||||
|
} => builder.add_label(
|
||||||
|
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
|
||||||
|
format!(
|
||||||
"Variable {} does not exist in this context.",
|
"Variable {} does not exist in this context.",
|
||||||
identifier.fg(identifier_color)
|
identifier.fg(identifier_color)
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ValidationError::CannotIndex { r#type, position } => builder.add_label(
|
ValidationError::CannotIndex { r#type, position } => builder.add_label(
|
||||||
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
|
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -13,10 +13,11 @@ use stanza::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPos, WithPosition},
|
abstract_tree::{AbstractNode, Action, Block, Type, WithPos, WithPosition},
|
||||||
built_in_functions::BuiltInFunction,
|
built_in_functions::BuiltInFunction,
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -71,7 +72,7 @@ impl Value {
|
|||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn structure(name: Identifier, fields: Vec<(Identifier, Value)>) -> Self {
|
pub fn structure(name: WithPosition<Identifier>, fields: Vec<(Identifier, Value)>) -> Self {
|
||||||
Value(Arc::new(ValueInner::Structure { name, fields }))
|
Value(Arc::new(ValueInner::Structure { name, fields }))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +177,7 @@ impl Display for Value {
|
|||||||
table = table.with_row([identifier.as_str(), &value.to_string()]);
|
table = table.with_row([identifier.as_str(), &value.to_string()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "{name}\n{}", Console::default().render(&table))
|
write!(f, "{}\n{}", name.node, Console::default().render(&table))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +208,7 @@ pub enum ValueInner {
|
|||||||
Range(Range<i64>),
|
Range(Range<i64>),
|
||||||
String(String),
|
String(String),
|
||||||
Structure {
|
Structure {
|
||||||
name: Identifier,
|
name: WithPosition<Identifier>,
|
||||||
fields: Vec<(Identifier, Value)>,
|
fields: Vec<(Identifier, Value)>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -244,10 +245,13 @@ impl ValueInner {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ValueInner::Structure { name, .. } => {
|
ValueInner::Structure { name, .. } => {
|
||||||
if let Some(r#type) = context.get_type(name)? {
|
if let Some(r#type) = context.get_type(&name.node)? {
|
||||||
r#type
|
r#type
|
||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::VariableNotFound(name.clone()));
|
return Err(ValidationError::VariableNotFound {
|
||||||
|
identifier: name.node.clone(),
|
||||||
|
position: name.position,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use dust_lang::{
|
use dust_lang::{
|
||||||
abstract_tree::Identifier,
|
|
||||||
error::{Error, ValidationError},
|
error::{Error, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,7 +69,10 @@ fn function_context_does_not_capture_values() {
|
|||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.errors(),
|
.errors(),
|
||||||
&vec![Error::Validation {
|
&vec![Error::Validation {
|
||||||
error: ValidationError::VariableNotFound(Identifier::new("x")),
|
error: ValidationError::VariableNotFound {
|
||||||
|
identifier: Identifier::new("x"),
|
||||||
|
position: (0, 0).into()
|
||||||
|
},
|
||||||
position: (32, 50).into()
|
position: (32, 50).into()
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use dust_lang::{
|
use dust_lang::{
|
||||||
abstract_tree::{Identifier, Type},
|
abstract_tree::{Type, WithPos},
|
||||||
error::{Error, TypeConflict, ValidationError},
|
error::{Error, TypeConflict, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
interpret, Value,
|
interpret, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ fn simple_structure() {
|
|||||||
"
|
"
|
||||||
),
|
),
|
||||||
Ok(Some(Value::structure(
|
Ok(Some(Value::structure(
|
||||||
Identifier::new("Foo"),
|
Identifier::new("Foo").with_position((0, 0)),
|
||||||
vec![
|
vec![
|
||||||
(Identifier::new("bar"), Value::integer(42)),
|
(Identifier::new("bar"), Value::integer(42)),
|
||||||
(Identifier::new("baz"), Value::string("hiya".to_string())),
|
(Identifier::new("baz"), Value::string("hiya".to_string())),
|
||||||
@ -83,11 +84,11 @@ fn nested_structure() {
|
|||||||
"
|
"
|
||||||
),
|
),
|
||||||
Ok(Some(Value::structure(
|
Ok(Some(Value::structure(
|
||||||
Identifier::new("Foo"),
|
Identifier::new("Foo").with_position((0, 0)),
|
||||||
vec![(
|
vec![(
|
||||||
Identifier::new("bar"),
|
Identifier::new("bar"),
|
||||||
Value::structure(
|
Value::structure(
|
||||||
Identifier::new("Bar"),
|
Identifier::new("Bar").with_position((0, 0)),
|
||||||
vec![(Identifier::new("baz"), Value::integer(42))]
|
vec![(Identifier::new("baz"), Value::integer(42))]
|
||||||
)
|
)
|
||||||
),]
|
),]
|
||||||
@ -109,7 +110,10 @@ fn undefined_struct() {
|
|||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.errors(),
|
.errors(),
|
||||||
&vec![Error::Validation {
|
&vec![Error::Validation {
|
||||||
error: ValidationError::VariableNotFound(Identifier::new("Foo")),
|
error: ValidationError::VariableNotFound {
|
||||||
|
identifier: Identifier::new("Foo"),
|
||||||
|
position: (0, 0).into()
|
||||||
|
},
|
||||||
position: (17, 69).into()
|
position: (17, 69).into()
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use dust_lang::{
|
use dust_lang::{
|
||||||
abstract_tree::{Identifier, Type, WithPos},
|
abstract_tree::{Type, WithPos},
|
||||||
error::{Error, TypeConflict, ValidationError},
|
error::{Error, TypeConflict, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use dust_lang::{
|
use dust_lang::{
|
||||||
abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos},
|
abstract_tree::{Block, Expression, Statement, Type, WithPos},
|
||||||
error::{Error, TypeConflict, ValidationError},
|
error::{Error, TypeConflict, ValidationError},
|
||||||
|
identifier::Identifier,
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,9 +50,8 @@ fn function_variable() {
|
|||||||
vec![(Identifier::new("x"), Type::Integer.with_position((13, 16)))],
|
vec![(Identifier::new("x"), Type::Integer.with_position((13, 16)))],
|
||||||
Type::Integer.with_position((18, 21)),
|
Type::Integer.with_position((18, 21)),
|
||||||
Block::new(vec![Statement::Expression(Expression::Identifier(
|
Block::new(vec![Statement::Expression(Expression::Identifier(
|
||||||
Identifier::new("x")
|
Identifier::new("x").with_position((0, 0))
|
||||||
))
|
))])
|
||||||
.with_position((24, 25))])
|
|
||||||
.with_position((9, 27))
|
.with_position((9, 27))
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
|
18
examples/fizzbuzz.ds
Normal file
18
examples/fizzbuzz.ds
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
count = 1
|
||||||
|
|
||||||
|
while count <= 15 {
|
||||||
|
divides_by_3 = count % 3 == 0
|
||||||
|
divides_by_5 = count % 5 == 0
|
||||||
|
|
||||||
|
if divides_by_3 && divides_by_5 {
|
||||||
|
output('fizzbuzz')
|
||||||
|
} else if divides_by_3 {
|
||||||
|
output('fizz')
|
||||||
|
} else if divides_by_5 {
|
||||||
|
output('buzz')
|
||||||
|
} else {
|
||||||
|
output(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user