luau-syntax 0.732.0

Luau lexer, parser, AST, CST, and source utilities
Documentation
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()),
        })
    }
}