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 itertools::{chain, Itertools};
14use rustemo::{log, LOG, LOG_BOLD};
15use yansi::Paint;
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 .paint(LOG_BOLD),
125 self.items
126 .iter()
127 .map(|i| i.to_string(self.grammar))
128 .collect::<Vec<_>>()
129 .join("\n\t")
130 )
131 }
132}
133
134impl std::fmt::Debug for LRState<'_> {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 f.debug_struct("LRState")
137 .field("idx", &self.idx)
138 .field("symbol", &self.symbol)
139 .field("items", &self.items)
140 .field("actions", &self.actions)
141 .field("gotos", &self.gotos)
142 .field("sorted_terminals", &self.sorted_terminals)
143 .field("max_prior_for_term", &self.max_prior_for_term)
144 .finish()
145 }
146}
147
148impl<'g> LRState<'g> {
149 fn new(grammar: &'g Grammar, index: StateIndex, symbol: SymbolIndex) -> Self {
150 Self {
151 grammar,
152 idx: index,
153 symbol,
154 items: ItemVec::new(),
155 actions: grammar.new_termvec(vec![]),
156 gotos: grammar.new_nontermvec(None),
157 max_prior_for_term: BTreeMap::new(),
158 sorted_terminals: Vec::new(),
159 }
160 }
161
162 fn new_with_items(
163 grammar: &'g Grammar,
164 index: StateIndex,
165 symbol: SymbolIndex,
166 items: ItemVec<LRItem>,
167 ) -> Self {
168 Self {
169 grammar,
170 idx: index,
171 symbol,
172 items,
173 actions: grammar.new_termvec(vec![]),
174 gotos: grammar.new_nontermvec(None),
175 max_prior_for_term: BTreeMap::new(),
176 sorted_terminals: Vec::new(),
177 }
178 }
179
180 fn add_item(mut self, item: LRItem) -> Self {
181 self.items.push(item);
182 self
183 }
184
185 fn kernel_items(&self) -> Vec<&LRItem> {
186 self.items.iter().filter(|i| i.is_kernel()).collect()
187 }
188
189 fn nonkernel_items(&self) -> Vec<&LRItem> {
190 self.items.iter().filter(|i| !i.is_kernel()).collect()
191 }
192
193 fn closure(&mut self, first_sets: &FirstSets, prod_rn_lengths: &Option<ProdVec<usize>>) {
200 loop {
201 #[allow(clippy::mutable_key_type)]
204 let mut new_items: BTreeSet<LRItem> = BTreeSet::new();
205
206 for item in &self.items {
207 if let Some(symbol) = item.symbol_at_position(self.grammar) {
208 if self.grammar.is_nonterm(symbol) {
209 let mut new_follow;
210 if item.position + 1 < self.grammar.productions[item.prod].rhs.len() {
213 new_follow = firsts(
214 self.grammar,
215 first_sets,
216 &self.grammar.production_rhs_symbols(item.prod)
217 [item.position + 1..],
218 );
219 if new_follow.contains(&self.grammar.empty_index) {
222 new_follow.remove(&self.grammar.empty_index);
223 new_follow.extend(item.follow.borrow().iter());
224 }
225 } else {
226 new_follow = Follow::new();
229 new_follow.extend(item.follow.borrow().iter());
230 }
231
232 let nonterm = self.grammar.symbol_to_nonterm_index(symbol);
235 for prod in &self.grammar.nonterminals[nonterm].productions {
236 new_items.insert(LRItem::with_follow(
237 self.grammar,
238 *prod,
239 prod_rn_lengths.as_ref().map(|p| p[*prod]),
240 new_follow.clone(),
241 ));
242 }
243 }
244 }
245 }
246
247 let mut change = false;
250 for new_item in new_items {
251 match self.items.iter_mut().find(|x| *x == &new_item) {
252 Some(item) => {
253 let l = item.follow.borrow().len();
255 item.follow
256 .borrow_mut()
257 .extend(new_item.follow.borrow().iter());
258 if item.follow.borrow().len() > l {
259 change = true;
260 }
261 }
262 None => {
263 self.items.push(new_item);
264 change = true;
265 }
266 }
267 }
268 if !change {
269 break;
270 }
271 }
272 }
273
274 fn group_per_next_symbol(&mut self) -> BTreeMap<SymbolIndex, Vec<ItemIndex>> {
277 let mut per_next_symbol: BTreeMap<SymbolIndex, Vec<ItemIndex>> = BTreeMap::new();
278
279 for (idx, item) in self.items.iter().enumerate() {
280 let symbol = item.symbol_at_position(self.grammar);
281 if let Some(symbol) = symbol {
282 per_next_symbol.entry(symbol).or_default().push(idx.into());
283 if self.grammar.is_term(symbol) {
284 let symbol = self.grammar.symbol_to_term_index(symbol);
285 let prod_prio = self.grammar.productions[item.prod].prio;
286 self.max_prior_for_term
287 .entry(symbol)
288 .and_modify(|v| *v = cmp::max(*v, prod_prio))
289 .or_insert(prod_prio);
290 }
291 }
292 }
293 per_next_symbol
294 }
295}
296
297#[derive(Debug, Eq, Clone, PartialOrd, Ord)]
302struct LRItem {
303 prod: ProdIndex,
304
305 prod_len: usize,
307
308 rn_len: Option<usize>,
312
313 position: usize,
315
316 follow: RefCell<Follow>,
317}
318
319impl std::hash::Hash for LRItem {
320 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
321 self.prod.hash(state);
322 self.position.hash(state);
323 }
324}
325
326impl PartialEq for LRItem {
327 fn eq(&self, other: &Self) -> bool {
328 self.prod == other.prod && self.position == other.position
329 }
330}
331
332impl LRItem {
358 #[cfg(test)]
359 fn new(grammar: &Grammar, prod: ProdIndex, rn_len: Option<usize>) -> Self {
360 LRItem {
361 prod,
362 prod_len: grammar.production_len(prod),
363 rn_len,
364 position: 0,
365 follow: RefCell::new(Follow::new()),
366 }
367 }
368
369 fn with_follow(
370 grammar: &Grammar,
371 prod: ProdIndex,
372 rn_len: Option<usize>,
373 follow: Follow,
374 ) -> Self {
375 LRItem {
376 prod,
377 prod_len: grammar.production_len(prod),
378 rn_len,
379 position: 0,
380 follow: RefCell::new(follow),
381 }
382 }
383
384 fn symbol_at_position(&self, grammar: &Grammar) -> Option<SymbolIndex> {
385 Some(res_symbol(
386 grammar.productions.get(self.prod)?.rhs.get(self.position)?,
387 ))
388 }
389
390 #[inline]
392 fn inc_position(mut self) -> Self {
393 assert!(self.position < self.prod_len);
394 self.position += 1;
395 self
396 }
397
398 #[inline]
403 fn is_kernel(&self) -> bool {
404 self.position > 0 || self.prod == ProdIndex(0)
405 }
406
407 #[inline]
408 fn is_reducing(&self) -> bool {
409 self.position == self.prod_len
410 || match self.rn_len {
411 Some(rn_len) => self.position >= rn_len,
412 None => false,
413 }
414 }
415
416 fn to_string(&self, grammar: &Grammar) -> String {
417 let prod = &grammar.productions[self.prod];
418 let mut rhs = prod
419 .rhs_symbols()
420 .iter()
421 .map(|s| grammar.symbol_name(*s))
422 .collect::<Vec<_>>();
423 rhs.insert(self.position, ".".into());
424 format!(
425 "{}: {}: {} {{{}}}",
426 prod.idx.to_string().paint(LOG),
427 grammar
428 .symbol_name(grammar.nonterm_to_symbol_index(prod.nonterminal))
429 .paint(LOG),
430 rhs.join(" "),
431 self.follow
432 .borrow()
433 .iter()
434 .map(|f| grammar.symbol_name(*f))
435 .collect::<Vec<_>>()
436 .join(", ")
437 )
438 }
439}
440
441pub enum ConflictKind {
442 ShiftReduce(ProdIndex),
443 ReduceReduce(ProdIndex, ProdIndex),
444}
445
446pub struct Conflict<'g, 's> {
447 state: &'s LRState<'g>,
448 follow: TermIndex,
449 kind: ConflictKind,
450}
451
452impl Display for Conflict<'_, '_> {
453 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
454 write!(f, "")?;
455 Ok(())
456 }
457}
458
459pub struct LRTable<'g, 's> {
460 pub states: StateVec<LRState<'g>>,
461 pub layout_state: Option<StateIndex>,
462 grammar: &'g Grammar,
463 settings: &'s Settings,
464 first_sets: FirstSets,
465
466 pub production_rn_lengths: Option<ProdVec<usize>>,
474}
475
476impl<'g, 's> LRTable<'g, 's> {
477 pub fn new(grammar: &'g Grammar, settings: &'s Settings) -> Result<Self> {
478 let first_sets = first_sets(grammar);
479 let production_rn_lengths = match settings.table_type {
480 TableType::LALR_RN => Some(production_rn_lengths(&first_sets, grammar)),
481 TableType::LALR | TableType::LALR_PAGER => None,
482 };
483 let mut table = Self {
484 grammar,
485 settings,
486 states: StateVec::new(),
487 layout_state: None,
488 first_sets,
489 production_rn_lengths,
490 };
491
492 table.check_empty_sets()?;
493
494 table.calc_states(grammar.augmented_index);
495 if let Some(augmented_layout_index) = grammar.augmented_layout_index {
496 table.layout_state = Some(StateIndex(table.states.len()));
497 table.calc_states(augmented_layout_index)
498 }
499
500 log!("LR states constructed. Updating follows.");
501 table.propagate_follows();
502
503 log!(
504 "Calculate REDUCTION entries in ACTION tables and resolve \
505 possible conflicts."
506 );
507 table.calculate_reductions();
508
509 log!("Sort terminals for lexical disambiguation");
510 table.sort_terminals();
511
512 println!("Terminals: {}", grammar.terminals.len());
513 println!("Non-terminals: {}", grammar.nonterminals().len());
514 println!("Productions: {}", grammar.productions().len());
515 println!("States: {}", table.states.len());
516
517 if settings.print_table {
518 println!("LR TABLE:");
519 println!("{table}");
520 }
521
522 Ok(table)
523 }
524
525 fn calc_states(&mut self, start_symbol: SymbolIndex) {
529 let mut current_state_idx = self.states.len();
530
531 let prods = &self.grammar.symbol_to_nonterm(start_symbol).productions;
532 assert_eq!(prods.len(), 1);
533
534 let state = LRState::new(self.grammar, StateIndex(current_state_idx), start_symbol)
536 .add_item(LRItem::with_follow(
537 self.grammar,
538 prods[0],
539 self.production_rn_lengths.as_ref().map(|p| p[prods[0]]),
540 Follow::from([self.grammar.stop_index]),
541 ));
542 current_state_idx += 1;
543
544 let mut state_queue = VecDeque::from([state]);
546
547 log!("Calculating LR automaton states.");
548 while let Some(mut state) = state_queue.pop_front() {
549 state.closure(&self.first_sets, &self.production_rn_lengths);
554
555 let per_next_symbol = state.group_per_next_symbol();
559
560 for &symbol in per_next_symbol.keys() {
562 if symbol == self.grammar.stop_index {
563 state.actions[self.grammar.symbol_to_term_index(symbol)] =
564 vec![Action::Accept];
565 break;
566 }
567 }
568
569 let new_states = Self::create_new_states(self.grammar, &state, per_next_symbol);
571
572 for mut new_state in new_states {
575 let target_state_symbol = new_state.symbol;
576 let mut new_state_found = true;
577 let mut target_state_idx = StateIndex(current_state_idx);
578 for old_state in self
579 .states
580 .iter_mut()
581 .chain(state_queue.iter_mut())
582 .chain(iter::once(&mut state))
583 .filter(|x| **x == new_state)
584 {
585 if Self::merge_state(self.settings, old_state, &new_state) {
587 new_state_found = false;
588 target_state_idx = old_state.idx;
589 break;
590 }
591 }
592
593 if self.grammar.is_nonterm(target_state_symbol) {
595 state.gotos[self.grammar.symbol_to_nonterm_index(target_state_symbol)] =
596 Some(target_state_idx);
597 } else {
598 let term = self.grammar.symbol_to_term_index(new_state.symbol);
599 state.actions[term].push(Action::Shift(target_state_idx));
600 }
601
602 if new_state_found {
603 new_state.idx = StateIndex(current_state_idx);
605
606 state_queue.push_back(new_state);
607 current_state_idx += 1;
608 }
609 }
610
611 self.states.push(state);
612 }
613 }
614
615 fn merge_state(
621 settings: &Settings,
622 old_state: &mut LRState<'g>,
623 new_state: &LRState<'g>,
624 ) -> bool {
625 if old_state != new_state {
627 return false;
628 }
629
630 let old_state_items = old_state
631 .items
632 .clone()
633 .into_iter()
634 .filter(|item| item.is_kernel());
635
636 let item_pairs: Vec<(&mut LRItem, &LRItem)> = iter::zip(
638 old_state.items.iter_mut().filter(|item| item.is_kernel()),
639 old_state_items.map(|x| new_state.items.iter().find(|&i| *i == x).unwrap()),
640 )
641 .collect();
642
643 if settings.table_type != TableType::LALR {
644 for (old, new) in &item_pairs {
653 if !old.is_reducing() {
654 continue;
655 }
656 for (old_in, new_in) in &item_pairs {
657 if old == old_in {
658 continue;
659 }
660 for t in chain(
665 old.follow.borrow().intersection(&*new_in.follow.borrow()),
666 old_in.follow.borrow().intersection(&*new.follow.borrow()),
667 ) {
668 if old
670 .follow
671 .borrow()
672 .intersection(&*old_in.follow.borrow())
673 .all(|x| x != t)
674 && new
675 .follow
676 .borrow()
677 .intersection(&*new_in.follow.borrow())
678 .all(|x| x != t)
679 {
680 return false;
683 }
684 }
685 }
686 }
687 }
688
689 for (old, new) in item_pairs {
691 old.follow.borrow_mut().extend(new.follow.borrow().iter())
692 }
693 true
694 }
695
696 fn propagate_follows(&mut self) {
702 let mut changed = true;
703 while changed {
704 changed = false;
705 for state in self.states.iter_mut() {
706 state.closure(&self.first_sets, &self.production_rn_lengths);
710 }
711
712 for state in self.states.iter() {
713 state
715 .gotos
716 .iter()
717 .filter_map(|x| x.as_ref())
718 .chain(state.actions.iter().flat_map(|x| {
719 x.iter().filter_map(|a| match a {
720 Action::Shift(state) => Some(state),
721 _ => None,
722 })
723 }))
724 .for_each(|&target_state| {
725 for target_item in &mut self.states[target_state]
726 .items
727 .iter()
728 .filter(|x| x.is_kernel())
729 {
730 if let Some(source_item) = state.items.iter().find(|&x| {
732 x.prod == target_item.prod
733 && x.position == target_item.position - 1
734 }) {
735 let follow_len = target_item.follow.borrow().len();
737 target_item
738 .follow
739 .borrow_mut()
740 .extend(source_item.follow.borrow().iter());
741
742 if target_item.follow.borrow().len() > follow_len {
744 changed = true
745 }
746 }
747 }
748 })
749 }
750 }
751 }
752
753 fn calculate_reductions(&mut self) {
756 let mut aug_symbols = vec![self.grammar.augmented_index];
757 if let Some(layout_index) = self.grammar.augmented_layout_index {
758 aug_symbols.push(layout_index);
759 }
760 for state in &mut self.states {
761 for item in state.items.iter().filter(|x| x.is_reducing()) {
762 let prod = &self.grammar.productions[item.prod];
763
764 if aug_symbols.contains(&self.grammar.nonterm_to_symbol_index(prod.nonterminal)) {
770 if item.position == item.prod_len {
771 let actions = &mut state.actions[TermIndex(0)];
772 actions.push(Action::Accept);
773 }
774 continue;
775 }
776
777 let new_reduce = Action::Reduce(item.prod, item.position);
778 for follow_symbol in item.follow.borrow().iter() {
779 let follow_term = self.grammar.symbol_to_term(*follow_symbol);
780 let actions = &mut state.actions[follow_term.idx];
781 if actions.is_empty() {
782 actions.push(new_reduce.clone());
785 } else {
786 let (shifts, reduces): (Vec<_>, Vec<_>) = actions
788 .clone()
789 .into_iter()
790 .partition(|x| matches!(x, Action::Shift(_) | Action::Accept));
791 assert!(shifts.len() <= 1);
794
795 let mut should_reduce = true;
796 if let Some(shift) = shifts.first() {
797 let shift_prio = match shift {
801 Action::Accept => DEFAULT_PRIORITY,
802 _ => state.max_prior_for_term[&follow_term.idx],
803 };
804 match prod.prio.cmp(&shift_prio) {
805 Ordering::Less => {
806 should_reduce = false
809 }
810 Ordering::Equal => {
811 match (&prod.assoc, &follow_term.assoc) {
815 (Associativity::Left, Associativity::None)
816 | (_, Associativity::Right) => {
817 assert!(actions.len() == 1);
819 actions.pop();
820 }
821 (Associativity::Right, Associativity::None)
822 | (_, Associativity::Left) => {
823 should_reduce = false;
829 }
830 (Associativity::None, Associativity::None) => {
831 let empty = prod.rhs.is_empty();
835 let prod_pse = empty
836 && self.settings.prefer_shifts_over_empty
837 && !prod.nopse;
838 let prod_ps = !empty
839 && self.settings.prefer_shifts
840 && !prod.nops;
841 should_reduce = !(prod_pse || prod_ps);
842 }
843 }
844 }
845 Ordering::Greater => {
846 assert!(actions.len() == 1);
849 actions.pop();
850 }
851 }
852 }
853
854 if should_reduce {
855 if reduces.is_empty() {
856 actions.push(new_reduce.clone())
857 } else {
858 let reduces_prio = reduces
861 .iter()
862 .map(|x| match x {
863 Action::Reduce(prod, ..) => {
864 self.grammar.productions[*prod].prio
865 }
866 other => panic!("This should not happen. Got {other:?}"),
867 })
868 .collect::<Vec<_>>();
869 if reduces_prio.iter().all(|x| prod.prio < *x) {
870 } else if reduces_prio.iter().all(|x| prod.prio > *x) {
873 actions.retain(|x| !matches!(x, Action::Reduce(..)));
877 actions.push(new_reduce.clone())
878 } else {
879 if let ParserAlgo::LR = self.settings.parser_algo {
882 actions.retain(
884 |x| !matches!(x, Action::Reduce(_, len) if *len == 0),
885 );
886
887 if item.prod_len > 0 || actions.is_empty() {
888 actions.push(new_reduce.clone())
890 }
891 } else {
892 actions.push(new_reduce.clone())
897 }
898 }
899 }
900 }
901 }
902 }
903 }
904 }
905 }
906
907 fn sort_terminals(&mut self) {
912 for state in &mut self.states {
913 let mut terminals = state
914 .actions
915 .iter()
916 .enumerate()
917 .filter(|(_, actions)| !actions.is_empty())
918 .map(|(idx, _)| self.grammar.term_by_index(TermIndex(idx)))
919 .collect::<Vec<_>>();
920
921 let term_prio = |term: &Terminal| -> u32 {
922 term.prio * 1000
923 + if self.settings.lexical_disamb_most_specific {
924 match &term.recognizer {
925 Some(recognizer) => {
926 (match recognizer {
927 Recognizer::StrConst(str_rec) => str_rec.as_ref().len(),
928 Recognizer::RegexTerm(_) => 0,
929 }) as u32
930 }
931 None => 0,
932 }
933 } else {
934 0
935 }
936 };
937 terminals.sort_by(|&l, &r| {
938 let l_term_prio = term_prio(l);
939 let r_term_prio = term_prio(r);
940 r_term_prio.cmp(&l_term_prio)
941 });
942
943 let mut sorted_terminals: Vec<(TermIndex, bool)> = vec![];
945 let mut last_prio = None;
946 for terminal in terminals {
947 let finish = self.settings.lexical_disamb_most_specific
948 && matches!(terminal.recognizer, Some(Recognizer::StrConst(_)));
949 let last_finish = last_prio.is_some_and(|prio| terminal.prio != prio);
950 last_prio = Some(terminal.prio);
951 if let Some(t) = sorted_terminals.last_mut() {
952 t.1 |= last_finish
953 }
954 sorted_terminals.push((terminal.idx, finish));
955 }
956
957 state.sorted_terminals = sorted_terminals;
958 }
959 }
960
961 fn create_new_states(
963 grammar: &'g Grammar,
964 state: &LRState,
965 per_next_symbol: BTreeMap<SymbolIndex, Vec<ItemIndex>>,
966 ) -> Vec<LRState<'g>> {
967 let mut states = Vec::new();
968 for (symbol, items) in per_next_symbol {
969 let next_state_items = items
970 .into_iter()
971 .map(|i| state.items[i].clone().inc_position())
972 .collect();
973 states.push(LRState::new_with_items(
974 grammar,
975 StateIndex(0), symbol,
977 next_state_items,
978 ));
979 }
980 states
981 }
982
983 fn check_empty_sets(&self) -> Result<()> {
987 if let Some((idx, _)) = self
988 .first_sets
989 .iter()
990 .enumerate()
991 .find(|(_, s)| s.is_empty())
992 {
993 return Err(Error::Error(format!(
994 "First set empty for grammar symbol {:?}.\n\
995 An infinite recursion on the grammar symbol.",
996 &self.grammar.symbol_name(SymbolIndex(idx))
997 )));
998 }
999 Ok(())
1000 }
1001
1002 pub fn get_conflicts(&'s self) -> Vec<Conflict<'g, 's>> {
1003 self.states
1004 .iter()
1005 .flat_map(|state| {
1006 state
1007 .actions
1008 .iter()
1009 .enumerate()
1010 .filter(|(_, actions)| actions.len() > 1)
1011 .flat_map(|(idx, actions)| {
1012 actions
1013 .iter()
1014 .combinations(2)
1015 .map(move |conflict| (idx, conflict))
1016 })
1017 .map(|(term_index, conflict)| {
1018 let kind = match &conflict[..] {
1019 [Action::Shift(_), Action::Reduce(prod, _)]
1020 | [Action::Reduce(prod, _), Action::Shift(_)] => {
1021 ConflictKind::ShiftReduce(*prod)
1022 }
1023 [Action::Reduce(prod1, _), Action::Reduce(prod2, _)] => {
1024 ConflictKind::ReduceReduce(*prod1, *prod2)
1025 }
1026 e => {
1027 eprint!("{e:?}");
1029 unreachable!()
1030 }
1031 };
1032 Conflict {
1033 state,
1034 follow: TermIndex(term_index),
1035 kind,
1036 }
1037 })
1038 })
1039 .collect()
1040 }
1041
1042 pub fn print_conflicts_report(&self, conflicts: &Vec<Conflict<'g, 's>>) {
1043 for conflict in conflicts {
1044 println!("{} {}", "In".paint(LOG_BOLD), conflict.state);
1045 print!(
1046 "When I saw {} and see token {} ahead I can't decide",
1047 self.grammar.symbol_name(conflict.state.symbol).paint(LOG),
1048 self.grammar
1049 .symbol_name(self.grammar.term_to_symbol_index(conflict.follow))
1050 .paint(LOG)
1051 );
1052 match conflict.kind {
1053 ConflictKind::ShiftReduce(prod) => {
1054 println!(
1055 " should I shift or reduce by production:\n{}\n",
1056 self.grammar.productions[prod]
1057 .to_string(self.grammar)
1058 .paint(LOG)
1059 );
1060 }
1061 ConflictKind::ReduceReduce(prod1, prod2) => {
1062 println!(
1063 " should I reduce by production:\n{}\nor production:\n{}\n",
1064 self.grammar.productions[prod1]
1065 .to_string(self.grammar)
1066 .paint(LOG),
1067 self.grammar.productions[prod2]
1068 .to_string(self.grammar)
1069 .paint(LOG)
1070 );
1071 }
1072 }
1073 }
1074 let shift_reduce_len = conflicts
1075 .iter()
1076 .filter(|c| matches!(c.kind, ConflictKind::ShiftReduce(..)))
1077 .count();
1078 let reduce_reduce_len = conflicts
1079 .iter()
1080 .filter(|c| matches!(c.kind, ConflictKind::ReduceReduce(..)))
1081 .count();
1082 println!(
1083 "{}",
1084 format!(
1085 "{} conflict(s). {} Shift/Reduce and {} Reduce/Reduce.",
1086 shift_reduce_len + reduce_reduce_len,
1087 shift_reduce_len,
1088 reduce_reduce_len
1089 )
1090 .paint(LOG)
1091 );
1092 }
1093
1094 #[inline]
1096 pub fn max_actions(&self) -> usize {
1097 self.states
1098 .iter()
1099 .map(|state| state.actions.iter().map(|a| a.len()).max().unwrap_or(0))
1100 .max()
1101 .unwrap()
1102 }
1103
1104 #[inline]
1105 pub fn max_recognizers(&self) -> usize {
1106 self.states
1107 .iter()
1108 .map(|state| state.actions.iter().filter(|a| !a.is_empty()).count())
1109 .max()
1110 .unwrap()
1111 }
1112
1113 pub fn to_dot(&self) -> String {
1114 let mut dot = String::from(
1115 r#"
1116 digraph grammar {
1117 rankdir=LR
1118 fontname = "Bitstream Vera Sans"
1119 fontsize = 8
1120 node[
1121 shape=record,
1122 style=filled,
1123 fillcolor=aliceblue
1124 ]
1125 nodesep = 0.3
1126 edge[dir=black,arrowtail=empty]
1127
1128 "#,
1129 );
1130
1131 let dot_escape = |s: &String| {
1132 s.replace('\n', r"\n")
1133 .replace('\\', "\\\\")
1134 .replace('"', r#"\""#)
1135 .replace('|', r"\|")
1136 .replace('{', r"\{")
1137 .replace('}', r"\}")
1138 .replace('>', r"\>")
1139 .replace('<', r"\<")
1140 .replace('?', r"\?")
1141 };
1142
1143 yansi::disable();
1144
1145 let conflicts = self.get_conflicts();
1146 let is_conflict_state = |state: &LRState| conflicts.iter().any(|s| s.state == state);
1147
1148 for state in &self.states {
1149 let mut kernel_items_str = String::new();
1150 for item in state.kernel_items() {
1151 kernel_items_str += &format!("{}\\l", dot_escape(&item.to_string(self.grammar)));
1152 }
1153
1154 let nonkernel_items = state.nonkernel_items();
1155 let mut nonkernel_items_str = if !nonkernel_items.is_empty() {
1156 String::from("|")
1157 } else {
1158 String::new()
1159 };
1160
1161 for item in nonkernel_items {
1162 nonkernel_items_str +=
1163 &format!("{}\\l", dot_escape(&item.to_string(self.grammar)));
1164 }
1165
1166 let mut reductions: Vec<String> = vec![];
1167 for term in &self.grammar.terminals {
1168 let mut term_reduction_prods: Vec<String> = vec![];
1169 for action in &state.actions[term.idx] {
1170 match action {
1171 Action::Shift(target_state_idx) => {
1172 dot += &format!(
1173 "{} -> {} [label=\"SHIFT:{}\"]\n",
1174 state.idx, target_state_idx, term.name
1175 )
1176 }
1177 Action::Reduce(prod_idx, len) => {
1178 term_reduction_prods.push(format!("({prod_idx},{len})"));
1179 }
1180 Action::Accept => {
1181 dot += &format!("{} -> ACCEPT [label=\"{}\"]\n", state.idx, term.name)
1182 }
1183 }
1184 }
1185 if !term_reduction_prods.is_empty() {
1186 let r = term_reduction_prods.join(", ");
1187 reductions.push(if term_reduction_prods.len() > 1 {
1188 format!("{}:[{}]", dot_escape(&term.name), r)
1189 } else {
1190 format!("{}:{}", dot_escape(&term.name), r)
1191 });
1192 }
1193 }
1194 let reductions = if !reductions.is_empty() {
1195 format!("|Reductions:\\l{}", reductions.join(", "))
1196 } else {
1197 String::new()
1198 };
1199
1200 dot += &format!(
1201 "{} [label=\"{}|{}{}{}\"{}]\n",
1202 state.idx,
1203 dot_escape(&format!(
1204 "{}:{}",
1205 state.idx,
1206 self.grammar.symbol_name(state.symbol)
1207 )),
1208 kernel_items_str,
1209 nonkernel_items_str,
1210 reductions,
1211 if is_conflict_state(state) {
1212 ", fillcolor=\"lightpink\""
1213 } else {
1214 ""
1215 }
1216 );
1217
1218 for nonterm in &self.grammar.nonterminals {
1220 if let Some(target_state_idx) = state.gotos[nonterm.idx] {
1221 dot += &format!(
1222 "{} -> {} [label=\"GOTO:{}\"]\n",
1223 state.idx, target_state_idx, nonterm.name
1224 )
1225 }
1226 }
1227 }
1228
1229 yansi::enable();
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 .paint(LOG),
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:".paint(LOG))?;
1296 for (term, action) in actions {
1297 writeln!(f, "\t\t{term} {} {action}", "=>".paint(LOG))?;
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:".paint(LOG))?;
1322 for (nonterm, goto) in gotos {
1323 writeln!(f, "\t\t{nonterm} {} {goto}", "=>".paint(LOG))?;
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}