Pass analyzer test
This commit is contained in:
parent
6a488c2245
commit
f510cce0ee
@ -323,7 +323,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
))) = literal_type
|
))) = literal_type
|
||||||
{
|
{
|
||||||
if integer >= length as i64 {
|
if integer >= length as i64 {
|
||||||
self.errors.push(AnalysisError::IndexOutOfBounds {
|
self.errors.push(AnalysisError::ListIndexOutOfBounds {
|
||||||
index: index.clone(),
|
index: index.clone(),
|
||||||
length,
|
length,
|
||||||
list: list.clone(),
|
list: list.clone(),
|
||||||
@ -358,7 +358,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
))) = literal_type
|
))) = literal_type
|
||||||
{
|
{
|
||||||
if integer >= length as i64 {
|
if integer >= length as i64 {
|
||||||
self.errors.push(AnalysisError::IndexOutOfBounds {
|
self.errors.push(AnalysisError::ListIndexOutOfBounds {
|
||||||
index: index.clone(),
|
index: index.clone(),
|
||||||
length,
|
length,
|
||||||
list: list.clone(),
|
list: list.clone(),
|
||||||
@ -634,7 +634,42 @@ impl<'a> Analyzer<'a> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expression::TupleAccess(tuple_access) => {
|
Expression::TupleAccess(tuple_access) => {
|
||||||
let TupleAccessExpression { tuple, .. } = tuple_access.inner.as_ref();
|
let TupleAccessExpression { tuple, index } = tuple_access.inner.as_ref();
|
||||||
|
|
||||||
|
let tuple_type = match tuple.return_type(&self.context) {
|
||||||
|
Ok(Some(tuple_type)) => tuple_type,
|
||||||
|
Ok(None) => {
|
||||||
|
self.errors
|
||||||
|
.push(AnalysisError::ExpectedValueFromExpression {
|
||||||
|
expression: tuple.clone(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(ast_error) => {
|
||||||
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Type::Tuple {
|
||||||
|
fields: Some(fields),
|
||||||
|
} = tuple_type
|
||||||
|
{
|
||||||
|
if index.inner >= fields.len() {
|
||||||
|
self.errors.push(AnalysisError::TupleIndexOutOfBounds {
|
||||||
|
index: expression.clone(),
|
||||||
|
tuple: tuple.clone(),
|
||||||
|
index_value: index.inner as i64,
|
||||||
|
length: fields.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.errors.push(AnalysisError::ExpectedType {
|
||||||
|
expected: Type::Tuple { fields: None },
|
||||||
|
actual: tuple_type,
|
||||||
|
actual_expression: tuple.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self.analyze_expression(tuple, statement_position);
|
self.analyze_expression(tuple, statement_position);
|
||||||
}
|
}
|
||||||
@ -720,12 +755,18 @@ pub enum AnalysisError {
|
|||||||
actual: usize,
|
actual: usize,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IndexOutOfBounds {
|
ListIndexOutOfBounds {
|
||||||
list: Expression,
|
list: Expression,
|
||||||
index: Expression,
|
index: Expression,
|
||||||
index_value: i64,
|
index_value: i64,
|
||||||
length: usize,
|
length: usize,
|
||||||
},
|
},
|
||||||
|
TupleIndexOutOfBounds {
|
||||||
|
tuple: Expression,
|
||||||
|
index: Expression,
|
||||||
|
index_value: i64,
|
||||||
|
length: usize,
|
||||||
|
},
|
||||||
NegativeIndex {
|
NegativeIndex {
|
||||||
list: Expression,
|
list: Expression,
|
||||||
index: Expression,
|
index: Expression,
|
||||||
@ -775,7 +816,8 @@ impl AnalysisError {
|
|||||||
AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(),
|
AnalysisError::ExpectedIdentifierOrString { actual } => actual.position(),
|
||||||
AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(),
|
AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(),
|
||||||
AnalysisError::ExpectedValueArgumentCount { position, .. } => *position,
|
AnalysisError::ExpectedValueArgumentCount { position, .. } => *position,
|
||||||
AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
|
AnalysisError::ListIndexOutOfBounds { index, .. } => index.position(),
|
||||||
|
AnalysisError::TupleIndexOutOfBounds { index, .. } => index.position(),
|
||||||
AnalysisError::LetExpectedValueFromStatement { actual } => actual.position(),
|
AnalysisError::LetExpectedValueFromStatement { actual } => actual.position(),
|
||||||
AnalysisError::NegativeIndex { index, .. } => index.position(),
|
AnalysisError::NegativeIndex { index, .. } => index.position(),
|
||||||
AnalysisError::TypeConflict {
|
AnalysisError::TypeConflict {
|
||||||
@ -840,7 +882,7 @@ impl Display for AnalysisError {
|
|||||||
AnalysisError::ExpectedValueArgumentCount {
|
AnalysisError::ExpectedValueArgumentCount {
|
||||||
expected, actual, ..
|
expected, actual, ..
|
||||||
} => write!(f, "Expected {} value arguments, found {}", expected, actual),
|
} => write!(f, "Expected {} value arguments, found {}", expected, actual),
|
||||||
AnalysisError::IndexOutOfBounds {
|
AnalysisError::ListIndexOutOfBounds {
|
||||||
list,
|
list,
|
||||||
index_value,
|
index_value,
|
||||||
length,
|
length,
|
||||||
@ -860,6 +902,16 @@ impl Display for AnalysisError {
|
|||||||
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),
|
||||||
|
AnalysisError::TupleIndexOutOfBounds {
|
||||||
|
tuple,
|
||||||
|
index_value,
|
||||||
|
length,
|
||||||
|
..
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"Index {} out of bounds for tuple {} with length {}",
|
||||||
|
index_value, tuple, length
|
||||||
|
),
|
||||||
AnalysisError::TypeConflict {
|
AnalysisError::TypeConflict {
|
||||||
actual_expression: actual_statement,
|
actual_expression: actual_statement,
|
||||||
actual_type,
|
actual_type,
|
||||||
@ -871,6 +923,7 @@ impl Display for AnalysisError {
|
|||||||
expected, actual_statement, actual_type
|
expected, actual_statement, actual_type
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalysisError::UndefinedFieldIdentifier {
|
AnalysisError::UndefinedFieldIdentifier {
|
||||||
identifier,
|
identifier,
|
||||||
container,
|
container,
|
||||||
@ -899,6 +952,8 @@ impl Display for AnalysisError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::RangeableType;
|
use crate::RangeableType;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -994,7 +1049,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
analyze(source),
|
analyze(source),
|
||||||
Err(DustError::Analysis {
|
Err(DustError::Analysis {
|
||||||
analysis_errors: vec![AnalysisError::IndexOutOfBounds {
|
analysis_errors: vec![AnalysisError::ListIndexOutOfBounds {
|
||||||
list: Expression::list(
|
list: Expression::list(
|
||||||
vec![
|
vec![
|
||||||
Expression::literal(1, (1, 2)),
|
Expression::literal(1, (1, 2)),
|
||||||
@ -1062,12 +1117,26 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
analyze(source),
|
analyze(source),
|
||||||
Err(DustError::Analysis {
|
Err(DustError::analysis(
|
||||||
analysis_errors: vec![AnalysisError::ExpectedIdentifierOrString {
|
[AnalysisError::ExpectedType {
|
||||||
actual: Expression::literal(0, (10, 11))
|
expected: Type::Tuple { fields: None },
|
||||||
|
actual: Type::Struct(StructType::Fields {
|
||||||
|
name: Identifier::new("Foo"),
|
||||||
|
fields: HashMap::from([(Identifier::new("x"), Type::Integer)])
|
||||||
|
}),
|
||||||
|
actual_expression: Expression::r#struct(
|
||||||
|
StructExpression::Fields {
|
||||||
|
name: Node::new(Identifier::new("Foo"), (22, 25)),
|
||||||
|
fields: vec![(
|
||||||
|
Node::new(Identifier::new("x"), (28, 29)),
|
||||||
|
Expression::literal(1, (31, 32))
|
||||||
|
)],
|
||||||
|
},
|
||||||
|
(22, 35)
|
||||||
|
),
|
||||||
}],
|
}],
|
||||||
source,
|
source
|
||||||
})
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +476,10 @@ impl Expression {
|
|||||||
position: tuple.position(),
|
position: tuple.position(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Type::Tuple(fields) = tuple_value {
|
if let Type::Tuple {
|
||||||
|
fields: Some(fields),
|
||||||
|
} = tuple_value
|
||||||
|
{
|
||||||
fields.get(index.inner).cloned()
|
fields.get(index.inner).cloned()
|
||||||
} else {
|
} else {
|
||||||
Err(AstError::ExpectedTupleType {
|
Err(AstError::ExpectedTupleType {
|
||||||
|
@ -34,9 +34,9 @@ impl<'src> DustError<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analysis(analysis_errors: Vec<AnalysisError>, source: &'src str) -> Self {
|
pub fn analysis<T: Into<Vec<AnalysisError>>>(analysis_errors: T, source: &'src str) -> Self {
|
||||||
DustError::Analysis {
|
DustError::Analysis {
|
||||||
analysis_errors,
|
analysis_errors: analysis_errors.into(),
|
||||||
source,
|
source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,9 @@ pub enum Type {
|
|||||||
length: Option<usize>,
|
length: Option<usize>,
|
||||||
},
|
},
|
||||||
Struct(StructType),
|
Struct(StructType),
|
||||||
Tuple(Vec<Type>),
|
Tuple {
|
||||||
|
fields: Option<Vec<Type>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
@ -295,18 +297,22 @@ impl Display for Type {
|
|||||||
Type::Range { r#type } => write!(f, "{type} range"),
|
Type::Range { r#type } => write!(f, "{type} range"),
|
||||||
Type::String { .. } => write!(f, "str"),
|
Type::String { .. } => write!(f, "str"),
|
||||||
Type::Struct(struct_type) => write!(f, "{struct_type}"),
|
Type::Struct(struct_type) => write!(f, "{struct_type}"),
|
||||||
Type::Tuple(fields) => {
|
Type::Tuple { fields } => {
|
||||||
write!(f, "(")?;
|
if let Some(fields) = fields {
|
||||||
|
write!(f, "(")?;
|
||||||
|
|
||||||
for (index, r#type) in fields.iter().enumerate() {
|
for (index, r#type) in fields.iter().enumerate() {
|
||||||
write!(f, "{type}")?;
|
write!(f, "{type}")?;
|
||||||
|
|
||||||
if index != fields.len() - 1 {
|
if index != fields.len() - 1 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
|
} else {
|
||||||
|
write!(f, "tuple")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,8 +391,9 @@ impl Ord for Type {
|
|||||||
left_struct.cmp(right_struct)
|
left_struct.cmp(right_struct)
|
||||||
}
|
}
|
||||||
(Type::Struct(_), _) => Ordering::Greater,
|
(Type::Struct(_), _) => Ordering::Greater,
|
||||||
(Type::Tuple(left_tuple), Type::Tuple(right_tuple)) => left_tuple.cmp(right_tuple),
|
|
||||||
(Type::Tuple(_), _) => Ordering::Greater,
|
(Type::Tuple { fields: left }, Type::Tuple { fields: right }) => left.cmp(right),
|
||||||
|
(Type::Tuple { .. }, _) => Ordering::Greater,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -939,7 +939,9 @@ impl ValueData {
|
|||||||
ValueData::Tuple(values) => {
|
ValueData::Tuple(values) => {
|
||||||
let fields = values.iter().map(|value| value.r#type()).collect();
|
let fields = values.iter().map(|value| value.r#type()).collect();
|
||||||
|
|
||||||
Type::Tuple(fields)
|
Type::Tuple {
|
||||||
|
fields: Some(fields),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user