Add spans to all statements

This commit is contained in:
Jeff 2024-03-16 15:01:45 -04:00
parent 5b79af6e85
commit 15b1808741
12 changed files with 634 additions and 382 deletions

View File

@ -115,7 +115,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -138,7 +138,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::AddAssign, AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(41))), Statement::expression(Expression::Value(ValueNode::Integer(41)), (0..0).into()),
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -161,7 +161,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::SubAssign, AssignmentOperator::SubAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(1))), Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into()),
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -178,7 +178,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::Boolean), Some(Type::Boolean),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
) )
.validate(&Context::new()); .validate(&Context::new());

View File

@ -61,9 +61,9 @@ mod tests {
#[test] #[test]
fn run_returns_value_of_final_statement() { fn run_returns_value_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::Integer(1))), Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(2))), Statement::expression(Expression::Value(ValueNode::Integer(2)), (0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
]); ]);
assert_eq!( assert_eq!(
@ -75,8 +75,11 @@ mod tests {
#[test] #[test]
fn expected_type_returns_type_of_final_statement() { fn expected_type_returns_type_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))), Statement::expression(
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Expression::Value(ValueNode::String("42".to_string())),
(0..0).into(),
),
Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
]); ]);
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer)) assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))

View File

@ -62,8 +62,7 @@ impl AbstractTree for IfElse {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
abstract_tree::{Action, Statement, ValueNode}, abstract_tree::{Statement, ValueNode},
context::Context,
Value, Value,
}; };
@ -74,9 +73,10 @@ mod tests {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string())),
)),]), (0..0).into()
)]),
None None
) )
.run(&Context::new()), .run(&Context::new()),
@ -89,12 +89,14 @@ mod tests {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(false)), Expression::Value(ValueNode::Boolean(false)),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string())),
)),]), (0..0).into()
Some(Block::new(vec![Statement::Expression(Expression::Value( ),]),
ValueNode::String("bar".to_string()) Some(Block::new(vec![Statement::expression(
))])) Expression::Value(ValueNode::String("bar".to_string())),
(0..0).into()
)]))
) )
.run(&Context::new()), .run(&Context::new()),
Ok(Action::Return(Value::string("bar".to_string()))) Ok(Action::Return(Value::string("bar".to_string())))

View File

