1 //!
2 
3 use collections::{Map, Set};
4 use ena::unify::InPlaceUnificationTable;
5 use grammar::repr::*;
6 use lr1::build;
7 use lr1::core::*;
8 use lr1::first::FirstSets;
9 use lr1::lane_table::lane::LaneTracer;
10 use lr1::lane_table::table::context_set::OverlappingLookahead;
11 use lr1::lane_table::table::{ConflictIndex, LaneTable};
12 use lr1::lookahead::{Lookahead, TokenSet};
13 use lr1::state_graph::StateGraph;
14 use std::rc::Rc;
15 
16 mod merge;
17 use self::merge::Merge;
18 
19 mod state_set;
20 use self::state_set::StateSet;
21 
22 pub struct LaneTableConstruct<'grammar> {
23     grammar: &'grammar Grammar,
24     first_sets: FirstSets,
25     start_nt: NonterminalString,
26 }
27 
28 impl<'grammar> LaneTableConstruct<'grammar> {
new(grammar: &'grammar Grammar, start_nt: NonterminalString) -> Self29     pub fn new(grammar: &'grammar Grammar, start_nt: NonterminalString) -> Self {
30         let first_sets = FirstSets::new(grammar);
31         LaneTableConstruct {
32             grammar,
33             start_nt,
34             first_sets,
35         }
36     }
37 
construct(self) -> Result<Vec<LR1State<'grammar>>, LR1TableConstructionError<'grammar>>38     pub fn construct(self) -> Result<Vec<LR1State<'grammar>>, LR1TableConstructionError<'grammar>> {
39         let states = {
40             match build::build_lr0_states(self.grammar, self.start_nt.clone()) {
41                 Ok(states) => {
42                     // In this case, the grammar is actually
43                     // LR(0). This is very rare -- it means that the
44                     // grammar does not need lookahead to execute. In
45                     // principle, we could stop here, except that if
46                     // we do so, then the lookahead values that we get
47                     // are very broad.
48                     //
49                     // Broad lookahead values will cause "eager"
50                     // reduce at runtime -- i.e., if there is some
51                     // scenario where the lookahead tells you we are
52                     // in error, but we would have to reduce a few
53                     // states before we see it. This, in turn, can
54                     // cause infinite loops around error recovery
55                     // (#240).
56                     //
57                     // Since we want to behave as a LR(1) parser
58                     // would, we'll just go ahead and run the
59                     // algorithm.
60                     states
61                 }
62                 Err(TableConstructionError { states, .. }) => states,
63             }
64         };
65 
66         // Convert the LR(0) states into LR(0-1) states.
67         let mut states = self.promote_lr0_states(states);
68 
69         // For each inconsistent state, apply the lane-table algorithm to
70         // resolve it.
71         for i in 0.. {
72             if i >= states.len() {
73                 break;
74             }
75 
76             match self.resolve_inconsistencies(&mut states, StateIndex(i)) {
77                 Ok(()) => {}
78                 Err(_) => {
79                     // We failed because of irreconcilable conflicts
80                     // somewhere. Just compute the conflicts from the final set of
81                     // states.
82                     debug!(
83                         "construct: failed to resolve inconsistencies in state {:#?}",
84                         states[i]
85                     );
86                     let conflicts: Vec<Conflict<'grammar, TokenSet>> = states
87                         .iter()
88                         .flat_map(|s| Lookahead::conflicts(&s))
89                         .collect();
90                     return Err(TableConstructionError { states, conflicts });
91                 }
92             }
93         }
94 
95         Ok(states)
96     }
97 
98     /// Given a set of LR0 states, returns LR1 states where the lookahead
99     /// is always `TokenSet::all()`. We refer to these states as LR(0-1)
100     /// states in the README.
promote_lr0_states(&self, lr0: Vec<LR0State<'grammar>>) -> Vec<LR1State<'grammar>>101     fn promote_lr0_states(&self, lr0: Vec<LR0State<'grammar>>) -> Vec<LR1State<'grammar>> {
102         let all = TokenSet::all();
103         debug!("promote_lr0_states: all={:?}", all);
104         lr0.into_iter()
105             .map(|s| {
106                 let items = s
107                     .items
108                     .vec
109                     .iter()
110                     .map(|item| Item {
111                         production: item.production,
112                         index: item.index,
113                         lookahead: all.clone(),
114                     })
115                     .collect();
116                 let reductions = s
117                     .reductions
118                     .into_iter()
119                     .map(|(_, p)| (all.clone(), p))
120                     .collect();
121                 State {
122                     index: s.index,
123                     items: Items {
124                         vec: Rc::new(items),
125                     },
126                     shifts: s.shifts,
127                     reductions,
128                     gotos: s.gotos,
129                 }
130             })
131             .collect()
132     }
133 
resolve_inconsistencies( &self, states: &mut Vec<LR1State<'grammar>>, inconsistent_state: StateIndex, ) -> Result<(), StateIndex>134     fn resolve_inconsistencies(
135         &self,
136         states: &mut Vec<LR1State<'grammar>>,
137         inconsistent_state: StateIndex,
138     ) -> Result<(), StateIndex> {
139         debug!(
140             "resolve_inconsistencies(inconsistent_state={:?}/{:#?}",
141             inconsistent_state, states[inconsistent_state.0]
142         );
143 
144         let mut actions = super::conflicting_actions(&states[inconsistent_state.0]);
145         if actions.is_empty() {
146             // This can mean one of two things: only shifts, or a
147             // single reduction. We have to be careful about states
148             // with a single reduction: even though such a state is
149             // not inconsistent (there is only one possible course of
150             // action), we still want to run the lane table algorithm,
151             // because otherwise we get states with "complete"
152             // lookahead, which messes with error recovery.
153             //
154             // In particular, if there is too much lookahead, we will
155             // reduce even when it is inappropriate to do so.
156             actions = states[inconsistent_state.0]
157                 .reductions
158                 .iter()
159                 .map(|&(_, prod)| Action::Reduce(prod))
160                 .collect();
161             if actions.is_empty() {
162                 return Ok(());
163             }
164         }
165 
166         debug!("resolve_inconsistencies: conflicting_actions={:?}", actions);
167 
168         let table = self.build_lane_table(states, inconsistent_state, &actions);
169 
170         // Consider first the "LALR" case, where the lookaheads for each
171         // action are completely disjoint.
172         if self.attempt_lalr(&mut states[inconsistent_state.0], &table, &actions) {
173             return Ok(());
174         }
175 
176         // Construct the initial states; each state will map to a
177         // context-set derived from its row in the lane-table. This is
178         // fallible, because a state may be internally inconstent.
179         //
180         // (To handle unification, we also map each state to a
181         // `StateSet` that is its entry in the `ena` table.)
182         let rows = table.rows()?;
183         let mut unify = InPlaceUnificationTable::<StateSet>::new();
184         let mut state_sets = Map::new();
185         for (&state_index, context_set) in &rows {
186             let state_set = unify.new_key(context_set.clone());
187             state_sets.insert(state_index, state_set);
188             debug!(
189                 "resolve_inconsistencies: state_index={:?}, state_set={:?}",
190                 state_index, state_set
191             );
192         }
193 
194         // Now merge state-sets, cloning states where needed.
195         let mut merge = Merge::new(
196             &table,
197             &mut unify,
198             states,
199             &mut state_sets,
200             inconsistent_state,
201         );
202         let beachhead_states = table.beachhead_states();
203         for beachhead_state in beachhead_states {
204             match merge.start(beachhead_state) {
205                 Ok(()) => {}
206                 Err((source, _)) => {
207                     debug!(
208                         "resolve_inconsistencies: failed to merge, source={:?}",
209                         source
210                     );
211                     return Err(source);
212                 }
213             }
214         }
215         merge.patch_target_starts(&actions);
216 
217         Ok(())
218     }
219 
attempt_lalr( &self, state: &mut LR1State<'grammar>, table: &LaneTable<'grammar>, actions: &Set<Action<'grammar>>, ) -> bool220     fn attempt_lalr(
221         &self,
222         state: &mut LR1State<'grammar>,
223         table: &LaneTable<'grammar>,
224         actions: &Set<Action<'grammar>>,
225     ) -> bool {
226         match table.columns() {
227             Ok(columns) => {
228                 debug!("attempt_lalr, columns={:#?}", columns);
229                 columns.apply(state, actions);
230                 debug!("attempt_lalr, state={:#?}", state);
231                 true
232             }
233             Err(OverlappingLookahead) => {
234                 debug!("attempt_lalr, OverlappingLookahead");
235                 false
236             }
237         }
238     }
239 
build_lane_table( &self, states: &[LR1State<'grammar>], inconsistent_state: StateIndex, actions: &Set<Action<'grammar>>, ) -> LaneTable<'grammar>240     fn build_lane_table(
241         &self,
242         states: &[LR1State<'grammar>],
243         inconsistent_state: StateIndex,
244         actions: &Set<Action<'grammar>>,
245     ) -> LaneTable<'grammar> {
246         let state_graph = StateGraph::new(states);
247         let mut tracer = LaneTracer::new(
248             self.grammar,
249             self.start_nt.clone(),
250             states,
251             &self.first_sets,
252             &state_graph,
253             actions.len(),
254         );
255         for (i, action) in actions.iter().enumerate() {
256             tracer.start_trace(inconsistent_state, ConflictIndex::new(i), action.clone());
257         }
258         tracer.into_table()
259     }
260 }
261