grit_pattern_matcher/pattern/
list.rs1use super::{
2 list_index,
3 patterns::{Matcher, Pattern, PatternName},
4 resolved_pattern::ResolvedPattern,
5 state::State,
6};
7use crate::context::QueryContext;
8use core::fmt::Debug;
9use grit_util::{
10 error::{GritPatternError, GritResult},
11 AnalysisLogs,
12};
13use std::borrow::Cow;
14
15#[derive(Debug, Clone)]
16pub struct List<Q: QueryContext> {
17 pub patterns: Vec<Pattern<Q>>,
18}
19
20impl<Q: QueryContext> List<Q> {
21 pub fn new(patterns: Vec<Pattern<Q>>) -> Self {
22 Self { patterns }
23 }
24
25 pub fn get(&self, index: isize) -> Option<&Pattern<Q>> {
26 self.patterns
27 .get(list_index::to_unsigned(index, self.patterns.len())?)
28 }
29}
30
31impl<Q: QueryContext> PatternName for List<Q> {
32 fn name(&self) -> &'static str {
33 "LIST"
34 }
35}
36
37impl<Q: QueryContext> Matcher<Q> for List<Q> {
38 fn execute<'a>(
39 &'a self,
40 binding: &Q::ResolvedPattern<'a>,
41 state: &mut State<'a, Q>,
42 context: &'a Q::ExecContext<'a>,
43 logs: &mut AnalysisLogs,
44 ) -> GritResult<bool> {
45 if let Some(items) = binding.get_list_binding_items() {
46 let patterns: Vec<_> = items.map(Cow::Owned).collect();
47 execute_assoc(&self.patterns, &patterns, state, context, logs)
48 } else if let Some(items) = binding.get_list_items() {
49 let patterns: Vec<_> = items.map(Cow::Borrowed).collect();
50 execute_assoc(&self.patterns, &patterns, state, context, logs)
51 } else {
52 Ok(false)
53 }
54 }
55}
56
57fn execute_assoc<'a, Q: QueryContext>(
58 patterns: &'a [Pattern<Q>],
59 children: &[Cow<Q::ResolvedPattern<'a>>],
60 current_state: &mut State<'a, Q>,
61 context: &'a Q::ExecContext<'a>,
62 logs: &mut AnalysisLogs,
63) -> GritResult<bool> {
64 let mut working_state = current_state.clone();
65 match patterns {
66 [pattern_for_first_node, Pattern::Dots] => {
68 if children.is_empty() {
69 return Ok(false);
70 }
71 let first_node = children[0].clone();
72 if pattern_for_first_node.execute(&first_node, &mut working_state, context, logs)? {
73 *current_state = working_state;
74 Ok(true)
75 } else {
76 Ok(false)
77 }
78 }
79 [Pattern::Dots, pattern_for_last_node] => {
81 if let Some(last_node) = children.last() {
82 if pattern_for_last_node.execute(last_node, &mut working_state, context, logs)? {
83 *current_state = working_state;
84 Ok(true)
85 } else {
86 Ok(false)
87 }
88 } else {
89 Ok(false)
90 }
91 }
92 [Pattern::Dots, head_pattern, tail_patterns @ ..] => {
93 if let Pattern::Dots = head_pattern {
94 return Err(GritPatternError::new(
95 "Multiple subsequent dots are not allowed.",
96 ));
97 }
98 for index in 0..children.len() {
99 if head_pattern.execute(&children[index], &mut working_state, context, logs)?
100 && execute_assoc(
101 tail_patterns,
102 &children[index + 1..],
103 &mut working_state,
104 context,
105 logs,
106 )?
107 {
108 *current_state = working_state;
109 return Ok(true);
110 }
111 }
112 Ok(false)
113 }
114 [Pattern::Dots] => Ok(true),
115 [only_pattern] => {
116 if children.len() == 1 {
117 if only_pattern.execute(&children[0], &mut working_state, context, logs)? {
118 *current_state = working_state;
119 Ok(true)
120 } else {
121 Ok(false)
122 }
123 } else {
124 Ok(false)
125 }
126 }
127 [head_pattern, tail_patterns @ ..] => match children {
128 [head_node, tail_nodes @ ..] => {
129 if head_pattern.execute(head_node, &mut working_state, context, logs)? {
130 if let Ok(true) =
131 execute_assoc(tail_patterns, tail_nodes, &mut working_state, context, logs)
132 {
133 *current_state = working_state;
134 Ok(true)
135 } else {
136 Ok(false)
137 }
138 } else {
139 Ok(false)
140 }
141 }
142 [] => Ok(false),
143 },
144 [] => Ok(children.is_empty()),
145 }
146}