1 #![allow(dead_code)]
2 
3 use std::fmt::Debug;
4 
5 const DEBUG_ENABLED: bool = false;
6 
7 macro_rules! debug {
8     ($($args:expr),* $(,)*) => {
9         if DEBUG_ENABLED {
10             eprintln!($($args),*);
11         }
12     }
13 }
14 
15 pub trait ParserDefinition: Sized {
16     /// Represents a location in the input text. If you are using the
17     /// default tokenizer, this will be a `usize`.
18     type Location: Clone + Debug;
19 
20     /// Represents a "user error" -- this can get produced by
21     /// `reduce()` if the grammar includes `=>?` actions.
22     type Error;
23 
24     /// The type emitted by the user's tokenizer (excluding the
25     /// location information).
26     type Token: Clone + Debug;
27 
28     /// We assign a unique index to each token in the grammar, which
29     /// we call its *index*. When we pull in a new `Token` from the
30     /// input, we then match against it to determine its index.  Note
31     /// that the actual `Token` is retained too, as it may carry
32     /// additional information (e.g., an `ID` terminal often has a
33     /// string value associated with it; this is not important to the
34     /// parser, but the semantic analyzer will want it).
35     type TokenIndex: Copy + Clone + Debug;
36 
37     /// The type representing things on the LALRPOP stack. Represents
38     /// the union of terminals and nonterminals.
39     type Symbol;
40 
41     /// Type produced by reducing the start symbol.
42     type Success;
43 
44     /// Identifies a state. Typically an i8, i16, or i32 (depending on
45     /// how many states you have).
46     type StateIndex: Copy + Clone + Debug;
47 
48     /// Identifies an action.
49     type Action: ParserAction<Self>;
50 
51     /// Identifies a reduction.
52     type ReduceIndex: Copy + Clone + Debug;
53 
54     /// Identifies a nonterminal.
55     type NonterminalIndex: Copy + Clone + Debug;
56 
57     /// Returns a location representing the "start of the input".
start_location(&self) -> Self::Location58     fn start_location(&self) -> Self::Location;
59 
60     /// Returns the initial state.
start_state(&self) -> Self::StateIndex61     fn start_state(&self) -> Self::StateIndex;
62 
63     /// Converts the user's tokens into an internal index; this index
64     /// is then used to index into actions and the like. When using an
65     /// internal tokenizer, these indices are directly produced. When
66     /// using an **external** tokenier, however, this function matches
67     /// against the patterns given by the user: it is fallible
68     /// therefore as these patterns may not be exhaustive. If a token
69     /// value is found that doesn't match any of the patterns the user
70     /// supplied, then this function returns `None`, which is
71     /// translated into a parse error by LALRPOP ("unrecognized
72     /// token").
token_to_index(&self, token: &Self::Token) -> Option<Self::TokenIndex>73     fn token_to_index(&self, token: &Self::Token) -> Option<Self::TokenIndex>;
74 
75     /// Given the top-most state and the pending terminal, returns an
76     /// action. This can be either SHIFT(state), REDUCE(action), or
77     /// ERROR.
action(&self, state: Self::StateIndex, token_index: Self::TokenIndex) -> Self::Action78     fn action(&self, state: Self::StateIndex, token_index: Self::TokenIndex) -> Self::Action;
79 
80     /// Returns the action to take if an error occurs in the given
81     /// state. This function is the same as the ordinary `action`,
82     /// except that it applies not to the user's terminals but to the
83     /// "special terminal" `!`.
error_action(&self, state: Self::StateIndex) -> Self::Action84     fn error_action(&self, state: Self::StateIndex) -> Self::Action;
85 
86     /// Action to take if EOF occurs in the given state. This function
87     /// is the same as the ordinary `action`, except that it applies
88     /// not to the user's terminals but to the "special terminal" `$`.
eof_action(&self, state: Self::StateIndex) -> Self::Action89     fn eof_action(&self, state: Self::StateIndex) -> Self::Action;
90 
91     /// If we reduce to a nonterminal in the given state, what state
92     /// do we go to? This is infallible due to the nature of LR(1)
93     /// grammars.
goto(&self, state: Self::StateIndex, nt: Self::NonterminalIndex) -> Self::StateIndex94     fn goto(&self, state: Self::StateIndex, nt: Self::NonterminalIndex) -> Self::StateIndex;
95 
96     /// "Upcast" a terminal into a symbol so we can push it onto the
97     /// parser stack.
token_to_symbol(&self, token_index: Self::TokenIndex, token: Self::Token) -> Self::Symbol98     fn token_to_symbol(&self, token_index: Self::TokenIndex, token: Self::Token) -> Self::Symbol;
99 
100     /// Returns the expected tokens in a given state. This is used for
101     /// error reporting.
expected_tokens(&self, state: Self::StateIndex) -> Vec<String>102     fn expected_tokens(&self, state: Self::StateIndex) -> Vec<String>;
103 
104     /// True if this grammar supports error recovery.
uses_error_recovery(&self) -> bool105     fn uses_error_recovery(&self) -> bool;
106 
107     /// Given error information, creates an error recovery symbol that
108     /// we push onto the stack (and supply to user actions).
error_recovery_symbol(&self, recovery: ErrorRecovery<Self>) -> Self::Symbol109     fn error_recovery_symbol(&self, recovery: ErrorRecovery<Self>) -> Self::Symbol;
110 
111     /// Execute a reduction in the given state: that is, execute user
112     /// code. The start location indicates the "starting point" of the
113     /// current lookahead that is triggering the reduction (it is
114     /// `None` for EOF).
115     ///
116     /// The `states` and `symbols` vectors represent the internal
117     /// state machine vectors; they are given to `reduce` so that it
118     /// can pop off states that no longer apply (and consume their
119     /// symbols). At the end, it should also push the new state and
120     /// symbol produced.
121     ///
122     /// Returns a `Some` if we reduced the start state and hence
123     /// parsing is complete, or if we encountered an irrecoverable
124     /// error.
125     ///
126     /// FIXME. It would be nice to not have so much logic live in
127     /// reduce.  It should just be given an iterator of popped symbols
128     /// and return the newly produced symbol (or error). We can use
129     /// `simulate_reduce` and our own information to drive the rest,
130     /// right? This would also allow us -- I think -- to extend error
131     /// recovery to cover user-produced errors.
reduce( &mut self, reduce_index: Self::ReduceIndex, start_location: Option<&Self::Location>, states: &mut Vec<Self::StateIndex>, symbols: &mut Vec<SymbolTriple<Self>>, ) -> Option<ParseResult<Self>>132     fn reduce(
133         &mut self,
134         reduce_index: Self::ReduceIndex,
135         start_location: Option<&Self::Location>,
136         states: &mut Vec<Self::StateIndex>,
137         symbols: &mut Vec<SymbolTriple<Self>>,
138     ) -> Option<ParseResult<Self>>;
139 
140     /// Returns information about how many states will be popped
141     /// during a reduction, and what nonterminal would be produced as
142     /// a result.
simulate_reduce(&self, action: Self::ReduceIndex) -> SimulatedReduce<Self>143     fn simulate_reduce(&self, action: Self::ReduceIndex) -> SimulatedReduce<Self>;
144 }
145 
146 pub trait ParserAction<D: ParserDefinition>: Copy + Clone + Debug {
as_shift(self) -> Option<D::StateIndex>147     fn as_shift(self) -> Option<D::StateIndex>;
as_reduce(self) -> Option<D::ReduceIndex>148     fn as_reduce(self) -> Option<D::ReduceIndex>;
is_shift(self) -> bool149     fn is_shift(self) -> bool;
is_reduce(self) -> bool150     fn is_reduce(self) -> bool;
is_error(self) -> bool151     fn is_error(self) -> bool;
152 }
153 
154 pub enum SimulatedReduce<D: ParserDefinition> {
155     Reduce {
156         states_to_pop: usize,
157         nonterminal_produced: D::NonterminalIndex,
158     },
159 
160     // This reduce is the "start" fn, so the parse is done.
161     Accept,
162 }
163 
164 // These aliases are an elaborate hack to get around
165 // the warnings when you define a type alias like `type Foo<D: Trait>`
166 #[doc(hidden)]
167 pub type Location<D> = <D as ParserDefinition>::Location;
168 #[doc(hidden)]
169 pub type Token<D> = <D as ParserDefinition>::Token;
170 #[doc(hidden)]
171 pub type Error<D> = <D as ParserDefinition>::Error;
172 #[doc(hidden)]
173 pub type Success<D> = <D as ParserDefinition>::Success;
174 #[doc(hidden)]
175 pub type Symbol<D> = <D as ParserDefinition>::Symbol;
176 
177 pub type ParseError<D> = ::ParseError<Location<D>, Token<D>, Error<D>>;
178 pub type ParseResult<D> = Result<Success<D>, ParseError<D>>;
179 pub type TokenTriple<D> = (Location<D>, Token<D>, Location<D>);
180 pub type SymbolTriple<D> = (Location<D>, Symbol<D>, Location<D>);
181 pub type ErrorRecovery<D> = ::ErrorRecovery<Location<D>, Token<D>, Error<D>>;
182 
183 pub struct Parser<D, I>
184 where
185     D: ParserDefinition,
186     I: Iterator<Item = Result<TokenTriple<D>, ParseError<D>>>,
187 {
188     definition: D,
189     tokens: I,
190     states: Vec<D::StateIndex>,
191     symbols: Vec<SymbolTriple<D>>,
192     last_location: D::Location,
193 }
194 
195 enum NextToken<D: ParserDefinition> {
196     FoundToken(TokenTriple<D>, D::TokenIndex),
197     EOF,
198     Done(ParseResult<D>),
199 }
200 
201 impl<D, I> Parser<D, I>
202 where
203     D: ParserDefinition,
204     I: Iterator<Item = Result<TokenTriple<D>, ParseError<D>>>,
205 {
drive(definition: D, tokens: I) -> ParseResult<D>206     pub fn drive(definition: D, tokens: I) -> ParseResult<D> {
207         let last_location = definition.start_location();
208         let start_state = definition.start_state();
209         Parser {
210             definition,
211             tokens,
212             states: vec![start_state],
213             symbols: vec![],
214             last_location,
215         }.parse()
216     }
217 
top_state(&self) -> D::StateIndex218     fn top_state(&self) -> D::StateIndex {
219         *self.states.last().unwrap()
220     }
221 
parse(&mut self) -> ParseResult<D>222     fn parse(&mut self) -> ParseResult<D> {
223         // Outer loop: each time we continue around this loop, we
224         // shift a new token from the input. We break from the loop
225         // when the end of the input is reached (we return early if an
226         // error occurs).
227         'shift: loop {
228             let (mut lookahead, mut token_index) = match self.next_token() {
229                 NextToken::FoundToken(l, i) => (l, i),
230                 NextToken::EOF => return self.parse_eof(),
231                 NextToken::Done(e) => return e,
232             };
233 
234             debug!("+ SHIFT: {:?}", lookahead);
235 
236             debug!("\\ token_index: {:?}", token_index);
237 
238             'inner: loop {
239                 let top_state = self.top_state();
240                 let action = self.definition.action(top_state, token_index);
241                 debug!("\\ action: {:?}", action);
242 
243                 if let Some(target_state) = action.as_shift() {
244                     debug!("\\ shift to: {:?}", target_state);
245 
246                     // Shift and transition to state `action - 1`
247                     let symbol = self.definition.token_to_symbol(token_index, lookahead.1);
248                     self.states.push(target_state);
249                     self.symbols.push((lookahead.0, symbol, lookahead.2));
250                     continue 'shift;
251                 } else if let Some(reduce_index) = action.as_reduce() {
252                     debug!("\\ reduce to: {:?}", reduce_index);
253 
254                     if let Some(r) = self.definition.reduce(
255                         reduce_index,
256                         Some(&lookahead.0),
257                         &mut self.states,
258                         &mut self.symbols,
259                     ) {
260                         return match r {
261                             // we reached eof, but still have lookahead
262                             Ok(_) => Err(::ParseError::ExtraToken { token: lookahead }),
263                             Err(e) => Err(e),
264                         };
265                     }
266                 } else {
267                     debug!("\\ error -- initiating error recovery!");
268 
269                     match self.error_recovery(Some(lookahead), Some(token_index)) {
270                         NextToken::FoundToken(l, i) => {
271                             lookahead = l;
272                             token_index = i;
273                             continue 'inner;
274                         }
275                         NextToken::EOF => return self.parse_eof(),
276                         NextToken::Done(e) => return e,
277                     }
278                 }
279             }
280         }
281     }
282 
283     /// Invoked when we have no more tokens to consume.
parse_eof(&mut self) -> ParseResult<D>284     fn parse_eof(&mut self) -> ParseResult<D> {
285         loop {
286             let top_state = self.top_state();
287             let action = self.definition.eof_action(top_state);
288             if let Some(reduce_index) = action.as_reduce() {
289                 if let Some(result) =
290                     self.definition
291                         .reduce(reduce_index, None, &mut self.states, &mut self.symbols)
292                 {
293                     return result;
294                 }
295             } else {
296                 match self.error_recovery(None, None) {
297                     NextToken::FoundToken(..) => panic!("cannot find token at EOF"),
298                     NextToken::Done(e) => return e,
299                     NextToken::EOF => continue,
300                 }
301             }
302         }
303     }
304 
error_recovery( &mut self, mut opt_lookahead: Option<TokenTriple<D>>, mut opt_token_index: Option<D::TokenIndex>, ) -> NextToken<D>305     fn error_recovery(
306         &mut self,
307         mut opt_lookahead: Option<TokenTriple<D>>,
308         mut opt_token_index: Option<D::TokenIndex>,
309     ) -> NextToken<D> {
310         debug!(
311             "\\+ error_recovery(opt_lookahead={:?}, opt_token_index={:?})",
312             opt_lookahead,
313             opt_token_index,
314         );
315 
316         if !self.definition.uses_error_recovery() {
317             debug!("\\ error -- no error recovery!");
318 
319             return NextToken::Done(Err(self.unrecognized_token_error(
320                 opt_lookahead,
321                 self.top_state(),
322             )));
323         }
324 
325         let error = self.unrecognized_token_error(opt_lookahead.clone(), self.top_state());
326 
327         let mut dropped_tokens = vec![];
328 
329         // We are going to insert ERROR into the lookahead. So, first,
330         // perform all reductions from current state triggered by having
331         // ERROR in the lookahead.
332         loop {
333             let state = self.top_state();
334             let action = self.definition.error_action(state);
335             if let Some(reduce_index) = action.as_reduce() {
336                 debug!("\\\\ reducing: {:?}", reduce_index);
337 
338                 if let Some(result) =
339                     self.reduce(reduce_index, opt_lookahead.as_ref().map(|l| &l.0))
340                 {
341                     debug!("\\\\ reduced to a result");
342 
343                     return NextToken::Done(result);
344                 }
345             } else {
346                 break;
347             }
348         }
349 
350         // Now try to find the recovery state.
351         let states_len = self.states.len();
352         let top = 'find_state: loop {
353             // Go backwards through the states...
354             debug!(
355                 "\\\\+ error_recovery: find_state loop, {:?} states = {:?}",
356                 self.states.len(),
357                 self.states,
358             );
359 
360             for top in (0..states_len).rev() {
361                 let state = self.states[top];
362                 debug!("\\\\\\ top = {:?}, state = {:?}", top, state);
363 
364                 // ...fetch action for error token...
365                 let action = self.definition.error_action(state);
366                 debug!("\\\\\\ action = {:?}", action);
367                 if let Some(error_state) = action.as_shift() {
368                     // If action is a shift that takes us into `error_state`,
369                     // and `error_state` can accept this lookahead, we are done.
370                     if self.accepts(error_state, &self.states[..top + 1], opt_token_index) {
371                         debug!("\\\\\\ accepted!");
372                         break 'find_state top;
373                     }
374                 } else {
375                     // ...else, if action is error or reduce, go to next state.
376                     continue;
377                 }
378             }
379 
380             // Otherwise, if we couldn't find a state that would --
381             // after shifting the error token -- accept the lookahead,
382             // then drop the lookahead and advance to next token in
383             // the input.
384             match opt_lookahead.take() {
385                 // If the lookahead is EOF, we can't drop any more
386                 // tokens, abort error recovery and just report the
387                 // original error (it might be nice if we would
388                 // propagate back the dropped tokens, though).
389                 None => {
390                     debug!("\\\\\\ no more lookahead, report error");
391                     return NextToken::Done(Err(error));
392                 }
393 
394                 // Else, drop the current token and shift to the
395                 // next. If there is a next token, we will `continue`
396                 // to the start of the `'find_state` loop.
397                 Some(lookahead) => {
398                     debug!("\\\\\\ dropping lookahead token");
399 
400                     dropped_tokens.push(lookahead);
401                     match self.next_token() {
402                         NextToken::FoundToken(next_lookahead, next_token_index) => {
403                             opt_lookahead = Some(next_lookahead);
404                             opt_token_index = Some(next_token_index);
405                         }
406                         NextToken::EOF => {
407                             debug!("\\\\\\ reached EOF");
408                             opt_lookahead = None;
409                             opt_token_index = None;
410                         }
411                         NextToken::Done(e) => {
412                             debug!("\\\\\\ no more tokens");
413                             return NextToken::Done(e);
414                         }
415                     }
416                 }
417             }
418         };
419 
420         // If we get here, we are ready to push the error recovery state.
421 
422         // We have to compute the span for the error recovery
423         // token. We do this first, before we pop any symbols off the
424         // stack. There are several possibilities, in order of
425         // preference.
426         //
427         // For the **start** of the message, we prefer to use the start of any
428         // popped states. This represents parts of the input we had consumed but
429         // had to roll back and ignore.
430         //
431         // Example:
432         //
433         //       a + (b + /)
434         //              ^ start point is here, since this `+` will be popped off
435         //
436         // If there are no popped states, but there *are* dropped tokens, we can use
437         // the start of those.
438         //
439         // Example:
440         //
441         //       a + (b + c e)
442         //                  ^ start point would be here
443         //
444         // Finally, if there are no popped states *nor* dropped tokens, we can use
445         // the end of the top-most state.
446 
447         let start = if let Some(popped_sym) = self.symbols.get(top) {
448             popped_sym.0.clone()
449         } else if let Some(dropped_token) = dropped_tokens.first() {
450             dropped_token.0.clone()
451         } else if top > 0 {
452             self.symbols[top - 1].2.clone()
453         } else {
454             self.definition.start_location()
455         };
456 
457         // For the end span, here are the possibilities:
458         //
459         // We prefer to use the end of the last dropped token.
460         //
461         // Examples:
462         //
463         //       a + (b + /)
464         //              ---
465         //       a + (b c)
466         //              -
467         //
468         // But, if there are no dropped tokens, we will use the end of the popped states,
469         // if any:
470         //
471         //       a + /
472         //         -
473         //
474         // If there are neither dropped tokens *or* popped states,
475         // then the user is simulating insertion of an operator. In
476         // this case, we prefer the start of the lookahead, but
477         // fallback to the start if we are at EOF.
478         //
479         // Examples:
480         //
481         //       a + (b c)
482         //             -
483 
484         let end = if let Some(dropped_token) = dropped_tokens.last() {
485             dropped_token.2.clone()
486         } else if states_len - 1 > top {
487             self.symbols.last().unwrap().2.clone()
488         } else if let Some(lookahead) = opt_lookahead.as_ref() {
489             lookahead.0.clone()
490         } else {
491             start.clone()
492         };
493 
494         self.states.truncate(top + 1);
495         self.symbols.truncate(top);
496 
497         let recover_state = self.states[top];
498         let error_action = self.definition.error_action(recover_state);
499         let error_state = error_action.as_shift().unwrap();
500         self.states.push(error_state);
501         let recovery = self.definition.error_recovery_symbol(::ErrorRecovery {
502             error: error,
503             dropped_tokens: dropped_tokens,
504         });
505         self.symbols.push((start, recovery, end));
506 
507         match (opt_lookahead, opt_token_index) {
508             (Some(l), Some(i)) => NextToken::FoundToken(l, i),
509             (None, None) => NextToken::EOF,
510             (l, i) => panic!("lookahead and token_index mismatched: {:?}, {:?}", l, i),
511         }
512     }
513 
514     /// The `accepts` function has the job of figuring out whether the
515     /// given error state would "accept" the given lookahead. We
516     /// basically trace through the LR automaton looking for one of
517     /// two outcomes:
518     ///
519     /// - the lookahead is eventually shifted
520     /// - we reduce to the end state successfully (in the case of EOF).
521     ///
522     /// If we used the pure LR(1) algorithm, we wouldn't need this
523     /// function, because we would be guaranteed to error immediately
524     /// (and not after some number of reductions). But with an LALR
525     /// (or Lane Table) generated automaton, it is possible to reduce
526     /// some number of times before encountering an error. Failing to
527     /// take this into account can lead error recovery into an
528     /// infinite loop (see the `error_recovery_lalr_loop` test) or
529     /// produce crappy results (see `error_recovery_lock_in`).
accepts( &self, error_state: D::StateIndex, states: &[D::StateIndex], opt_token_index: Option<D::TokenIndex>, ) -> bool530     fn accepts(
531         &self,
532         error_state: D::StateIndex,
533         states: &[D::StateIndex],
534         opt_token_index: Option<D::TokenIndex>,
535     ) -> bool {
536         debug!(
537             "\\\\\\+ accepts(error_state={:?}, states={:?}, opt_token_index={:?})",
538             error_state,
539             states,
540             opt_token_index,
541         );
542 
543         let mut states = states.to_vec();
544         states.push(error_state);
545         loop {
546             let mut states_len = states.len();
547             let top = states[states_len - 1];
548             let action = match opt_token_index {
549                 None => self.definition.eof_action(top),
550                 Some(i) => self.definition.action(top, i),
551             };
552 
553             // If we encounter an error action, we do **not** accept.
554             if action.is_error() {
555                 debug!("\\\\\\\\ accepts: error");
556                 return false;
557             }
558 
559             // If we encounter a reduce action, we need to simulate its
560             // effect on the state stack.
561             if let Some(reduce_action) = action.as_reduce() {
562                 match self.definition.simulate_reduce(reduce_action) {
563                     SimulatedReduce::Reduce {
564                         states_to_pop,
565                         nonterminal_produced,
566                     } => {
567                         states_len -= states_to_pop;
568                         states.truncate(states_len);
569                         let top = states[states_len - 1];
570                         let next_state = self.definition.goto(top, nonterminal_produced);
571                         states.push(next_state);
572                     }
573 
574                     SimulatedReduce::Accept => {
575                         debug!("\\\\\\\\ accepts: reduce accepts!");
576                         return true;
577                     }
578                 }
579             } else {
580                 // If we encounter a shift action, we DO accept.
581                 debug!("\\\\\\\\ accepts: shift accepts!");
582                 assert!(action.is_shift());
583                 return true;
584             }
585         }
586     }
587 
reduce( &mut self, action: D::ReduceIndex, lookahead_start: Option<&D::Location>, ) -> Option<ParseResult<D>>588     fn reduce(
589         &mut self,
590         action: D::ReduceIndex,
591         lookahead_start: Option<&D::Location>,
592     ) -> Option<ParseResult<D>> {
593         self.definition
594             .reduce(action, lookahead_start, &mut self.states, &mut self.symbols)
595     }
596 
unrecognized_token_error( &self, token: Option<TokenTriple<D>>, top_state: D::StateIndex, ) -> ParseError<D>597     fn unrecognized_token_error(
598         &self,
599         token: Option<TokenTriple<D>>,
600         top_state: D::StateIndex,
601     ) -> ParseError<D> {
602         ::ParseError::UnrecognizedToken {
603             token: token,
604             expected: self.definition.expected_tokens(top_state),
605         }
606     }
607 
608     /// Consume the next token from the input and classify it into a
609     /// token index. Classification can fail with an error. If there
610     /// are no more tokens, signal EOF.
next_token(&mut self) -> NextToken<D>611     fn next_token(&mut self) -> NextToken<D> {
612         let token = match self.tokens.next() {
613             Some(Ok(v)) => v,
614             Some(Err(e)) => return NextToken::Done(Err(e)),
615             None => return NextToken::EOF,
616         };
617 
618         self.last_location = token.2.clone();
619 
620         let token_index = match self.definition.token_to_index(&token.1) {
621             Some(i) => i,
622             None => {
623                 return NextToken::Done(Err(
624                     self.unrecognized_token_error(Some(token), self.top_state())
625                 ))
626             }
627         };
628 
629         NextToken::FoundToken(token, token_index)
630     }
631 }
632 
633 /// In LALRPOP generated rules, we actually use `i32`, `i16`, or `i8`
634 /// to represent all of the various indices (we use the smallest one
635 /// that will fit). So implement `ParserAction` for each of those.
636 macro_rules! integral_indices {
637     ($t:ty) => {
638         impl<D: ParserDefinition<StateIndex = $t, ReduceIndex = $t>> ParserAction<D> for $t {
639             fn as_shift(self) -> Option<D::StateIndex> {
640                 if self > 0 {
641                     Some(self - 1)
642                 } else {
643                     None
644                 }
645             }
646 
647             fn as_reduce(self) -> Option<D::ReduceIndex> {
648                 if self < 0 {
649                     Some(-(self + 1))
650                 } else {
651                     None
652                 }
653             }
654 
655             fn is_shift(self) -> bool {
656                 self > 0
657             }
658 
659             fn is_reduce(self) -> bool {
660                 self < 0
661             }
662 
663             fn is_error(self) -> bool {
664                 self == 0
665             }
666         }
667     };
668 }
669 
670 integral_indices!(i32);
671 integral_indices!(i16);
672 integral_indices!(i8);
673