Allow indexing lists with ranges

This commit is contained in:
Jeff 2024-08-12 10:43:18 -04:00
parent 2a0737fd45
commit f62cb13089
3 changed files with 45 additions and 12 deletions

View File

@ -334,10 +334,14 @@ impl<'a> Analyzer<'a> {
} }
if let Some(Type::List { .. }) = left.inner.expected_type(self.context) { 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 // Allow indexing lists with integers
} else if let Some(Type::Range) = right_type {
// Allow indexing lists with ranges
} else { } else {
return Err(AnalyzerError::ExpectedInteger { return Err(AnalyzerError::ExpectedIntegerOrRange {
actual: right.as_ref().clone(), actual: right.as_ref().clone(),
}); });
} }
@ -408,7 +412,7 @@ pub enum AnalyzerError {
ExpectedIdentifierOrString { ExpectedIdentifierOrString {
actual: Node<Statement>, actual: Node<Statement>,
}, },
ExpectedInteger { ExpectedIntegerOrRange {
actual: Node<Statement>, actual: Node<Statement>,
}, },
ExpectedValue { ExpectedValue {
@ -441,7 +445,7 @@ impl AnalyzerError {
AnalyzerError::ExpectedBoolean { actual, .. } => actual.position, AnalyzerError::ExpectedBoolean { actual, .. } => actual.position,
AnalyzerError::ExpectedIdentifier { actual, .. } => actual.position, AnalyzerError::ExpectedIdentifier { actual, .. } => actual.position,
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position, AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position,
AnalyzerError::ExpectedInteger { actual, .. } => actual.position, AnalyzerError::ExpectedIntegerOrRange { actual, .. } => actual.position,
AnalyzerError::ExpectedValue { actual } => actual.position, AnalyzerError::ExpectedValue { actual } => actual.position,
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position, AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position,
AnalyzerError::TypeConflict { AnalyzerError::TypeConflict {
@ -468,8 +472,8 @@ impl Display for AnalyzerError {
AnalyzerError::ExpectedIdentifierOrString { actual } => { AnalyzerError::ExpectedIdentifierOrString { actual } => {
write!(f, "Expected identifier or string, found {}", actual) write!(f, "Expected identifier or string, found {}", actual)
} }
AnalyzerError::ExpectedInteger { actual, .. } => { AnalyzerError::ExpectedIntegerOrRange { actual, .. } => {
write!(f, "Expected integer, found {}", actual) write!(f, "Expected integer or range, found {}", actual)
} }
AnalyzerError::ExpectedValue { actual, .. } => { AnalyzerError::ExpectedValue { actual, .. } => {
write!(f, "Expected value, found {}", actual) write!(f, "Expected value, found {}", actual)
@ -514,7 +518,7 @@ mod tests {
assert_eq!( assert_eq!(
analyze(source), analyze(source),
Err(DustError::AnalyzerError { Err(DustError::AnalyzerError {
analyzer_error: AnalyzerError::ExpectedInteger { analyzer_error: AnalyzerError::ExpectedIntegerOrRange {
actual: Node::new(Statement::Identifier(Identifier::new("foo")), (10, 13)), actual: Node::new(Statement::Identifier(Identifier::new("foo")), (10, 13)),
}, },
source source

View File

@ -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> { pub fn add(&self, other: &Value) -> Result<Value, ValueError> {
match (self.inner().as_ref(), other.inner().as_ref()) { match (self.inner().as_ref(), other.inner().as_ref()) {
(ValueInner::Float(left), ValueInner::Float(right)) => Ok(Value::float(left + right)), (ValueInner::Float(left), ValueInner::Float(right)) => Ok(Value::float(left + right)),

View File

@ -485,6 +485,14 @@ impl Vm {
return Ok(value); 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)) = if let (Some(map), Statement::Identifier(identifier)) =
@ -495,7 +503,7 @@ impl Vm {
return Ok(value); return Ok(value);
} }
Err(VmError::ExpectedIdentifierOrInteger { Err(VmError::ExpectedIdentifierIntegerOrRange {
position: right_span, position: right_span,
}) })
} }
@ -575,7 +583,7 @@ pub enum VmError {
ExpectedIdentifier { ExpectedIdentifier {
position: Span, position: Span,
}, },
ExpectedIdentifierOrInteger { ExpectedIdentifierIntegerOrRange {
position: Span, position: Span,
}, },
ExpectedInteger { ExpectedInteger {
@ -613,7 +621,7 @@ impl VmError {
Self::BuiltInFunctionError { position, .. } => *position, Self::BuiltInFunctionError { position, .. } => *position,
Self::ExpectedBoolean { position } => *position, Self::ExpectedBoolean { position } => *position,
Self::ExpectedIdentifier { position } => *position, Self::ExpectedIdentifier { position } => *position,
Self::ExpectedIdentifierOrInteger { position } => *position, Self::ExpectedIdentifierIntegerOrRange { position } => *position,
Self::ExpectedInteger { position } => *position, Self::ExpectedInteger { position } => *position,
Self::ExpectedFunction { position, .. } => *position, Self::ExpectedFunction { position, .. } => *position,
Self::ExpectedList { position } => *position, Self::ExpectedList { position } => *position,
@ -654,10 +662,10 @@ impl Display for VmError {
Self::ExpectedIdentifier { position } => { Self::ExpectedIdentifier { position } => {
write!(f, "Expected an identifier at position: {:?}", position) write!(f, "Expected an identifier at position: {:?}", position)
} }
Self::ExpectedIdentifierOrInteger { position } => { Self::ExpectedIdentifierIntegerOrRange { position } => {
write!( write!(
f, f,
"Expected an identifier or integer at position: {:?}", "Expected an identifier, integer, or range at position: {:?}",
position position
) )
} }
@ -693,6 +701,19 @@ impl Display for VmError {
mod tests { mod tests {
use super::*; 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] #[test]
fn range() { fn range() {
let input = "1..5"; let input = "1..5";