use super::*;
impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
pub(in crate::parser) fn parse_table_constructor(
&mut self,
location: Location,
) -> Result<Expression<'ast>> {
let table = self.parse_table_fields()?;
let mut end = self.current_token_location().end;
if self.current.kind() == TokenKind::RightBrace {
self.advance();
} else {
let error = self.matched_token_error(Token::RightBrace.name(), "{", location);
self.report_parse_error(error);
if self.peek().kind() == TokenKind::RightBrace {
self.advance();
self.advance();
} else {
end = self.previous_token_end_position();
}
}
Ok(self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(location.begin, end),
ExpressionKind::Table { items: table.items },
),
table
.cst_items
.map(|items| CstNode::ExprTable(CstExprTable { items })),
))
}
pub(in crate::parser) fn parse_table_fields(&mut self) -> Result<ParsedTableFields<'ast>> {
let mut items = self.temp_table_items();
let mut cst_items = self.cst.enabled().then(|| self.temp_cst_table_items());
while self.current.kind() != TokenKind::RightBrace {
let mut cst_item = self.cst.enabled().then_some(CstExprTableItem {
indexer_open: None,
indexer_close: None,
equals: None,
separator: None,
separator_position: None,
});
let current = self.current;
match current {
Token::Ident(name)
if self.peek().kind() == TokenKind::Equal && !name.is_reserved_word() =>
{
let key_location = self.current_token_location();
let field_name = name;
let key = self.alloc_expression(ExpressionInit::new(
key_location,
ExpressionKind::String {
value: self.ast_string(name.bytes()),
quote_style: StringQuoteStyle::Unquoted,
},
));
self.advance();
if let Some(cst_item) = &mut cst_item {
cst_item.equals = if self.current.kind() == TokenKind::Equal {
Some(self.current_position())
} else {
None
};
}
self.expect_and_consume(Token::Equal, "table field");
let value = match self.current {
Token::Reserved(R::Function) => {
let location = self.current_location();
self.parse_function_literal_with_debug_name(
ParsedAttributes::default(),
location,
Some(field_name),
)?
}
Token::Attribute(_) | Token::AttributeOpen => {
let location = self.current_location();
let attributes = self.parse_attributes()?;
if let Token::Reserved(R::Function) = self.current {
self.parse_function_literal_with_debug_name(
attributes,
location,
Some(field_name),
)?
} else {
let message_index = self
.report_parse_error(self.attribute_expression_error(location));
self.arena.alloc_expression_error_direct(
location,
self.empty_expression_slice(),
message_index,
)
}
}
_ => self.parse_expression_mut()?,
};
items.push_back(TableItem::Record { key, value });
}
Token::LeftBracket => {
let indexer_open = self.current_position();
if let Some(cst_item) = &mut cst_item {
cst_item.indexer_open = Some(indexer_open);
}
self.advance();
let key = self.parse_expression()?;
if let Some(cst_item) = &mut cst_item {
cst_item.indexer_close = if self.current.kind() == TokenKind::RightBracket {
Some(self.current_position())
} else {
None
};
}
self.expect_match_token(
Token::RightBracket,
"]",
"[",
Location::new(indexer_open, indexer_open),
false,
);
if let Some(cst_item) = &mut cst_item {
cst_item.equals = if self.current.kind() == TokenKind::Equal {
Some(self.current_position())
} else {
None
};
}
self.expect_and_consume(Token::Equal, "table field");
let value = self.parse_expression()?;
items.push_back(TableItem::General { key, value });
}
_ => {
items.push_back(TableItem::List {
value: self.parse_expression()?,
});
}
}
if let Some(cst_item) = &mut cst_item {
cst_item.separator = match self.current {
Token::Comma => Some(TableSeparator::Comma),
Token::Semicolon => Some(TableSeparator::Semicolon),
_ => None,
};
cst_item.separator_position =
cst_item.separator.as_ref().map(|_| self.current_position());
}
if let (Some(cst_items), Some(cst_item)) = (&mut cst_items, cst_item) {
cst_items.push_back(cst_item);
}
match self.current {
Token::Comma | Token::Semicolon => {
self.advance();
if self.current.kind() == TokenKind::RightBrace {
break;
}
}
Token::RightBrace => {
break;
}
Token::Ident(_) | Token::LeftBracket => {
self.report_parse_error(
self.located("Expected ',' after table constructor element"),
);
}
_ => {
break;
}
}
}
Ok(ParsedTableFields {
items: self.arena.alloc_slice_copy(items.as_slice()),
cst_items: cst_items.as_ref().map(|items| items.as_slice().to_vec()),
})
}
}