Begin fixing map property parsing
This commit is contained in:
parent
f62cb13089
commit
a61c1756f2
@ -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";
|
||||||
|
@ -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)),
|
||||||
|
@ -495,14 +495,24 @@ 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 {
|
||||||
position: right_span,
|
position: right_span,
|
||||||
})
|
})
|
||||||
@ -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";
|
||||||
|
Loading…
Reference in New Issue
Block a user