grit_pattern_matcher/pattern/
range.rs1use super::{
2 patterns::{Matcher, PatternName},
3 resolved_pattern::ResolvedPattern,
4 state::State,
5};
6use crate::context::{ExecContext, QueryContext};
7use grit_util::{
8 error::{GritPatternError, GritResult},
9 AnalysisLogs, UtilRange,
10};
11
12#[derive(Debug, Clone)]
13pub struct Point {
14 line: u32,
15 column: Option<u32>,
16}
17
18impl Point {
19 pub fn new(line: Option<u32>, column: Option<u32>) -> GritResult<Option<Self>> {
20 if let Some(line) = line {
21 Ok(Some(Self { line, column }))
22 } else {
23 column
24 .map(|_| {
25 Err(GritPatternError::new(
26 "cannot have a point with a column index, but no line",
27 ))
28 })
29 .unwrap_or(Ok(None))
30 }
31 }
32}
33
34#[derive(Debug, Clone)]
35pub struct Range {
36 pub start: Option<Point>,
37 pub end: Option<Point>,
38}
39
40impl From<UtilRange> for Range {
41 fn from(util_range: UtilRange) -> Self {
42 match util_range {
44 UtilRange::Range(range) => Self {
45 start: Some(Point {
46 line: range.start.line,
47 column: Some(range.start.column),
48 }),
49 end: Some(Point {
50 line: range.end.line,
51 column: Some(range.end.column),
52 }),
53 },
54 UtilRange::RangeWithoutByte(range_without_byte) => Self {
55 start: Some(Point {
56 line: range_without_byte.start.line,
57 column: Some(range_without_byte.start.column),
58 }),
59 end: Some(Point {
60 line: range_without_byte.end.line,
61 column: Some(range_without_byte.end.column),
62 }),
63 },
64 }
65 }
66}
67
68impl<Q: QueryContext> Matcher<Q> for Range {
69 fn execute<'a>(
70 &'a self,
71 binding: &Q::ResolvedPattern<'a>,
72 _state: &mut State<'a, Q>,
73 context: &'a Q::ExecContext<'a>,
74 _logs: &mut AnalysisLogs,
75 ) -> GritResult<bool> {
76 if let Some(range) = binding.position(context.language()) {
77 if let Some(start) = &self.start {
78 if start.line > range.start.line {
79 return Ok(false);
80 }
81 if let Some(column) = start.column {
82 if start.line == range.start.line && column > range.start.column {
83 return Ok(false);
84 }
85 }
86 }
87 if let Some(end) = &self.end {
88 if end.line < range.end.line {
89 return Ok(false);
90 }
91 if let Some(column) = end.column {
92 if end.line == range.end.line && column < range.end.column {
93 return Ok(false);
94 }
95 }
96 }
97 return Ok(true);
98 }
99 Ok(false)
100 }
101}
102
103impl PatternName for Range {
104 fn name(&self) -> &'static str {
105 "RANGE"
106 }
107}