Allow indexing lists with ranges
This commit is contained in:
parent
2a0737fd45
commit
f62cb13089
@ -334,10 +334,14 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
|
||||
if let Some(Type::List { .. }) = left.inner.expected_type(self.context) {
|
||||
if let Some(Type::Integer) = right.inner.expected_type(self.context) {
|
||||
let right_type = right.inner.expected_type(self.context);
|
||||
|
||||
if let Some(Type::Integer) = right_type {
|
||||
// Allow indexing lists with integers
|
||||
} else if let Some(Type::Range) = right_type {
|
||||
// Allow indexing lists with ranges
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedInteger {
|
||||
return Err(AnalyzerError::ExpectedIntegerOrRange {
|
||||
actual: right.as_ref().clone(),
|
||||
});
|
||||
}
|
||||
@ -408,7 +412,7 @@ pub enum AnalyzerError {
|
||||
ExpectedIdentifierOrString {
|
||||
actual: Node<Statement>,
|
||||
},
|
||||
ExpectedInteger {
|
||||
ExpectedIntegerOrRange {
|
||||
actual: Node<Statement>,
|
||||
},
|
||||
ExpectedValue {
|
||||
@ -441,7 +445,7 @@ impl AnalyzerError {
|
||||
AnalyzerError::ExpectedBoolean { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedIdentifier { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position,
|
||||
AnalyzerError::ExpectedInteger { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedIntegerOrRange { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedValue { actual } => actual.position,
|
||||
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position,
|
||||
AnalyzerError::TypeConflict {
|
||||
@ -468,8 +472,8 @@ impl Display for AnalyzerError {
|
||||
AnalyzerError::ExpectedIdentifierOrString { actual } => {
|
||||
write!(f, "Expected identifier or string, found {}", actual)
|
||||
}
|
||||
AnalyzerError::ExpectedInteger { actual, .. } => {
|
||||
write!(f, "Expected integer, found {}", actual)
|
||||
AnalyzerError::ExpectedIntegerOrRange { actual, .. } => {
|
||||
write!(f, "Expected integer or range, found {}", actual)
|
||||
}
|
||||
AnalyzerError::ExpectedValue { actual, .. } => {
|
||||
write!(f, "Expected value, found {}", actual)
|
||||
@ -514,7 +518,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::ExpectedInteger {
|
||||
analyzer_error: AnalyzerError::ExpectedIntegerOrRange {
|
||||
actual: Node::new(Statement::Identifier(Identifier::new("foo")), (10, 13)),
|
||||
},
|
||||
source
|
||||
|
@ -145,6 +145,14 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_range(&self) -> Option<&Range<i64>> {
|
||||
if let ValueInner::Range(range) = self.inner().as_ref() {
|
||||
Some(range)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&self, other: &Value) -> Result<Value, ValueError> {
|
||||
match (self.inner().as_ref(), other.inner().as_ref()) {
|
||||
(ValueInner::Float(left), ValueInner::Float(right)) => Ok(Value::float(left + right)),
|
||||
|
@ -485,6 +485,14 @@ impl Vm {
|
||||
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
if let Some(range) = value.as_range() {
|
||||
let range = range.start as usize..range.end as usize;
|
||||
|
||||
if let Some(items) = list.get(range) {
|
||||
return Ok(Some(Value::list(items.to_vec())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(map), Statement::Identifier(identifier)) =
|
||||
@ -495,7 +503,7 @@ impl Vm {
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
Err(VmError::ExpectedIdentifierOrInteger {
|
||||
Err(VmError::ExpectedIdentifierIntegerOrRange {
|
||||
position: right_span,
|
||||
})
|
||||
}
|
||||
@ -575,7 +583,7 @@ pub enum VmError {
|
||||
ExpectedIdentifier {
|
||||
position: Span,
|
||||
},
|
||||
ExpectedIdentifierOrInteger {
|
||||
ExpectedIdentifierIntegerOrRange {
|
||||
position: Span,
|
||||
},
|
||||
ExpectedInteger {
|
||||
@ -613,7 +621,7 @@ impl VmError {
|
||||
Self::BuiltInFunctionError { position, .. } => *position,
|
||||
Self::ExpectedBoolean { position } => *position,
|
||||
Self::ExpectedIdentifier { position } => *position,
|
||||
Self::ExpectedIdentifierOrInteger { position } => *position,
|
||||
Self::ExpectedIdentifierIntegerOrRange { position } => *position,
|
||||
Self::ExpectedInteger { position } => *position,
|
||||
Self::ExpectedFunction { position, .. } => *position,
|
||||
Self::ExpectedList { position } => *position,
|
||||
@ -654,10 +662,10 @@ impl Display for VmError {
|
||||
Self::ExpectedIdentifier { position } => {
|
||||
write!(f, "Expected an identifier at position: {:?}", position)
|
||||
}
|
||||
Self::ExpectedIdentifierOrInteger { position } => {
|
||||
Self::ExpectedIdentifierIntegerOrRange { position } => {
|
||||
write!(
|
||||
f,
|
||||
"Expected an identifier or integer at position: {:?}",
|
||||
"Expected an identifier, integer, or range at position: {:?}",
|
||||
position
|
||||
)
|
||||
}
|
||||
@ -693,6 +701,19 @@ impl Display for VmError {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn list_index_range() {
|
||||
let input = "[1, 2, 3, 4, 5].1..3";
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::list(vec![
|
||||
Value::integer(2),
|
||||
Value::integer(3)
|
||||
])))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range() {
|
||||
let input = "1..5";
|
||||
|
Loading…
Reference in New Issue
Block a user