1use cfg_grammar::CfgRule;
4use cfg_symbol_bit_matrix::CfgSymbolBitMatrixExt;
5use cfg_symbol_bit_matrix::ReachabilityMatrix;
6
7use cfg_grammar::Cfg;
8use cfg_grammar::SymbolBitSet;
9use cfg_symbol::Symbol;
10
11pub struct Usefulness {
14 reachability: ReachabilityMatrix,
15 reachable_syms: SymbolBitSet,
16 productivity: SymbolBitSet,
17}
18
19#[derive(Copy, Clone, Debug)]
21pub struct UsefulnessForRule<'a> {
22 rule: &'a CfgRule,
23 usefulness: RuleUsefulness,
24}
25
26#[derive(Copy, Clone, Debug)]
28pub struct RuleUsefulness {
29 pub reachable: bool,
31 pub productive: bool,
33}
34
35impl<'a> UsefulnessForRule<'a> {
36 pub fn rule(&self) -> &CfgRule {
38 self.rule
39 }
40
41 pub fn usefulness(&self) -> RuleUsefulness {
43 self.usefulness
44 }
45}
46
47impl RuleUsefulness {
48 fn is_useless(&self) -> bool {
49 !self.reachable || !self.productive
50 }
51}
52
53fn productive_syms(grammar: &Cfg) -> SymbolBitSet {
59 let mut productive_syms = SymbolBitSet::new();
60 productive_syms.terminal(grammar);
61 productive_syms.nulling(grammar);
62 grammar.rhs_closure_for_all(&mut productive_syms);
63 productive_syms
64}
65
66impl Usefulness {
67 pub fn new(grammar: &Cfg) -> Self {
70 let mut productivity = productive_syms(grammar);
71 let reachability: ReachabilityMatrix = grammar.reachability_matrix().reflexive();
72 let mut unused_syms = SymbolBitSet::new();
73 unused_syms.unused(grammar);
74 let mut reachable_syms = SymbolBitSet::from_elem(grammar, false);
75
76 productivity.union(&unused_syms);
77 reachable_syms.union(&unused_syms);
78
79 debug_assert_eq!(
80 reachability.size(),
81 (productivity.space(), productivity.space())
82 );
83
84 Usefulness {
85 productivity,
86 reachability,
87 reachable_syms,
88 }
89 }
90
91 pub fn productivity(&self, sym: Symbol) -> bool {
94 self.productivity[sym]
95 }
96
97 pub fn reachable(&mut self, syms: impl AsRef<[Symbol]>) {
99 for &sym in syms.as_ref() {
100 for derived in self.reachability.iter_row_syms(sym) {
101 self.reachable_syms.set(derived, true);
102 }
103 }
104 }
105
106 pub fn all_useful(&self) -> bool {
108 self.productivity.all() && self.reachable_syms.all()
109 }
110
111 pub fn all_productive(&self) -> bool {
113 self.productivity.all()
114 }
115
116 pub fn all_reachable(&self) -> bool {
118 self.reachable_syms.all()
119 }
120
121 pub fn usefulness<'r>(&self, rule: &'r CfgRule) -> UsefulnessForRule<'r> {
123 let productive = rule.rhs.iter().all(|&sym| self.productivity[sym]);
124 let reachable = self.reachable_syms[rule.lhs];
125 UsefulnessForRule {
126 rule,
127 usefulness: RuleUsefulness {
128 productive,
129 reachable,
130 },
131 }
132 }
133
134 fn uselessness_if_useless<'r>(&self, rule: &'r CfgRule) -> Option<UsefulnessForRule<'r>> {
135 let usefulness = self.usefulness(rule);
136 if usefulness.usefulness.is_useless() {
137 Some(usefulness)
138 } else {
139 None
140 }
141 }
142
143 pub fn useless_rules<'a, 'g>(
145 &'a self,
146 grammar: &'g Cfg,
147 ) -> impl Iterator<Item = UsefulnessForRule<'g>> + 'a
148 where
149 'g: 'a,
150 {
151 grammar
152 .rules()
153 .filter_map(|rule| self.uselessness_if_useless(rule))
154 }
155
156 pub fn remove_useless_rules(&self, grammar: &mut Cfg) {
158 if !self.all_useful() {
159 let productivity = &self.productivity;
160 let reachable_syms = &self.reachable_syms;
161 let rule_is_useful = |rule: &CfgRule| {
162 let productive = rule.rhs.iter().all(|&sym| productivity[sym]);
163 let reachable = reachable_syms[rule.lhs];
164 productive && reachable
165 };
166 grammar.retain(rule_is_useful);
167 }
168 }
169}