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::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
|
||||||
|
@ -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)),
|
||||||
|
@ -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";
|
||||||
|
Loading…
Reference in New Issue
Block a user