/// Generated by rustemo. Do not edit manually!
use std::fmt::Debug;
use std::hash::Hash;
use rustemo::{
    Result, Input as InputT, Lexer, Token, TokenRecognizer as TokenRecognizerT, Parser,
    ParserDefinition, State as StateT, Builder,
};
use rustemo::regex::Regex;
use rustemo::once_cell::sync::Lazy;
use rustemo::StringLexer;
use rustemo::LRBuilder;
use super::calculator_actions;
use rustemo::{LRParser, LRContext};
use rustemo::Action::{self, Shift, Reduce, Accept};
#[allow(unused_imports)]
use rustemo::debug::{log, logn};
#[allow(unused_imports)]
#[cfg(debug_assertions)]
use rustemo::colors::*;
#[allow(unused_imports)]
#[cfg(debug_assertions)]
use rustemo::yansi::Paint;
pub type Input = str;
const STATE_COUNT: usize = 11usize;
const MAX_RECOGNIZERS: usize = 5usize;
#[allow(dead_code)]
const TERMINAL_COUNT: usize = 6usize;
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TokenKind {
    #[default]
    STOP,
    Number,
    Plus,
    Minus,
    Mul,
    Div,
}
use TokenKind as TK;
impl From<TokenKind> for usize {
    fn from(t: TokenKind) -> Self {
        t as usize
    }
}
#[allow(clippy::enum_variant_names)]
#[derive(Clone, Copy, PartialEq)]
pub enum ProdKind {
    EP1,
    EP2,
    EP3,
    EP4,
    EP5,
}
use ProdKind as PK;
impl std::fmt::Debug for ProdKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let name = match self {
            ProdKind::EP1 => "E: E Plus E",
            ProdKind::EP2 => "E: E Minus E",
            ProdKind::EP3 => "E: E Mul E",
            ProdKind::EP4 => "E: E Div E",
            ProdKind::EP5 => "E: Number",
        };
        write!(f, "{name}")
    }
}
#[allow(clippy::upper_case_acronyms)]
#[allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub enum NonTermKind {
    EMPTY,
    AUG,
    E,
}
impl From<ProdKind> for NonTermKind {
    fn from(prod: ProdKind) -> Self {
        match prod {
            ProdKind::EP1 => NonTermKind::E,
            ProdKind::EP2 => NonTermKind::E,
            ProdKind::EP3 => NonTermKind::E,
            ProdKind::EP4 => NonTermKind::E,
            ProdKind::EP5 => NonTermKind::E,
        }
    }
}
#[allow(clippy::enum_variant_names)]
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum State {
    #[default]
    AUGS0,
    NumberS1,
    ES2,
    PlusS3,
    MinusS4,
    MulS5,
    DivS6,
    ES7,
    ES8,
    ES9,
    ES10,
}
impl StateT for State {
    fn default_layout() -> Option<Self> {
        None
    }
}
impl From<State> for usize {
    fn from(s: State) -> Self {
        s as usize
    }
}
impl std::fmt::Debug for State {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let name = match self {
            State::AUGS0 => "0:AUG",
            State::NumberS1 => "1:Number",
            State::ES2 => "2:E",
            State::PlusS3 => "3:Plus",
            State::MinusS4 => "4:Minus",
            State::MulS5 => "5:Mul",
            State::DivS6 => "6:Div",
            State::ES7 => "7:E",
            State::ES8 => "8:E",
            State::ES9 => "9:E",
            State::ES10 => "10:E",
        };
        write!(f, "{name}")
    }
}
#[derive(Debug)]
pub enum Symbol {
    Terminal(Terminal),
    NonTerminal(NonTerminal),
}
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug)]
pub enum Terminal {
    Number(calculator_actions::Number),
    Plus,
    Minus,
    Mul,
    Div,
}
#[derive(Debug)]
pub enum NonTerminal {
    E(calculator_actions::E),
}
type ActionFn = fn(token: TokenKind) -> Vec<Action<State, ProdKind>>;
pub struct CalculatorParserDefinition {
    actions: [ActionFn; STATE_COUNT],
    gotos: [fn(nonterm: NonTermKind) -> State; STATE_COUNT],
    token_kinds: [[Option<(TokenKind, bool)>; MAX_RECOGNIZERS]; STATE_COUNT],
}
fn action_aug_s0(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::Number => Vec::from(&[Shift(State::NumberS1)]),
        _ => vec![],
    }
}
fn action_number_s1(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::STOP => Vec::from(&[Reduce(PK::EP5, 1usize)]),
        TK::Plus => Vec::from(&[Reduce(PK::EP5, 1usize)]),
        TK::Minus => Vec::from(&[Reduce(PK::EP5, 1usize)]),
        TK::Mul => Vec::from(&[Reduce(PK::EP5, 1usize)]),
        TK::Div => Vec::from(&[Reduce(PK::EP5, 1usize)]),
        _ => vec![],
    }
}
fn action_e_s2(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::STOP => Vec::from(&[Accept]),
        TK::Plus => Vec::from(&[Shift(State::PlusS3)]),
        TK::Minus => Vec::from(&[Shift(State::MinusS4)]),
        TK::Mul => Vec::from(&[Shift(State::MulS5)]),
        TK::Div => Vec::from(&[Shift(State::DivS6)]),
        _ => vec![],
    }
}
fn action_plus_s3(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::Number => Vec::from(&[Shift(State::NumberS1)]),
        _ => vec![],
    }
}
fn action_minus_s4(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::Number => Vec::from(&[Shift(State::NumberS1)]),
        _ => vec![],
    }
}
fn action_mul_s5(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::Number => Vec::from(&[Shift(State::NumberS1)]),
        _ => vec![],
    }
}
fn action_div_s6(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::Number => Vec::from(&[Shift(State::NumberS1)]),
        _ => vec![],
    }
}
fn action_e_s7(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::STOP => Vec::from(&[Reduce(PK::EP1, 3usize)]),
        TK::Plus => Vec::from(&[Reduce(PK::EP1, 3usize)]),
        TK::Minus => Vec::from(&[Reduce(PK::EP1, 3usize)]),
        TK::Mul => Vec::from(&[Shift(State::MulS5)]),
        TK::Div => Vec::from(&[Shift(State::DivS6)]),
        _ => vec![],
    }
}
fn action_e_s8(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::STOP => Vec::from(&[Reduce(PK::EP2, 3usize)]),
        TK::Plus => Vec::from(&[Reduce(PK::EP2, 3usize)]),
        TK::Minus => Vec::from(&[Reduce(PK::EP2, 3usize)]),
        TK::Mul => Vec::from(&[Shift(State::MulS5)]),
        TK::Div => Vec::from(&[Shift(State::DivS6)]),
        _ => vec![],
    }
}
fn action_e_s9(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::STOP => Vec::from(&[Reduce(PK::EP3, 3usize)]),
        TK::Plus => Vec::from(&[Reduce(PK::EP3, 3usize)]),
        TK::Minus => Vec::from(&[Reduce(PK::EP3, 3usize)]),
        TK::Mul => Vec::from(&[Reduce(PK::EP3, 3usize)]),
        TK::Div => Vec::from(&[Reduce(PK::EP3, 3usize)]),
        _ => vec![],
    }
}
fn action_e_s10(token_kind: TokenKind) -> Vec<Action<State, ProdKind>> {
    match token_kind {
        TK::STOP => Vec::from(&[Reduce(PK::EP4, 3usize)]),
        TK::Plus => Vec::from(&[Reduce(PK::EP4, 3usize)]),
        TK::Minus => Vec::from(&[Reduce(PK::EP4, 3usize)]),
        TK::Mul => Vec::from(&[Reduce(PK::EP4, 3usize)]),
        TK::Div => Vec::from(&[Reduce(PK::EP4, 3usize)]),
        _ => vec![],
    }
}
fn goto_aug_s0(nonterm_kind: NonTermKind) -> State {
    match nonterm_kind {
        NonTermKind::E => State::ES2,
        _ => {
            panic!(
                "Invalid terminal kind ({nonterm_kind:?}) for GOTO state ({:?}).",
                State::AUGS0
            )
        }
    }
}
fn goto_plus_s3(nonterm_kind: NonTermKind) -> State {
    match nonterm_kind {
        NonTermKind::E => State::ES7,
        _ => {
            panic!(
                "Invalid terminal kind ({nonterm_kind:?}) for GOTO state ({:?}).",
                State::PlusS3
            )
        }
    }
}
fn goto_minus_s4(nonterm_kind: NonTermKind) -> State {
    match nonterm_kind {
        NonTermKind::E => State::ES8,
        _ => {
            panic!(
                "Invalid terminal kind ({nonterm_kind:?}) for GOTO state ({:?}).",
                State::MinusS4
            )
        }
    }
}
fn goto_mul_s5(nonterm_kind: NonTermKind) -> State {
    match nonterm_kind {
        NonTermKind::E => State::ES9,
        _ => {
            panic!(
                "Invalid terminal kind ({nonterm_kind:?}) for GOTO state ({:?}).",
                State::MulS5
            )
        }
    }
}
fn goto_div_s6(nonterm_kind: NonTermKind) -> State {
    match nonterm_kind {
        NonTermKind::E => State::ES10,
        _ => {
            panic!(
                "Invalid terminal kind ({nonterm_kind:?}) for GOTO state ({:?}).",
                State::DivS6
            )
        }
    }
}
fn goto_invalid(_nonterm_kind: NonTermKind) -> State {
    panic!("Invalid GOTO entry!");
}
pub(crate) static PARSER_DEFINITION: CalculatorParserDefinition = CalculatorParserDefinition {
    actions: [
        action_aug_s0,
        action_number_s1,
        action_e_s2,
        action_plus_s3,
        action_minus_s4,
        action_mul_s5,
        action_div_s6,
        action_e_s7,
        action_e_s8,
        action_e_s9,
        action_e_s10,
    ],
    gotos: [
        goto_aug_s0,
        goto_invalid,
        goto_invalid,
        goto_plus_s3,
        goto_minus_s4,
        goto_mul_s5,
        goto_div_s6,
        goto_invalid,
        goto_invalid,
        goto_invalid,
        goto_invalid,
    ],
    token_kinds: [
        [Some((TK::Number, false)), None, None, None, None],
        [
            Some((TK::STOP, true)),
            Some((TK::Plus, true)),
            Some((TK::Minus, true)),
            Some((TK::Mul, true)),
            Some((TK::Div, true)),
        ],
        [
            Some((TK::STOP, true)),
            Some((TK::Plus, true)),
            Some((TK::Minus, true)),
            Some((TK::Mul, true)),
            Some((TK::Div, true)),
        ],
        [Some((TK::Number, false)), None, None, None, None],
        [Some((TK::Number, false)), None, None, None, None],
        [Some((TK::Number, false)), None, None, None, None],
        [Some((TK::Number, false)), None, None, None, None],
        [
            Some((TK::STOP, true)),
            Some((TK::Plus, true)),
            Some((TK::Minus, true)),
            Some((TK::Mul, true)),
            Some((TK::Div, true)),
        ],
        [
            Some((TK::STOP, true)),
            Some((TK::Plus, true)),
            Some((TK::Minus, true)),
            Some((TK::Mul, true)),
            Some((TK::Div, true)),
        ],
        [
            Some((TK::STOP, true)),
            Some((TK::Plus, true)),
            Some((TK::Minus, true)),
            Some((TK::Mul, true)),
            Some((TK::Div, true)),
        ],
        [
            Some((TK::STOP, true)),
            Some((TK::Plus, true)),
            Some((TK::Minus, true)),
            Some((TK::Mul, true)),
            Some((TK::Div, true)),
        ],
    ],
};
impl ParserDefinition<State, ProdKind, TokenKind, NonTermKind>
for CalculatorParserDefinition {
    fn actions(&self, state: State, token: TokenKind) -> Vec<Action<State, ProdKind>> {
        PARSER_DEFINITION.actions[state as usize](token)
    }
    fn goto(&self, state: State, nonterm: NonTermKind) -> State {
        PARSER_DEFINITION.gotos[state as usize](nonterm)
    }
    fn expected_token_kinds(&self, state: State) -> Vec<(TokenKind, bool)> {
        PARSER_DEFINITION.token_kinds[state as usize].iter().map_while(|t| *t).collect()
    }
    fn longest_match() -> bool {
        true
    }
    fn grammar_order() -> bool {
        true
    }
}
pub(crate) type Context<'i, I> = LRContext<'i, I, State, TokenKind>;
pub struct CalculatorParser<
    'i,
    I: InputT + ?Sized,
    L: Lexer<'i, Context<'i, I>, State, TokenKind, Input = I>,
    B,
