1
0

Overhaul AST

This commit is contained in:
Jeff 2024-03-25 00:16:55 -04:00
parent 4b460c0e68
commit e50b231958
29 changed files with 1406 additions and 1060 deletions

View File

@ -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());

View File

@ -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();

View File

@ -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))

View File

@ -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),
} }
} }
} }

View File

@ -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),
)); ));
}; };

View File

@ -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)
}
}

View File

@ -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()))
)
}
} }

View File

@ -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,
}, },
)) ))
} }

View File

@ -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,43 +84,43 @@ 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)
}; };
let run_and_expect_boolean = Ok(value)
|expression: WithPosition<Expression>| -> Result<bool, RuntimeError> { };
let action = expression.node.run(context)?;
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(expression.position),
));
};
if let ValueInner::Boolean(boolean) = value.inner().as_ref() { let run_and_expect_boolean = |expression: Expression| -> Result<bool, RuntimeError> {
Ok(*boolean) let expression_position = expression.position();
} else { let action = expression.run(context)?;
return Err(RuntimeError::ValidationFailure( let value = if let Action::Return(value) = action {
ValidationError::ExpectedBoolean { value
actual: value.r#type(context)?, } else {
position: expression.position, return Err(RuntimeError::ValidationFailure(
}, ValidationError::InterpreterExpectedReturn(expression_position),
)); ));
}
}; };
if let ValueInner::Boolean(boolean) = value.inner().as_ref() {
Ok(*boolean)
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: value.r#type(context)?,
position: expression_position,
},
));
}
};
let boolean = match self { let boolean = match self {
Logic::Equal(left, right) => { Logic::Equal(left, right) => {
let (left_value, right_value) = let (left_value, right_value) =
@ -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,8 +308,10 @@ 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(
.run(&Context::new()), ValueNode::Boolean(false).with_position((0, 0))
))
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true))) Ok(Action::Return(Value::boolean(true)))
) )
} }

View File

@ -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(
Identifier::new("i").with_position((0, 0)), Assignment::new(
None,
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
.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)),
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::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(1))) Statement::Expression(Expression::Value(
.with_position((0, 0)), ValueNode::Integer(1).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::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)),
),
Block::new(vec![Statement::Break(().with_position((0, 0)))]),
None,
Some(Block::new(vec![Statement::Assignment(
Assignment::new(
Identifier::new("i").with_position((0, 0)),
None,
AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(
ValueNode::Integer(1).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)),
)),
]) ])
.run(&Context::new()) .run(&Context::new())
.unwrap(); .unwrap();

View File

@ -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 =
collection if let Some(collection) = context.get_value(&collection_identifier.node)? {
} else { collection
return Err(ValidationError::VariableNotFound( } else {
collection_identifier.clone(), return Err(ValidationError::VariableNotFound {
)); 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(),
}, },
)) ))
} }

View File

@ -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),
)) ))
} }
} }

View File

@ -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]

View File

@ -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)
} }
} }
} }

View File

@ -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 {

View File

@ -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};

View File

@ -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),
)); ));
}; };

View File

@ -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![
Identifier::new("i").with_position((0, 0)), Statement::Assignment(
None, Assignment::new(
AssignmentOperator::Assign, Identifier::new("i").with_position((0, 0)),
Statement::Expression(Expression::Value(ValueNode::Integer(3))) None,
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(
ValueNode::Integer(3).with_position((0, 0)),
)),
)
.with_position((0, 0)), .with_position((0, 0)),
)) ),
.with_position((0, 0)), Statement::While(
Statement::While(While { While::new(
expression: Expression::Logic(Box::new(Logic::Less( Expression::Logic(
Expression::Identifier(Identifier::new("i")).with_position((0, 0)), Box::new(Logic::Less(
Expression::Value(ValueNode::Integer(3)).with_position((0, 0)), Expression::Identifier(Identifier::new("i").with_position((0, 0))),
))) Expression::Value(ValueNode::Integer(3).with_position((0, 0))),
.with_position((0, 0)), ))
statements: vec![Statement::Assignment(Assignment::new( .with_position((0, 0)),
),
vec![Statement::Assignment(
Assignment::new(
Identifier::new("i").with_position((0, 0)),
None,
AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(
ValueNode::Integer(1).with_position((0, 0)),
)),
)
.with_position((0, 0)),
)],
)
.with_position((0, 0)),
),
Statement::Expression(Expression::Identifier(
Identifier::new("i").with_position((0, 0)), Identifier::new("i").with_position((0, 0)),
None, )),
AssignmentOperator::AddAssign, ])
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
.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)),
]))
.run(&Context::new()) .run(&Context::new())
.unwrap(); .unwrap();

View File

@ -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,
}; };

View File

@ -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,

View 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)
}
}

View File

@ -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

View File

@ -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,
});
} }
} }
}; };

View File

@ -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()
}] }]
); );

View File

@ -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()
}] }]
) )

View File

@ -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,
*, *,
}; };

View File

@ -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
View 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
}