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, position: identifier.position,
})?; })?;
} else { } else {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::LetExpectedValueFromStatement {
expression: value.clone(), actual: value.clone(),
found_type: r#type,
}); });
} }
@ -234,7 +233,6 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
} else { } else {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: index.clone(), expression: index.clone(),
found_type: None,
}); });
}; };
@ -313,7 +311,6 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if list_type.is_none() { if list_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: list.clone(), expression: list.clone(),
found_type: list_type,
}); });
} }
} }
@ -361,14 +358,12 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if expected_type.is_none() { if expected_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: assignee.clone(), expression: assignee.clone(),
found_type: expected_type,
}); });
} }
if actual_type.is_none() { if actual_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: modifier.clone(), expression: modifier.clone(),
found_type: actual_type,
}); });
} }
@ -399,14 +394,12 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if left_type.is_none() { if left_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(), expression: left.clone(),
found_type: left_type,
}); });
} }
if right_type.is_none() { if right_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: right.clone(), expression: right.clone(),
found_type: right_type,
}); });
} }
@ -428,14 +421,12 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
if left_type.is_none() { if left_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(), expression: left.clone(),
found_type: left_type,
}); });
} }
if right_type.is_none() { if right_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression { return Err(AnalysisError::ExpectedValueFromExpression {
expression: right.clone(), expression: right.clone(),
found_type: right_type,
}); });
} }
@ -557,12 +548,11 @@ pub enum AnalysisError {
ExpectedIdentifierOrString { ExpectedIdentifierOrString {
actual: Expression, actual: Expression,
}, },
ExpectedValueFromStatement { LetExpectedValueFromStatement {
actual: Statement, actual: Expression,
}, },
ExpectedValueFromExpression { ExpectedValueFromExpression {
expression: Expression, expression: Expression,
found_type: Option<Type>,
}, },
ExpectedValueArgumentCount { ExpectedValueArgumentCount {
expected: usize, expected: usize,
@ -623,9 +613,9 @@ impl AnalysisError {
AnalysisError::ExpectedIdentifier { actual } => actual.position(), AnalysisError::ExpectedIdentifier { actual } => actual.position(),
AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(), AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(),
AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(), AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(),
AnalysisError::ExpectedValueFromStatement { actual } => actual.position(),
AnalysisError::ExpectedValueArgumentCount { position, .. } => *position, AnalysisError::ExpectedValueArgumentCount { position, .. } => *position,
AnalysisError::IndexOutOfBounds { index, .. } => index.position(), AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
AnalysisError::LetExpectedValueFromStatement { actual } => actual.position(),
AnalysisError::NegativeIndex { index, .. } => index.position(), AnalysisError::NegativeIndex { index, .. } => index.position(),
AnalysisError::TypeConflict { AnalysisError::TypeConflict {
actual_expression, .. actual_expression, ..
@ -653,7 +643,7 @@ impl Display for AnalysisError {
} => { } => {
write!( write!(
f, f,
"Expected type {:?}, found {:?} in {}", "Expected type {}, found {} in {}",
expected, actual, actual_expression expected, actual, actual_expression
) )
} }
@ -662,11 +652,19 @@ impl Display for AnalysisError {
actual, actual,
actual_expression, actual_expression,
} => { } => {
write!( write!(f, "Expected ")?;
f,
"Expected one of {:?}, found {:?} in {}", for (i, expected_type) in expected.iter().enumerate() {
expected, actual, actual_expression 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, .. } => { AnalysisError::ExpectedIdentifier { actual, .. } => {
@ -675,18 +673,8 @@ impl Display for AnalysisError {
AnalysisError::ExpectedIdentifierOrString { actual } => { AnalysisError::ExpectedIdentifierOrString { actual } => {
write!(f, "Expected identifier or string, found {}", actual) write!(f, "Expected identifier or string, found {}", actual)
} }
AnalysisError::ExpectedValueFromExpression { AnalysisError::ExpectedValueFromExpression { expression } => {
expression, write!(f, "Expected {} to produce a value", 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::ExpectedValueArgumentCount { AnalysisError::ExpectedValueArgumentCount {
expected, actual, .. expected, actual, ..
@ -701,6 +689,13 @@ impl Display for AnalysisError {
"Index {} out of bounds for list {} with length {}", "Index {} out of bounds for list {} with length {}",
index_value, list, 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 { AnalysisError::NegativeIndex {
list, index_value, .. list, index_value, ..
} => write!(f, "Negative index {} for list {}", index_value, list), } => 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 { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self { match self {
PrimitiveValueExpression::Boolean(boolean) => write!(f, "{boolean}"), 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::Float(float) => write!(f, "{float}"),
PrimitiveValueExpression::Integer(integer) => write!(f, "{integer}"), PrimitiveValueExpression::Integer(integer) => write!(f, "{integer}"),
} }
@ -772,7 +772,7 @@ impl Display for LiteralExpression {
LiteralExpression::Primitive(primitive) => { LiteralExpression::Primitive(primitive) => {
write!(f, "{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 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
BlockExpression::Async(statements) => { BlockExpression::Async(statements) => {
writeln!(f, "async {{ ")?; write!(f, "async {{ ")?;
for (i, statement) in statements.iter().enumerate() { for (i, statement) in statements.iter().enumerate() {
if i > 0 { if i > 0 {
writeln!(f, " ")?; write!(f, " ")?;
} }
writeln!(f, "{}", statement)?; write!(f, "{}", statement)?;
} }
write!(f, " }}") write!(f, " }}")
} }
BlockExpression::Sync(statements) => { BlockExpression::Sync(statements) => {
writeln!(f, "{{ ")?; write!(f, "{{ ")?;
for (i, statement) in statements.iter().enumerate() { for (i, statement) in statements.iter().enumerate() {
if i > 0 { if i > 0 {
writeln!(f, " ")?; write!(f, " ")?;
} }
writeln!(f, "{}", statement)?; write!(f, "{}", statement)?;
} }
write!(f, " }}") write!(f, " }}")

View File

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

View File

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

View File

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

View File

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