Clean up block/map parsing code

This commit is contained in:
Jeff 2024-08-11 15:39:42 -04:00
parent 9338d73621
commit 9a9d9458ae
2 changed files with 63 additions and 77 deletions

View File

@ -156,6 +156,20 @@ impl Statement {
Statement::While { .. } => None, Statement::While { .. } => None,
} }
} }
pub fn block_statements_mut(&mut self) -> Option<&mut Vec<Node<Statement>>> {
match self {
Statement::Block(statements) => Some(statements),
_ => None,
}
}
pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node<Statement>, Node<Statement>)>> {
match self {
Statement::Map(properties) => Some(properties),
_ => None,
}
}
} }
impl Display for Statement { impl Display for Statement {

View File

@ -313,41 +313,66 @@ impl<'src> Parser<'src> {
)); ));
} }
let mut statement = None; let first_node = self.parse_statement(0)?;
// Determine whether the new statement is a block or a map
//
// If the first node is an assignment, this might be a map
let mut statement = if let Statement::BinaryOperation {
left,
operator:
Node {
inner: BinaryOperator::Assign,
..
},
right,
} = first_node.inner
{
// If the current token is a comma or closing brace
if self.current.0 == Token::Comma || self.current.0 == Token::RightCurlyBrace {
// Allow commas after properties
if let Token::Comma = self.current.0 {
self.next_token()?;
}
// The new statement is a map
Statement::Map(vec![(*left, *right)])
} else {
// Otherwise, the new statement is a block
Statement::Block(vec![Node::new(
Statement::BinaryOperation {
left,
operator: Node::new(BinaryOperator::Assign, (0, 0)),
right,
},
first_node.position,
)])
}
// If the next node is not an assignment, the new statement is a block
} else {
Statement::Block(vec![first_node])
};
loop { loop {
// If a closing brace is found, return the new statement // If a closing brace is found, return the new statement
if let (Token::RightCurlyBrace, right_position) = self.current { if let (Token::RightCurlyBrace, right_position) = self.current {
self.next_token()?; self.next_token()?;
return Ok(Node::new( return Ok(Node::new(statement, (left_position.0, right_position.1)));
statement.unwrap(),
(left_position.0, right_position.1),
));
} }
let next_node = self.parse_statement(0)?; let next_node = self.parse_statement(0)?;
// If the new statement is already a block, add the next node to it // If the new statement is already a block, add the next node to it
if statement if let Some(block_statements) = statement.block_statements_mut() {
.as_ref() block_statements.push(next_node);
.is_some_and(|statement| matches!(statement, Statement::Block(_)))
{
if let Statement::Block(block) =
statement.get_or_insert_with(|| Statement::Block(Vec::new()))
{
block.push(next_node);
continue; continue;
}
} }
// If the new statement is already a map, expect the next node to be an // If the new statement is already a map
// assignment if let Some(map_properties) = statement.map_properties_mut() {
if statement // Expect the next node to be an assignment
.as_ref()
.is_some_and(|statement| matches!(statement, Statement::Map(_)))
{
if let Statement::BinaryOperation { if let Statement::BinaryOperation {
left, left,
operator: operator:
@ -358,12 +383,10 @@ impl<'src> Parser<'src> {
right, right,
} = next_node.inner } = next_node.inner
{ {
if let Statement::Map(map_properties) = // Add the new property to the map
statement.get_or_insert_with(|| Statement::Map(Vec::new())) map_properties.push((*left, *right));
{
map_properties.push((*left, *right));
}
// Allow commas after properties
if let Token::Comma = self.current.0 { if let Token::Comma = self.current.0 {
self.next_token()?; self.next_token()?;
} }
@ -373,57 +396,6 @@ impl<'src> Parser<'src> {
return Err(ParseError::ExpectedAssignment { actual: next_node }); return Err(ParseError::ExpectedAssignment { actual: next_node });
} }
} }
// If the next node is an assignment, this might be a map
if let Statement::BinaryOperation {
left,
operator:
Node {
inner: BinaryOperator::Assign,
..
},
right,
} = next_node.inner
{
// If the current token is a comma or closing brace
if self.current.0 == Token::Comma
|| self.current.0 == Token::RightCurlyBrace
{
// The new statement is a map
if let Statement::Map(map_properties) =
statement.get_or_insert_with(|| Statement::Map(Vec::new()))
{
// Add the new property to the map
map_properties.push((*left, *right));
}
// Allow commas after properties
if let Token::Comma = self.current.0 {
self.next_token()?;
}
} else {
// Otherwise, the new statement is a block
if let Statement::Block(statements) =
statement.get_or_insert_with(|| Statement::Block(Vec::new()))
{
// Add the assignment statement to the block
statements.push(Node::new(
Statement::BinaryOperation {
left,
operator: Node::new(BinaryOperator::Assign, left_position),
right,
},
next_node.position,
));
}
}
// Otherwise, the new statement is a block
} else if let Statement::Block(statements) =
statement.get_or_insert_with(|| Statement::Block(Vec::new()))
{
// Add the statement to the block
statements.push(next_node);
}
} }
} }
(Token::LeftParenthesis, left_position) => { (Token::LeftParenthesis, left_position) => {