Fix tests; Refine parsing

This commit is contained in:
Jeff 2024-03-17 07:31:45 -04:00
parent f9b4b1bc01
commit 4ea19f238e
19 changed files with 291 additions and 302 deletions

View File

@ -3,14 +3,14 @@ use crate::{
Context,
};
use super::{AbstractTree, Action, Identifier, Positioned, Statement, Type};
use super::{AbstractTree, Action, Identifier, Statement, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Assignment {
identifier: Identifier,
r#type: Option<Positioned<Type>>,
r#type: Option<WithPosition<Type>>,
operator: AssignmentOperator,
statement: Box<Positioned<Statement>>,
statement: Box<WithPosition<Statement>>,
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
@ -23,9 +23,9 @@ pub enum AssignmentOperator {
impl Assignment {
pub fn new(
identifier: Identifier,
r#type: Option<Positioned<Type>>,
r#type: Option<WithPosition<Type>>,
operator: AssignmentOperator,
statement: Positioned<Statement>,
statement: WithPosition<Statement>,
) -> Self {
Self {
identifier,
@ -44,7 +44,7 @@ impl AbstractTree for Assignment {
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
let statement_type = self.statement.node.expected_type(context)?;
if let Some(Positioned {
if let Some(WithPosition {
node: expected_type,
position: expected_position,
}) = &self.r#type
@ -125,12 +125,8 @@ mod tests {
Identifier::new("foobar"),
None,
AssignmentOperator::Assign,
Positioned {
node: Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
),
position: (0, 0),
},
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
.with_position((0..0).into()),
)
.run(&context)
.unwrap();
@ -153,12 +149,8 @@ mod tests {
Identifier::new("foobar"),
None,
AssignmentOperator::AddAssign,
Positioned {
node: Statement::Expression(
Expression::Value(ValueNode::Integer(41)).positioned((0..1).into()),
),
position: (0, 0),
},
Statement::Expression(Expression::Value(ValueNode::Integer(41)))
.with_position((0..0).into()),
)
.run(&context)
.unwrap();
@ -181,12 +173,8 @@ mod tests {
Identifier::new("foobar"),
None,
AssignmentOperator::SubAssign,
Positioned {
node: Statement::Expression(
Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()),
),
position: (0, 0),
},
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
.with_position((0..0).into()),
)
.run(&context)
.unwrap();
@ -201,17 +189,13 @@ mod tests {
fn type_check() {
let validation = Assignment::new(
Identifier::new("foobar"),
Some(Positioned {
Some(WithPosition {
node: Type::Boolean,
position: (0, 0),
}),
AssignmentOperator::Assign,
Positioned {
node: Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
),
position: (0, 0),
},
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
.with_position((0..0).into()),
)
.validate(&Context::new());

View File

@ -3,15 +3,15 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Positioned, Statement, Type};
use super::{AbstractTree, Action, Statement, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Block {
statements: Vec<Positioned<Statement>>,
statements: Vec<WithPosition<Statement>>,
}
impl Block {
pub fn new(statements: Vec<Positioned<Statement>>) -> Self {
pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
Self { statements }
}
}
@ -61,18 +61,12 @@ mod tests {
#[test]
fn run_returns_value_of_final_statement() {
let block = Block::new(vec![
Statement::Expression(
Expression::Value(ValueNode::Integer(1)).positioned((0..0).into()),
)
.positioned((0..0).into()),
Statement::Expression(
Expression::Value(ValueNode::Integer(2)).positioned((0..0).into()),
)
.positioned((0..0).into()),
Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
)
.positioned((0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
.with_position((0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(2)))
.with_position((0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
.with_position((0..0).into()),
]);
assert_eq!(
@ -84,14 +78,10 @@ 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())).positioned((0..0).into()),
)
.positioned((0..0).into()),
Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
)
.positioned((0..0).into()),
Statement::Expression(Expression::Value(ValueNode::String("42".to_string())))
.with_position((0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
.with_position((0..0).into()),
]);
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))

View File

@ -3,16 +3,19 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Expression, Positioned, Type};
use super::{AbstractTree, Action, Expression, Type, WithPosition};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub struct FunctionCall {
function: Box<Positioned<Expression>>,
arguments: Vec<Positioned<Expression>>,
function: Box<WithPosition<Expression>>,
arguments: Vec<WithPosition<Expression>>,
}
impl FunctionCall {
pub fn new(function: Positioned<Expression>, arguments: Vec<Positioned<Expression>>) -> Self {
pub fn new(
function: WithPosition<Expression>,
arguments: Vec<WithPosition<Expression>>,
) -> Self {
FunctionCall {
function: Box::new(function),
arguments,

View File

@ -3,20 +3,20 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Block, Expression, Positioned, Type};
use super::{AbstractTree, Action, Block, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct IfElse {
if_expression: Positioned<Expression>,
if_block: Positioned<Block>,
else_block: Option<Positioned<Block>>,
if_expression: WithPosition<Expression>,
if_block: WithPosition<Block>,
else_block: Option<WithPosition<Block>>,
}
impl IfElse {
pub fn new(
if_expression: Positioned<Expression>,
if_block: Positioned<Block>,
else_block: Option<Positioned<Block>>,
if_expression: WithPosition<Expression>,
if_block: WithPosition<Block>,
else_block: Option<WithPosition<Block>>,
) -> Self {
Self {
if_expression,
@ -83,13 +83,12 @@ mod tests {
fn simple_if() {
assert_eq!(
IfElse::new(
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
Block::new(vec![Statement::Expression(
Expression::Value(ValueNode::String("foo".to_string()))
.positioned((0..0).into())
)
.positioned((0..0).into())])
.positioned((0..0).into()),
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
))
.with_position((0..0).into())])
.with_position((0..0).into()),
None
)
.run(&Context::new()),
@ -101,20 +100,18 @@ mod tests {
fn simple_if_else() {
assert_eq!(
IfElse::new(
Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()),
Block::new(vec![Statement::Expression(
Expression::Value(ValueNode::String("foo".to_string()))
.positioned((0..0).into())
)
.positioned((0..0).into())])
.positioned((0..0).into()),
Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()),
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
))
.with_position((0..0).into())])
.with_position((0..0).into()),
Some(
Block::new(vec![Statement::Expression(
Expression::Value(ValueNode::String("bar".to_string()))
.positioned((0..0).into())
)
.positioned((0..0).into())])
.positioned((0..0).into())
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("bar".to_string())
))
.with_position((0..0).into())])
.with_position((0..0).into())
)
)
.run(&Context::new()),

View File

@ -3,16 +3,16 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Expression, Positioned, Type, ValueNode};
use super::{AbstractTree, Action, Expression, Type, ValueNode, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Index {
left: Positioned<Expression>,
right: Positioned<Expression>,
left: WithPosition<Expression>,
right: WithPosition<Expression>,
}
impl Index {
pub fn new(left: Positioned<Expression>, right: Positioned<Expression>) -> Self {
pub fn new(left: WithPosition<Expression>, right: WithPosition<Expression>) -> Self {
Self { left, right }
}
}

View File

@ -4,19 +4,19 @@ use crate::{
Value,
};
use super::{AbstractTree, Action, Expression, Positioned, Type};
use super::{AbstractTree, Action, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Logic {
Equal(Positioned<Expression>, Positioned<Expression>),
NotEqual(Positioned<Expression>, Positioned<Expression>),
Greater(Positioned<Expression>, Positioned<Expression>),
Less(Positioned<Expression>, Positioned<Expression>),
GreaterOrEqual(Positioned<Expression>, Positioned<Expression>),
LessOrEqual(Positioned<Expression>, Positioned<Expression>),
And(Positioned<Expression>, Positioned<Expression>),
Or(Positioned<Expression>, Positioned<Expression>),
Not(Positioned<Expression>),
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>),
}
impl AbstractTree for Logic {
@ -139,8 +139,8 @@ mod tests {
#[test]
fn equal() {
assert!(Logic::Equal(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -153,8 +153,8 @@ mod tests {
#[test]
fn not_equal() {
assert!(Logic::NotEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -167,8 +167,8 @@ mod tests {
#[test]
fn greater() {
assert!(Logic::Greater(
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -181,8 +181,8 @@ mod tests {
#[test]
fn less() {
assert!(Logic::Less(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -195,8 +195,8 @@ mod tests {
#[test]
fn greater_or_equal() {
assert!(Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(41)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(41)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -206,8 +206,8 @@ mod tests {
.unwrap());
assert!(Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -220,8 +220,8 @@ mod tests {
#[test]
fn less_or_equal() {
assert!(Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -231,8 +231,8 @@ mod tests {
.unwrap());
assert!(Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -245,8 +245,8 @@ mod tests {
#[test]
fn and() {
assert!(Logic::And(
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -259,8 +259,8 @@ mod tests {
#[test]
fn or() {
assert!(Logic::Or(
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()),
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()),
)
.run(&Context::new())
.unwrap()
@ -272,14 +272,14 @@ mod tests {
#[test]
fn not() {
assert!(
Logic::Not(Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()))
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap()
assert!(Logic::Not(
Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into())
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
}
}

View File

@ -3,15 +3,15 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Positioned, Statement, Type};
use super::{AbstractTree, Action, Statement, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Loop {
statements: Vec<Positioned<Statement>>,
statements: Vec<WithPosition<Statement>>,
}
impl Loop {
pub fn new(statements: Vec<Positioned<Statement>>) -> Self {
pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
Self { statements }
}
}
@ -58,7 +58,7 @@ mod tests {
#[test]
fn basic_loop() {
let result = Loop {
statements: vec![Statement::Break.positioned((0..0).into())],
statements: vec![Statement::Break.with_position((0..0).into())],
}
.run(&Context::new());

View File

@ -5,15 +5,15 @@ use crate::{
Value,
};
use super::{AbstractTree, Action, Expression, Positioned, Type};
use super::{AbstractTree, Action, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Math {
Add(Positioned<Expression>, Positioned<Expression>),
Subtract(Positioned<Expression>, Positioned<Expression>),
Multiply(Positioned<Expression>, Positioned<Expression>),
Divide(Positioned<Expression>, Positioned<Expression>),
Modulo(Positioned<Expression>, Positioned<Expression>),
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>),
}
impl AbstractTree for Math {

View File

@ -39,7 +39,7 @@ use crate::{
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Positioned<T> {
pub struct WithPosition<T> {
pub node: T,
pub position: (usize, usize),
}
@ -49,8 +49,8 @@ pub trait AbstractTree: Sized {
fn validate(&self, context: &Context) -> Result<(), ValidationError>;
fn run(self, context: &Context) -> Result<Action, RuntimeError>;
fn positioned(self, span: SimpleSpan) -> Positioned<Self> {
Positioned {
fn with_position(self, span: SimpleSpan) -> WithPosition<Self> {
WithPosition {
node: self,
position: (span.start(), span.end()),
}

View File

@ -3,16 +3,14 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{
AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Positioned, Type, While,
};
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement {
Assignment(Assignment),
Block(Block),
Break,
Expression(Positioned<Expression>),
Expression(Expression),
IfElse(IfElse),
Loop(Loop),
While(While),
@ -24,7 +22,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.expected_type(_context),
Statement::Block(block) => block.expected_type(_context),
Statement::Break => Ok(Type::None),
Statement::Expression(expression) => expression.node.expected_type(_context),
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),
@ -36,7 +34,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.validate(_context),
Statement::Block(block) => block.validate(_context),
Statement::Break => Ok(()),
Statement::Expression(expression) => expression.node.validate(_context),
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),
@ -48,7 +46,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.run(_context),
Statement::Block(block) => block.run(_context),
Statement::Break => Ok(Action::Break),
Statement::Expression(expression) => expression.node.run(_context),
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),

View File

@ -6,21 +6,27 @@ use crate::{
Value,
};
use super::{AbstractTree, Action, Block, Expression, Identifier, Positioned, Type};
use super::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosition};
#[derive(Clone, Debug, PartialEq)]
pub enum ValueNode {
Boolean(bool),
Float(f64),
Integer(i64),
List(Vec<Positioned<Expression>>),
Map(Vec<(Identifier, Option<Positioned<Type>>, Positioned<Expression>)>),
List(Vec<WithPosition<Expression>>),
Map(
Vec<(
Identifier,
Option<WithPosition<Type>>,
WithPosition<Expression>,
)>,
),
Range(Range<i64>),
String(String),
Function {
parameters: Vec<(Identifier, Positioned<Type>)>,
return_type: Positioned<Type>,
body: Positioned<Block>,
parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: WithPosition<Type>,
body: WithPosition<Block>,
},
}
@ -70,7 +76,7 @@ impl AbstractTree for ValueNode {
actual_position: expression.position,
expected_position: expected_type.position,
}
});
})?;
}
}
}

View File

@ -3,16 +3,16 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Block, Expression, Positioned, Type};
use super::{AbstractTree, Action, Block, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct While {
expression: Positioned<Expression>,
expression: WithPosition<Expression>,
block: Block,
}
impl While {
pub fn new(expression: Positioned<Expression>, block: Block) -> Self {
pub fn new(expression: WithPosition<Expression>, block: Block) -> Self {
Self { expression, block }
}
}

View File

@ -19,7 +19,10 @@ pub enum Error {
span: (usize, usize),
},
Runtime(RuntimeError),
Validation(ValidationError, (usize, usize)),
Validation {
error: ValidationError,
position: (usize, usize),
},
}
impl Error {
@ -46,7 +49,7 @@ impl Error {
.finish()
}
Error::Runtime(_) => todo!(),
Error::Validation(validation_error, position) => {
Error::Validation { error, position } => {
let mut report = Report::build(
ReportKind::Custom("Validation Error: The code was not run.", Color::White),
(),
@ -56,7 +59,7 @@ impl Error {
Label::new(position.0..position.1).with_message("Error found in this item."),
);
match validation_error {
match error {
ValidationError::ExpectedBoolean => {
report =
report.with_label(Label::new(0..0).with_message("Expected boolean."));

View File

@ -5,7 +5,7 @@ pub mod lexer;
pub mod parser;
pub mod value;
use abstract_tree::{AbstractTree, Action};
use abstract_tree::{AbstractTree, Action, WithPosition};
use context::Context;
use error::Error;
use lexer::lex;
@ -33,12 +33,13 @@ impl Interpreter {
let statements = parse(&tokens)?;
let errors = statements
.iter()
.filter_map(|statement| {
statement
.node
.validate(&self.context)
.filter_map(|WithPosition { node, position }| {
node.validate(&self.context)
.err()
.map(|validation_error| Error::Validation(validation_error, statement.position))
.map(|error| Error::Validation {
error,
position: position.clone(),
})
})
.collect::<Vec<Error>>();

View File

@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed<
'src,
'src,
ParserInput<'src>,
Vec<Positioned<Statement>>,
Vec<WithPosition<Statement>>,
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
>;
@ -21,7 +21,7 @@ pub type ParserInput<'src> =
pub fn parse<'src>(
tokens: &'src [(Token<'src>, SimpleSpan)],
) -> Result<Vec<Positioned<Statement>>, Vec<Error>> {
) -> Result<Vec<WithPosition<Statement>>, Vec<Error>> {
parser()
.parse(tokens.spanned((tokens.len()..tokens.len()).into()))
.into_result()
@ -53,7 +53,7 @@ pub fn parser<'src>() -> DustParser<'src> {
Token::Float(float) => ValueNode::Float(float),
Token::String(string) => ValueNode::String(string.to_string()),
}
.map_with(|value, state| Expression::Value(value).positioned(state.span()))
.map_with(|value, state| Expression::Value(value).with_position(state.span()))
.boxed();
let r#type = recursive(|r#type| {
@ -106,12 +106,12 @@ pub fn parser<'src>() -> DustParser<'src> {
.map(|identifier| Type::Custom(identifier)),
))
})
.map_with(|r#type, state| r#type.positioned(state.span()));
.map_with(|r#type, state| r#type.with_position(state.span()));
let type_specification = just(Token::Control(Control::Colon)).ignore_then(r#type.clone());
let statement = recursive(|statement| {
let block = statement
let positioned_statement = recursive(|positioned_statement| {
let block = positioned_statement
.clone()
.repeated()
.collect()
@ -123,11 +123,11 @@ pub fn parser<'src>() -> DustParser<'src> {
let positioned_block = block
.clone()
.map_with(|block, state| block.positioned(state.span()));
.map_with(|block, state| block.with_position(state.span()));
let expression = recursive(|expression| {
let positioned_expression = recursive(|positioned_expression| {
let identifier_expression = identifier.clone().map_with(|identifier, state| {
Expression::Identifier(identifier).positioned(state.span())
Expression::Identifier(identifier).with_position(state.span())
});
let range = {
@ -140,11 +140,11 @@ pub fn parser<'src>() -> DustParser<'src> {
.then_ignore(just(Token::Control(Control::DoubleDot)))
.then(raw_integer)
.map_with(|(start, end), state| {
Expression::Value(ValueNode::Range(start..end)).positioned(state.span())
Expression::Value(ValueNode::Range(start..end)).with_position(state.span())
})
};
let list = expression
let list = positioned_expression
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.allow_trailing()
@ -154,14 +154,14 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::SquareClose)),
)
.map_with(|list, state| {
Expression::Value(ValueNode::List(list)).positioned(state.span())
Expression::Value(ValueNode::List(list)).with_position(state.span())
});
let map_assignment = identifier
.clone()
.then(type_specification.clone().or_not())
.then_ignore(just(Token::Operator(Operator::Assign)))
.then(expression.clone())
.then(positioned_expression.clone())
.map(|((identifier, r#type), expression)| (identifier, r#type, expression));
let map = map_assignment
@ -173,7 +173,8 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::CurlyClose)),
)
.map_with(|map_assigment_list, state| {
Expression::Value(ValueNode::Map(map_assigment_list)).positioned(state.span())
Expression::Value(ValueNode::Map(map_assigment_list))
.with_position(state.span())
});
let function = identifier
@ -191,16 +192,16 @@ pub fn parser<'src>() -> DustParser<'src> {
Expression::Value(ValueNode::Function {
parameters,
return_type,
body: body.positioned(state.span()),
body: body.with_position(state.span()),
})
.positioned(state.span())
.with_position(state.span())
});
let function_expression = choice((identifier_expression.clone(), function.clone()));
let function_call = function_expression
.then(
expression
positioned_expression
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.collect()
@ -211,7 +212,7 @@ pub fn parser<'src>() -> DustParser<'src> {
)
.map_with(|(function, arguments), state| {
Expression::FunctionCall(FunctionCall::new(function, arguments))
.positioned(state.span())
.with_position(state.span())
});
let atom = choice((
@ -219,7 +220,7 @@ pub fn parser<'src>() -> DustParser<'src> {
identifier_expression.clone(),
basic_value.clone(),
list.clone(),
expression.clone().delimited_by(
positioned_expression.clone().delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
),
@ -229,41 +230,42 @@ pub fn parser<'src>() -> DustParser<'src> {
let logic_math_and_index = atom.pratt((
prefix(2, just(Token::Operator(Not)), |_, expression, span| {
Expression::Logic(Box::new(Logic::Not(expression))).positioned(span)
Expression::Logic(Box::new(Logic::Not(expression))).with_position(span)
}),
infix(
left(3),
just(Token::Control(Control::Dot)),
|left, _, right, span| {
Expression::Index(Box::new(Index::new(left, right))).positioned(span)
Expression::Index(Box::new(Index::new(left, right))).with_position(span)
},
),
infix(
left(1),
just(Token::Operator(Equal)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::Equal(left, right))).positioned(span)
Expression::Logic(Box::new(Logic::Equal(left, right))).with_position(span)
},
),
infix(
left(1),
just(Token::Operator(NotEqual)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::NotEqual(left, right))).positioned(span)
Expression::Logic(Box::new(Logic::NotEqual(left, right)))
.with_position(span)
},
),
infix(
left(1),
just(Token::Operator(Greater)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::Greater(left, right))).positioned(span)
Expression::Logic(Box::new(Logic::Greater(left, right))).with_position(span)
},
),
infix(
left(1),
just(Token::Operator(Less)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::Less(left, right))).positioned(span)
Expression::Logic(Box::new(Logic::Less(left, right))).with_position(span)
},
),
infix(
@ -271,7 +273,7 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Operator(GreaterOrEqual)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right)))
.positioned(span)
.with_position(span)
},
),
infix(
@ -279,56 +281,56 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Operator(LessOrEqual)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::LessOrEqual(left, right)))
.positioned(span)
.with_position(span)
},
),
infix(
left(1),
just(Token::Operator(And)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::And(left, right))).positioned(span)
Expression::Logic(Box::new(Logic::And(left, right))).with_position(span)
},
),
infix(
left(1),
just(Token::Operator(Or)),
|left, _, right, span| {
Expression::Logic(Box::new(Logic::Or(left, right))).positioned(span)
Expression::Logic(Box::new(Logic::Or(left, right))).with_position(span)
},
),
infix(
left(1),
just(Token::Operator(Add)),
|left, _, right, span| {
Expression::Math(Box::new(Math::Add(left, right))).positioned(span)
Expression::Math(Box::new(Math::Add(left, right))).with_position(span)
},
),
infix(
left(1),
just(Token::Operator(Subtract)),
|left, _, right, span| {
Expression::Math(Box::new(Math::Subtract(left, right))).positioned(span)
Expression::Math(Box::new(Math::Subtract(left, right))).with_position(span)
},
),
infix(
left(2),
just(Token::Operator(Multiply)),
|left, _, right, span| {
Expression::Math(Box::new(Math::Multiply(left, right))).positioned(span)
Expression::Math(Box::new(Math::Multiply(left, right))).with_position(span)
},
),
infix(
left(2),
just(Token::Operator(Divide)),
|left, _, right, span| {
Expression::Math(Box::new(Math::Divide(left, right))).positioned(span)
Expression::Math(Box::new(Math::Divide(left, right))).with_position(span)
},
),
infix(
left(1),
just(Token::Operator(Modulo)),
|left, _, right, span| {
Expression::Math(Box::new(Math::Modulo(left, right))).positioned(span)
Expression::Math(Box::new(Math::Modulo(left, right))).with_position(span)
},
),
));
@ -345,12 +347,15 @@ pub fn parser<'src>() -> DustParser<'src> {
))
});
let expression_statement = expression.clone().map_with(|expression, state| {
Statement::Expression(expression).positioned(state.span())
});
let expression_statement =
positioned_expression
.clone()
.map_with(|positioned_expression, state| {
Statement::Expression(positioned_expression.node).with_position(state.span())
});
let r#break = just(Token::Keyword("break"))
.map_with(|_, state| Statement::Break.positioned(state.span()));
.map_with(|_, state| Statement::Break.with_position(state.span()));
let assignment = identifier
.clone()
@ -360,17 +365,17 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign),
just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign),
)))
.then(statement.clone())
.then(positioned_statement.clone())
.map_with(|(((identifier, r#type), operator), statement), state| {
Statement::Assignment(Assignment::new(identifier, r#type, operator, statement))
.positioned(state.span())
.with_position(state.span())
});
let block_statement = block
.clone()
.map_with(|block, state| Statement::Block(block).positioned(state.span()));
.map_with(|block, state| Statement::Block(block).with_position(state.span()));
let r#loop = statement
let r#loop = positioned_statement
.clone()
.repeated()
.at_least(1)
@ -380,18 +385,18 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::CurlyClose)),
)
.map_with(|statements, state| {
Statement::Loop(Loop::new(statements)).positioned(state.span())
Statement::Loop(Loop::new(statements)).with_position(state.span())
});
let r#while = just(Token::Keyword("while"))
.ignore_then(expression.clone())
.ignore_then(positioned_expression.clone())
.then(block.clone())
.map_with(|(expression, block), state| {
Statement::While(While::new(expression, block)).positioned(state.span())
Statement::While(While::new(expression, block)).with_position(state.span())
});
let if_else = just(Token::Keyword("if"))
.ignore_then(expression.clone())
.ignore_then(positioned_expression.clone())
.then(positioned_block.clone())
.then(
just(Token::Keyword("else"))
@ -400,7 +405,7 @@ pub fn parser<'src>() -> DustParser<'src> {
)
.map_with(|((if_expression, if_block), else_block), state| {
Statement::IfElse(IfElse::new(if_expression, if_block, else_block))
.positioned(state.span())
.with_position(state.span())
});
choice((
@ -415,7 +420,7 @@ pub fn parser<'src>() -> DustParser<'src> {
.then_ignore(just(Token::Control(Control::Semicolon)).or_not())
});
statement.repeated().collect().boxed()
positioned_statement.repeated().collect().boxed()
}
#[cfg(test)]
@ -429,19 +434,18 @@ mod tests {
assert_eq!(
parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0],
Statement::While(While::new(
Expression::Value(ValueNode::Boolean(true)).positioned((6..11).into()),
Block::new(vec![Statement::Expression(
Expression::FunctionCall(FunctionCall::new(
Expression::Value(ValueNode::Boolean(true)).with_position((6..11).into()),
Block::new(vec![Statement::Expression(Expression::FunctionCall(
FunctionCall::new(
Expression::Identifier(Identifier::new("output"))
.positioned((13..19).into()),
.with_position((13..19).into()),
vec![Expression::Value(ValueNode::String("hi".to_string()))
.positioned((20..24).into())]
))
.positioned((13..26).into())
)
.positioned((13..26).into())])
.with_position((20..24).into())]
)
))
.with_position((13..26).into())])
))
.positioned((0..27).into())
.with_position((0..27).into())
)
}
@ -451,14 +455,12 @@ mod tests {
parse(&lex("foobar : bool = true").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Some(Type::Boolean.positioned((9..14).into())),
Some(Type::Boolean.with_position((9..14).into())),
AssignmentOperator::Assign,
Statement::Expression(
Expression::Value(ValueNode::Boolean(true)).positioned((16..20).into())
)
.positioned((16..20).into())
Statement::Expression(Expression::Value(ValueNode::Boolean(true)))
.with_position((16..20).into())
),)
.positioned((0..20).into())
.with_position((0..20).into())
);
}
@ -468,18 +470,15 @@ mod tests {
parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Some(Type::ListOf(Box::new(Type::Boolean)).positioned((9..20).into())),
Some(Type::ListOf(Box::new(Type::Boolean)).with_position((9..20).into())),
AssignmentOperator::Assign,
Statement::Expression(
Expression::Value(ValueNode::List(vec![Expression::Value(
ValueNode::Boolean(true)
)
.positioned((23..27).into())]))
.positioned((22..28).into())
Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value(
ValueNode::Boolean(true)
)
.positioned((22..28).into())
.with_position((23..27).into())])))
.with_position((22..28).into())
))
.positioned((0..28).into())
.with_position((0..28).into())
);
}
@ -489,19 +488,19 @@ mod tests {
parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Some(Type::ListExact(vec![Type::Boolean, Type::String]).positioned((9..21).into())),
Some(
Type::ListExact(vec![Type::Boolean, Type::String])
.with_position((9..21).into())
),
AssignmentOperator::Assign,
Statement::Expression(
Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Boolean(true)).positioned((24..28).into()),
Expression::Value(ValueNode::String("42".to_string()))
.positioned((30..34).into())
]))
.positioned((23..35).into())
)
.positioned((23..35).into())
Statement::Expression(Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Boolean(true)).with_position((24..28).into()),
Expression::Value(ValueNode::String("42".to_string()))
.with_position((30..34).into())
])))
.with_position((23..35).into())
),)
.positioned((0..35).into())
.with_position((0..35).into())
);
}
@ -516,40 +515,36 @@ mod tests {
parameter_types: vec![],
return_type: Box::new(Type::Any)
}
.positioned((9..19).into())
.with_position((9..19).into())
),
AssignmentOperator::Assign,
Statement::Expression(
Expression::Identifier(Identifier::new("some_function"))
.positioned((21..34).into())
)
.positioned((21..34).into())
Statement::Expression(Expression::Identifier(Identifier::new("some_function")))
.with_position((21..34).into())
),)
.positioned((0..34).into())
.with_position((0..34).into())
);
}
// #[test]
// fn function_call() {
// assert_eq!(
// parse(&lex("output()").unwrap()).unwrap()[0],
// Statement::expression(
// Expression::FunctionCall(FunctionCall::new(
// Expression::Identifier(Identifier::new("output")),
// Vec::with_capacity(0),
// )),
// (0..0).into()
// )
// )
// }
#[test]
fn function_call() {
assert_eq!(
parse(&lex("output()").unwrap()).unwrap()[0],
Statement::Expression(Expression::FunctionCall(FunctionCall::new(
Expression::Identifier(Identifier::new("output")).with_position((0..6).into()),
Vec::with_capacity(0),
)))
.with_position((0..8).into())
)
}
// #[test]
// fn range() {
// assert_eq!(
// parse(&lex("1..10").unwrap()).unwrap()[0],
// Statement::expression(Expression::Value(ValueNode::Range(1..10)), (0..0).into())
// )
// }
#[test]
fn range() {
assert_eq!(
parse(&lex("1..10").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Range(1..10)))
.with_position((0..5).into())
)
}
// #[test]
// fn function() {

View File

@ -13,7 +13,7 @@ use stanza::{
};
use crate::{
abstract_tree::{AbstractTree, Action, Block, Identifier, Positioned, Type},
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
context::Context,
error::{RuntimeError, ValidationError},
};
@ -55,9 +55,9 @@ impl Value {
}
pub fn function(
parameters: Vec<(Identifier, Positioned<Type>)>,
return_type: Positioned<Type>,
body: Positioned<Block>,
parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: WithPosition<Type>,
body: WithPosition<Block>,
) -> Self {
Value(Arc::new(ValueInner::Function(Function::Parsed(
ParsedFunction {
@ -330,9 +330,9 @@ impl Function {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct ParsedFunction {
parameters: Vec<(Identifier, Positioned<Type>)>,
return_type: Positioned<Type>,
body: Positioned<Block>,
parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: WithPosition<Type>,
body: WithPosition<Block>,
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]

View File

@ -62,7 +62,7 @@ fn function_context_does_not_capture_values() {
),
Err(vec![Error::Validation {
error: ValidationError::VariableNotFound(Identifier::new("x")),
span: (32, 66)
position: (0, 0)
}])
);

View File

@ -136,11 +136,15 @@ fn map_type_errors() {
assert_eq!(
interpret("{ foo : bool = 'bar' }"),
Err(vec![Error::Validation {
error: ValidationError::TypeCheck(TypeConflict {
actual: Type::String,
expected: Type::Boolean
}),
span: (0, 22)
error: ValidationError::TypeCheck {
conflict: TypeConflict {
actual: Type::String,
expected: Type::Boolean
},
actual_position: (0, 0),
expected_position: (0, 0),
},
position: (0, 22)
}])
);
}

View File

@ -1,5 +1,5 @@
use dust_lang::{
abstract_tree::{Block, Expression, Identifier, Statement, Type},
abstract_tree::{AbstractTree, Block, Expression, Identifier, Statement, Type},
error::{Error, TypeConflict, ValidationError},
*,
};
@ -25,11 +25,15 @@ fn set_variable_with_type_error() {
assert_eq!(
interpret("foobar: str = true"),
Err(vec![Error::Validation {
error: ValidationError::TypeCheck(TypeConflict {
actual: Type::Boolean,
expected: Type::String
}),
span: (0, 18)
error: ValidationError::TypeCheck {
conflict: TypeConflict {
actual: Type::Boolean,
expected: Type::String
},
actual_position: (0, 0),
expected_position: (0, 0)
},
position: (0, 18)
}])
);
}
@ -39,12 +43,16 @@ fn function_variable() {
assert_eq!(
interpret("foobar = (x: int): int { x }; foobar"),
Ok(Some(Value::function(
vec![(Identifier::new("x"), Type::Integer)],
Type::Integer,
Block::new(vec![Statement::expression(
Expression::Identifier(Identifier::new("x")),
(0..0).into()
)])
vec![(
Identifier::new("x"),
Type::Integer.with_position((0..0).into())
)],
Type::Integer.with_position((0..0).into()),
Block::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("x")
))
.with_position((0..0).into())])
.with_position((0..0).into())
)))
);
}