@ -122,7 +122,7 @@ impl AbstractTree for Logic {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::abstract_tree::{Expression, ValueNode}; use crate::abstract_tree::ValueNode;
use super::*; use super::*;

View File

@ -58,7 +58,7 @@ mod tests {
#[test] #[test]
fn basic_loop() { fn basic_loop() {
let result = Loop { let result = Loop {
statements: vec![Statement::Break], statements: vec![Statement::r#break((0..1).into())],
} }
.run(&Context::new()); .run(&Context::new());

View File

@ -1,3 +1,5 @@
use chumsky::span::{SimpleSpan, Span};
use crate::{ use crate::{
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
@ -6,7 +8,72 @@ use crate::{
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While}; use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement { pub struct Statement {
pub inner: StatementInner,
pub span: (usize, usize),
}
impl Statement {
pub fn assignment(assignment: Assignment, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Assignment(assignment),
span: (span.start(), span.end()),
}
}
pub fn block(block: Block, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Block(block),
span: (span.start(), span.end()),
}
}
pub fn r#break(span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Break,
span: (span.start(), span.end()),
}
}
pub fn expression(expression: Expression, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Expression(expression),
span: (span.start(), span.end()),
}
}
pub fn if_else(if_else: IfElse, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::IfElse(if_else),
span: (span.start(), span.end()),
}
}
pub fn r#loop(r#loop: Loop, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Loop(r#loop),
span: (span.start(), span.end()),
}
}
pub fn r#while(r#while: While, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::While(r#while),
span: (span.start(), span.end()),
}
}
pub fn span(&self) -> (usize, usize) {
self.span
}
pub fn inner(&self) -> &StatementInner {
&self.inner
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum StatementInner {
Assignment(Assignment), Assignment(Assignment),
Block(Block), Block(Block),
Break, Break,
@ -18,38 +85,38 @@ pub enum Statement {
impl AbstractTree for Statement { impl AbstractTree for Statement {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
match self { match &self.inner {
Statement::Assignment(assignment) => assignment.expected_type(_context), StatementInner::Assignment(assignment) => assignment.expected_type(_context),
Statement::Block(block) => block.expected_type(_context), StatementInner::Block(block) => block.expected_type(_context),
Statement::Break => Ok(Type::None), StatementInner::Break => Ok(Type::None),
Statement::Expression(expression) => expression.expected_type(_context), StatementInner::Expression(expression) => expression.expected_type(_context),
Statement::IfElse(if_else) => if_else.expected_type(_context), StatementInner::IfElse(if_else) => if_else.expected_type(_context),
Statement::Loop(r#loop) => r#loop.expected_type(_context), StatementInner::Loop(r#loop) => r#loop.expected_type(_context),
Statement::While(r#while) => r#while.expected_type(_context), StatementInner::While(r#while) => r#while.expected_type(_context),
} }
} }
fn validate(&self, _context: &Context) -> Result<(), ValidationError> { fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
match self { match &self.inner {
Statement::Assignment(assignment) => assignment.validate(_context), StatementInner::Assignment(assignment) => assignment.validate(_context),
Statement::Block(block) => block.validate(_context), StatementInner::Block(block) => block.validate(_context),
Statement::Break => Ok(()), StatementInner::Break => Ok(()),
Statement::Expression(expression) => expression.validate(_context), StatementInner::Expression(expression) => expression.validate(_context),
Statement::IfElse(if_else) => if_else.validate(_context), StatementInner::IfElse(if_else) => if_else.validate(_context),
Statement::Loop(r#loop) => r#loop.validate(_context), StatementInner::Loop(r#loop) => r#loop.validate(_context),
Statement::While(r#while) => r#while.validate(_context), StatementInner::While(r#while) => r#while.validate(_context),
} }
} }
fn run(self, _context: &Context) -> Result<Action, RuntimeError> { fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
match self { match self.inner {
Statement::Assignment(assignment) => assignment.run(_context), StatementInner::Assignment(assignment) => assignment.run(_context),
Statement::Block(block) => block.run(_context), StatementInner::Block(block) => block.run(_context),
Statement::Break => Ok(Action::Break), StatementInner::Break => Ok(Action::Break),
Statement::Expression(expression) => expression.run(_context), StatementInner::Expression(expression) => expression.run(_context),
Statement::IfElse(if_else) => if_else.run(_context), StatementInner::IfElse(if_else) => if_else.run(_context),
Statement::Loop(r#loop) => r#loop.run(_context), StatementInner::Loop(r#loop) => r#loop.run(_context),
Statement::While(r#while) => r#while.run(_context), StatementInner::While(r#while) => r#while.run(_context),
} }
} }
} }

View File

@ -1,7 +1,7 @@
use std::sync::PoisonError; use std::sync::PoisonError;
use ariadne::{Color, Label, Report, ReportKind}; use ariadne::{Color, Label, Report, ReportKind};
use chumsky::{prelude::Rich, span::SimpleSpan}; use chumsky::{prelude::Rich, span::Span};
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Type},
@ -12,76 +12,70 @@ use crate::{
pub enum Error { pub enum Error {
Parse { Parse {
expected: String, expected: String,
span: SimpleSpan, span: (usize, usize),
}, },
Lex { Lex {
expected: String, expected: String,
span: SimpleSpan, span: (usize, usize),
}, },
Runtime(RuntimeError), Runtime(RuntimeError),
Validation { Validation {
error: ValidationError, error: ValidationError,
span: SimpleSpan, span: (usize, usize),
}, },
} }
impl Error { impl Error {
pub fn report(&self) -> Report { pub fn report(&self) -> Report {
match self { match self {
Error::Parse { expected, span } => Report::build( Error::Parse { expected, span } => {
ReportKind::Custom("Parsing Error", Color::White), let message = match expected.as_str() {
(), "" => "Invalid character.".to_string(),
span.start, expected => format!("Expected {expected}."),
)
.with_label(
Label::new(span.start..span.end).with_message(format!("Expected {expected}.")),
)
.finish(),
Error::Lex { expected, span } => {
let expected = match expected.as_str() {
"" => "something else",
expected => expected,
}; };
Report::build( Report::build(ReportKind::Custom("Lexing Error", Color::White), (), span.0)
ReportKind::Custom("Lexing Error", Color::White), .with_label(Label::new(span.0..span.1).with_message(message))
(), .finish()
span.start, }
) Error::Lex { expected, span } => {
.with_label( let message = match expected.as_str() {
Label::new(span.start..span.end).with_message(format!("Expected {expected}.")), "" => "Invalid character.".to_string(),
) expected => format!("Expected {expected}."),
.finish() };
Report::build(ReportKind::Custom("Lexing Error", Color::White), (), span.0)
.with_label(Label::new(span.0..span.1).with_message(message))
.finish()
} }
Error::Runtime(_) => todo!(), Error::Runtime(_) => todo!(),
Error::Validation { error, span } => { Error::Validation { error, span } => {
let mut report = Report::build( let mut report = Report::build(
ReportKind::Custom("Validation Error", Color::White), ReportKind::Custom("Validation Error", Color::White),
(), (),
span.start, span.0,
); );
match error { match error {
ValidationError::ExpectedBoolean => { ValidationError::ExpectedBoolean => {
report = report.with_label( report = report.with_label(
Label::new(span.start..span.end).with_message("Expected boolean."), Label::new(span.0..span.1).with_message("Expected boolean."),
); );
} }
ValidationError::ExpectedIntegerOrFloat => { ValidationError::ExpectedIntegerOrFloat => {
report = report.with_label( report = report.with_label(
Label::new(span.start..span.end) Label::new(span.0..span.1).with_message("Expected integer or float."),
.with_message("Expected integer or float."),
); );
} }
ValidationError::RwLockPoison(_) => todo!(), ValidationError::RwLockPoison(_) => todo!(),
ValidationError::TypeCheck(TypeCheckError { actual, expected }) => { ValidationError::TypeCheck(TypeCheckError { actual, expected }) => {
report = report.with_label(Label::new(span.start..span.end).with_message( report = report.with_label(Label::new(span.0..span.1).with_message(
format!("Type error. Expected {expected} but got {actual}."), format!("Type error. Expected {expected} but got {actual}."),
)); ));
} }
ValidationError::VariableNotFound(identifier) => { ValidationError::VariableNotFound(identifier) => {
report = report report = report
.with_label(Label::new(span.start..span.end).with_message(format!( .with_label(Label::new(span.0..span.1).with_message(format!(
"The variable {identifier} does not exist." "The variable {identifier} does not exist."
))); )));
} }
@ -102,7 +96,7 @@ impl From<Rich<'_, char>> for Error {
fn from(error: Rich<'_, char>) -> Self { fn from(error: Rich<'_, char>) -> Self {
Error::Lex { Error::Lex {
expected: error.expected().map(|error| error.to_string()).collect(), expected: error.expected().map(|error| error.to_string()).collect(),
span: error.span().clone(), span: (error.span().start(), error.span().end()),
} }
} }
} }
@ -111,7 +105,7 @@ impl<'src> From<Rich<'_, Token<'src>>> for Error {
fn from(error: Rich<'_, Token<'src>>) -> Self { fn from(error: Rich<'_, Token<'src>>) -> Self {
Error::Parse { Error::Parse {
expected: error.expected().map(|error| error.to_string()).collect(), expected: error.expected().map(|error| error.to_string()).collect(),
span: error.span().clone(), span: (error.span().start(), error.span().end()),
} }
} }
} }

View File

@ -33,12 +33,12 @@ impl Interpreter {
let statements = parse(&tokens)?; let statements = parse(&tokens)?;
let errors = statements let errors = statements
.iter() .iter()
.filter_map(|(statement, span)| { .filter_map(|statement| {
statement statement
.validate(&self.context) .validate(&self.context)
.map_err(|validation_error| Error::Validation { .map_err(|validation_error| Error::Validation {
error: validation_error, error: validation_error,
span: span.clone(), span: statement.span(),
}) })
.err() .err()
}) })
@ -50,7 +50,7 @@ impl Interpreter {
let mut value = None; let mut value = None;
for (statement, _span) in statements { for statement in statements {
value = match statement.run(&self.context) { value = match statement.run(&self.context) {
Ok(action) => match action { Ok(action) => match action {
Action::Break => None, Action::Break => None,

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -140,7 +140,7 @@ fn map_type_errors() {
actual: Type::String, actual: Type::String,
expected: Type::Boolean expected: Type::Boolean
}), }),
span: (0..22).into() span: (0, 22)
}]) }])
); );
} }

View File

@ -29,7 +29,7 @@ fn set_variable_with_type_error() {
actual: Type::Boolean, actual: Type::Boolean,
expected: Type::String expected: Type::String
}), }),
span: (0..18).into() span: (0, 18)
}]) }])
); );
} }
@ -41,9 +41,10 @@ fn function_variable() {
Ok(Some(Value::function( Ok(Some(Value::function(
vec![(Identifier::new("x"), Type::Integer)], vec![(Identifier::new("x"), Type::Integer)],
Type::Integer, Type::Integer,
Block::new(vec![Statement::Expression(Expression::Identifier( Block::new(vec![Statement::expression(
Identifier::new("x") Expression::Identifier(Identifier::new("x")),
))]) (0..0).into()
)])
))) )))
); );
} }