grit_pattern_matcher/pattern/
includes.rs1use super::{
2 patterns::{Matcher, Pattern, PatternName},
3 resolved_pattern::ResolvedPattern,
4 State,
5};
6use crate::context::{ExecContext, QueryContext};
7use core::fmt::Debug;
8use grit_util::{
9 error::{GritPatternError, GritResult},
10 AnalysisLogs,
11};
12
13#[derive(Debug, Clone)]
14pub struct Includes<Q: QueryContext> {
15 pub includes: Pattern<Q>,
16}
17
18impl<Q: QueryContext> Includes<Q> {
19 pub fn new(includes: Pattern<Q>) -> Self {
20 Self { includes }
21 }
22}
23
24impl<Q: QueryContext> PatternName for Includes<Q> {
25 fn name(&self) -> &'static str {
26 "INCLUDES"
27 }
28}
29
30fn execute<'a, Q: QueryContext>(
31 pattern: &'a Pattern<Q>,
32 binding: &Q::ResolvedPattern<'a>,
33 state: &mut State<'a, Q>,
34 context: &'a Q::ExecContext<'a>,
35 logs: &mut AnalysisLogs,
36) -> GritResult<bool> {
37 match &pattern {
38 Pattern::Regex(pattern) => pattern.execute_matching(binding, state, context, logs, false),
39 Pattern::Or(pattern) => {
40 for p in pattern.patterns.iter() {
41 if execute(p, binding, state, context, logs)? {
42 return Ok(true);
43 }
44 }
45 Ok(false)
46 }
47 Pattern::Any(pattern) => {
48 let mut any_matched = false;
50 for p in pattern.patterns.iter() {
51 if execute(p, binding, state, context, logs)? {
52 any_matched = true;
53 }
54 }
55 Ok(any_matched)
56 }
57 Pattern::And(pattern) => {
58 for p in pattern.patterns.iter() {
59 if !execute(p, binding, state, context, logs)? {
60 return Ok(false);
61 }
62 }
63 Ok(true)
64 }
65 Pattern::AstNode(_)
66 | Pattern::List(_)
67 | Pattern::ListIndex(_)
68 | Pattern::Map(_)
69 | Pattern::Accessor(_)
70 | Pattern::Call(_)
71 | Pattern::File(_)
72 | Pattern::Files(_)
73 | Pattern::Bubble(_)
74 | Pattern::Limit(_)
75 | Pattern::CallBuiltIn(_)
76 | Pattern::CallFunction(_)
77 | Pattern::CallForeignFunction(_)
78 | Pattern::Assignment(_)
79 | Pattern::Accumulate(_)
80 | Pattern::Maybe(_)
81 | Pattern::Not(_)
82 | Pattern::If(_)
83 | Pattern::Undefined
84 | Pattern::Top
85 | Pattern::Bottom
86 | Pattern::Underscore
87 | Pattern::StringConstant(_)
88 | Pattern::AstLeafNode(_)
89 | Pattern::IntConstant(_)
90 | Pattern::FloatConstant(_)
91 | Pattern::BooleanConstant(_)
92 | Pattern::Dynamic(_)
93 | Pattern::CodeSnippet(_)
94 | Pattern::Variable(_)
95 | Pattern::Rewrite(_)
96 | Pattern::Range(_)
97 | Pattern::Contains(_)
98 | Pattern::Includes(_)
99 | Pattern::Within(_)
100 | Pattern::After(_)
101 | Pattern::Before(_)
102 | Pattern::Where(_)
103 | Pattern::Some(_)
104 | Pattern::Every(_)
105 | Pattern::Add(_)
106 | Pattern::Subtract(_)
107 | Pattern::Multiply(_)
108 | Pattern::Divide(_)
109 | Pattern::Modulo(_)
110 | Pattern::Dots
111 | Pattern::Sequential(_)
112 | Pattern::Like(_)
113 | Pattern::CallbackPattern(_) => {
114 let resolved = Q::ResolvedPattern::from_pattern(pattern, state, context, logs)
115 .map_err(|err| {
116 GritPatternError::new(format!(
117 "{err} \n includes can only be used with patterns that can be resolved"
118 ))
119 })?;
120 let substring = resolved.text(&state.files, context.language()).map_err(|err| {
121 GritPatternError::new(
122 format!("{err} \n includes can only be used with patterns that can be resolved to a string")
123 )
124 })?;
125 let string = binding.text(&state.files, context.language()).map_err(|err| {
126 GritPatternError::new(
127 format!("{err} \n includes can only be used with patterns that can be resolved to a string")
128 )
129 })?;
130 if string.contains(&*substring) {
131 Ok(true)
132 } else {
133 Ok(false)
134 }
135 }
136 }
137}
138
139impl<Q: QueryContext> Matcher<Q> for Includes<Q> {
142 fn execute<'a>(
143 &'a self,
144 binding: &Q::ResolvedPattern<'a>,
145 state: &mut State<'a, Q>,
146 context: &'a Q::ExecContext<'a>,
147 logs: &mut AnalysisLogs,
148 ) -> GritResult<bool> {
149 execute(&self.includes, binding, state, context, logs)
150 }
151}