1use std::fmt::Display;
2
3use itertools::Itertools;
4
5use crate::Mode;
6
7use self::rule::Rule;
8
9pub mod rule;
10pub mod structure;
11
12pub trait Vectorize<T> {
13 fn vectorize(self) -> Vec<T>;
17}
18
19impl<T> Vectorize<T> for Vec<T> {
20 fn vectorize(self) -> Vec<T> {
22 self
23 }
24}
25
26impl<T> Vectorize<T> for T {
27 fn vectorize(self) -> Vec<T> {
29 vec![self]
30 }
31}
32
33impl<T> Vectorize<T> for Vec<Vec<T>> {
34 fn vectorize(self) -> Vec<T> {
36 let mut vec = vec![];
37 for v in self {
38 vec.extend(v);
39 }
40 vec
41 }
42}
43
44impl<T> Vectorize<T> for Option<T> {
45 fn vectorize(self) -> Vec<T> {
47 self.into_iter().collect()
48 }
49}
50
51impl<T> Vectorize<T> for Vec<Option<T>> {
52 fn vectorize(self) -> Vec<T> {
54 self.into_iter().filter_map(|e| e).collect()
55 }
56}
57
58impl<T> Vectorize<T> for Option<Vec<T>> {
59 fn vectorize(self) -> Vec<T> {
60 self.unwrap_or_default()
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub struct Span {
67 pub start: usize,
68 pub end: usize,
69}
70
71impl Span {
72 pub fn includes(&self, pos: usize) -> bool {
74 self.start <= pos && pos < self.end
75 }
76
77 pub fn contains(&self, other: &Span) -> bool {
79 self.start <= other.start && other.end <= self.end
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub struct LineCol {
86 pub line: usize,
87 pub column: usize,
88}
89
90#[derive(Debug, PartialEq, Eq, Hash)]
93pub struct CstText {
94 pub text: String,
95 pub lines: Vec<usize>,
96 pub cst: Cst,
97}
98
99impl CstText {
100 pub fn parse<F>(
102 text: &str,
103 parser: F,
104 ) -> std::result::Result<Self, (LineCol, Vec<&'static str>)>
105 where
106 F: Fn(&str) -> std::result::Result<Cst, peg::error::ParseError<peg::str::LineCol>>,
107 {
108 let mut lines = vec![0usize];
109 lines.extend(text.match_indices('\n').map(|(p, _)| p + 1));
110 match parser(text) {
111 Ok(cst) => Ok(CstText {
112 text: text.to_owned(),
113 lines,
114 cst,
115 }),
116 Err(e) => {
117 let peg::str::LineCol { line, column, .. } = e.location;
118 let lc = LineCol {
119 line: line - 1,
120 column: column - 1,
121 }; let expected: Vec<_> = e.expected.tokens().collect();
123 Err((lc, expected))
124 }
125 }
126 }
127
128 pub fn get_text_from_span(&self, span: Span) -> &str {
130 let text = self.text.as_str();
131 let Span { start, end } = span;
132 &text[start..end]
133 }
134
135 pub fn get_text(&self, cst: &Cst) -> &str {
137 let text = self.text.as_str();
138 let Span { start, end } = cst.span;
139 &text[start..end]
140 }
141
142 pub fn get_line_col(&self, pos: usize) -> Option<LineCol> {
144 if pos > self.text.len() {
145 return None;
146 }
147 let line = match self.lines.binary_search(&pos) {
148 Ok(i) => i,
149 Err(i) => i - 1,
150 };
151 let column = pos - self.lines[line];
152 Some(LineCol { line, column })
153 }
154
155 pub fn from_line_col(&self, line: usize, column: usize) -> Option<usize> {
157 let idxline = self.lines.get(line)?;
158 let max_idx = match self.lines.get(line + 1) {
159 Some(idx) => *idx,
160 None => self.text.len(),
161 };
162 if (*idxline + column) < max_idx {
163 Some(*idxline + column)
164 } else {
165 None
166 }
167 }
168
169 pub fn pritty_cst_recursive(&self, cst: &Cst) -> String {
171 fn print_cst(csttext: &CstText, cst: &Cst, indent: usize) -> String {
172 let mut s = String::new();
173
174 s.push_str(&" ".repeat(indent));
175 s.push_str(&csttext.pritty_cst(cst));
176 s.push('\n');
177
178 for child in &cst.inner {
179 s.push_str(&print_cst(csttext, child, indent + 1))
180 }
181 s
182 }
183
184 print_cst(&self, cst, 0)
185 }
186
187 pub fn pritty_cst(&self, cst: &Cst) -> String {
189 let mut s = String::new();
190 s.push_str(&format!("[{:?}]", cst.rule));
191
192 let Span { start, end } = cst.span;
194 let slice = &self.text[start..end];
195 if !slice.contains('\n') && slice.len() < 80 {
196 s.push_str(&format!(": \"{}\"", slice));
197 } else {
198 let LineCol {
199 line: start_line,
200 column: start_column,
201 } = self.get_line_col(start).unwrap();
202 let LineCol {
203 line: end_line,
204 column: end_column,
205 } = self.get_line_col(end).unwrap();
206 s.push_str(&format!(
207 " (L{}-C{} .. L{}-C{})",
208 start_line + 1,
209 start_column + 1,
210 end_line + 1,
211 end_column + 1
212 ));
213 }
214 s
215 }
216
217 pub fn is_comment(&self, pos: usize) -> bool {
219 let dig = self.cst.dig(pos);
220 let cst = dig.get(0);
221 if cst.is_none() {
222 return false;
223 }
224 let cst = cst.unwrap();
225 let span = cst
228 .get_terminal_spans()
229 .into_iter()
230 .find(|span| span.includes(pos));
231 if span.is_none() {
232 return false;
234 }
235 let span = span.unwrap();
236
237 let text = self.get_text_from_span(span);
239 let char_indices = text.char_indices().map(|(idx, _)| idx).collect_vec();
240 let pos_char = char_indices
241 .binary_search(&(pos - span.start))
242 .unwrap_or_else(|x| x);
243 for c in text.chars().take(pos_char).collect_vec().into_iter().rev() {
244 match c {
245 '\n' => return false,
247 '%' => return true,
249 _ => continue,
250 }
251 }
252 false
254 }
255}
256
257#[test]
258fn test_is_comment() {
259 use crate::grammar;
260
261 let csttext = CstText::parse("let x = 1 in% foo \n 2", grammar::program).unwrap();
262 assert_eq!(csttext.is_comment(11), false); assert_eq!(csttext.is_comment(12), false); assert_eq!(csttext.is_comment(13), true); assert_eq!(csttext.is_comment(14), true); assert_eq!(csttext.is_comment(17), true); assert_eq!(csttext.is_comment(18), true); assert_eq!(csttext.is_comment(19), false); }
270
271impl Display for CstText {
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 let text = self.pritty_cst_recursive(&self.cst);
274 write!(f, "{}", text)
275 }
276}
277
278#[derive(Debug, PartialEq, Eq, Clone, Hash)]
281pub struct Cst {
282 pub rule: Rule,
284 pub span: Span,
285 pub inner: Vec<Cst>,
286}
287
288impl Cst {
289 pub fn new(rule: Rule, range: (usize, usize), inner: Vec<Cst>) -> Self {
291 let span = Span {
292 start: range.0,
293 end: range.1,
294 };
295 Self { rule, span, inner }
296 }
297
298 pub fn as_str<'a>(&'a self, text: &'a str) -> &'a str {
299 let Span { start, end } = self.span;
300 &text[start..end]
301 }
302
303 pub fn pickup(&self, rule: Rule) -> Vec<&Cst> {
305 let mut vec = vec![];
306 for cst in &self.inner {
307 if cst.rule == rule {
308 vec.push(cst)
309 }
310 let v = cst.pickup(rule);
311 vec.extend(v);
312 }
313 vec
314 }
315
316 pub fn choose(&self, pos: usize) -> Option<&Cst> {
318 for cst in &self.inner {
319 if cst.span.includes(pos) {
320 return Some(cst);
321 }
322 }
323 None
324 }
325
326 pub fn dig(&self, pos: usize) -> Vec<&Cst> {
329 let child = self.choose(pos);
330 let mut v = if let Some(child) = child {
331 let mut v = child.dig(pos);
332 v.push(child);
333 v
334 } else {
335 vec![]
336 };
337 if self.span.includes(pos) {
338 v.push(self);
339 }
340 v
341 }
342
343 pub fn get_parent(&self, child: &Cst) -> Option<&Cst> {
346 let child_pos = child.span.start;
347 self.dig(child_pos)
348 .into_iter()
349 .find(|&cst| cst.span.contains(&child.span) && cst.span != child.span)
350 }
351
352 pub fn mode(&self, pos: usize) -> Mode {
353 let csts = self.dig(pos);
354 let rules = csts.iter().map(|cst| cst.rule);
355
356 for rule in rules {
357 if let Some(mode) = rule.mode() {
358 return mode;
359 }
360 }
361 Mode::Program
362 }
363
364 pub fn listup(&self) -> Vec<&Cst> {
366 let mut v = vec![];
367 v.push(self);
368 for cst in &self.inner {
369 let inner = cst.listup();
370 v.extend(inner);
371 }
372 v
373 }
374
375 pub fn get_terminal_spans(&self) -> Vec<Span> {
378 let mut v = vec![];
379 let mut i = self.span.start;
380 for inner in &self.inner {
381 if i != inner.span.start {
382 v.push(Span {
383 start: i,
384 end: inner.span.start,
385 })
386 }
387 i = inner.span.end;
388 }
389 if i != self.span.end {
390 v.push(Span {
391 start: i,
392 end: self.span.end,
393 })
394 }
395 v
396 }
397}
398
399#[macro_export]
401macro_rules! cst {
402
403 ($rule:ident ($s:expr, $e:expr) []) => {
404 Cst {
405 rule: Rule::$rule,
406 span: Span {start: $s, end: $e},
407 inner: vec![]
408 }
409 };
410
411 ($rule:ident ($s:expr, $e:expr) [$($inner:expr),*]) => {
412 Cst {
413 rule: Rule::$rule,
414 span: Span {start: $s, end: $e},
415 inner: vec![$($inner.vectorize()),*].vectorize()
416 }
417 };
418
419}