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 new(
        source: &'source [u8],
        arena: &'ast AstArena,
        names: &'names mut AstNameTable<'name>,
        options: ParseOptions,
        fragment_resume: Option<&FragmentParseResumeSettings<'ast>>,
    ) -> Self {
        let store_cst_data = options.store_cst_data();
        let base_position =
            fragment_resume.map_or(Position::zero(), |settings| settings.resume_position);
        let local_stack =
            fragment_resume.map_or_else(Vec::new, |settings| settings.local_stack.clone());
        let local_map = fragment_resume.map_or_else(
            || DenseHashMap::new(AstName::empty_key()),
            |settings| settings.local_map.clone(),
        );
        let name_self = names.get_or_add("self");
        let name_number = names.get_or_add("number");
        let name_error = names.get_or_add("%error-id%");
        let name_nil = names.get_or_add("nil");
        let mut parser = Self {
            options,
            lexer: Lexer::with_position(source, names, base_position),
            base_position,
            arena,
            current: Token::Eof,
            diagnostics: DiagnosticState::default(),
            comments: CommentState::new(),
            cst: CstState::new(store_cst_data),
            contexts: ContextState::default(),
            locals: LocalState::new(local_map, local_stack),
            recovery: RecoveryState::default(),
            name_self,
            name_number,
            name_error,
            name_nil,
            declared_export_bindings: DenseHashMap::new(AstName::empty_key()),
            has_module_return: false,
            scratch_stat: ScratchVec::default(),
            scratch_expr: ScratchVec::default(),
            scratch_expr_aux: ScratchVec::default(),
            scratch_string: ScratchVec::default(),
            scratch_string2: ScratchVec::default(),
            scratch_attr: ScratchVec::default(),
            scratch_binding: ScratchVec::default(),
            scratch_table_items: ScratchVec::default(),
            scratch_cst_table_items: ScratchVec::default(),
            scratch_class_members: ScratchVec::default(),
            scratch_declared_extern_type_props: ScratchVec::default(),
            scratch_type: ScratchVec::default(),
            scratch_type_or_pack: ScratchVec::default(),
            scratch_arg_name: ScratchVec::default(),
            scratch_opt_arg_name: ScratchVec::default(),
            scratch_generic_types: ScratchVec::default(),
            scratch_generic_type_packs: ScratchVec::default(),
            scratch_local: ScratchVec::default(),
            scratch_table_type_props: ScratchVec::default(),
            scratch_cst_table_type_items: ScratchVec::default(),
            scratch_position: ScratchVec::default(),
            scratch_position2: ScratchVec::default(),
        };
        parser.locals.stack.reserve(16);
        parser.scratch_stat.reserve(16);
        parser.scratch_expr.reserve(16);
        parser.scratch_local.reserve(16);
        parser.scratch_binding.reserve(16);
        parser.advance();
        parser
    }

    pub(in crate::parser) fn parse(
        mut self,
    ) -> std::result::Result<ParseResult<'ast>, ParseErrors> {
        static PARSE_SCOPE: OnceLock<u16> = OnceLock::new();
        let _time_trace = time_trace::Scope::new(&PARSE_SCOPE, "Parser::parse", "Parser");

        match self.parse_statements() {
            Ok(statements) => {
                if self.current.kind() != TokenKind::Eof {
                    let error = self.expected_eof_error();
                    self.report_parse_error(error);
                }
                if self.diagnostics.error_limit_reached
                    && !self.options.no_error_limit()
                    && let Some(errors) = self.take_parse_errors()
                {
                    return Err(errors);
                }

                let root = self.root_block(statements);
                let lines = self.source_line_count();
                let (hotcomments, comment_locations) = self.comments.into_parts();
                Ok(ParseResult::new(
                    root,
                    ParseMetadata::new(
                        lines,
                        hotcomments,
                        self.diagnostics.errors,
                        comment_locations,
                        self.cst.into_nodes(),
                    ),
                ))
            }
            Err(error) => Err(self.finish_with_error(error)),
        }
    }

    pub(in crate::parser) fn parse_node<T>(
        mut self,
        parse: impl FnOnce(&mut Self) -> Result<T>,
    ) -> std::result::Result<ParseNodeResult<'ast, T>, ParseErrors> {
        static PARSE_SCOPE: OnceLock<u16> = OnceLock::new();
        let _time_trace = time_trace::Scope::new(&PARSE_SCOPE, "Parser::parse", "Parser");

        let node = match parse(&mut self) {
            Ok(node) => node,
            Err(error) => {
                return Err(self.finish_with_error(error));
            }
        };
        if self.current.kind() != TokenKind::Eof {
            let error = ParseError::new(self.current_location(), "Expected end of file");
            return Err(self.finish_with_error(error));
        }
        if self.diagnostics.error_limit_reached
            && !self.options.no_error_limit()
            && let Some(errors) = self.take_parse_errors()
        {
            return Err(errors);
        }

        let lines = self.source_line_count();
        let (hotcomments, comment_locations) = self.comments.into_parts();
        Ok(ParseNodeResult::new(
            node,
            ParseMetadata::new(
                lines,
                hotcomments,
                self.diagnostics.errors,
                comment_locations,
                self.cst.into_nodes(),
            ),
        ))
    }

    fn finish_with_error(&mut self, error: ParseError) -> ParseErrors {
        let fallback = error.clone();
        self.report_parse_error(error);
        self.take_parse_errors()
            .unwrap_or_else(|| ParseErrors::single(fallback))
    }

    fn take_parse_errors(&mut self) -> Option<ParseErrors> {
        ParseErrors::new(std::mem::take(&mut self.diagnostics.errors))
    }

    fn parse_statements(&mut self) -> Result<Vec<Statement<'ast>>> {
        let locals_begin = self.locals.stack.len();
        let mut statements = self.temp_statements();
        self.parse_block_until_inner_into(BLOCK_FOLLOW, &mut statements)?;
        self.restore_locals(locals_begin);
        Ok(statements.as_slice().to_vec())
    }

    fn root_block(&mut self, statements: Vec<Statement<'ast>>) -> Block<'ast> {
        let statements = self.arena.alloc_slice_copy(&statements);
        let location = Location::new(self.base_position, self.current_token_location().begin);
        self.arena
            .alloc_block(BlockNode::new(statements, true, location))
    }
}