Pass analyzer tests

This commit is contained in:
Jeff 2024-08-20 19:20:38 -04:00
parent e22d0254f5
commit e1e40cf931

View File

@ -225,7 +225,18 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
Expression::ListIndex(list_index_expression) => { Expression::ListIndex(list_index_expression) => {
let ListIndexExpression { list, index } = list_index_expression.inner.as_ref(); let ListIndexExpression { list, index } = list_index_expression.inner.as_ref();
self.analyze_expression(list)?;
self.analyze_expression(index)?;
let list_type = list.return_type(&self.context)?; let list_type = list.return_type(&self.context)?;
let index_type = if let Some(r#type) = index.return_type(&self.context)? {
r#type
} else {
return Err(AnalysisError::ExpectedValueFromExpression {
expression: index.clone(),
found_type: None,
});
};
let literal_type = if let Expression::Literal(Node { inner, .. }) = index { let literal_type = if let Expression::Literal(Node { inner, .. }) = index {
Some(inner.as_ref().clone()) Some(inner.as_ref().clone())
@ -233,12 +244,31 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
None None
}; };
if let Some(LiteralExpression::Primitive(PrimitiveValueExpression::Integer(
integer,
))) = literal_type
{
if integer < 0 {
return Err(AnalysisError::NegativeIndex {
index: index.clone(),
index_value: integer,
list: list.clone(),
});
}
} else {
return Err(AnalysisError::ExpectedType {
expected: Type::Integer,
actual: index_type,
actual_expression: index.clone(),
});
}
if let Some(Type::List { length, .. }) = list_type { if let Some(Type::List { length, .. }) = list_type {
if let Some(LiteralExpression::Primitive(PrimitiveValueExpression::Integer( if let Some(LiteralExpression::Primitive(PrimitiveValueExpression::Integer(
integer, integer,
))) = literal_type ))) = literal_type
{ {
if integer < 0 || integer >= length as i64 { if integer >= length as i64 {
return Err(AnalysisError::IndexOutOfBounds { return Err(AnalysisError::IndexOutOfBounds {
index: index.clone(), index: index.clone(),
length, length,
@ -257,7 +287,7 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
integer, integer,
))) = literal_type ))) = literal_type
{ {
if integer < 0 || integer >= length as i64 { if integer >= length as i64 {
return Err(AnalysisError::IndexOutOfBounds { return Err(AnalysisError::IndexOutOfBounds {
index: index.clone(), index: index.clone(),
length, length,
@ -274,9 +304,6 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
found_type: list_type, found_type: list_type,
}); });
} }
self.analyze_expression(list)?;
self.analyze_expression(index)?;
} }
Expression::Literal(_) => { Expression::Literal(_) => {
// Literals don't need to be analyzed // Literals don't need to be analyzed
@ -536,6 +563,11 @@ pub enum AnalysisError {
index_value: i64, index_value: i64,
length: usize, length: usize,
}, },
NegativeIndex {
list: Expression,
index: Expression,
index_value: i64,
},
TypeConflict { TypeConflict {
actual_expression: Expression, actual_expression: Expression,
actual_type: Type, actual_type: Type,
@ -582,6 +614,7 @@ impl AnalysisError {
AnalysisError::ExpectedValueFromStatement { actual } => actual.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::NegativeIndex { index, .. } => index.position(),
AnalysisError::TypeConflict { AnalysisError::TypeConflict {
actual_expression, .. actual_expression, ..
} => actual_expression.position(), } => actual_expression.position(),
@ -601,7 +634,6 @@ impl Display for AnalysisError {
match self { match self {
AnalysisError::AstError(ast_error) => write!(f, "{}", ast_error), AnalysisError::AstError(ast_error) => write!(f, "{}", ast_error),
AnalysisError::ContextError { error, .. } => write!(f, "{}", error), AnalysisError::ContextError { error, .. } => write!(f, "{}", error),
AnalysisError::ExpectedType { AnalysisError::ExpectedType {
expected, expected,
actual, actual,
@ -657,6 +689,9 @@ 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::NegativeIndex {
list, index_value, ..
} => write!(f, "Negative index {} for list {}", index_value, list),
AnalysisError::TypeConflict { AnalysisError::TypeConflict {
actual_expression: actual_statement, actual_expression: actual_statement,
actual_type, actual_type,
@ -798,7 +833,17 @@ mod tests {
fn malformed_list_index() { fn malformed_list_index() {
let source = "[1, 2, 3]['foo']"; let source = "[1, 2, 3]['foo']";
assert_eq!(analyze(source), todo!()); assert_eq!(
analyze(source),
Err(DustError::Analysis {
analysis_error: AnalysisError::ExpectedType {
expected: Type::Integer,
actual: Type::String { length: Some(3) },
actual_expression: Expression::literal("foo", (10, 15)),
},
source,
})
);
} }
#[test] #[test]
@ -829,19 +874,22 @@ mod tests {
fn integer_plus_boolean() { fn integer_plus_boolean() {
let source = "42 + true"; let source = "42 + true";
assert_eq!(analyze(source), todo!()); assert_eq!(
analyze(source),
Err(DustError::Analysis {
analysis_error: AnalysisError::ExpectedType {
expected: Type::Integer,
actual: Type::Boolean,
actual_expression: Expression::literal(true, (5, 9)),
},
source,
})
);
} }
#[test] #[test]
fn is_even_expects_number() { fn nonexistant_field() {
let source = "is_even('hello')"; let source = "'hello'.foo";
assert_eq!(analyze(source), todo!());
}
#[test]
fn is_odd_expects_number() {
let source = "is_odd('hello')";
assert_eq!(analyze(source), todo!()); assert_eq!(analyze(source), todo!());
} }