luau-syntax 0.732.0

Luau lexer, parser, AST, CST, and source utilities
Documentation
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Position {
    pub line: u32,
    pub column: u32,
}

impl Position {
    pub const fn missing() -> Self {
        Self {
            line: u32::MAX,
            column: u32::MAX,
        }
    }

    pub const fn zero() -> Self {
        Self { line: 0, column: 0 }
    }

    pub const fn new(line: u32, column: u32) -> Self {
        Self { line, column }
    }

    pub const fn has_value(self) -> bool {
        self.line != u32::MAX || self.column != u32::MAX
    }

    pub fn shift(&mut self, start: Position, old_end: Position, new_end: Position) {
        // Upstream Luau uses unsigned Position fields and applies the same arithmetic directly.
        if *self >= start {
            if self.line > old_end.line {
                self.line = self
                    .line
                    .wrapping_add(new_end.line.wrapping_sub(old_end.line));
            } else {
                self.line = new_end.line;
                self.column = self
                    .column
                    .wrapping_add(new_end.column.wrapping_sub(old_end.column));
            }
        }
    }
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Location {
    pub begin: Position,
    pub end: Position,
}

impl Location {
    pub const fn zero() -> Self {
        Self {
            begin: Position::zero(),
            end: Position::zero(),
        }
    }

    pub const fn new(begin: Position, end: Position) -> Self {
        Self { begin, end }
    }

    pub const fn from_length(begin: Position, length: u32) -> Self {
        Self {
            begin,
            end: Position {
                line: begin.line,
                column: begin.column + length,
            },
        }
    }

    pub const fn spanning(begin: Location, end: Location) -> Self {
        Self {
            begin: begin.begin,
            end: end.end,
        }
    }

    pub fn encloses(self, location: Location) -> bool {
        self.begin <= location.begin && self.end >= location.end
    }

    pub fn overlaps(self, location: Location) -> bool {
        (self.begin <= location.begin && self.end >= location.begin)
            || (self.begin <= location.end && self.end >= location.end)
            || (self.begin >= location.begin && self.end <= location.end)
    }

    pub fn contains(self, position: Position) -> bool {
        self.begin <= position && position < self.end
    }

    pub fn contains_closed(self, position: Position) -> bool {
        self.begin <= position && position <= self.end
    }

    pub fn extend(&mut self, other: Location) {
        if other.begin < self.begin {
            self.begin = other.begin;
        }
        if other.end > self.end {
            self.end = other.end;
        }
    }

    pub fn shift(&mut self, start: Position, old_end: Position, new_end: Position) {
        self.begin.shift(start, old_end, new_end);
        self.end.shift(start, old_end, new_end);
    }
}