lib_ruby_parser/loc_ext.rs
1use crate::source::DecodedInput;
2pub use lib_ruby_parser_ast::Loc;
3
4/// A set of parser-specific extensions for `Loc`
5pub trait LocExt {
6 /// Returns line and column of the `begin` of the `Loc` on a given `Input`
7 fn begin_line_col(&self, input: &DecodedInput) -> Option<(usize, usize)>;
8 /// Expands `Loc` to the whole line and returns line number and new `Loc`
9 fn expand_to_line(&self, input: &DecodedInput) -> Option<(usize, Loc)>;
10 /// Returns source code of the current `Loc` on a given `Input`
11 fn source(&self, input: &DecodedInput) -> Option<String>;
12}
13
14impl LocExt for Loc {
15 fn begin_line_col(&self, input: &DecodedInput) -> Option<(usize, usize)> {
16 input.line_col_for_pos(self.begin)
17 }
18
19 fn expand_to_line(&self, input: &DecodedInput) -> Option<(usize, Loc)> {
20 let (begin_line, _) = self.begin_line_col(input)?;
21 let line_no = begin_line;
22 let line = input.line_at(line_no);
23 Some((
24 line_no,
25 Self {
26 begin: line.start,
27 end: line.line_end(),
28 },
29 ))
30 }
31
32 /// Returns source code of the current `Loc` on a given `Input`
33 fn source(&self, input: &DecodedInput) -> Option<String> {
34 let bytes = input.substr_at(self.begin, self.end)?;
35 Some(String::from_utf8_lossy(bytes).into_owned())
36 }
37}
38
39// impl Loc {
40// /// Converts location to a range
41// pub fn to_range(&self) -> std::ops::Range<usize> {
42// self.begin..self.end
43// }
44
45// /// Returns size of the `Loc` (i.e. `end - begin`)
46// pub fn size(&self) -> usize {
47// self.end - self.begin
48// }
49
50// /// Returns a new `Loc` with given `begin` and current `end`
51// pub fn with_begin(&self, begin: usize) -> Loc {
52// Self {
53// begin,
54// end: self.end,
55// }
56// }
57
58// /// Returns a new `Loc` with given `end` and current `begin`
59// pub fn with_end(&self, end: usize) -> Loc {
60// Self {
61// begin: self.begin,
62// end,
63// }
64// }
65
66// /// Adds given `delta` to `begin`
67// pub fn adjust_begin(&self, delta: i32) -> Loc {
68// let begin: i32 = self
69// .begin
70// .try_into()
71// .expect("failed to convert location to i32 (is it too big?)");
72// let begin: usize = (begin + delta)
73// .try_into()
74// .expect("failed to convert location to usize (is it negative?)");
75// Self {
76// begin,
77// end: self.end,
78// }
79// }
80
81// /// Adds given `delta` to `end`
82// pub fn adjust_end(&self, d: i32) -> Loc {
83// let end: i32 = self
84// .end
85// .try_into()
86// .expect("failed to convert location to i32 (is it too big?)");
87// let end: usize = (end + d)
88// .try_into()
89// .expect("failed to convert location to usize (is it negative?)");
90// Self {
91// begin: self.begin,
92// end,
93// }
94// }
95
96// /// Returns a new `Loc` with the same `begin`, but adjusted `end`,
97// /// so that its size is equal to given `new_size`
98// pub fn resize(&self, new_size: usize) -> Loc {
99// self.with_end(self.begin + new_size)
100// }
101
102// /// Joins two `Loc`s by choosing `min(begin)` + `max(end)`
103// pub fn join(&self, other: &Self) -> Loc {
104// Self {
105// begin: std::cmp::min(self.begin, other.begin),
106// end: std::cmp::max(self.end, other.end),
107// }
108// }
109
110// pub(crate) fn maybe_join(&self, other: &Option<Loc>) -> Loc {
111// match other.as_ref() {
112// Some(other) => self.join(other),
113// None => *self,
114// }
115// }
116
117// /// Returns true if `Loc` is empty (i.e. `begin` == `end`)
118// pub fn is_empty(&self) -> bool {
119// self.begin == self.end
120// }
121
122// pub(crate) fn begin_line_col(&self, input: &DecodedInput) -> Option<(usize, usize)> {
123// input.line_col_for_pos(self.begin)
124// }
125
126// pub(crate) fn expand_to_line(&self, input: &DecodedInput) -> Option<(usize, Loc)> {
127// let (begin_line, _) = self.begin_line_col(input)?;
128// let line_no = begin_line;
129// let line = input.line_at(line_no);
130// Some((
131// line_no,
132// Self {
133// begin: line.start,
134// end: line.line_end(),
135// },
136// ))
137// }
138
139// /// Returns source code of the current `Loc` on a given `Input`
140// pub fn source(&self, input: &DecodedInput) -> Option<String> {
141// let bytes = input.substr_at(self.begin, self.end)?;
142// Some(String::from_utf8_lossy(bytes).into_owned())
143// }
144
145// pub(crate) fn print(&self, name: &str) {
146// println!(
147// "{}{} {}",
148// " ".repeat(self.begin),
149// "~".repeat(self.size()),
150// name
151// )
152// }
153// }
154
155// impl std::fmt::Debug for Loc {
156// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157// f.write_str(&format!("{}...{}", self.begin, self.end))
158// }
159// }
160
161// #[test]
162// fn test_to_range() {
163// assert_eq!(Loc { begin: 10, end: 20 }.to_range(), 10..20)
164// }
165
166// #[test]
167// fn test_fmt() {
168// assert_eq!(format!("{:?}", Loc { begin: 10, end: 20 }), "10...20")
169// }
170
171// #[test]
172// fn test_is_empty() {
173// assert!(Loc { begin: 1, end: 1 }.is_empty());
174// assert!(!Loc { begin: 1, end: 2 }.is_empty());
175// }