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