Improve errors
This commit is contained in:
parent
0d0a2d2237
commit
e84bb2ea70
@ -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),
|
||||||
|
@ -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, " }}")
|
||||||
|
@ -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 {
|
||||||
|
@ -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; }";
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
Loading…
Reference in New Issue
Block a user