luau-syntax 0.732.0

Luau lexer, parser, AST, CST, and source utilities
Documentation
use super::*;

impl<'ast, 'name> Parser<'_, 'ast, 'name, '_>
where
    'name: 'ast,
{
    pub(in crate::parser) fn push_local_scope(&mut self) {
        self.locals.scope_offsets.push(self.locals.stack.len());
    }

    pub(in crate::parser) fn pop_local_scope(&mut self) {
        let Some(offset) = self.locals.scope_offsets.pop() else {
            unreachable!("parser local scope is balanced");
        };
        debug_assert!(offset <= self.locals.stack.len());
        self.restore_locals(offset);
    }

    pub(in crate::parser) fn declare_local(
        &mut self,
        name: AstName<'ast>,
        location: Location,
        annotation: Option<Type<'ast>>,
        is_const: bool,
        is_exported: bool,
    ) -> &'ast Local<'ast> {
        // Match Luau's localMap[name] access by probing the slot once and then
        // reading/updating that same entry around the local allocation.
        let shadow_slot = {
            let (slot, _) = self.locals.map.try_insert(name, None);
            slot as *mut Option<&'ast Local<'ast>>
        };
        let shadow = unsafe { *shadow_slot };
        let local = self.arena.alloc_local(Local::new(LocalInit {
            name,
            location,
            shadow,
            function_depth: self.contexts.functions.len(),
            loop_depth: self.current_function().loop_depth,
            annotation,
            is_const,
            is_exported,
        }));
        unsafe { *shadow_slot = Some(local) };
        self.locals.stack.push(local);
        local
    }

    #[inline(always)]
    pub(in crate::parser) fn visible_local(
        &self,
        name: AstName<'ast>,
    ) -> Option<&'ast Local<'ast>> {
        self.locals.map.get(&name).copied().flatten()
    }

    pub(in crate::parser) fn restore_locals(&mut self, offset: usize) {
        let stack_len = self.locals.stack.len();
        for index in (offset..stack_len).rev() {
            let local = self.locals.stack[index];
            self.locals.map.insert(local.name, local.shadow);
        }

        self.locals.stack.truncate(offset);
    }

    #[inline(always)]
    pub(in crate::parser) fn local_is_type_function_capture(&self, local: &Local<'_>) -> bool {
        let Some(depth) = self.locals.type_function_local_depth else {
            return false;
        };

        local.function_depth < depth
    }
}