Add test; Attempt to clean up map and block parsing

This commit is contained in:
Jeff 2024-08-11 13:16:16 -04:00
parent 37e3e1116d
commit 24e21aa0b5
2 changed files with 76 additions and 16 deletions

View File

@ -85,11 +85,7 @@ impl Statement {
pub fn expected_type(&self, context: &Context) -> Option<Type> { pub fn expected_type(&self, context: &Context) -> Option<Type> {
match self { match self {
Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context), Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context),
Statement::BinaryOperation { Statement::BinaryOperation { left, operator, .. } => match operator.inner {
left,
operator,
right,
} => match operator.inner {
BinaryOperator::Add BinaryOperator::Add
| BinaryOperator::Divide | BinaryOperator::Divide
| BinaryOperator::Modulo | BinaryOperator::Modulo

View File

@ -247,23 +247,57 @@ impl<'src> Parser<'src> {
statement.get_or_insert_with(|| Statement::Block(Vec::new())) statement.get_or_insert_with(|| Statement::Block(Vec::new()))
{ {
block.push(next_node); block.push(next_node);
continue;
} }
}
// If the new statement is already a map, expect the next node to be an
// assignment
if statement
.as_ref()
.is_some_and(|statement| matches!(statement, Statement::Map(_)))
{
if let Statement::BinaryOperation {
left,
operator:
Node {
inner: BinaryOperator::Assign,
..
},
right,
} = next_node.inner
{
if let Statement::Map(map_properties) =
statement.get_or_insert_with(|| Statement::Map(Vec::new()))
{
map_properties.push((*left, *right));
}
if let Token::Comma = self.current.0 {
self.next_token()?;
}
continue;
} else {
return Err(ParseError::ExpectedAssignment { actual: next_node });
}
}
// If the next node is an assignment, this might be a map // If the next node is an assignment, this might be a map
} else if let Statement::BinaryOperation { if let Statement::BinaryOperation {
left, left,
operator: operator:
Node { Node {
inner: BinaryOperator::Assign, inner: BinaryOperator::Assign,
position: operator_position, ..
}, },
right, right,
} = next_node.inner } = next_node.inner
{ {
// If the current token is a comma, or the new statement is already a map // If the current token is a comma or closing brace
if self.current.0 == Token::Comma if self.current.0 == Token::Comma
|| statement || self.current.0 == Token::RightCurlyBrace
.as_ref()
.is_some_and(|statement| matches!(statement, Statement::Map(_)))
{ {
// The new statement is a map // The new statement is a map
if let Statement::Map(map_properties) = if let Statement::Map(map_properties) =
@ -282,14 +316,11 @@ impl<'src> Parser<'src> {
if let Statement::Block(statements) = if let Statement::Block(statements) =
statement.get_or_insert_with(|| Statement::Block(Vec::new())) statement.get_or_insert_with(|| Statement::Block(Vec::new()))
{ {
// Add the statement to the block // Add the assignment statement to the block
statements.push(Node::new( statements.push(Node::new(
Statement::BinaryOperation { Statement::BinaryOperation {
left, left,
operator: Node::new( operator: Node::new(BinaryOperator::Assign, left_position),
BinaryOperator::Assign,
operator_position,
),
right, right,
}, },
next_node.position, next_node.position,
@ -565,6 +596,9 @@ pub enum ParseError {
position: Span, position: Span,
}, },
LexError(LexError), LexError(LexError),
ExpectedAssignment {
actual: Node<Statement>,
},
ExpectedIdentifier { ExpectedIdentifier {
actual: TokenOwned, actual: TokenOwned,
position: Span, position: Span,
@ -598,6 +632,7 @@ impl ParseError {
pub fn position(&self) -> Span { pub fn position(&self) -> Span {
match self { match self {
ParseError::BooleanError { position, .. } => *position, ParseError::BooleanError { position, .. } => *position,
ParseError::ExpectedAssignment { actual } => actual.position,
ParseError::ExpectedIdentifier { position, .. } => *position, ParseError::ExpectedIdentifier { position, .. } => *position,
ParseError::ExpectedToken { position, .. } => *position, ParseError::ExpectedToken { position, .. } => *position,
ParseError::FloatError { position, .. } => *position, ParseError::FloatError { position, .. } => *position,
@ -621,6 +656,7 @@ impl Display for ParseError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Self::BooleanError { error, .. } => write!(f, "{}", error), Self::BooleanError { error, .. } => write!(f, "{}", error),
Self::ExpectedAssignment { .. } => write!(f, "Expected assignment"),
Self::ExpectedIdentifier { actual, .. } => { Self::ExpectedIdentifier { actual, .. } => {
write!(f, "Expected identifier, found {actual}") write!(f, "Expected identifier, found {actual}")
} }
@ -641,6 +677,34 @@ mod tests {
use super::*; use super::*;
#[test]
fn malformed_map() {
let input = "{ x = 1, y = 2, z = 3; }";
assert_eq!(
parse(input),
Err(ParseError::ExpectedAssignment {
actual: Node::new(
Statement::Nil(Box::new(Node::new(
Statement::BinaryOperation {
left: Box::new(Node::new(
Statement::Identifier(Identifier::new("z")),
(16, 17)
)),
operator: Node::new(BinaryOperator::Assign, (18, 19)),
right: Box::new(Node::new(
Statement::Constant(Value::integer(3)),
(20, 21)
)),
},
(16, 21)
))),
(16, 24)
)
})
);
}
#[test] #[test]
fn while_loop() { fn while_loop() {
let input = "while x < 10 { x += 1 }"; let input = "while x < 10 { x += 1 }";