1use std::{
2 cmp::Ordering,
3 collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque},
4 hash::BuildHasherDefault,
5};
6
7use indexmap::{map::Entry, IndexMap};
8use log::warn;
9use rustc_hash::FxHasher;
10use serde::Serialize;
11use thiserror::Error;
12
13use super::{
14 item::{ParseItem, ParseItemSet, ParseItemSetCore, ParseItemSetEntry},
15 item_set_builder::ParseItemSetBuilder,
16};
17use crate::{
18 grammars::{LexicalGrammar, PrecedenceEntry, ReservedWordSetId, SyntaxGrammar, VariableType},
19 node_types::VariableInfo,
20 rules::{Associativity, Precedence, Symbol, SymbolType, TokenSet},
21 tables::{
22 FieldLocation, GotoAction, ParseAction, ParseState, ParseStateId, ParseTable,
23 ParseTableEntry, ProductionInfo, ProductionInfoId,
24 },
25};
26
27type SymbolSequence = Vec<Symbol>;
30
31type AuxiliarySymbolSequence = Vec<AuxiliarySymbolInfo>;
32pub type ParseStateInfo<'a> = (SymbolSequence, ParseItemSet<'a>);
33
34#[derive(Clone, PartialEq)]
35struct AuxiliarySymbolInfo {
36 auxiliary_symbol: Symbol,
37 parent_symbols: Vec<Symbol>,
38}
39
40#[derive(Debug, Default)]
41struct ReductionInfo {
42 precedence: Precedence,
43 symbols: Vec<Symbol>,
44 has_left_assoc: bool,
45 has_right_assoc: bool,
46 has_non_assoc: bool,
47}
48
49struct ParseStateQueueEntry {
50 state_id: ParseStateId,
51 preceding_auxiliary_symbols: AuxiliarySymbolSequence,
52}
53
54struct ParseTableBuilder<'a> {
55 item_set_builder: ParseItemSetBuilder<'a>,
56 syntax_grammar: &'a SyntaxGrammar,
57 lexical_grammar: &'a LexicalGrammar,
58 variable_info: &'a [VariableInfo],
59 core_ids_by_core: HashMap<ParseItemSetCore<'a>, usize>,
60 state_ids_by_item_set: IndexMap<ParseItemSet<'a>, ParseStateId, BuildHasherDefault<FxHasher>>,
61 parse_state_info_by_id: Vec<ParseStateInfo<'a>>,
62 parse_state_queue: VecDeque<ParseStateQueueEntry>,
63 non_terminal_extra_states: Vec<(Symbol, usize)>,
64 actual_conflicts: HashSet<Vec<Symbol>>,
65 parse_table: ParseTable,
66}
67
68pub type BuildTableResult<T> = Result<T, ParseTableBuilderError>;
69
70#[derive(Debug, Error, Serialize)]
71pub enum ParseTableBuilderError {
72 #[error("Unresolved conflict for symbol sequence:\n\n{0}")]
73 Conflict(#[from] ConflictError),
74 #[error("Extra rules must have unambiguous endings. Conflicting rules: {0}")]
75 AmbiguousExtra(#[from] AmbiguousExtraError),
76 #[error(
77 "The non-terminal rule `{0}` is used in a non-terminal `extra` rule, which is not allowed."
78 )]
79 ImproperNonTerminalExtra(String),
80 #[error("State count `{0}` exceeds the max value {max}.", max=u16::MAX)]
81 StateCount(usize),
82}
83
84#[derive(Default, Debug, Serialize, Error)]
85pub struct ConflictError {
86 pub symbol_sequence: Vec<String>,
87 pub conflicting_lookahead: String,
88 pub possible_interpretations: Vec<Interpretation>,
89 pub possible_resolutions: Vec<Resolution>,
90}
91
92#[derive(Default, Debug, Serialize, Error)]
93pub struct Interpretation {
94 pub preceding_symbols: Vec<String>,
95 pub variable_name: String,
96 pub production_step_symbols: Vec<String>,
97 pub step_index: u32,
98 pub done: bool,
99 pub conflicting_lookahead: String,
100 pub precedence: Option<String>,
101 pub associativity: Option<String>,
102}
103
104#[derive(Debug, Serialize)]
105pub enum Resolution {
106 Precedence { symbols: Vec<String> },
107 Associativity { symbols: Vec<String> },
108 AddConflict { symbols: Vec<String> },
109}
110
111#[derive(Debug, Serialize, Error)]
112pub struct AmbiguousExtraError {
113 pub parent_symbols: Vec<String>,
114}
115
116impl std::fmt::Display for ConflictError {
117 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
118 for symbol in &self.symbol_sequence {
119 write!(f, " {symbol}")?;
120 }
121 writeln!(f, " • {} …\n", self.conflicting_lookahead)?;
122
123 writeln!(f, "Possible interpretations:\n")?;
124 let mut interpretations = self
125 .possible_interpretations
126 .iter()
127 .map(|i| {
128 let line = i.to_string();
129 let prec_line = if let (Some(precedence), Some(associativity)) =
130 (&i.precedence, &i.associativity)
131 {
132 Some(format!(
133 "(precedence: {precedence}, associativity: {associativity})",
134 ))
135 } else {
136 i.precedence
137 .as_ref()
138 .map(|precedence| format!("(precedence: {precedence})"))
139 };
140
141 (line, prec_line)
142 })
143 .collect::<Vec<_>>();
144 let max_interpretation_length = interpretations
145 .iter()
146 .map(|i| i.0.chars().count())
147 .max()
148 .unwrap();
149 interpretations.sort_unstable();
150 for (i, (line, prec_suffix)) in interpretations.into_iter().enumerate() {
151 write!(f, " {}:", i + 1).unwrap();
152 write!(f, "{line}")?;
153 if let Some(prec_suffix) = prec_suffix {
154 write!(
155 f,
156 "{:1$}",
157 "",
158 max_interpretation_length.saturating_sub(line.chars().count()) + 2
159 )?;
160 write!(f, "{prec_suffix}")?;
161 }
162 writeln!(f)?;
163 }
164
165 writeln!(f, "\nPossible resolutions:\n")?;
166 for (i, resolution) in self.possible_resolutions.iter().enumerate() {
167 writeln!(f, " {}: {resolution}", i + 1)?;
168 }
169 Ok(())
170 }
171}
172
173impl std::fmt::Display for Interpretation {
174 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
175 for symbol in &self.preceding_symbols {
176 write!(f, " {symbol}")?;
177 }
178 write!(f, " ({}", self.variable_name)?;
179 for (i, symbol) in self.production_step_symbols.iter().enumerate() {
180 if i == self.step_index as usize {
181 write!(f, " •")?;
182 }
183 write!(f, " {symbol}")?;
184 }
185 write!(f, ")")?;
186 if self.done {
187 write!(f, " • {} …", self.conflicting_lookahead)?;
188 }
189 Ok(())
190 }
191}
192
193impl std::fmt::Display for Resolution {
194 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
195 match self {
196 Self::Precedence { symbols } => {
197 write!(f, "Specify a higher precedence in ")?;
198 for (i, symbol) in symbols.iter().enumerate() {
199 if i > 0 {
200 write!(f, " and ")?;
201 }
202 write!(f, "`{symbol}`")?;
203 }
204 write!(f, " than in the other rules.")?;
205 }
206 Self::Associativity { symbols } => {
207 write!(f, "Specify a left or right associativity in ")?;
208 for (i, symbol) in symbols.iter().enumerate() {
209 if i > 0 {
210 write!(f, ", ")?;
211 }
212 write!(f, "`{symbol}`")?;
213 }
214 }
215 Self::AddConflict { symbols } => {
216 write!(f, "Add a conflict for these rules: ")?;
217 for (i, symbol) in symbols.iter().enumerate() {
218 if i > 0 {
219 write!(f, ", ")?;
220 }
221 write!(f, "`{symbol}`")?;
222 }
223 }
224 }
225 Ok(())
226 }
227}
228
229impl std::fmt::Display for AmbiguousExtraError {
230 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
231 for (i, symbol) in self.parent_symbols.iter().enumerate() {
232 if i > 0 {
233 write!(f, ", ")?;
234 }
235 write!(f, "{symbol}")?;
236 }
237 Ok(())
238 }
239}
240
241impl<'a> ParseTableBuilder<'a> {
242 fn new(
243 syntax_grammar: &'a SyntaxGrammar,
244 lexical_grammar: &'a LexicalGrammar,
245 item_set_builder: ParseItemSetBuilder<'a>,
246 variable_info: &'a [VariableInfo],
247 ) -> Self {
248 Self {
249 syntax_grammar,
250 lexical_grammar,
251 item_set_builder,
252 variable_info,
253 non_terminal_extra_states: Vec::new(),
254 state_ids_by_item_set: IndexMap::default(),
255 core_ids_by_core: HashMap::new(),
256 parse_state_info_by_id: Vec::new(),
257 parse_state_queue: VecDeque::new(),
258 actual_conflicts: syntax_grammar.expected_conflicts.iter().cloned().collect(),
259 parse_table: ParseTable {
260 states: Vec::new(),
261 symbols: Vec::new(),
262 external_lex_states: Vec::new(),
263 production_infos: Vec::new(),
264 max_aliased_production_length: 1,
265 },
266 }
267 }
268
269 fn build(mut self) -> BuildTableResult<(ParseTable, Vec<ParseStateInfo<'a>>)> {
270 self.parse_table
272 .production_infos
273 .push(ProductionInfo::default());
274
275 self.add_parse_state(&Vec::new(), &Vec::new(), ParseItemSet::default());
277
278 self.add_parse_state(
280 &Vec::new(),
281 &Vec::new(),
282 ParseItemSet {
283 entries: vec![ParseItemSetEntry {
284 item: ParseItem::start(),
285 lookaheads: std::iter::once(Symbol::end()).collect(),
286 following_reserved_word_set: ReservedWordSetId::default(),
287 }],
288 },
289 );
290
291 let mut non_terminal_extra_item_sets_by_first_terminal = BTreeMap::new();
293 for extra_non_terminal in self
294 .syntax_grammar
295 .extra_symbols
296 .iter()
297 .filter(|s| s.is_non_terminal())
298 {
299 let variable = &self.syntax_grammar.variables[extra_non_terminal.index];
300 for production in &variable.productions {
301 non_terminal_extra_item_sets_by_first_terminal
302 .entry(production.first_symbol().unwrap())
303 .or_insert_with(ParseItemSet::default)
304 .insert(ParseItem {
305 variable_index: extra_non_terminal.index as u32,
306 production,
307 step_index: 1,
308 has_preceding_inherited_fields: false,
309 })
310 .lookaheads
311 .insert(Symbol::end_of_nonterminal_extra());
312 }
313 }
314
315 let non_terminal_sets_len = non_terminal_extra_item_sets_by_first_terminal.len();
316 self.non_terminal_extra_states
317 .reserve(non_terminal_sets_len);
318 self.parse_state_info_by_id.reserve(non_terminal_sets_len);
319 self.parse_table.states.reserve(non_terminal_sets_len);
320 self.parse_state_queue.reserve(non_terminal_sets_len);
321 for (terminal, item_set) in non_terminal_extra_item_sets_by_first_terminal {
323 if terminal.is_non_terminal() {
324 Err(ParseTableBuilderError::ImproperNonTerminalExtra(
325 self.symbol_name(&terminal),
326 ))?;
327 }
328
329 let state_id = self.add_parse_state(&Vec::new(), &Vec::new(), item_set);
332 self.non_terminal_extra_states.push((terminal, state_id));
333 }
334
335 while let Some(entry) = self.parse_state_queue.pop_front() {
336 let item_set = self
337 .item_set_builder
338 .transitive_closure(&self.parse_state_info_by_id[entry.state_id].1);
339
340 self.add_actions(
341 self.parse_state_info_by_id[entry.state_id].0.clone(),
342 entry.preceding_auxiliary_symbols,
343 entry.state_id,
344 &item_set,
345 )?;
346 }
347
348 if !self.actual_conflicts.is_empty() {
349 warn!(
350 "unnecessary conflicts:\n {}",
351 self.actual_conflicts
352 .iter()
353 .map(|conflict| {
354 conflict
355 .iter()
356 .map(|symbol| format!("`{}`", self.symbol_name(symbol)))
357 .collect::<Vec<_>>()
358 .join(", ")
359 })
360 .collect::<Vec<_>>()
361 .join("\n ")
362 );
363 }
364
365 Ok((self.parse_table, self.parse_state_info_by_id))
366 }
367
368 fn add_parse_state(
369 &mut self,
370 preceding_symbols: &SymbolSequence,
371 preceding_auxiliary_symbols: &AuxiliarySymbolSequence,
372 item_set: ParseItemSet<'a>,
373 ) -> ParseStateId {
374 match self.state_ids_by_item_set.entry(item_set) {
375 Entry::Occupied(o) => *o.get(),
378
379 Entry::Vacant(v) => {
382 let core = v.key().core();
383 let core_count = self.core_ids_by_core.len();
384 let core_id = *self.core_ids_by_core.entry(core).or_insert(core_count);
385
386 let state_id = self.parse_table.states.len();
387 self.parse_state_info_by_id
388 .push((preceding_symbols.clone(), v.key().clone()));
389
390 self.parse_table.states.push(ParseState {
391 id: state_id,
392 lex_state_id: 0,
393 external_lex_state_id: 0,
394 terminal_entries: IndexMap::default(),
395 nonterminal_entries: IndexMap::default(),
396 reserved_words: TokenSet::default(),
397 core_id,
398 });
399 self.parse_state_queue.push_back(ParseStateQueueEntry {
400 state_id,
401 preceding_auxiliary_symbols: preceding_auxiliary_symbols.clone(),
402 });
403 v.insert(state_id);
404 state_id
405 }
406 }
407 }
408
409 fn add_actions(
410 &mut self,
411 mut preceding_symbols: SymbolSequence,
412 mut preceding_auxiliary_symbols: AuxiliarySymbolSequence,
413 state_id: ParseStateId,
414 item_set: &ParseItemSet<'a>,
415 ) -> BuildTableResult<()> {
416 let mut terminal_successors = BTreeMap::new();
417 let mut non_terminal_successors = BTreeMap::new();
418 let mut lookaheads_with_conflicts = TokenSet::new();
419 let mut reduction_infos = HashMap::<Symbol, ReductionInfo>::new();
420
421 for ParseItemSetEntry {
424 item,
425 lookaheads,
426 following_reserved_word_set: reserved_lookaheads,
427 } in &item_set.entries
428 {
429 if let Some(next_symbol) = item.symbol() {
433 let mut successor = item.successor();
434 let successor_set = if next_symbol.is_non_terminal() {
435 let variable = &self.syntax_grammar.variables[next_symbol.index];
436
437 if variable.is_auxiliary() {
441 preceding_auxiliary_symbols
442 .push(self.get_auxiliary_node_info(item_set, next_symbol));
443 }
444
445 if variable.is_hidden()
455 && !self.variable_info[next_symbol.index].fields.is_empty()
456 {
457 successor.has_preceding_inherited_fields = true;
458 }
459
460 non_terminal_successors
461 .entry(next_symbol)
462 .or_insert_with(ParseItemSet::default)
463 } else {
464 terminal_successors
465 .entry(next_symbol)
466 .or_insert_with(ParseItemSet::default)
467 };
468 let successor_entry = successor_set.insert(successor);
469 successor_entry.lookaheads.insert_all(lookaheads);
470 successor_entry.following_reserved_word_set = successor_entry
471 .following_reserved_word_set
472 .max(*reserved_lookaheads);
473 }
474 else {
477 let symbol = Symbol::non_terminal(item.variable_index as usize);
478 let action = if item.is_augmented() {
479 ParseAction::Accept
480 } else {
481 ParseAction::Reduce {
482 symbol,
483 child_count: item.step_index as usize,
484 dynamic_precedence: item.production.dynamic_precedence,
485 production_id: self.get_production_id(item),
486 }
487 };
488
489 let precedence = item.precedence();
490 let associativity = item.associativity();
491 for lookahead in lookaheads.iter() {
492 let table_entry = self.parse_table.states[state_id]
493 .terminal_entries
494 .entry(lookahead)
495 .or_insert_with(ParseTableEntry::new);
496 let reduction_info = reduction_infos.entry(lookahead).or_default();
497
498 if table_entry.actions.is_empty() {
502 table_entry.actions.push(action);
503 } else {
504 match Self::compare_precedence(
505 self.syntax_grammar,
506 precedence,
507 &[symbol],
508 &reduction_info.precedence,
509 &reduction_info.symbols,
510 ) {
511 Ordering::Greater => {
512 table_entry.actions.clear();
513 table_entry.actions.push(action);
514 lookaheads_with_conflicts.remove(&lookahead);
515 *reduction_info = ReductionInfo::default();
516 }
517 Ordering::Equal => {
518 table_entry.actions.push(action);
519 lookaheads_with_conflicts.insert(lookahead);
520 }
521 Ordering::Less => continue,
522 }
523 }
524
525 reduction_info.precedence.clone_from(precedence);
526 if let Err(i) = reduction_info.symbols.binary_search(&symbol) {
527 reduction_info.symbols.insert(i, symbol);
528 }
529 match associativity {
530 Some(Associativity::Left) => reduction_info.has_left_assoc = true,
531 Some(Associativity::Right) => reduction_info.has_right_assoc = true,
532 None => reduction_info.has_non_assoc = true,
533 }
534 }
535 }
536 }
537
538 preceding_auxiliary_symbols.dedup();
539
540 for (symbol, next_item_set) in terminal_successors {
544 preceding_symbols.push(symbol);
545 let next_state_id = self.add_parse_state(
546 &preceding_symbols,
547 &preceding_auxiliary_symbols,
548 next_item_set,
549 );
550 preceding_symbols.pop();
551
552 let entry = self.parse_table.states[state_id]
553 .terminal_entries
554 .entry(symbol);
555 if let Entry::Occupied(e) = &entry {
556 if !e.get().actions.is_empty() {
557 lookaheads_with_conflicts.insert(symbol);
558 }
559 }
560
561 entry
562 .or_insert_with(ParseTableEntry::new)
563 .actions
564 .push(ParseAction::Shift {
565 state: next_state_id,
566 is_repetition: false,
567 });
568 }
569
570 for (symbol, next_item_set) in non_terminal_successors {
571 preceding_symbols.push(symbol);
572 let next_state_id = self.add_parse_state(
573 &preceding_symbols,
574 &preceding_auxiliary_symbols,
575 next_item_set,
576 );
577 preceding_symbols.pop();
578 self.parse_table.states[state_id]
579 .nonterminal_entries
580 .insert(symbol, GotoAction::Goto(next_state_id));
581 }
582
583 for symbol in lookaheads_with_conflicts.iter() {
589 self.handle_conflict(
590 item_set,
591 state_id,
592 &preceding_symbols,
593 &preceding_auxiliary_symbols,
594 symbol,
595 reduction_infos.get(&symbol).unwrap(),
596 )?;
597 }
598
599 let state = &mut self.parse_table.states[state_id];
601 let is_end_of_non_terminal_extra = state.is_end_of_non_terminal_extra();
602
603 if is_end_of_non_terminal_extra {
607 if state.terminal_entries.len() > 1 {
608 let parent_symbols = item_set
609 .entries
610 .iter()
611 .filter_map(|ParseItemSetEntry { item, .. }| {
612 if !item.is_augmented() && item.step_index > 0 {
613 Some(item.variable_index)
614 } else {
615 None
616 }
617 })
618 .collect::<HashSet<_>>();
619 let parent_symbol_names = parent_symbols
620 .iter()
621 .map(|&variable_index| {
622 self.syntax_grammar.variables[variable_index as usize]
623 .name
624 .clone()
625 })
626 .collect::<Vec<_>>();
627
628 Err(AmbiguousExtraError {
629 parent_symbols: parent_symbol_names,
630 })?;
631 }
632 }
633 else {
635 for (terminal, state_id) in &self.non_terminal_extra_states {
636 state
637 .terminal_entries
638 .entry(*terminal)
639 .or_insert(ParseTableEntry {
640 reusable: true,
641 actions: vec![ParseAction::Shift {
642 state: *state_id,
643 is_repetition: false,
644 }],
645 });
646 }
647
648 for extra_token in &self.syntax_grammar.extra_symbols {
652 if extra_token.is_non_terminal() {
653 state
654 .nonterminal_entries
655 .insert(*extra_token, GotoAction::ShiftExtra);
656 } else {
657 state
658 .terminal_entries
659 .entry(*extra_token)
660 .or_insert(ParseTableEntry {
661 reusable: true,
662 actions: vec![ParseAction::ShiftExtra],
663 });
664 }
665 }
666 }
667
668 if let Some(keyword_capture_token) = self.syntax_grammar.word_token {
669 let reserved_word_set_id = item_set
670 .entries
671 .iter()
672 .filter_map(|entry| {
673 if let Some(next_step) = entry.item.step() {
674 if next_step.symbol == keyword_capture_token {
675 Some(next_step.reserved_word_set_id)
676 } else {
677 None
678 }
679 } else if entry.lookaheads.contains(&keyword_capture_token) {
680 Some(entry.following_reserved_word_set)
681 } else {
682 None
683 }
684 })
685 .max();
686 if let Some(reserved_word_set_id) = reserved_word_set_id {
687 state.reserved_words =
688 self.syntax_grammar.reserved_word_sets[reserved_word_set_id.0].clone();
689 }
690 }
691
692 Ok(())
693 }
694
695 fn handle_conflict(
696 &mut self,
697 item_set: &ParseItemSet,
698 state_id: ParseStateId,
699 preceding_symbols: &SymbolSequence,
700 preceding_auxiliary_symbols: &[AuxiliarySymbolInfo],
701 conflicting_lookahead: Symbol,
702 reduction_info: &ReductionInfo,
703 ) -> BuildTableResult<()> {
704 let entry = self.parse_table.states[state_id]
705 .terminal_entries
706 .get_mut(&conflicting_lookahead)
707 .unwrap();
708
709 let mut considered_associativity = false;
716 let mut shift_precedence = Vec::<(&Precedence, Symbol)>::new();
717 let mut conflicting_items = BTreeSet::new();
718 for ParseItemSetEntry {
719 item, lookaheads, ..
720 } in &item_set.entries
721 {
722 if let Some(step) = item.step() {
723 if item.step_index > 0
724 && self
725 .item_set_builder
726 .first_set(&step.symbol)
727 .contains(&conflicting_lookahead)
728 {
729 if item.variable_index != u32::MAX {
730 conflicting_items.insert(item);
731 }
732
733 let p = (
734 item.precedence(),
735 Symbol::non_terminal(item.variable_index as usize),
736 );
737 if let Err(i) = shift_precedence.binary_search(&p) {
738 shift_precedence.insert(i, p);
739 }
740 }
741 } else if lookaheads.contains(&conflicting_lookahead) && item.variable_index != u32::MAX
742 {
743 conflicting_items.insert(item);
744 }
745 }
746
747 if let ParseAction::Shift { is_repetition, .. } = entry.actions.last_mut().unwrap() {
748 let conflicting_variable_index =
754 conflicting_items.iter().next().unwrap().variable_index;
755 if self.syntax_grammar.variables[conflicting_variable_index as usize].is_auxiliary()
756 && conflicting_items
757 .iter()
758 .all(|item| item.variable_index == conflicting_variable_index)
759 {
760 *is_repetition = true;
761 return Ok(());
762 }
763
764 let mut shift_is_less = false;
766 let mut shift_is_equal = false;
767 let mut shift_is_more = false;
768 for p in shift_precedence {
769 match Self::compare_precedence(
770 self.syntax_grammar,
771 p.0,
772 &[p.1],
773 &reduction_info.precedence,
774 &reduction_info.symbols,
775 ) {
776 Ordering::Greater => shift_is_more = true,
777 Ordering::Less => shift_is_less = true,
778 Ordering::Equal => shift_is_equal = true,
779 }
780 }
781
782 if shift_is_more && !shift_is_less {
783 entry.actions.drain(0..entry.actions.len() - 1);
784 }
785 else if shift_is_less && !shift_is_more {
787 if shift_is_equal
795 && matches!(
796 (
797 reduction_info.has_left_assoc,
798 reduction_info.has_non_assoc,
799 reduction_info.has_right_assoc,
800 ),
801 (false, false, true)
802 )
803 {
804 entry.actions.drain(0..entry.actions.len() - 1);
805 } else {
806 entry.actions.pop();
807 conflicting_items.retain(|item| item.is_done());
808 }
809 }
810 else if !shift_is_less && !shift_is_more {
813 considered_associativity = true;
814
815 match (
818 reduction_info.has_left_assoc,
819 reduction_info.has_non_assoc,
820 reduction_info.has_right_assoc,
821 ) {
822 (true, false, false) => {
823 entry.actions.pop();
824 conflicting_items.retain(|item| item.is_done());
825 }
826 (false, false, true) => {
827 entry.actions.drain(0..entry.actions.len() - 1);
828 }
829 _ => {}
830 }
831 }
832 }
833
834 let entry = self.parse_table.states[state_id]
836 .terminal_entries
837 .get_mut(&conflicting_lookahead)
838 .unwrap();
839 if entry.actions.len() == 1 {
840 return Ok(());
841 }
842
843 let mut actual_conflict = Vec::new();
845 for item in &conflicting_items {
846 let symbol = Symbol::non_terminal(item.variable_index as usize);
847 if self.syntax_grammar.variables[symbol.index].is_auxiliary() {
848 actual_conflict.extend(
849 preceding_auxiliary_symbols
850 .iter()
851 .rev()
852 .find_map(|info| {
853 if info.auxiliary_symbol == symbol {
854 Some(&info.parent_symbols)
855 } else {
856 None
857 }
858 })
859 .unwrap()
860 .iter(),
861 );
862 } else {
863 actual_conflict.push(symbol);
864 }
865 }
866 actual_conflict.sort_unstable();
867 actual_conflict.dedup();
868
869 if self
871 .syntax_grammar
872 .expected_conflicts
873 .contains(&actual_conflict)
874 {
875 self.actual_conflicts.remove(&actual_conflict);
876 return Ok(());
877 }
878
879 let mut conflict_error = ConflictError::default();
880 for symbol in preceding_symbols {
881 conflict_error
882 .symbol_sequence
883 .push(self.symbol_name(symbol));
884 }
885 conflict_error.conflicting_lookahead = self.symbol_name(&conflicting_lookahead);
886
887 let interpretations = conflicting_items
888 .iter()
889 .map(|item| {
890 let preceding_symbols = preceding_symbols
891 .iter()
892 .take(preceding_symbols.len() - item.step_index as usize)
893 .map(|symbol| self.symbol_name(symbol))
894 .collect::<Vec<_>>();
895
896 let variable_name = self.syntax_grammar.variables[item.variable_index as usize]
897 .name
898 .clone();
899
900 let production_step_symbols = item
901 .production
902 .steps
903 .iter()
904 .map(|step| self.symbol_name(&step.symbol))
905 .collect::<Vec<_>>();
906
907 let precedence = match item.precedence() {
908 Precedence::None => None,
909 _ => Some(item.precedence().to_string()),
910 };
911
912 let associativity = item.associativity().map(|assoc| format!("{assoc:?}"));
913
914 Interpretation {
915 preceding_symbols,
916 variable_name,
917 production_step_symbols,
918 step_index: item.step_index,
919 done: item.is_done(),
920 conflicting_lookahead: self.symbol_name(&conflicting_lookahead),
921 precedence,
922 associativity,
923 }
924 })
925 .collect::<Vec<_>>();
926 conflict_error.possible_interpretations = interpretations;
927
928 let mut shift_items = Vec::new();
929 let mut reduce_items = Vec::new();
930 for item in conflicting_items {
931 if item.is_done() {
932 reduce_items.push(item);
933 } else {
934 shift_items.push(item);
935 }
936 }
937 shift_items.sort_unstable();
938 reduce_items.sort_unstable();
939
940 let get_rule_names = |items: &[&ParseItem]| -> Vec<String> {
941 let mut last_rule_id = None;
942 let mut result = Vec::with_capacity(items.len());
943 for item in items {
944 if last_rule_id == Some(item.variable_index) {
945 continue;
946 }
947 last_rule_id = Some(item.variable_index);
948 result.push(self.symbol_name(&Symbol::non_terminal(item.variable_index as usize)));
949 }
950
951 result
952 };
953
954 if actual_conflict.len() > 1 {
955 if !shift_items.is_empty() {
956 let names = get_rule_names(&shift_items);
957 conflict_error
958 .possible_resolutions
959 .push(Resolution::Precedence { symbols: names });
960 }
961
962 for item in &reduce_items {
963 let name = self.symbol_name(&Symbol::non_terminal(item.variable_index as usize));
964 conflict_error
965 .possible_resolutions
966 .push(Resolution::Precedence {
967 symbols: vec![name],
968 });
969 }
970 }
971
972 if considered_associativity {
973 let names = get_rule_names(&reduce_items);
974 conflict_error
975 .possible_resolutions
976 .push(Resolution::Associativity { symbols: names });
977 }
978
979 conflict_error
980 .possible_resolutions
981 .push(Resolution::AddConflict {
982 symbols: actual_conflict
983 .iter()
984 .map(|s| self.symbol_name(s))
985 .collect(),
986 });
987
988 self.actual_conflicts.insert(actual_conflict);
989
990 Err(conflict_error)?
991 }
992
993 fn compare_precedence(
994 grammar: &SyntaxGrammar,
995 left: &Precedence,
996 left_symbols: &[Symbol],
997 right: &Precedence,
998 right_symbols: &[Symbol],
999 ) -> Ordering {
1000 let precedence_entry_matches =
1001 |entry: &PrecedenceEntry, precedence: &Precedence, symbols: &[Symbol]| -> bool {
1002 match entry {
1003 PrecedenceEntry::Name(n) => {
1004 if let Precedence::Name(p) = precedence {
1005 n == p
1006 } else {
1007 false
1008 }
1009 }
1010 PrecedenceEntry::Symbol(n) => symbols
1011 .iter()
1012 .any(|s| &grammar.variables[s.index].name == n),
1013 }
1014 };
1015
1016 match (left, right) {
1017 (Precedence::Integer(l), Precedence::Integer(r)) if *l != 0 || *r != 0 => l.cmp(r),
1020 (Precedence::Integer(l), Precedence::None) if *l != 0 => l.cmp(&0),
1021 (Precedence::None, Precedence::Integer(r)) if *r != 0 => 0.cmp(r),
1022
1023 _ => grammar
1025 .precedence_orderings
1026 .iter()
1027 .find_map(|list| {
1028 let mut saw_left = false;
1029 let mut saw_right = false;
1030 for entry in list {
1031 let matches_left = precedence_entry_matches(entry, left, left_symbols);
1032 let matches_right = precedence_entry_matches(entry, right, right_symbols);
1033 if matches_left {
1034 saw_left = true;
1035 if saw_right {
1036 return Some(Ordering::Less);
1037 }
1038 } else if matches_right {
1039 saw_right = true;
1040 if saw_left {
1041 return Some(Ordering::Greater);
1042 }
1043 }
1044 }
1045 None
1046 })
1047 .unwrap_or(Ordering::Equal),
1048 }
1049 }
1050
1051 fn get_auxiliary_node_info(
1052 &self,
1053 item_set: &ParseItemSet,
1054 symbol: Symbol,
1055 ) -> AuxiliarySymbolInfo {
1056 let parent_symbols = item_set
1057 .entries
1058 .iter()
1059 .filter_map(|ParseItemSetEntry { item, .. }| {
1060 let variable_index = item.variable_index as usize;
1061 if item.symbol() == Some(symbol)
1062 && !self.syntax_grammar.variables[variable_index].is_auxiliary()
1063 {
1064 Some(Symbol::non_terminal(variable_index))
1065 } else {
1066 None
1067 }
1068 })
1069 .collect();
1070 AuxiliarySymbolInfo {
1071 auxiliary_symbol: symbol,
1072 parent_symbols,
1073 }
1074 }
1075
1076 fn get_production_id(&mut self, item: &ParseItem) -> ProductionInfoId {
1077 let mut production_info = ProductionInfo {
1078 alias_sequence: Vec::new(),
1079 field_map: BTreeMap::new(),
1080 };
1081
1082 for (i, step) in item.production.steps.iter().enumerate() {
1083 production_info.alias_sequence.push(step.alias.clone());
1084 if let Some(field_name) = &step.field_name {
1085 production_info
1086 .field_map
1087 .entry(field_name.clone())
1088 .or_default()
1089 .push(FieldLocation {
1090 index: i,
1091 inherited: false,
1092 });
1093 }
1094
1095 if step.symbol.kind == SymbolType::NonTerminal
1096 && !self.syntax_grammar.variables[step.symbol.index]
1097 .kind
1098 .is_visible()
1099 {
1100 let info = &self.variable_info[step.symbol.index];
1101 for field_name in info.fields.keys() {
1102 production_info
1103 .field_map
1104 .entry(field_name.clone())
1105 .or_default()
1106 .push(FieldLocation {
1107 index: i,
1108 inherited: true,
1109 });
1110 }
1111 }
1112 }
1113
1114 while production_info.alias_sequence.last() == Some(&None) {
1115 production_info.alias_sequence.pop();
1116 }
1117
1118 if item.production.steps.len() > self.parse_table.max_aliased_production_length {
1119 self.parse_table.max_aliased_production_length = item.production.steps.len();
1120 }
1121
1122 if let Some(index) = self
1123 .parse_table
1124 .production_infos
1125 .iter()
1126 .position(|seq| *seq == production_info)
1127 {
1128 index
1129 } else {
1130 self.parse_table.production_infos.push(production_info);
1131 self.parse_table.production_infos.len() - 1
1132 }
1133 }
1134
1135 fn symbol_name(&self, symbol: &Symbol) -> String {
1136 match symbol.kind {
1137 SymbolType::End | SymbolType::EndOfNonTerminalExtra => "EOF".to_string(),
1138 SymbolType::External => self.syntax_grammar.external_tokens[symbol.index]
1139 .name
1140 .clone(),
1141 SymbolType::NonTerminal => self.syntax_grammar.variables[symbol.index].name.clone(),
1142 SymbolType::Terminal => {
1143 let variable = &self.lexical_grammar.variables[symbol.index];
1144 if variable.kind == VariableType::Named {
1145 variable.name.clone()
1146 } else {
1147 format!("'{}'", variable.name)
1148 }
1149 }
1150 }
1151 }
1152}
1153
1154pub fn build_parse_table<'a>(
1155 syntax_grammar: &'a SyntaxGrammar,
1156 lexical_grammar: &'a LexicalGrammar,
1157 item_set_builder: ParseItemSetBuilder<'a>,
1158 variable_info: &'a [VariableInfo],
1159) -> BuildTableResult<(ParseTable, Vec<ParseStateInfo<'a>>)> {
1160 ParseTableBuilder::new(
1161 syntax_grammar,
1162 lexical_grammar,
1163 item_set_builder,
1164 variable_info,
1165 )
1166 .build()
1167}