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_function_declaration(
        &mut self,
        location: Location,
        attributes: ParsedAttributes<'ast>,
    ) -> Result<ParsedStatement<'ast>> {
        let function_keyword = self.current_position();
        self.advance();
        let attr_lists = attributes.attr_lists.clone();

        let name = self.parse_function_name()?;
        let self_parameter = name.has_self.then_some(location);
        let parsed = match self.parse_function_after_name(FunctionParseContext {
            attributes,
            location,
            match_location: location,
            function_keyword,
            self_parameter,
            debug_name: Some(name.debug_name),
        }) {
            Ok(function) => function,
            Err(error) => {
                let error_location = error.location;
                return Ok(self.report_statement_error(error_location, error));
            }
        };
        let statement_location = Location::new(location.begin, parsed.function.location.end);
        let name_expression = self.check_assignable_expression(name.expression);
        let statement = self
            .arena
            .alloc_statement_node(StatementFunctionDeclaration::new(
                statement_location,
                false,
                name_expression,
                parsed.function,
            ));

        Ok(self.parsed_statement_from_node(
            statement,
            if self.cst.enabled() {
                Some(CstNode::StatFunction(CstStatFunction {
                    attr_lists,
                    function_keyword,
                }))
            } else {
                None
            },
        ))
    }

    pub(in crate::parser) fn parse_function_name(&mut self) -> Result<ParsedFunctionName<'ast>> {
        let (mut debug_name, mut expression) = if let Token::Ident(name) = self.current {
            let name_location = self.current_token_location();
            let debug_name = name;
            self.advance();
            let expression = if let Some(local) = self.visible_local(debug_name) {
                if self.local_is_type_function_capture(local) {
                    let error_location = self.current_location();
                    let message_index = self.report_parse_error(self.error_at(
                        error_location,
                        self.name_message(
                            b"Type function cannot reference outer local '",
                            local.name,
                            b"'",
                        ),
                    ));
                    self.arena.alloc_expression_error_direct(
                        error_location,
                        self.empty_expression_slice(),
                        message_index,
                    )
                } else {
                    self.arena.alloc_expression_local_direct(
                        name_location,
                        local,
                        local.function_depth != self.contexts.functions.len(),
                    )
                }
            } else {
                self.arena
                    .alloc_expression_global_direct(name_location, debug_name)
            };
            (debug_name, expression)
        } else {
            let name_location = self.current_token_location();
            let message_index =
                self.report_parse_error(self.identifier_error(Some("function name")));
            let debug_name = self.name_error;
            (
                debug_name,
                self.arena.alloc_expression_error_direct(
                    name_location,
                    self.empty_expression_slice(),
                    message_index,
                ),
            )
        };
        let mut has_self = false;

        let old_recursion_counter = self.contexts.recursion_counter;
        loop {
            match self.current {
                Token::Dot => {
                    let op_position = self.current_position();
                    self.advance();

                    let field = self.parse_name("field name");
                    debug_name = field.name;

                    expression = self.arena.alloc_expression_index_name_direct(
                        Location::new(expression.location().begin, field.location.end),
                        expression,
                        debug_name,
                        field.location,
                        op_position,
                        IndexNameOp::Dot,
                    );
                    if let Err(error) = self.enter_recursion("function name") {
                        self.contexts.recursion_counter = old_recursion_counter;
                        return Err(error);
                    }
                }
                Token::Colon => {
                    let op_position = self.current_position();
                    self.advance();
                    has_self = true;

                    let field = self.parse_name("method name");
                    debug_name = field.name;
                    expression = self.arena.alloc_expression_index_name_direct(
                        Location::new(expression.location().begin, field.location.end),
                        expression,
                        debug_name,
                        field.location,
                        op_position,
                        IndexNameOp::Colon,
                    );
                    break;
                }
                _ => break,
            }
        }
        self.contexts.recursion_counter = old_recursion_counter;

        let expression = self.check_assignable_expression(expression);
        Ok(ParsedFunctionName {
            expression,
            has_self,
            debug_name,
        })
    }
}