Skip to main content

luau_syntax/
location.rs

1#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2pub struct Position {
3    pub line: u32,
4    pub column: u32,
5}
6
7impl Position {
8    pub const fn missing() -> Self {
9        Self {
10            line: u32::MAX,
11            column: u32::MAX,
12        }
13    }
14
15    pub const fn zero() -> Self {
16        Self { line: 0, column: 0 }
17    }
18
19    pub const fn new(line: u32, column: u32) -> Self {
20        Self { line, column }
21    }
22
23    pub const fn has_value(self) -> bool {
24        self.line != u32::MAX || self.column != u32::MAX
25    }
26
27    pub fn shift(&mut self, start: Position, old_end: Position, new_end: Position) {
28        // Upstream Luau uses unsigned Position fields and applies the same arithmetic directly.
29        if *self >= start {
30            if self.line > old_end.line {
31                self.line = self
32                    .line
33                    .wrapping_add(new_end.line.wrapping_sub(old_end.line));
34            } else {
35                self.line = new_end.line;
36                self.column = self
37                    .column
38                    .wrapping_add(new_end.column.wrapping_sub(old_end.column));
39            }
40        }
41    }
42}
43
44#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
45pub struct Location {
46    pub begin: Position,
47    pub end: Position,
48}
49
50impl Location {
51    pub const fn zero() -> Self {
52        Self {
53            begin: Position::zero(),
54            end: Position::zero(),
55        }
56    }
57
58    pub const fn new(begin: Position, end: Position) -> Self {
59        Self { begin, end }
60    }
61
62    pub const fn from_length(begin: Position, length: u32) -> Self {
63        Self {
64            begin,
65            end: Position {
66                line: begin.line,
67                column: begin.column + length,
68            },
69        }
70    }
71
72    pub const fn spanning(begin: Location, end: Location) -> Self {
73        Self {
74            begin: begin.begin,
75            end: end.end,
76        }
77    }
78
79    pub fn encloses(self, location: Location) -> bool {
80        self.begin <= location.begin && self.end >= location.end
81    }
82
83    pub fn overlaps(self, location: Location) -> bool {
84        (self.begin <= location.begin && self.end >= location.begin)
85            || (self.begin <= location.end && self.end >= location.end)
86            || (self.begin >= location.begin && self.end <= location.end)
87    }
88
89    pub fn contains(self, position: Position) -> bool {
90        self.begin <= position && position < self.end
91    }
92
93    pub fn contains_closed(self, position: Position) -> bool {
94        self.begin <= position && position <= self.end
95    }
96
97    pub fn extend(&mut self, other: Location) {
98        if other.begin < self.begin {
99            self.begin = other.begin;
100        }
101        if other.end > self.end {
102            self.end = other.end;
103        }
104    }
105
106    pub fn shift(&mut self, start: Position, old_end: Position, new_end: Position) {
107        self.begin.shift(start, old_end, new_end);
108        self.end.shift(start, old_end, new_end);
109    }
110}