cfg_classify/
recursive.rs1use cfg_grammar::{Cfg, CfgRule};
4use cfg_predict_distance::MinimalDistance;
5use cfg_symbol_bit_matrix::{CfgSymbolBitMatrixExt, ReachabilityMatrix};
6
7pub struct Recursion<'a> {
10 grammar: &'a Cfg,
11 derivation: ReachabilityMatrix,
12}
13
14#[derive(Eq, PartialEq, Debug, Clone, Copy)]
16pub struct RecursionKind {
17 pub left: bool,
19 pub middle: bool,
21 pub right: bool,
23}
24
25#[derive(Eq, PartialEq, Debug, Clone, Copy)]
38pub struct RecursiveRule<'a> {
39 pub rule: &'a CfgRule,
41 pub recursion: RecursionKind,
43 pub distances: Option<(usize, usize)>,
46}
47
48pub struct RecursiveRules<'a, 'b, R: Iterator<Item = &'b CfgRule>> {
51 rules: R,
52 recursion: &'b Recursion<'a>,
53}
54
55pub struct RecursiveRulesWithDistances<'a, 'b, R: Iterator<Item = (usize, &'b CfgRule)>> {
59 rules: R,
60 recursion: &'b Recursion<'a>,
61 minimal_distance: MinimalDistance<'a>,
62}
63
64impl<'a> Recursion<'a> {
65 pub fn new(grammar: &'a Cfg) -> Self {
67 let reachability = grammar.reachability_matrix();
68
69 Recursion {
70 grammar: grammar,
71 derivation: reachability,
72 }
73 }
74
75 pub fn minimal_distances<'b>(&'b self) -> impl Iterator<Item = RecursiveRule<'b>> {
83 let mut minimal_distance = MinimalDistance::new(&self.grammar);
84 let mut dots = vec![];
85 for (idx, rule) in self.grammar.rules().enumerate() {
86 let recursive_dot_pos = rule
87 .rhs
88 .iter()
89 .enumerate()
90 .filter(|&(_dot_pos, &rhs_sym)| self.derivation[(rhs_sym, rule.lhs)]);
91 for (dot_pos, _rhs_sym) in recursive_dot_pos {
92 dots.push((idx, dot_pos));
93 }
94 }
95 minimal_distance.minimal_distances(
96 &dots[..],
97 cfg_predict_distance::DistanceDirection::Symmetric,
98 );
99 RecursiveRulesWithDistances {
100 rules: self.grammar.rules().enumerate(),
101 recursion: self,
102 minimal_distance,
103 }
104 }
105
106 pub fn recursive_rules<'b>(&'b self) -> impl Iterator<Item = RecursiveRule<'b>> {
109 RecursiveRules {
110 rules: self.grammar.rules(),
111 recursion: self,
112 }
113 }
114}
115
116impl<'a, 'b, R: Iterator<Item = &'b CfgRule>> Iterator for RecursiveRules<'a, 'b, R> {
117 type Item = RecursiveRule<'b>;
118
119 fn next(&mut self) -> Option<Self::Item> {
120 while let Some(rule) = self.rules.next() {
121 if let Some(recursion) = rule_recursion(rule, &self.recursion.derivation) {
122 return Some(RecursiveRule {
123 rule,
124 recursion,
125 distances: None,
126 });
127 }
128 }
129 None
130 }
131}
132
133impl<'a, 'b, R: Iterator<Item = (usize, &'b CfgRule)>> Iterator
134 for RecursiveRulesWithDistances<'a, 'b, R>
135{
136 type Item = RecursiveRule<'b>;
137
138 fn next(&mut self) -> Option<Self::Item> {
139 while let Some((idx, rule)) = self.rules.next() {
140 if let Some(recursion) = rule_recursion(rule, &self.recursion.derivation) {
141 let rule_distances = &self.minimal_distance.distances()[idx][..];
143 return Some(RecursiveRule {
144 rule,
145 recursion,
146 distances: Some((
147 rule_distances[0].unwrap_or(u32::MAX) as usize,
148 rule_distances[rule_distances.len() - 1].unwrap_or(u32::MAX) as usize,
149 )),
150 });
151 }
152 }
153 None
154 }
155}
156
157fn rule_recursion(rule: &CfgRule, derivation: &ReachabilityMatrix) -> Option<RecursionKind> {
158 if rule.rhs.len() == 0 {
159 return None;
160 }
161 let rec_kind = RecursionKind {
162 left: rule
163 .rhs
164 .first()
165 .map(|&rhs_sym| derivation[(rhs_sym, rule.lhs)])
166 == Some(true),
167 right: rule
168 .rhs
169 .last()
170 .map(|&rhs_sym| derivation[(rhs_sym, rule.lhs)])
171 == Some(true),
172 middle: rule
173 .rhs
174 .iter()
175 .skip(1)
176 .take(rule.rhs.len().saturating_sub(2))
177 .any(|&rhs_sym| derivation[(rhs_sym, rule.lhs)]),
178 };
179 if rec_kind.any() { Some(rec_kind) } else { None }
180}
181
182impl RecursionKind {
183 fn any(self) -> bool {
184 self.left || self.middle || self.right
185 }
186}