Add parsing for list access
This commit is contained in:
parent
80a7700d68
commit
8c5ac0b89e
@ -205,6 +205,30 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn list_access() {
|
||||
let input = "[1, 2, 3].0";
|
||||
|
||||
assert_eq!(
|
||||
parse(input),
|
||||
Ok([Node::new(
|
||||
Statement::PropertyAccess(
|
||||
Box::new(Node::new(
|
||||
Statement::List(vec![
|
||||
Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
|
||||
Node::new(Statement::Constant(Value::integer(2)), (4, 5)),
|
||||
Node::new(Statement::Constant(Value::integer(3)), (7, 8)),
|
||||
]),
|
||||
(0, 9)
|
||||
)),
|
||||
Box::new(Node::new(Statement::Constant(Value::integer(0)), (10, 11))),
|
||||
),
|
||||
(0, 11),
|
||||
)]
|
||||
.into())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn property_access() {
|
||||
let input = "a.b";
|
||||
|
@ -119,6 +119,29 @@ impl Value {
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_access(&self, index: i64) -> Result<Value, ValueError> {
|
||||
match self.inner().as_ref() {
|
||||
ValueInner::List(list) => {
|
||||
if index < 0 {
|
||||
return Err(ValueError::IndexOutOfBounds {
|
||||
value: self.clone(),
|
||||
index,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(value) = list.get(index as usize) {
|
||||
Ok(value.clone())
|
||||
} else {
|
||||
Err(ValueError::IndexOutOfBounds {
|
||||
value: self.clone(),
|
||||
index,
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => Err(ValueError::ExpectedList(self.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
@ -560,4 +583,6 @@ impl Ord for ValueInner {
|
||||
pub enum ValueError {
|
||||
CannotAdd(Value, Value),
|
||||
PropertyNotFound { value: Value, property: Identifier },
|
||||
IndexOutOfBounds { value: Value, index: i64 },
|
||||
ExpectedList(Value),
|
||||
}
|
||||
|
@ -110,17 +110,24 @@ impl Vm {
|
||||
});
|
||||
};
|
||||
let right_span = right.span;
|
||||
let right = if let Statement::Identifier(identifier) = &right.statement {
|
||||
identifier
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: right_span,
|
||||
});
|
||||
};
|
||||
|
||||
let value = left.property_access(right)?;
|
||||
if let Statement::Identifier(identifier) = &right.statement {
|
||||
let value = left.property_access(identifier)?;
|
||||
|
||||
Ok(Some(value))
|
||||
return Ok(Some(value));
|
||||
}
|
||||
|
||||
if let Statement::Constant(value) = &right.statement {
|
||||
if let Some(index) = value.as_integer() {
|
||||
let value = left.list_access(index)?;
|
||||
|
||||
return Ok(Some(value));
|
||||
}
|
||||
}
|
||||
|
||||
Err(VmError::ExpectedIdentifierOrInteger {
|
||||
position: right_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -134,6 +141,7 @@ pub enum VmError {
|
||||
// Anaylsis Failures
|
||||
// These should be prevented by running the analyzer before the VM
|
||||
ExpectedValue { position: Span },
|
||||
ExpectedIdentifierOrInteger { position: (usize, usize) },
|
||||
}
|
||||
|
||||
impl From<ParseError> for VmError {
|
||||
@ -152,6 +160,13 @@ impl From<ValueError> for VmError {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn list_access() {
|
||||
let input = "[1, 2, 3][1]";
|
||||
|
||||
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn property_access() {
|
||||
let input = "[1, 2, 3].length";
|
||||
|
Loading…
Reference in New Issue
Block a user