Add spans to all statements
This commit is contained in:
parent
5b79af6e85
commit
15b1808741
@ -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());
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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())))
|
||||
|
@ -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::*;
|
||||
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
62
src/error.rs
62
src/error.rs
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
769
src/parser.rs
769
src/parser.rs
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
}])
|
||||
);
|
||||
|
||||
|
@ -140,7 +140,7 @@ fn map_type_errors() {
|
||||
actual: Type::String,
|
||||
expected: Type::Boolean
|
||||
}),
|
||||
span: (0..22).into()
|
||||
span: (0, 22)
|
||||
}])
|
||||
);
|
||||
}
|
||||
|
@ -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()
|
||||
)])
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user