>(
    LRParser<
        'i,
        Context<'i, I>,
        State,
        ProdKind,
        TokenKind,
        NonTermKind,
        CalculatorParserDefinition,
        L,
        B,
        I,
    >,
);
#[allow(dead_code)]
impl<
    'i,
> CalculatorParser<
    'i,
    Input,
    StringLexer<Context<'i, Input>, State, TokenKind, TokenRecognizer, TERMINAL_COUNT>,
    DefaultBuilder,
> {
    pub fn new() -> Self {
        Self(
            LRParser::new(
                &PARSER_DEFINITION,
                State::default(),
                false,
                false,
                StringLexer::new(true, &RECOGNIZERS),
                DefaultBuilder::new(),
            ),
        )
    }
}
#[allow(dead_code)]
impl<'i, I, L, B> Parser<'i, I, Context<'i, I>, State, TokenKind>
for CalculatorParser<'i, I, L, B>
where
    I: InputT + ?Sized + Debug,
    L: Lexer<'i, Context<'i, I>, State, TokenKind, Input = I>,
    B: LRBuilder<'i, I, Context<'i, I>, State, ProdKind, TokenKind>,
{
    type Output = B::Output;
    fn parse(&self, input: &'i I) -> Result<Self::Output> {
        self.0.parse(input)
    }
    fn parse_with_context(
        &self,
        context: &mut Context<'i, I>,
        input: &'i I,
    ) -> Result<Self::Output> {
        self.0.parse_with_context(context, input)
    }
    fn parse_file<'a, F: AsRef<std::path::Path>>(
        &'a mut self,
        file: F,
    ) -> Result<Self::Output>
    where
        'a: 'i,
    {
        self.0.parse_file(file)
    }
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum Recognizer {
    Stop,
    StrMatch(&'static str),
    RegexMatch(Lazy<Regex>),
}
#[allow(dead_code)]
#[derive(Debug)]
pub struct TokenRecognizer(TokenKind, Recognizer);
impl<'i> TokenRecognizerT<'i> for TokenRecognizer {
    fn recognize(&self, input: &'i str) -> Option<&'i str> {
        match &self {
            #[allow(unused_variables)]
            TokenRecognizer(token_kind, Recognizer::StrMatch(s)) => {
                logn!("{} {:?} -- ", "    Recognizing".paint(LOG), token_kind);
                if input.starts_with(s) {
                    log!("{}", "recognized".paint(LOG_BOLD));
                    Some(s)
                } else {
                    log!("{}", "not recognized".paint(WARN));
                    None
                }
            }
            #[allow(unused_variables)]
            TokenRecognizer(token_kind, Recognizer::RegexMatch(r)) => {
                logn!("{} {:?} -- ", "    Recognizing".paint(LOG), token_kind);
                let match_str = r.find(input);
                match match_str {
                    Some(x) => {
                        let x_str = x.as_str();
                        log!("{} '{}'", "recognized".paint(LOG_BOLD), x_str);
                        Some(x_str)
                    }
                    _ => {
                        log!("{}", "not recognized".paint(WARN));
                        None
                    }
                }
            }
            TokenRecognizer(_, Recognizer::Stop) => {
                logn!("{} STOP -- ", "    Recognizing".paint(LOG));
                if input.is_empty() {
                    log!("{}", "recognized".paint(LOG_BOLD));
                    Some("")
                } else {
                    log!("{}", "not recognized".paint(WARN));
                    None
                }
            }
        }
    }
}
pub(crate) static RECOGNIZERS: [TokenRecognizer; TERMINAL_COUNT] = [
    TokenRecognizer(TokenKind::STOP, Recognizer::Stop),
    TokenRecognizer(
        TokenKind::Number,
        Recognizer::RegexMatch(
            Lazy::new(|| { Regex::new(concat!("^", "\\d+(\\.\\d+)?")).unwrap() }),
        ),
    ),
    TokenRecognizer(TokenKind::Plus, Recognizer::StrMatch("+")),
    TokenRecognizer(TokenKind::Minus, Recognizer::StrMatch("-")),
    TokenRecognizer(TokenKind::Mul, Recognizer::StrMatch("*")),
    TokenRecognizer(TokenKind::Div, Recognizer::StrMatch("/")),
];
pub struct DefaultBuilder {
    res_stack: Vec<Symbol>,
}
impl DefaultBuilder {
    #[allow(dead_code)]
    pub fn new() -> Self {
        Self { res_stack: vec![] }
    }
}
impl Builder for DefaultBuilder {
    type Output = calculator_actions::E;
    fn get_result(&mut self) -> Self::Output {
        match self.res_stack.pop().unwrap() {
            Symbol::NonTerminal(NonTerminal::E(r)) => r,
            _ => panic!("Invalid result on the parse stack!"),
        }
    }
}
impl<'i> LRBuilder<'i, Input, Context<'i, Input>, State, ProdKind, TokenKind>
for DefaultBuilder {
    #![allow(unused_variables)]
    fn shift_action(
        &mut self,
        context: &Context<'i, Input>,
        token: Token<'i, Input, TokenKind>,
    ) {
        let val = match token.kind {
            TokenKind::STOP => panic!("Cannot shift STOP token!"),
            TokenKind::Number => {
                Terminal::Number(calculator_actions::number(context, token))
            }
            TokenKind::Plus => Terminal::Plus,
            TokenKind::Minus => Terminal::Minus,
            TokenKind::Mul => Terminal::Mul,
            TokenKind::Div => Terminal::Div,
        };
        self.res_stack.push(Symbol::Terminal(val));
    }
    fn reduce_action(
        &mut self,
        context: &Context<'i, Input>,
        prod: ProdKind,
        prod_len: usize,
    ) {
        let prod = match prod {
            ProdKind::EP1 => {
                let mut i = self
                    .res_stack
                    .split_off(self.res_stack.len() - 3usize)
                    .into_iter();
                match (i.next().unwrap(), i.next().unwrap(), i.next().unwrap()) {
                    (
                        Symbol::NonTerminal(NonTerminal::E(p0)),
                        _,
                        Symbol::NonTerminal(NonTerminal::E(p1)),
                    ) => NonTerminal::E(calculator_actions::e_c1(context, p0, p1)),
                    _ => panic!("Invalid symbol parse stack data."),
                }
            }
            ProdKind::EP2 => {
                let mut i = self
                    .res_stack
                    .split_off(self.res_stack.len() - 3usize)
                    .into_iter();
                match (i.next().unwrap(), i.next().unwrap(), i.next().unwrap()) {
                    (
                        Symbol::NonTerminal(NonTerminal::E(p0)),
                        _,
                        Symbol::NonTerminal(NonTerminal::E(p1)),
                    ) => NonTerminal::E(calculator_actions::e_c2(context, p0, p1)),
                    _ => panic!("Invalid symbol parse stack data."),
                }
            }
            ProdKind::EP3 => {
                let mut i = self
                    .res_stack
                    .split_off(self.res_stack.len() - 3usize)
                    .into_iter();
                match (i.next().unwrap(), i.next().unwrap(), i.next().unwrap()) {
                    (
                        Symbol::NonTerminal(NonTerminal::E(p0)),
                        _,
                        Symbol::NonTerminal(NonTerminal::E(p1)),
                    ) => NonTerminal::E(calculator_actions::e_c3(context, p0, p1)),
                    _ => panic!("Invalid symbol parse stack data."),
                }
            }
            ProdKind::EP4 => {
                let mut i = self
                    .res_stack
                    .split_off(self.res_stack.len() - 3usize)
                    .into_iter();
                match (i.next().unwrap(), i.next().unwrap(), i.next().unwrap()) {
                    (
                        Symbol::NonTerminal(NonTerminal::E(p0)),
                        _,
                        Symbol::NonTerminal(NonTerminal::E(p1)),
                    ) => NonTerminal::E(calculator_actions::e_c4(context, p0, p1)),
                    _ => panic!("Invalid symbol parse stack data."),
                }
            }
            ProdKind::EP5 => {
                let mut i = self
                    .res_stack
                    .split_off(self.res_stack.len() - 1usize)
                    .into_iter();
                match i.next().unwrap() {
                    Symbol::Terminal(Terminal::Number(p0)) => {
                        NonTerminal::E(calculator_actions::e_number(context, p0))
                    }
                    _ => panic!("Invalid symbol parse stack data."),
                }
            }
        };
        self.res_stack.push(Symbol::NonTerminal(prod));
    }
}
