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

View File

@ -61,9 +61,9 @@ mod tests {
#[test]
fn run_returns_value_of_final_statement() {
let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::Integer(1))),
Statement::Expression(Expression::Value(ValueNode::Integer(2))),
Statement::Expression(Expression::Value(ValueNode::Integer(42))),
Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into()),
Statement::expression(Expression::Value(ValueNode::Integer(2)), (0..0).into()),
Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
]);
assert_eq!(
@ -75,8 +75,11 @@ 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()))),
Statement::Expression(Expression::Value(ValueNode::Integer(42))),
Statement::expression(
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))

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
use std::sync::PoisonError;
use ariadne::{Color, Label, Report, ReportKind};
use chumsky::{prelude::Rich, span::SimpleSpan};
use chumsky::{prelude::Rich, span::Span};
use crate::{
abstract_tree::{Identifier, Type},
@ -12,76 +12,70 @@ use crate::{
pub enum Error {
Parse {
expected: String,
span: SimpleSpan,
span: (usize, usize),
},
Lex {
expected: String,
span: SimpleSpan,
span: (usize, usize),
},
Runtime(RuntimeError),
Validation {
error: ValidationError,
span: SimpleSpan,
span: (usize, usize),
},
}
impl Error {
pub fn report(&self) -> Report {
match self {
Error::Parse { expected, span } => Report::build(
ReportKind::Custom("Parsing Error", Color::White),
(),
span.start,
)
.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,
Error::Parse { expected, span } => {
let message = match expected.as_str() {
"" => "Invalid character.".to_string(),
expected => format!("Expected {expected}."),
};
Report::build(
ReportKind::Custom("Lexing Error", Color::White),
(),
span.start,
)
.with_label(
Label::new(span.start..span.end).with_message(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::Lex { expected, span } => {
let message = match expected.as_str() {
"" => "Invalid character.".to_string(),
expected => format!("Expected {expected}."),
};
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::Validation { error, span } => {
let mut report = Report::build(
ReportKind::Custom("Validation Error", Color::White),
(),
span.start,
span.0,
);
match error {
ValidationError::ExpectedBoolean => {
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 => {
report = report.with_label(
Label::new(span.start..span.end)
.with_message("Expected integer or float."),
Label::new(span.0..span.1).with_message("Expected integer or float."),
);
}
ValidationError::RwLockPoison(_) => todo!(),
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}."),
));
}
ValidationError::VariableNotFound(identifier) => {
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."
)));
}
@ -102,7 +96,7 @@ impl From<Rich<'_, char>> for Error {
fn from(error: Rich<'_, char>) -> Self {
Error::Lex {
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 {
Error::Parse {
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 errors = statements
.iter()
.filter_map(|(statement, span)| {
.filter_map(|statement| {
statement
.validate(&self.context)
.map_err(|validation_error| Error::Validation {
error: validation_error,
span: span.clone(),
span: statement.span(),
})
.err()
})
@ -50,7 +50,7 @@ impl Interpreter {
let mut value = None;
for (statement, _span) in statements {
for statement in statements {
value = match statement.run(&self.context) {
Ok(action) => match action {
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 {
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,
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,
expected: Type::String
}),
span: (0..18).into()
span: (0, 18)
}])
);
}
@ -41,9 +41,10 @@ fn function_variable() {
Ok(Some(Value::function(
vec![(Identifier::new("x"), Type::Integer)],
Type::Integer,
Block::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("x")
))])
Block::new(vec![Statement::expression(
Expression::Identifier(Identifier::new("x")),
(0..0).into()
)])
)))
);
}