Begin fixing map property parsing

This commit is contained in:
Jeff 2024-08-12 11:24:24 -04:00
parent f62cb13089
commit a61c1756f2
3 changed files with 104 additions and 12 deletions

View File

@ -596,11 +596,17 @@ impl<'src> Parser<'src> {
fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> { fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
let left_start = left.position.0; let left_start = left.position.0;
let operator_precedence = self.current.0.precedence()
- if self.current.0.is_right_associative() {
1
} else {
0
};
if let Token::Dot = &self.current.0 { if let Token::Dot = &self.current.0 {
self.next_token()?; self.next_token()?;
let right = self.parse_statement(0)?; let right = self.parse_statement(operator_precedence)?;
let right_end = right.position.1; let right_end = right.position.1;
if let Statement::BuiltInFunctionCall { if let Statement::BuiltInFunctionCall {
@ -679,12 +685,6 @@ impl<'src> Parser<'src> {
}); });
} }
}; };
let operator_precedence = self.current.0.precedence()
- if self.current.0.is_right_associative() {
1
} else {
0
};
self.next_token()?; self.next_token()?;
@ -845,6 +845,59 @@ mod tests {
use super::*; use super::*;
#[test]
fn map_property_nested() {
let input = "{ x = { y = 42 } }.x.y";
assert_eq!(
parse(input),
Ok(AbstractSyntaxTree {
nodes: [Node {
inner: Statement::PropertyAccess(
Box::new(Node {
inner: Statement::Map(vec![(
Node {
inner: Statement::Identifier(Identifier::new("x")),
position: (2, 3)
},
Node {
inner: Statement::Map(vec![(
Node {
inner: Statement::Identifier(Identifier::new("y")),
position: (8, 9)
},
Node {
inner: Statement::Constant(Value::integer(42)),
position: (12, 14)
}
)]),
position: (6, 16)
}
)]),
position: (0, 18)
}),
Box::new(Node {
inner: Statement::PropertyAccess(
Box::new(Node {
inner: Statement::Identifier(Identifier::new("x")),
position: (19, 20)
}),
Box::new(Node {
inner: Statement::Identifier(Identifier::new("y")),
position: (21, 22)
})
),
position: (19, 22)
})
),
position: (0, 22)
}]
.into()
})
)
}
#[test] #[test]
fn range() { fn range() {
let input = "0..42"; let input = "0..42";

View File

@ -153,6 +153,14 @@ impl Value {
} }
} }
pub fn as_string(&self) -> Option<&String> {
if let ValueInner::String(string) = self.inner().as_ref() {
Some(string)
} 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

@ -495,12 +495,22 @@ impl Vm {
} }
} }
if let (Some(map), Statement::Identifier(identifier)) = if let Some(map) = left_value.as_map() {
(left_value.as_map(), &right.inner) if let Statement::Identifier(identifier) = right.inner {
{ let value = map.get(&identifier).cloned();
let value = map.get(identifier).cloned();
return Ok(value); return Ok(value);
}
if let Some(value) = self.run_statement(*right)? {
if let Some(string) = value.as_string() {
let identifier = Identifier::new(string);
let value = map.get(&identifier).cloned();
return Ok(value);
}
}
} }
Err(VmError::ExpectedIdentifierIntegerOrRange { Err(VmError::ExpectedIdentifierIntegerOrRange {
@ -701,6 +711,27 @@ impl Display for VmError {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn map_property() {
let input = "{ x = 42 }.x";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn map_property_nested() {
let input = "{ x = { y = 42 } }.x.y";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn map_property_access_expression() {
let input = "{ foobar = 42 }.('foo' + 'bar')";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test] #[test]
fn list_index_range() { fn list_index_range() {
let input = "[1, 2, 3, 4, 5].1..3"; let input = "[1, 2, 3, 4, 5].1..3";