1
0

Add parsing for list access

This commit is contained in:
Jeff 2024-08-05 14:58:58 -04:00
parent 80a7700d68
commit 8c5ac0b89e
3 changed files with 73 additions and 9 deletions

View File

@ -205,6 +205,30 @@ mod tests {
use super::*; 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] #[test]
fn property_access() { fn property_access() {
let input = "a.b"; let input = "a.b";

View File

@ -119,6 +119,29 @@ impl Value {
_ => todo!(), _ => 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 { impl Display for Value {
@ -560,4 +583,6 @@ impl Ord for ValueInner {
pub enum ValueError { pub enum ValueError {
CannotAdd(Value, Value), CannotAdd(Value, Value),
PropertyNotFound { value: Value, property: Identifier }, PropertyNotFound { value: Value, property: Identifier },
IndexOutOfBounds { value: Value, index: i64 },
ExpectedList(Value),
} }

View File

@ -110,17 +110,24 @@ impl Vm {
}); });
}; };
let right_span = right.span; 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 // Anaylsis Failures
// These should be prevented by running the analyzer before the VM // These should be prevented by running the analyzer before the VM
ExpectedValue { position: Span }, ExpectedValue { position: Span },
ExpectedIdentifierOrInteger { position: (usize, usize) },
} }
impl From<ParseError> for VmError { impl From<ParseError> for VmError {
@ -152,6 +160,13 @@ impl From<ValueError> for VmError {
mod tests { mod tests {
use super::*; 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] #[test]
fn property_access() { fn property_access() {
let input = "[1, 2, 3].length"; let input = "[1, 2, 3].length";