diff --git a/lalrpop/src/lr1/core/mod.rs b/lalrpop/src/lr1/core/mod.rs index b37d7f7..6602d48 100644 --- a/lalrpop/src/lr1/core/mod.rs +++ b/lalrpop/src/lr1/core/mod.rs @@ -88,6 +88,8 @@ impl<'session, 'grammar> LR1<'session, 'grammar> { let prev = this_state.tokens.insert(item.lookahead, action); if let Some(conflict) = prev { return Err(TableConstructionError { + states: Some(states), + index: index, items: items.clone(), lookahead: item.lookahead, production: item.production, diff --git a/lalrpop/src/lr1/la0/mod.rs b/lalrpop/src/lr1/la0/mod.rs index 1b2043c..2f520a8 100644 --- a/lalrpop/src/lr1/la0/mod.rs +++ b/lalrpop/src/lr1/la0/mod.rs @@ -93,7 +93,7 @@ pub fn collapse_to_lalr_states<'grammar>(lr_states: &[State<'grammar>]) Entry::Occupied(slot) => { let old_action = *slot.get(); if old_action != lalr1_action { - return Err(conflict(&lalr1_state.items, lookahead, + return Err(conflict(lalr1_index, &lalr1_state.items, lookahead, old_action, lalr1_action)); } } @@ -130,7 +130,8 @@ pub fn collapse_to_lalr_states<'grammar>(lr_states: &[State<'grammar>]) .collect()) } -fn conflict<'grammar>(items: &[Item<'grammar>], +fn conflict<'grammar>(index: StateIndex, + items: &[Item<'grammar>], lookahead: Lookahead, action1: Action<'grammar>, action2: Action<'grammar>) @@ -145,6 +146,8 @@ fn conflict<'grammar>(items: &[Item<'grammar>], }; TableConstructionError { + states: None, + index: index, items: Items { vec: Rc::new(items.to_vec()) }, lookahead: lookahead, production: production, diff --git a/lalrpop/src/lr1/mod.rs b/lalrpop/src/lr1/mod.rs index b10ac7f..074bd9e 100644 --- a/lalrpop/src/lr1/mod.rs +++ b/lalrpop/src/lr1/mod.rs @@ -55,6 +55,21 @@ struct Item<'grammar> { #[derive(Debug)] pub struct TableConstructionError<'grammar> { + // completed states: note that these may reference states that + // were never processed, so you can't follow outgoing edges with + // impunity. + // + // This is optional because, in the current LALR(1) code, we don't + // have a notion of "complete" states to supply. Really we should + // special case the error reporting there. Or, better yet, make + // the LR(1) -> LALR(1) compression infallible, by just detecting + // when it's going to work. (Or, the other way, only use the full + // LR(1) when needed.) + states: Option>>, + + // state index where we encountered a failure + index: StateIndex, + // when in this state: items: Items<'grammar>,