Improve errors

This commit is contained in:
Jeff 2024-08-23 05:54:58 -04:00
parent 0d0a2d2237
commit e84bb2ea70
6 changed files with 68 additions and 55 deletions

View File

@ -102,9 +102,8 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
position: identifier.position,
})?;
} else {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: value.clone(),
found_type: r#type,
return Err(AnalysisError::LetExpectedValueFromStatement {
actual: value.clone(),
});
}
@ -234,7 +233,6 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
} else {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: index.clone(),
found_type: None,
});
};
@ -313,7 +311,6 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if list_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: list.clone(),
found_type: list_type,
});
}
}
@ -361,14 +358,12 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if expected_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: assignee.clone(),
found_type: expected_type,
});
}
if actual_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: modifier.clone(),
found_type: actual_type,
});
}
@ -399,14 +394,12 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if left_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(),
found_type: left_type,
});
}
if right_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: right.clone(),
found_type: right_type,
});
}
@ -428,14 +421,12 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if left_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(),
found_type: left_type,
});
}
if right_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: right.clone(),
found_type: right_type,
});
}
@ -557,12 +548,11 @@ pub enum AnalysisError {
ExpectedIdentifierOrString {
actual: Expression,
},
ExpectedValueFromStatement {
actual: Statement,
LetExpectedValueFromStatement {
actual: Expression,
},
ExpectedValueFromExpression {
expression: Expression,
found_type: Option<Type>,
},
ExpectedValueArgumentCount {
expected: usize,
@ -623,9 +613,9 @@ impl AnalysisError {
AnalysisError::ExpectedIdentifier { actual } => actual.position(),
AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(),
AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(),
AnalysisError::ExpectedValueFromStatement { actual } => actual.position(),
AnalysisError::ExpectedValueArgumentCount { position, .. } => *position,
AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
AnalysisError::LetExpectedValueFromStatement { actual } => actual.position(),
AnalysisError::NegativeIndex { index, .. } => index.position(),
AnalysisError::TypeConflict {
actual_expression, ..
@ -653,7 +643,7 @@ impl Display for AnalysisError {
} => {
write!(
f,
"Expected type {:?}, found {:?} in {}",
"Expected type {}, found {} in {}",
expected, actual, actual_expression
)
}
@ -662,11 +652,19 @@ impl Display for AnalysisError {
actual,
actual_expression,
} => {
write!(
f,
"Expected one of {:?}, found {:?} in {}",
expected, actual, actual_expression
)
write!(f, "Expected ")?;
for (i, expected_type) in expected.iter().enumerate() {
if i == expected.len() - 1 {
write!(f, "or ")?;
} else if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", expected_type)?;
}
write!(f, ", found {} in {}", actual, actual_expression)
}
AnalysisError::ExpectedIdentifier { actual, .. } => {
@ -675,18 +673,8 @@ impl Display for AnalysisError {
AnalysisError::ExpectedIdentifierOrString { actual } => {
write!(f, "Expected identifier or string, found {}", actual)
}
AnalysisError::ExpectedValueFromExpression {
expression,
found_type,
} => {
write!(
f,
"Expected {} to produce a value, found {:?}",
expression, found_type
)
}
AnalysisError::ExpectedValueFromStatement { actual, .. } => {
write!(f, "Expected statement to produce a value, found {}", actual)
AnalysisError::ExpectedValueFromExpression { expression } => {
write!(f, "Expected {} to produce a value", expression)
}
AnalysisError::ExpectedValueArgumentCount {
expected, actual, ..
@ -701,6 +689,13 @@ impl Display for AnalysisError {
"Index {} out of bounds for list {} with length {}",
index_value, list, length
),
AnalysisError::LetExpectedValueFromStatement { actual, .. } => {
write!(
f,
"Cannot assign to nothing. This expression should produce a value, but {} does not",
actual
)
}
AnalysisError::NegativeIndex {
list, index_value, ..
} => write!(f, "Negative index {} for list {}", index_value, list),

View File

@ -681,7 +681,7 @@ impl Display for PrimitiveValueExpression {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
PrimitiveValueExpression::Boolean(boolean) => write!(f, "{boolean}"),
PrimitiveValueExpression::Character(character) => write!(f, "{character}"),
PrimitiveValueExpression::Character(character) => write!(f, "'{character}'"),
PrimitiveValueExpression::Float(float) => write!(f, "{float}"),
PrimitiveValueExpression::Integer(integer) => write!(f, "{integer}"),
}
@ -772,7 +772,7 @@ impl Display for LiteralExpression {
LiteralExpression::Primitive(primitive) => {
write!(f, "{primitive}")
}
LiteralExpression::String(string) => write!(f, "{string}"),
LiteralExpression::String(string) => write!(f, "\"{string}\""),
}
}
}
@ -1065,27 +1065,27 @@ impl Display for BlockExpression {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
BlockExpression::Async(statements) => {
writeln!(f, "async {{ ")?;
write!(f, "async {{ ")?;
for (i, statement) in statements.iter().enumerate() {
if i > 0 {
writeln!(f, " ")?;
write!(f, " ")?;
}
writeln!(f, "{}", statement)?;
write!(f, "{}", statement)?;
}
write!(f, " }}")
}
BlockExpression::Sync(statements) => {
writeln!(f, "{{ ")?;
write!(f, "{{ ")?;
for (i, statement) in statements.iter().enumerate() {
if i > 0 {
writeln!(f, " ")?;
write!(f, " ")?;
}
writeln!(f, "{}", statement)?;
write!(f, "{}", statement)?;
}
write!(f, " }}")

View File

@ -3,10 +3,7 @@
//! This module provides two lexing options:
//! - [`lex`], which lexes the entire input and returns a vector of tokens and their positions
//! - [`Lexer`], which lexes the input a token at a time
use std::{
error::Error,
fmt::{self, Display, Formatter},
};
use std::fmt::{self, Display, Formatter};
use crate::{ast::Span, Token};
@ -131,7 +128,7 @@ impl<'src> Lexer<'src> {
}
}
'a'..='z' | 'A'..='Z' => self.lex_alphanumeric()?,
'"' => self.lex_string('"')?,
'"' => self.lex_string()?,
'\'' => {
self.position += 1;
@ -465,13 +462,13 @@ impl<'src> Lexer<'src> {
Ok((token, (start_pos, self.position)))
}
fn lex_string(&mut self, delimiter: char) -> Result<(Token<'src>, Span), LexError> {
fn lex_string(&mut self) -> Result<(Token<'src>, Span), LexError> {
let start_pos = self.position;
self.next_char();
while let Some(c) = self.peek_char() {
if c == delimiter {
if c == '"' {
self.next_char();
break;
} else {

View File

@ -4,7 +4,6 @@
//! - `parse` convenience function
//! - `Parser` struct, which parses the input a statement at a time
use std::{
error::Error,
fmt::{self, Display, Formatter},
num::{ParseFloatError, ParseIntError},
str::ParseBoolError,
@ -436,6 +435,13 @@ impl<'src> Parser<'src> {
Ok(Expression::r#break(expression_option, position))
}
Token::Character(character) => {
self.next_token()?;
let expression = Expression::literal(character, start_position);
Ok(expression)
}
Token::Float(text) => {
self.next_token()?;
@ -1158,11 +1164,22 @@ impl Display for ParseError {
#[cfg(test)]
mod tests {
use crate::{Identifier, Type};
use super::*;
#[test]
fn character_literal() {
let source = "'a'";
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::literal('a', (0, 3)))
]))
);
}
#[test]
fn break_loop() {
let source = "loop { break; }";

View File

@ -1,8 +1,5 @@
//! Token and TokenOwned types.
use std::{
borrow::Borrow,
fmt::{self, Display, Formatter},
};
use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};

View File

@ -1402,11 +1402,18 @@ mod tests {
use super::*;
#[test]
fn character() {
let input = "'a'";
assert_eq!(run(input), Ok(Some(Value::character('a'))));
}
#[test]
fn break_loop() {
let input = "let mut x = 0; loop { x += 1; if x == 10 { break; } } x";
assert_eq!(run(input), Ok(Some(Value::mutable(Value::integer(10)))));
assert_eq!(run(input), Ok(Some(Value::integer(10))));
}
#[test]