1use std::{
3 cell::RefCell,
4 cmp::{self, Ordering},
5 collections::{BTreeMap, BTreeSet, VecDeque},
6 fmt::{self, Display},
7 iter::{self, repeat},
8 ops::{Index, IndexMut},
9 slice::{Iter, IterMut},
10};
11
12use clap::ValueEnum;
13use colored::Colorize;
14use itertools::{chain, Itertools};
15use rustemo::log;
16
17use crate::{
18 create_index,
19 error::{Error, Result},
20 grammar::{Associativity, Priority, Terminal, DEFAULT_PRIORITY},
21 index::{
22 NonTermIndex, NonTermVec, ProdIndex, ProdVec, StateIndex, StateVec, SymbolIndex,
23 SymbolVec, TermIndex, TermVec,
24 },
25 lang::rustemo_actions::Recognizer,
26 settings::{ParserAlgo, Settings},
27};
28
29use super::grammar::{res_symbol, Grammar};
30
31#[derive(Debug, Clone)]
32pub enum Action {
33 Shift(StateIndex),
34 Reduce(ProdIndex, usize),
35 Accept,
36}
37
38#[allow(non_camel_case_types)]
41#[derive(Debug, Default, Clone, PartialEq, Eq, ValueEnum)]
42pub enum TableType {
43 LALR,
46 #[default]
49 LALR_PAGER,
50 LALR_RN,
53}
54
55type Firsts = BTreeSet<SymbolIndex>;
56type FirstSets = SymbolVec<Firsts>;
57
58create_index!(ItemIndex, ItemVec);
59
60#[derive(Clone)]
62pub struct LRState<'g> {
63 grammar: &'g Grammar,
64
65 pub idx: StateIndex,
67
68 pub symbol: SymbolIndex,
73
74 items: ItemVec<LRItem>,
76
77 pub actions: TermVec<Vec<Action>>,
82
83 pub gotos: NonTermVec<Option<StateIndex>>,
86
87 pub sorted_terminals: Vec<(TermIndex, bool)>,
92
93 max_prior_for_term: BTreeMap<TermIndex, Priority>,
102}
103
104impl PartialEq for LRState<'_> {
106 fn eq(&self, other: &Self) -> bool {
107 let self_ki = self.kernel_items();
108 let other_ki = other.kernel_items();
109 self_ki.len() == other_ki.len() && self_ki.iter().zip(other_ki.iter()).all(|(x, y)| x == y)
110 }
111}
112impl Eq for LRState<'_> {}
113
114impl Display for LRState<'_> {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(
117 f,
118 "{}\n\t{}",
119 format!(
120 "State {}:{}",
121 self.idx,
122 self.grammar.symbol_name(self.symbol)
123 )
124 .green()
125 .bold(),
126 self.items
127 .iter()
128 .map(|i| i.to_string(self.grammar))
129 .collect::<Vec<_>>()
130 .join("\n\t")
131 )
132 }
133}
134
135impl std::fmt::Debug for LRState<'_> {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("LRState")
138 .field("idx", &self.idx)
139 .field("symbol", &self.symbol)
140 .field("items", &self.items)
141 .field("actions", &self.actions)
142 .field("gotos", &self.gotos)
143 .field("sorted_terminals", &self.sorted_terminals)
144 .field("max_prior_for_term", &self.max_prior_for_term)
145 .finish()
146 }
147}
148
149impl<'g> LRState<'g> {
150 fn new(grammar: &'g Grammar, index: StateIndex, symbol: SymbolIndex) -> Self {
151 Self {
152 grammar,
153 idx: index,
154 symbol,
155 items: ItemVec::new(),
156 actions: grammar.new_termvec(vec![]),
157 gotos: grammar.new_nontermvec(None),
158 max_prior_for_term: BTreeMap::new(),
159 sorted_terminals: Vec::new(),
160 }
161 }
162
163 fn new_with_items(
164 grammar: &'g Grammar,
165 index: StateIndex,
166 symbol: SymbolIndex,
167 items: ItemVec<LRItem>,
168 ) -> Self {
169 Self {
170 grammar,
171 idx: index,
172 symbol,
173 items,
174 actions: grammar.new_termvec(vec![]),
175 gotos: grammar.new_nontermvec(None),
176 max_prior_for_term: BTreeMap::new(),
177 sorted_terminals: Vec::new(),
178 }
179 }
180
181 fn add_item(mut self, item: LRItem) -> Self {
182 self.items.push(item);
183 self
184 }
185
186 fn kernel_items(&self) -> Vec<&LRItem> {
187 self.items.iter().filter(|i| i.is_kernel()).collect()
188 }
189
190 fn nonkernel_items(&self) -> Vec<&LRItem> {
191 self.items.iter().filter(|i| !i.is_kernel()).collect()
192 }
193
194 fn closure(&mut self, first_sets: &FirstSets, prod_rn_lengths: &Option<ProdVec<usize>>) {
201 loop {
202 #[allow(clippy::mutable_key_type)]
205 let mut new_items: BTreeSet<LRItem> = BTreeSet::new();
206
207 for item in &self.items {
208 if let Some(symbol) = item.symbol_at_position(self.grammar) {
209 if self.grammar.is_nonterm(symbol) {
210 let mut new_follow;
211 if item.position + 1 < self.grammar.productions[item.prod].rhs.len() {
214 new_follow = firsts(
215 self.grammar,
216 first_sets,
217 &self.grammar.production_rhs_symbols(item.prod)
218 [item.position + 1..],
219 );
220 if new_follow.contains(&self.grammar.empty_index) {
223 new_follow.remove(&self.grammar.empty_index);
224 new_follow.extend(item.follow.borrow().iter());
225 }
226 } else {
227 new_follow = Follow::new();
230 new_follow.extend(item.follow.borrow().iter());
231 }
232
233 let nonterm = self.grammar.symbol_to_nonterm_index(symbol);
236 for prod in &self.grammar.nonterminals[nonterm].productions {
237 new_items.insert(LRItem::with_follow(
238 self.grammar,
239 *prod,
240 prod_rn_lengths.as_ref().map(|p| p[*prod]),
241 new_follow.clone(),
242 ));
243 }
244 }
245 }
246 }
247
248 let mut change = false;
251 for new_item in new_items {
252 match self.items.iter_mut().find(|x| *x == &new_item) {
253 Some(item) => {
254 let l = item.follow.borrow().len();
256 item.follow
257 .borrow_mut()
258 .extend(new_item.follow.borrow().iter());
259 if item.follow.borrow().len() > l {
260 change = true;
261 }
262 }
263 None => {
264 self.items.push(new_item);
265 change = true;
266 }
267 }
268 }
269 if !change {
270 break;
271 }
272 }
273 }
274
275 fn group_per_next_symbol(&mut self) -> BTreeMap<SymbolIndex, Vec<ItemIndex>> {
278 let mut per_next_symbol: BTreeMap<SymbolIndex, Vec<ItemIndex>> = BTreeMap::new();
279
280 for (idx, item) in self.items.iter().enumerate() {
281 let symbol = item.symbol_at_position(self.grammar);
282 if let Some(symbol) = symbol {
283 per_next_symbol.entry(symbol).or_default().push(idx.into());
284 if self.grammar.is_term(symbol) {
285 let symbol = self.grammar.symbol_to_term_index(symbol);
286 let prod_prio = self.grammar.productions[item.prod].prio;
287 self.max_prior_for_term
288 .entry(symbol)
289 .and_modify(|v| *v = cmp::max(*v, prod_prio))
290 .or_insert(prod_prio);
291 }
292 }
293 }
294 per_next_symbol
295 }
296}
297
298#[derive(Debug, Eq, Clone, PartialOrd, Ord)]
303struct LRItem {
304 prod: ProdIndex,
305
306 prod_len: usize,
308
309 rn_len: Option<usize>,
313
314 position: usize,
316
317 follow: RefCell<Follow>,
318}
319
320impl std::hash::Hash for LRItem {
321 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
322 self.prod.hash(state);
323 self.position.hash(state);
324 }
325}
326
327impl PartialEq for LRItem {
328 fn eq(&self, other: &Self) -> bool {
329 self.prod == other.prod && self.position == other.position
330 }
331}
332
333impl LRItem {
359 #[cfg(test)]
360 fn new(grammar: &Grammar, prod: ProdIndex, rn_len: Option<usize>) -> Self {
361 LRItem {
362 prod,
363 prod_len: grammar.production_len(prod),
364 rn_len,
365 position: 0,
366 follow: RefCell::new(Follow::new()),
367 }
368 }
369
370 fn with_follow(
371 grammar: &Grammar,
372 prod: ProdIndex,
373 rn_len: Option<usize>,
374 follow: Follow,
375 ) -> Self {
376 LRItem {
377 prod,
378 prod_len: grammar.production_len(prod),
379 rn_len,
380 position: 0,
381 follow: RefCell::new(follow),
382 }
383 }
384
385 fn symbol_at_position(&self, grammar: &Grammar) -> Option<SymbolIndex> {
386 Some(res_symbol(
387 grammar.productions.get(self.prod)?.rhs.get(self.position)?,
388 ))
389 }
390
391 #[inline]
393 fn inc_position(mut self) -> Self {
394 assert!(self.position < self.prod_len);
395 self.position += 1;
396 self
397 }
398
399 #[inline]
404 fn is_kernel(&self) -> bool {
405 self.position > 0 || self.prod == ProdIndex(0)
406 }
407
408 #[inline]
409 fn is_reducing(&self) -> bool {
410 self.position == self.prod_len
411 || match self.rn_len {
412 Some(rn_len) => self.position >= rn_len,
413 None => false,
414 }
415 }
416
417 fn to_string(&self, grammar: &Grammar) -> String {
418 let prod = &grammar.productions[self.prod];
419 let mut rhs = prod
420 .rhs_symbols()
421 .iter()
422 .map(|s| grammar.symbol_name(*s))
423 .collect::<Vec<_>>();
424 rhs.insert(self.position, ".".into());
425 format!(
426 "{}: {}: {} {{{}}}",
427 prod.idx.to_string().green(),
428 grammar
429 .symbol_name(grammar.nonterm_to_symbol_index(prod.nonterminal))
430 .green(),
431 rhs.join(" "),
432 self.follow
433 .borrow()
434 .iter()
435 .map(|f| grammar.symbol_name(*f))
436 .collect::<Vec<_>>()
437 .join(", ")
438 )
439 }
440}
441
442pub enum ConflictKind {
443 ShiftReduce(ProdIndex),
444 ReduceReduce(ProdIndex, ProdIndex),
445}
446
447pub struct Conflict<'g, 's> {
448 state: &'s LRState<'g>,
449 follow: TermIndex,
450 kind: ConflictKind,
451}
452
453impl Display for Conflict<'_, '_> {
454 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
455 write!(f, "")?;
456 Ok(())
457 }
458}
459
460pub struct LRTable<'g, 's> {
461 pub states: StateVec<LRState<'g>>,
462 pub layout_state: Option<StateIndex>,
463 grammar: &'g Grammar,
464 settings: &'s Settings,
465 first_sets: FirstSets,
466
467 pub production_rn_lengths: Option<ProdVec<usize>>,
475}
476
477impl<'g, 's> LRTable<'g, 's> {
478 pub fn new(grammar: &'g Grammar, settings: &'s Settings) -> Result<Self> {
479 let first_sets = first_sets(grammar);
480 let production_rn_lengths = match settings.table_type {
481 TableType::LALR_RN => Some(production_rn_lengths(&first_sets, grammar)),
482 TableType::LALR | TableType::LALR_PAGER => None,
483 };
484 let mut table = Self {
485 grammar,
486 settings,
487 states: StateVec::new(),
488 layout_state: None,
489 first_sets,
490 production_rn_lengths,
491 };
492
493 table.check_empty_sets()?;
494
495 table.calc_states(grammar.augmented_index);
496 if let Some(augmented_layout_index) = grammar.augmented_layout_index {
497 table.layout_state = Some(StateIndex(table.states.len()));
498 table.calc_states(augmented_layout_index)
499 }
500
501 log!("LR states constructed. Updating follows.");
502 table.propagate_follows();
503
504 log!(
505 "Calculate REDUCTION entries in ACTION tables and resolve \
506 possible conflicts."
507 );
508 table.calculate_reductions();
509
510 log!("Sort terminals for lexical disambiguation");
511 table.sort_terminals();
512
513 println!("Terminals: {}", grammar.terminals.len());
514 println!("Non-terminals: {}", grammar.nonterminals().len());
515 println!("Productions: {}", grammar.productions().len());
516 println!("States: {}", table.states.len());
517
518 if settings.print_table {
519 println!("LR TABLE:");
520 println!("{table}");
521 }
522
523 Ok(table)
524 }
525
526 fn calc_states(&mut self, start_symbol: SymbolIndex) {
530 let mut current_state_idx = self.states.len();
531
532 let prods = &self.grammar.symbol_to_nonterm(start_symbol).productions;
533 assert_eq!(prods.len(), 1);
534
535 let state = LRState::new(self.grammar, StateIndex(current_state_idx), start_symbol)
537 .add_item(LRItem::with_follow(
538 self.grammar,
539 prods[0],
540 self.production_rn_lengths.as_ref().map(|p| p[prods[0]]),
541 Follow::from([self.grammar.stop_index]),
542 ));
543 current_state_idx += 1;
544
545 let mut state_queue = VecDeque::from([state]);
547
548 log!("Calculating LR automaton states.");
549 while let Some(mut state) = state_queue.pop_front() {
550 state.closure(&self.first_sets, &self.production_rn_lengths);
555
556 let per_next_symbol = state.group_per_next_symbol();
560
561 for &symbol in per_next_symbol.keys() {
563 if symbol == self.grammar.stop_index {
564 state.actions[self.grammar.symbol_to_term_index(symbol)] =
565 vec![Action::Accept];
566 break;
567 }
568 }
569
570 let new_states = Self::create_new_states(self.grammar, &state, per_next_symbol);
572
573 for mut new_state in new_states {
576 let target_state_symbol = new_state.symbol;
577 let mut new_state_found = true;
578 let mut target_state_idx = StateIndex(current_state_idx);
579 for old_state in self
580 .states
581 .iter_mut()
582 .chain(state_queue.iter_mut())
583 .chain(iter::once(&mut state))
584 .filter(|x| **x == new_state)
585 {
586 if Self::merge_state(self.settings, old_state, &new_state) {
588 new_state_found = false;
589 target_state_idx = old_state.idx;
590 break;
591 }
592 }
593
594 if self.grammar.is_nonterm(target_state_symbol) {
596 state.gotos[self.grammar.symbol_to_nonterm_index(target_state_symbol)] =
597 Some(target_state_idx);
598 } else {
599 let term = self.grammar.symbol_to_term_index(new_state.symbol);
600 state.actions[term].push(Action::Shift(target_state_idx));
601 }
602
603 if new_state_found {
604 new_state.idx = StateIndex(current_state_idx);
606
607 state_queue.push_back(new_state);
608 current_state_idx += 1;
609 }
610 }
611
612 self.states.push(state);
613 }
614 }
615
616 fn merge_state(
622 settings: &Settings,
623 old_state: &mut LRState<'g>,
624 new_state: &LRState<'g>,
625 ) -> bool {
626 if old_state != new_state {
628 return false;
629 }
630
631 let old_state_items = old_state
632 .items
633 .clone()
634 .into_iter()
635 .filter(|item| item.is_kernel());
636
637 let item_pairs: Vec<(&mut LRItem, &LRItem)> = iter::zip(
639 old_state.items.iter_mut().filter(|item| item.is_kernel()),
640 old_state_items.map(|x| new_state.items.iter().find(|&i| *i == x).unwrap()),
641 )
642 .collect();
643
644 if settings.table_type != TableType::LALR {
645 for (old, new) in &item_pairs {
654 if !old.is_reducing() {
655 continue;
656 }
657 for (old_in, new_in) in &item_pairs {
658 if old == old_in {
659 continue;
660 }
661 for t in chain(
666 old.follow.borrow().intersection(&*new_in.follow.borrow()),
667 old_in.follow.borrow().intersection(&*new.follow.borrow()),
668 ) {
669 if old
671 .follow
672 .borrow()
673 .intersection(&*old_in.follow.borrow())
674 .all(|x| x != t)
675 && new
676 .follow
677 .borrow()
678 .intersection(&*new_in.follow.borrow())
679 .all(|x| x != t)
680 {
681 return false;
684 }
685 }
686 }
687 }
688 }
689
690 for (old, new) in item_pairs {
692 old.follow.borrow_mut().extend(new.follow.borrow().iter())
693 }
694 true
695 }
696
697 fn propagate_follows(&mut self) {
703 let mut changed = true;
704 while changed {
705 changed = false;
706 for state in self.states.iter_mut() {
707 state.closure(&self.first_sets, &self.production_rn_lengths);
711 }
712
713 for state in self.states.iter() {
714 state
716 .gotos
717 .iter()
718 .filter_map(|x| x.as_ref())
719 .chain(state.actions.iter().flat_map(|x| {
720 x.iter().filter_map(|a| match a {
721 Action::Shift(state) => Some(state),
722 _ => None,
723 })
724 }))
725 .for_each(|&target_state| {
726 for target_item in &mut self.states[target_state]
727 .items
728 .iter()
729 .filter(|x| x.is_kernel())
730 {
731 if let Some(source_item) = state.items.iter().find(|&x| {
733 x.prod == target_item.prod
734 && x.position == target_item.position - 1
735 }) {
736 let follow_len = target_item.follow.borrow().len();
738 target_item
739 .follow
740 .borrow_mut()
741 .extend(source_item.follow.borrow().iter());
742
743 if target_item.follow.borrow().len() > follow_len {
745 changed = true
746 }
747 }
748 }
749 })
750 }
751 }
752 }
753
754 fn calculate_reductions(&mut self) {
757 let mut aug_symbols = vec![self.grammar.augmented_index];
758 if let Some(layout_index) = self.grammar.augmented_layout_index {
759 aug_symbols.push(layout_index);
760 }
761 for state in &mut self.states {
762 for item in state.items.iter().filter(|x| x.is_reducing()) {
763 let prod = &self.grammar.productions[item.prod];
764
765 if aug_symbols.contains(&self.grammar.nonterm_to_symbol_index(prod.nonterminal)) {
771 if item.position == item.prod_len {
772 let actions = &mut state.actions[TermIndex(0)];
773 actions.push(Action::Accept);
774 }
775 continue;
776 }
777
778 let new_reduce = Action::Reduce(item.prod, item.position);
779 for follow_symbol in item.follow.borrow().iter() {
780 let follow_term = self.grammar.symbol_to_term(*follow_symbol);
781 let actions = &mut state.actions[follow_term.idx];
782 if actions.is_empty() {
783 actions.push(new_reduce.clone());
786 } else {
787 let (shifts, reduces): (Vec<_>, Vec<_>) = actions
789 .clone()
790 .into_iter()
791 .partition(|x| matches!(x, Action::Shift(_) | Action::Accept));
792 assert!(shifts.len() <= 1);
795
796 let mut should_reduce = true;
797 if let Some(shift) = shifts.first() {
798 let shift_prio = match shift {
802 Action::Accept => DEFAULT_PRIORITY,
803 _ => state.max_prior_for_term[&follow_term.idx],
804 };
805 match prod.prio.cmp(&shift_prio) {
806 Ordering::Less => {
807 should_reduce = false
810 }
811 Ordering::Equal => {
812 match (&prod.assoc, &follow_term.assoc) {
816 (Associativity::Left, Associativity::None)
817 | (_, Associativity::Right) => {
818 assert!(actions.len() == 1);
820 actions.pop();
821 }
822 (Associativity::Right, Associativity::None)
823 | (_, Associativity::Left) => {
824 should_reduce = false;
830 }
831 (Associativity::None, Associativity::None) => {
832 let empty = prod.rhs.is_empty();
836 let prod_pse = empty
837 && self.settings.prefer_shifts_over_empty
838 && !prod.nopse;
839 let prod_ps = !empty
840 && self.settings.prefer_shifts
841 && !prod.nops;
842 should_reduce = !(prod_pse || prod_ps);
843 }
844 }
845 }
846 Ordering::Greater => {
847 assert!(actions.len() == 1);
850 actions.pop();
851 }
852 }
853 }
854
855 if should_reduce {
856 if reduces.is_empty() {
857 actions.push(new_reduce.clone())
858 } else {
859 let reduces_prio = reduces
862 .iter()
863 .map(|x| match x {
864 Action::Reduce(prod, ..) => {
865 self.grammar.productions[*prod].prio
866 }
867 other => panic!("This should not happen. Got {other:?}"),
868 })
869 .collect::<Vec<_>>();
870 if reduces_prio.iter().all(|x| prod.prio < *x) {
871 } else if reduces_prio.iter().all(|x| prod.prio > *x) {
874 actions.retain(|x| !matches!(x, Action::Reduce(..)));
878 actions.push(new_reduce.clone())
879 } else {
880 if let ParserAlgo::LR = self.settings.parser_algo {
883 actions.retain(
885 |x| !matches!(x, Action::Reduce(_, len) if *len == 0),
886 );
887
888 if item.prod_len > 0 || actions.is_empty() {
889 actions.push(new_reduce.clone())
891 }
892 } else {
893 actions.push(new_reduce.clone())
898 }
899 }
900 }
901 }
902 }
903 }
904 }
905 }
906 }
907
908 fn sort_terminals(&mut self) {
913 for state in &mut self.states {
914 let mut terminals = state
915 .actions
916 .iter()
917 .enumerate()
918 .filter(|(_, actions)| !actions.is_empty())
919 .map(|(idx, _)| self.grammar.term_by_index(TermIndex(idx)))
920 .collect::<Vec<_>>();
921
922 let term_prio = |term: &Terminal| -> u32 {
923 term.prio * 1000
924 + if self.settings.lexical_disamb_most_specific {
925 match &term.recognizer {
926 Some(recognizer) => {
927 (match recognizer {
928 Recognizer::StrConst(str_rec) => str_rec.as_ref().len(),
929 Recognizer::RegexTerm(_) => 0,
930 }) as u32
931 }
932 None => 0,
933 }
934 } else {
935 0
936 }
937 };
938 terminals.sort_by(|&l, &r| {
939 let l_term_prio = term_prio(l);
940 let r_term_prio = term_prio(r);
941 r_term_prio.cmp(&l_term_prio)
942 });
943
944 let mut sorted_terminals: Vec<(TermIndex, bool)> = vec![];
946 let mut last_prio = None;
947 for terminal in terminals {
948 let finish = self.settings.lexical_disamb_most_specific
949 && matches!(terminal.recognizer, Some(Recognizer::StrConst(_)));
950 let last_finish = last_prio.is_some_and(|prio| terminal.prio != prio);
951 last_prio = Some(terminal.prio);
952 if let Some(t) = sorted_terminals.last_mut() {
953 t.1 |= last_finish
954 }
955 sorted_terminals.push((terminal.idx, finish));
956 }
957
958 state.sorted_terminals = sorted_terminals;
959 }
960 }
961
962 fn create_new_states(
964 grammar: &'g Grammar,
965 state: &LRState,
966 per_next_symbol: BTreeMap<SymbolIndex, Vec<ItemIndex>>,
967 ) -> Vec<LRState<'g>> {
968 let mut states = Vec::new();
969 for (symbol, items) in per_next_symbol {
970 let next_state_items = items
971 .into_iter()
972 .map(|i| state.items[i].clone().inc_position())
973 .collect();
974 states.push(LRState::new_with_items(
975 grammar,
976 StateIndex(0), symbol,
978 next_state_items,
979 ));
980 }
981 states
982 }
983
984 fn check_empty_sets(&self) -> Result<()> {
988 if let Some((idx, _)) = self
989 .first_sets
990 .iter()
991 .enumerate()
992 .find(|(_, s)| s.is_empty())
993 {
994 return Err(Error::Error(format!(
995 "First set empty for grammar symbol {:?}.\n\
996 An infinite recursion on the grammar symbol.",
997 &self.grammar.symbol_name(SymbolIndex(idx))
998 )));
999 }
1000 Ok(())
1001 }
1002
1003 pub fn get_conflicts(&'s self) -> Vec<Conflict<'g, 's>> {
1004 self.states
1005 .iter()
1006 .flat_map(|state| {
1007 state
1008 .actions
1009 .iter()
1010 .enumerate()
1011 .filter(|(_, actions)| actions.len() > 1)
1012 .flat_map(|(idx, actions)| {
1013 actions
1014 .iter()
1015 .combinations(2)
1016 .map(move |conflict| (idx, conflict))
1017 })
1018 .map(|(term_index, conflict)| {
1019 let kind = match &conflict[..] {
1020 [Action::Shift(_), Action::Reduce(prod, _)]
1021 | [Action::Reduce(prod, _), Action::Shift(_)] => {
1022 ConflictKind::ShiftReduce(*prod)
1023 }
1024 [Action::Reduce(prod1, _), Action::Reduce(prod2, _)] => {
1025 ConflictKind::ReduceReduce(*prod1, *prod2)
1026 }
1027 e => {
1028 eprint!("{e:?}");
1030 unreachable!()
1031 }
1032 };
1033 Conflict {
1034 state,
1035 follow: TermIndex(term_index),
1036 kind,
1037 }
1038 })
1039 })
1040 .collect()
1041 }
1042
1043 pub fn print_conflicts_report(&self, conflicts: &Vec<Conflict<'g, 's>>) {
1044 for conflict in conflicts {
1045 println!("{} {}", "In".green().bold(), conflict.state);
1046 print!(
1047 "When I saw {} and see token {} ahead I can't decide",
1048 self.grammar.symbol_name(conflict.state.symbol).green(),
1049 self.grammar
1050 .symbol_name(self.grammar.term_to_symbol_index(conflict.follow))
1051 .green()
1052 );
1053 match conflict.kind {
1054 ConflictKind::ShiftReduce(prod) => {
1055 println!(
1056 " should I shift or reduce by production:\n{}\n",
1057 self.grammar.productions[prod]
1058 .to_string(self.grammar)
1059 .green()
1060 );
1061 }
1062 ConflictKind::ReduceReduce(prod1, prod2) => {
1063 println!(
1064 " should I reduce by production:\n{}\nor production:\n{}\n",
1065 self.grammar.productions[prod1]
1066 .to_string(self.grammar)
1067 .green(),
1068 self.grammar.productions[prod2]
1069 .to_string(self.grammar)
1070 .green()
1071 );
1072 }
1073 }
1074 }
1075 let shift_reduce_len = conflicts
1076 .iter()
1077 .filter(|c| matches!(c.kind, ConflictKind::ShiftReduce(..)))
1078 .count();
1079 let reduce_reduce_len = conflicts
1080 .iter()
1081 .filter(|c| matches!(c.kind, ConflictKind::ReduceReduce(..)))
1082 .count();
1083 println!(
1084 "{}",
1085 format!(
1086 "{} conflict(s). {} Shift/Reduce and {} Reduce/Reduce.",
1087 shift_reduce_len + reduce_reduce_len,
1088 shift_reduce_len,
1089 reduce_reduce_len
1090 )
1091 .green()
1092 );
1093 }
1094
1095 #[inline]
1097 pub fn max_actions(&self) -> usize {
1098 self.states
1099 .iter()
1100 .map(|state| state.actions.iter().map(|a| a.len()).max().unwrap_or(0))
1101 .max()
1102 .unwrap()
1103 }
1104
1105 #[inline]
1106 pub fn max_recognizers(&self) -> usize {
1107 self.states
1108 .iter()
1109 .map(|state| state.actions.iter().filter(|a| !a.is_empty()).count())
1110 .max()
1111 .unwrap()
1112 }
1113
1114 pub fn to_dot(&self) -> String {
1115 let mut dot = String::from(
1116 r#"
1117 digraph grammar {
1118 rankdir=LR
1119 fontname = "Bitstream Vera Sans"
1120 fontsize = 8
1121 node[
1122 shape=record,
1123 style=filled,
1124 fillcolor=aliceblue
1125 ]
1126 nodesep = 0.3
1127 edge[dir=black,arrowtail=empty]
1128
1129 "#,
1130 );
1131
1132 let dot_escape = |s: &String| {
1133 s.replace('\n', r"\n")
1134 .replace('\\', "\\\\")
1135 .replace('"', r#"\""#)
1136 .replace('|', r"\|")
1137 .replace('{', r"\{")
1138 .replace('}', r"\}")
1139 .replace('>', r"\>")
1140 .replace('<', r"\<")
1141 .replace('?', r"\?")
1142 };
1143
1144 colored::control::set_override(false);
1145
1146 let conflicts = self.get_conflicts();
1147 let is_conflict_state = |state: &LRState| conflicts.iter().any(|s| s.state == state);
1148
1149 for state in &self.states {
1150 let mut kernel_items_str = String::new();
1151 for item in state.kernel_items() {
1152 kernel_items_str += &format!("{}\\l", dot_escape(&item.to_string(self.grammar)));
1153 }
1154
1155 let nonkernel_items = state.nonkernel_items();
1156 let mut nonkernel_items_str = if !nonkernel_items.is_empty() {
1157 String::from("|")
1158 } else {
1159 String::new()
1160 };
1161
1162 for item in nonkernel_items {
1163 nonkernel_items_str +=
1164 &format!("{}\\l", dot_escape(&item.to_string(self.grammar)));
1165 }
1166
1167 let mut reductions: Vec<String> = vec![];
1168 for term in &self.grammar.terminals {
1169 let mut term_reduction_prods: Vec<String> = vec![];
1170 for action in &state.actions[term.idx] {
1171 match action {
1172 Action::Shift(target_state_idx) => {
1173 dot += &format!(
1174 "{} -> {} [label=\"SHIFT:{}\"]\n",
1175 state.idx, target_state_idx, term.name
1176 )
1177 }
1178 Action::Reduce(prod_idx, len) => {
1179 term_reduction_prods.push(format!("({prod_idx},{len})"));
1180 }
1181 Action::Accept => {
1182 dot += &format!("{} -> ACCEPT [label=\"{}\"]\n", state.idx, term.name)
1183 }
1184 }
1185 }
1186 if !term_reduction_prods.is_empty() {
1187 let r = term_reduction_prods.join(", ");
1188 reductions.push(if term_reduction_prods.len() > 1 {
1189 format!("{}:[{}]", dot_escape(&term.name), r)
1190 } else {
1191 format!("{}:{}", dot_escape(&term.name), r)
1192 });
1193 }
1194 }
1195 let reductions = if !reductions.is_empty() {
1196 format!("|Reductions:\\l{}", reductions.join(", "))
1197 } else {
1198 String::new()
1199 };
1200
1201 dot += &format!(
1202 "{} [label=\"{}|{}{}{}\"{}]\n",
1203 state.idx,
1204 dot_escape(&format!(
1205 "{}:{}",
1206 state.idx,
1207 self.grammar.symbol_name(state.symbol)
1208 )),
1209 kernel_items_str,
1210 nonkernel_items_str,
1211 reductions,
1212 if is_conflict_state(state) {
1213 ", fillcolor=\"lightpink\""
1214 } else {
1215 ""
1216 }
1217 );
1218
1219 for nonterm in &self.grammar.nonterminals {
1221 if let Some(target_state_idx) = state.gotos[nonterm.idx] {
1222 dot += &format!(
1223 "{} -> {} [label=\"GOTO:{}\"]\n",
1224 state.idx, target_state_idx, nonterm.name
1225 )
1226 }
1227 }
1228 }
1229 colored::control::unset_override();
1230
1231 dot += "\n}\n";
1232 dot
1233 }
1234}
1235
1236fn production_rn_lengths(
1237 first_sets: &SymbolVec<BTreeSet<SymbolIndex>>,
1238 grammar: &Grammar,
1239) -> ProdVec<usize> {
1240 let mut prod_rn_lens = ProdVec::new();
1241 for production in &grammar.productions {
1242 let mut rn_len = production.rhs.len();
1243 for symbol in production.rhs_symbols().iter().rev() {
1244 if first_sets[*symbol].contains(&grammar.empty_index) {
1245 rn_len -= 1;
1246 } else {
1247 break;
1248 }
1249 }
1250 prod_rn_lens.push(rn_len)
1251 }
1252 prod_rn_lens
1253}
1254
1255impl Display for LRTable<'_, '_> {
1256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1257 for state in &self.states {
1258 writeln!(
1259 f,
1260 "\n{}",
1261 format!(
1262 "State {}:{}",
1263 state.idx,
1264 self.grammar.symbol_name(state.symbol)
1265 )
1266 .green(),
1267 )?;
1268 for item in &state.items {
1269 writeln!(f, "\t{}", item.to_string(self.grammar))?;
1270 }
1271 let actions = state
1272 .actions
1273 .iter()
1274 .enumerate()
1275 .filter(|(_, a)| !a.is_empty())
1276 .flat_map(|(i, a)| repeat(i).zip(a.iter()))
1277 .map(|(i, a)| {
1278 (
1279 self.grammar.terminals[TermIndex(i)].name.clone(),
1280 match a {
1281 Action::Shift(s) => format!("Shift to {s}"),
1282 Action::Reduce(p, l) => {
1283 format!(
1284 "Reduce for len {l} by: {}",
1285 self.grammar.productions[*p].to_string(self.grammar)
1286 )
1287 }
1288 Action::Accept => "Accept".into(),
1289 },
1290 )
1291 })
1292 .collect::<Vec<_>>();
1293
1294 if !actions.is_empty() {
1295 writeln!(f, "{}", "\tACTIONS:".green())?;
1296 for (term, action) in actions {
1297 writeln!(f, "\t\t{term} {} {action}", "=>".green())?;
1298 }
1299 }
1300
1301 let gotos = state
1303 .gotos
1304 .iter()
1305 .enumerate()
1306 .filter(|(_, g)| g.is_some())
1307 .map(|(idx, g)| {
1308 let g = g.unwrap();
1309 (
1310 self.grammar.nonterminals[NonTermIndex(idx)].name.clone(),
1311 format!(
1312 "State {}:{}",
1313 self.grammar.symbol_name(self.states[g].symbol),
1314 g.0
1315 ),
1316 )
1317 })
1318 .collect::<Vec<_>>();
1319
1320 if !gotos.is_empty() {
1321 writeln!(f, "{}", "\tGOTOs:".green())?;
1322 for (nonterm, goto) in gotos {
1323 writeln!(f, "\t\t{nonterm} {} {goto}", "=>".green())?;
1324 }
1325 }
1326 }
1327 Ok(())
1328 }
1329}
1330
1331fn first_sets(grammar: &Grammar) -> FirstSets {
1336 let mut first_sets = SymbolVec::new();
1337
1338 for terminal in &grammar.terminals {
1340 let mut new_set = Firsts::new();
1341 new_set.insert(terminal.idx.symbol_index());
1342 first_sets.push(new_set);
1343 }
1344
1345 grammar
1347 .nonterminals
1348 .iter()
1349 .for_each(|_| first_sets.push(Firsts::new()));
1350
1351 first_sets[grammar.empty_index].insert(grammar.empty_index);
1353
1354 let mut additions = true;
1355 while additions {
1356 additions = false;
1357 for production in &grammar.productions {
1358 let lhs_nonterm = grammar.nonterm_to_symbol_index(production.nonterminal);
1359
1360 let rhs_firsts = firsts(grammar, &first_sets, &production.rhs_symbols());
1361
1362 let lhs_len = first_sets[lhs_nonterm].len();
1363
1364 first_sets[lhs_nonterm].extend(rhs_firsts);
1365
1366 if lhs_len < first_sets[lhs_nonterm].len() {
1368 additions = true
1369 }
1370 }
1371 }
1372 first_sets
1373}
1374
1375fn firsts(grammar: &Grammar, first_sets: &FirstSets, symbols: &[SymbolIndex]) -> Firsts {
1381 let mut firsts = Firsts::new();
1382 let mut break_out = false;
1383 for &symbol in symbols {
1384 let symbol_firsts = &first_sets[symbol];
1385 let mut empty = false;
1386
1387 for first in symbol_firsts {
1388 if *first == grammar.empty_index {
1389 empty = true;
1390 } else {
1391 firsts.insert(*first);
1392 }
1393 }
1394
1395 if !empty {
1398 break_out = true;
1399 break;
1400 }
1401 }
1402 if !break_out {
1403 firsts.insert(grammar.empty_index);
1406 }
1407 firsts
1408}
1409
1410type Follow = BTreeSet<SymbolIndex>;
1416#[allow(dead_code)]
1417type FollowSets = SymbolVec<Follow>;
1418#[cfg(test)]
1419fn follow_sets(grammar: &Grammar, first_sets: &FirstSets) -> FollowSets {
1420 let mut follow_sets = FollowSets::new();
1421 for _ in 0..first_sets.len() {
1422 follow_sets.push(Follow::new());
1423 }
1424
1425 follow_sets[grammar.augmented_index].insert(grammar.stop_index);
1428
1429 let mut additions = true;
1430 while additions {
1431 additions = false;
1432 for production in &grammar.productions {
1433 let lhs_symbol = grammar.nonterm_to_symbol_index(production.nonterminal);
1434
1435 for idx in 0..production.rhs.len() {
1438 let rhs_symbol = production.rhs_symbol(idx);
1439 let elements = follow_sets[rhs_symbol].len();
1440 let mut break_out = false;
1441 for rnext in &production.rhs[idx + 1..] {
1442 let follow_symbols = &first_sets[res_symbol(rnext)];
1443
1444 follow_sets[rhs_symbol]
1445 .extend(follow_symbols.iter().filter(|&&s| s != grammar.empty_index));
1446
1447 if !follow_symbols.contains(&grammar.empty_index) {
1448 break_out = true;
1449 break;
1450 }
1451 }
1452
1453 if !break_out {
1454 let lhs_follows: Follow = follow_sets[lhs_symbol].iter().copied().collect();
1458 follow_sets[rhs_symbol].extend(lhs_follows.iter());
1459 }
1460
1461 if follow_sets[rhs_symbol].len() > elements {
1462 additions = true
1463 }
1464 }
1465 }
1466 }
1467 follow_sets
1468}
1469
1470#[cfg(test)]
1471mod tests {
1472
1473 use std::cell::RefCell;
1474 use std::collections::BTreeSet;
1475
1476 use crate::index::{ProdIndex, StateIndex, SymbolIndex};
1477 use crate::table::{first_sets, follow_sets, ItemIndex, LRTable, TableType};
1478 use crate::{
1479 grammar::Grammar,
1480 output_cmp,
1481 settings::Settings,
1482 table::{Follow, LRItem},
1483 };
1484
1485 use super::{production_rn_lengths, LRState};
1486
1487 fn follow<T, I>(indexes: T) -> BTreeSet<SymbolIndex>
1488 where
1489 T: IntoIterator<Item = I>,
1490 I: Into<SymbolIndex>,
1491 {
1492 indexes.into_iter().map(|i| i.into()).collect()
1493 }
1494
1495 fn test_grammar() -> Grammar {
1496 r#"
1497 E: T Ep;
1498 Ep: "+" T Ep | EMPTY;
1499 T: F Tp;
1500 Tp: "*" F Tp | EMPTY;
1501 F: "(" E ")" | "id";
1502
1503 terminals
1504 Plus: "+";
1505 Mul: "*";
1506 LParen: "(";
1507 RParen: ")";
1508 id: "id";
1509 "#
1510 .parse()
1511 .unwrap()
1512 }
1513
1514 fn test_grammar_2() -> Grammar {
1515 r#"
1516 E: E "+" T | T;
1517 T: T "*" F | F;
1518 F: "(" E ")" | "id";
1519
1520 terminals
1521 Plus: "+";
1522 Mul: "*";
1523 LParen: "(";
1524 RParen: ")";
1525 id: "id";
1526 "#
1527 .parse()
1528 .unwrap()
1529 }
1530
1531 fn test_non_lalr_grammar() -> Grammar {
1535 r#"
1536 S: A "a" | "b" A "c" | B "c" | "b" B "a";
1537 A: "d";
1538 B: "d";
1539 terminals
1540 a_t: "a";
1541 b_t: "b";
1542 c_t: "c";
1543 d_t: "d";
1544 "#
1545 .parse()
1546 .unwrap()
1547 }
1548
1549 fn test_ambiguous_grammar() -> Grammar {
1550 r#"
1551 E: E "+" E {1, left}
1552 | E "*" E {2, left}
1553 | E "^" E {3, right}
1554 | "(" E ")"
1555 | "id";
1556
1557 terminals
1558 Plus: "+";
1559 Mul: "*";
1560 Power: "^";
1561 LParen: "(";
1562 RParen: ")";
1563 id: "id";
1564 "#
1565 .parse()
1566 .unwrap()
1567 }
1568
1569 #[test]
1570 fn test_first_sets() {
1571 let grammar = test_grammar();
1572 let first_sets = first_sets(&grammar);
1573
1574 assert_eq!(first_sets.len(), 13);
1575
1576 assert_eq!(
1578 &first_sets[grammar.symbol_index("id")],
1579 &follow(grammar.symbol_indexes(&["id"]))
1580 );
1581
1582 assert_eq!(
1583 &first_sets[grammar.symbol_index("F")],
1584 &follow(grammar.symbol_indexes(&["LParen", "id"]))
1585 );
1586 assert_eq!(
1587 &first_sets[grammar.symbol_index("T")],
1588 &follow(grammar.symbol_indexes(&["LParen", "id"]))
1589 );
1590 assert_eq!(
1591 &first_sets[grammar.symbol_index("E")],
1592 &follow(grammar.symbol_indexes(&["LParen", "id"]))
1593 );
1594 assert_eq!(
1595 &first_sets[grammar.symbol_index("Ep")],
1596 &follow(grammar.symbol_indexes(&["Plus", "EMPTY"]))
1597 );
1598 assert_eq!(
1599 &first_sets[grammar.symbol_index("Tp")],
1600 &follow(grammar.symbol_indexes(&["Mul", "EMPTY"]))
1601 );
1602 }
1603
1604 #[test]
1605 fn test_follow_sets() {
1606 let grammar = test_grammar();
1607 let follow_sets = follow_sets(&grammar, &first_sets(&grammar));
1608
1609 assert_eq!(
1610 &follow_sets[grammar.symbol_index("E")],
1611 &follow(grammar.symbol_indexes(&["RParen", "STOP"]))
1612 );
1613 assert_eq!(
1614 &follow_sets[grammar.symbol_index("Ep")],
1615 &follow(grammar.symbol_indexes(&["RParen", "STOP"]))
1616 );
1617 assert_eq!(
1618 &follow_sets[grammar.symbol_index("T")],
1619 &follow(grammar.symbol_indexes(&["Plus", "RParen", "STOP"]))
1620 );
1621 assert_eq!(
1622 &follow_sets[grammar.symbol_index("Tp")],
1623 &follow(grammar.symbol_indexes(&["Plus", "RParen", "STOP"]))
1624 );
1625 }
1626
1627 #[test]
1628 fn test_prooduction_rn_lengths() {
1629 let grammar = test_grammar();
1630 let first_sets = first_sets(&grammar);
1631
1632 let production_rn_lengths = production_rn_lengths(&first_sets, &grammar);
1633
1634 assert_eq!(production_rn_lengths[ProdIndex(1)], 1);
1636
1637 assert_eq!(production_rn_lengths[ProdIndex(2)], 2);
1639 }
1640
1641 #[test]
1642 fn test_symbol_at_position() {
1643 let grammar = test_grammar();
1644
1645 let prod = ProdIndex(1);
1646 let mut item = LRItem::new(&grammar, prod, None);
1647 assert_eq!(
1648 &grammar.symbol_names(grammar.productions[prod].rhs_symbols()),
1649 &["T", "Ep"]
1650 );
1651 assert_eq!(
1652 item.symbol_at_position(&grammar).unwrap(),
1653 grammar.symbol_index("T")
1654 );
1655 item.position = 1;
1656 assert_eq!(
1657 &grammar.symbol_name(item.symbol_at_position(&grammar).unwrap()),
1658 "Ep"
1659 );
1660 item.position = 2;
1661 assert!(item.symbol_at_position(&grammar).is_none());
1662 item.position = 3;
1663 assert!(item.symbol_at_position(&grammar).is_none());
1664 }
1665
1666 #[test]
1667 fn test_group_per_next_symbol() {
1668 let grammar = test_ambiguous_grammar();
1669
1670 let mut lr_state = LRState::new(&grammar, 0.into(), grammar.symbol_index("E"))
1672 .add_item(LRItem {
1673 prod: 1.into(),
1674 prod_len: grammar.production_len(1.into()),
1675 rn_len: None,
1676 position: 1,
1677 follow: RefCell::new(Follow::new()),
1678 })
1679 .add_item(LRItem {
1680 prod: 2.into(),
1681 prod_len: grammar.production_len(2.into()),
1682 rn_len: None,
1683 position: 1,
1684 follow: RefCell::new(Follow::new()),
1685 })
1686 .add_item(LRItem {
1687 prod: 3.into(),
1688 prod_len: grammar.production_len(2.into()),
1689 rn_len: None,
1690 position: 1,
1691 follow: RefCell::new(Follow::new()),
1692 })
1693 .add_item(LRItem {
1694 prod: 4.into(),
1695 prod_len: grammar.production_len(3.into()),
1696 rn_len: None,
1697 position: 2,
1698 follow: RefCell::new(Follow::new()),
1699 });
1700
1701 let per_next_symbol = lr_state.group_per_next_symbol();
1702
1703 assert_eq!(per_next_symbol.len(), 4);
1710 assert_eq!(
1711 per_next_symbol.keys().cloned().collect::<Vec<_>>(),
1712 [1, 2, 3, 5]
1713 .iter()
1714 .map(|v| SymbolIndex(*v))
1715 .collect::<Vec<_>>()
1716 );
1717 assert_eq!(
1718 per_next_symbol.values().cloned().collect::<Vec<_>>(),
1719 vec![
1720 vec![0.into()],
1721 vec![1.into()],
1722 vec![2.into()],
1723 vec![3.into()]
1724 ]
1725 );
1726
1727 assert_eq!(
1729 lr_state.max_prior_for_term
1730 [&grammar.symbol_to_term_index(grammar.term_by_name["Power"])],
1731 3
1732 );
1733 assert_eq!(
1734 lr_state.max_prior_for_term
1735 [&grammar.symbol_to_term_index(grammar.term_by_name["Mul"])],
1736 2
1737 );
1738 assert_eq!(
1739 lr_state.max_prior_for_term
1740 [&grammar.symbol_to_term_index(grammar.term_by_name["Plus"])],
1741 1
1742 );
1743 }
1744
1745 #[test]
1746 fn test_merge_states() {
1747 let grammar = test_grammar();
1748 let lr_item_1 = LRItem {
1749 prod: ProdIndex(1),
1750 prod_len: 2,
1751 rn_len: None,
1752 position: 2,
1753 follow: RefCell::new(Follow::new()),
1754 };
1755 let lr_item_2 = LRItem {
1756 prod: ProdIndex(2),
1757 prod_len: 3,
1758 rn_len: None,
1759 position: 3,
1760 follow: RefCell::new(Follow::new()),
1761 };
1762 let old_state = LRState::new(&grammar, 0.into(), 0.into())
1763 .add_item(LRItem {
1764 follow: RefCell::new(follow([1, 3])),
1765 ..lr_item_1
1766 })
1767 .add_item(LRItem {
1768 follow: RefCell::new(follow([2])),
1769 ..lr_item_2
1770 });
1771
1772 let new_state_1 = LRState::new(&grammar, 0.into(), 0.into())
1774 .add_item(LRItem {
1775 follow: RefCell::new(follow([1])),
1776 ..lr_item_1
1777 })
1778 .add_item(LRItem {
1779 follow: RefCell::new(follow([2, 4])),
1780 ..lr_item_2
1781 });
1782 let mut old_state_1 = old_state.clone();
1783 let settings = Settings::default();
1784 assert!(LRTable::merge_state(
1785 &settings,
1786 &mut old_state_1,
1787 &new_state_1
1788 ));
1789 assert_eq!(
1791 *old_state_1.items[ItemIndex(0)].follow.borrow(),
1792 follow([1, 3])
1793 );
1794 assert_eq!(
1795 *old_state_1.items[ItemIndex(1)].follow.borrow(),
1796 follow([2, 4])
1797 );
1798
1799 let new_state_2 = LRState::new(&grammar, 0.into(), 0.into())
1804 .add_item(LRItem {
1805 follow: RefCell::new(follow([3])),
1806 ..lr_item_1
1807 })
1808 .add_item(LRItem {
1809 follow: RefCell::new(follow([2, 1])),
1810 ..lr_item_2
1811 });
1812 let mut old_state_2 = old_state.clone();
1813 assert!(!LRTable::merge_state(
1814 &settings,
1815 &mut old_state_2,
1816 &new_state_2
1817 ));
1818 assert_eq!(
1820 *old_state_2.items[ItemIndex(0)].follow.borrow(),
1821 follow([1, 3])
1822 );
1823 assert_eq!(
1824 *old_state_2.items[ItemIndex(1)].follow.borrow(),
1825 follow([2])
1826 );
1827
1828 let new_state_3 = LRState::new(&grammar, 0.into(), 0.into())
1833 .add_item(LRItem {
1834 follow: RefCell::new(follow([1, 3])),
1835 ..lr_item_1
1836 })
1837 .add_item(LRItem {
1838 follow: RefCell::new(follow([2, 1])),
1839 ..lr_item_2
1840 });
1841 let mut old_state_3 = old_state.clone();
1842 assert!(LRTable::merge_state(
1843 &settings,
1844 &mut old_state_3,
1845 &new_state_3
1846 ));
1847 assert_eq!(
1849 *old_state_3.items[ItemIndex(0)].follow.borrow(),
1850 follow([1, 3])
1851 );
1852 assert_eq!(
1853 *old_state_3.items[ItemIndex(1)].follow.borrow(),
1854 follow([2, 1])
1855 );
1856 }
1857
1858 #[test]
1859 fn test_closure() {
1860 let grammar = test_grammar();
1861 let firsts = first_sets(&grammar);
1862
1863 let mut lr_state =
1865 LRState::new(&grammar, StateIndex(0), grammar.symbol_index("T")).add_item(
1866 LRItem::with_follow(&grammar, ProdIndex(1), None, follow([grammar.stop_index])),
1867 );
1868
1869 lr_state.closure(&firsts, &None);
1870
1871 let prods = [1, 4, 7, 8];
1872 let follow_sets = [
1873 grammar.symbol_indexes(&["STOP"]),
1874 grammar.symbol_indexes(&["STOP", "Plus"]),
1875 grammar.symbol_indexes(&["STOP", "Plus", "Mul"]),
1876 grammar.symbol_indexes(&["STOP", "Plus", "Mul"]),
1877 ];
1878
1879 assert_eq!(lr_state.items.len(), 4);
1880
1881 itertools::izip!(&lr_state.items, prods, follow_sets).for_each(|(item, prod, follows)| {
1882 assert_eq!(item.prod, prod.into());
1883 assert!(item.follow.borrow().iter().eq(follows.iter()));
1884 });
1885
1886 log!("{:?}", lr_state);
1887 }
1888
1889 #[test]
1890 fn test_lr_states_for_grammar_2() {
1891 let grammar = test_grammar_2();
1892
1893 let settings = Settings::new().table_type(TableType::LALR);
1894
1895 let table = LRTable::new(&grammar, &settings).unwrap();
1896 output_cmp!(
1897 "src/table/grammar_2.expected",
1898 format!("{:#?}", table.states)
1899 );
1900 }
1901
1902 #[test]
1903 fn test_lr_states_for_non_lalr_grammar() {
1904 let grammar = test_non_lalr_grammar();
1905
1906 let settings = Settings::new().table_type(TableType::LALR);
1914
1915 let table = LRTable::new(&grammar, &settings).unwrap();
1916
1917 output_cmp!(
1918 "src/table/grammar_nonlalr_lalr.expected",
1919 format!("{grammar}\n\n{:#?}", table.states)
1920 );
1921
1922 let settings = Settings::new().table_type(TableType::LALR_PAGER);
1931
1932 let table = LRTable::new(&grammar, &settings).unwrap();
1933
1934 output_cmp!(
1935 "src/table/grammar_nonlalr_lalr_pagerw.expected",
1936 format!("{grammar}\n\n{:#?}", table.states)
1937 );
1938 }
1939
1940 #[test]
1941 fn test_sorted_terminals() {
1942 let grammar: Grammar = r#"
1943 S: A | C | B;
1944 terminals
1945 A: /\d+/;
1946 B: "bb";
1947 C: "c";
1948 "#
1949 .parse()
1950 .unwrap();
1951
1952 let settings = Settings::new().table_type(TableType::LALR_PAGER);
1953
1954 let table = LRTable::new(&grammar, &settings).unwrap();
1955 assert_eq!(
1956 &table.states[StateIndex(0)]
1957 .sorted_terminals
1958 .iter()
1959 .map(|i| i.0 .0)
1960 .collect::<Vec<_>>(),
1961 &vec![2, 3, 1]
1962 );
1963 }
1964}