// Copyright (c) 2025 Redglyph (@gmail.com). All Rights Reserved.

// =============================================================================================
// Parser for the simplified grammars used in unit tests
// (lexer/parser generated by the build-rtsgen crate)

mod tests;

use std::collections::HashMap;
use std::io::Cursor;
use std::str::FromStr;
use iter_index::IndexerIterator;
use vectree::VecTree;
use lexigram_core::CollectJoin;
use crate::{General, NameFixer, NameTransformer, SymbolTable};
use crate::{TokenId, VarId};
use crate::grammar::{GrNode, GrTree, RuleTreeSet};
use crate::char_reader::CharReader;
use crate::lexer::{Lexer, TokenSpliterator};
use lexigram_core::log::{BufLog, LogStatus, Logger};
use crate::parser::{Parser, Symbol};
use crate::rtsgen::listener_types::*;
use crate::rtsgen::rtsgen_lexer::build_lexer;
use crate::rtsgen::rtsgen_parser::*;

static T_NAME_DICTIONARY: &[(&str, &str)] = &[
    ("+", "Add"), ("-", "Sub"), ("*", "Mul"), ("/", "Div"), ("%", "Percent"), ("++", "Inc"), ("--", "Dec"),
    ("<<", "Shl"), (">>", "Shr"), ("!", "Not"), ("^", "Exp"), ("~", "Tilde"),
    ("&", "And"), ("|", "Or"), ("&&", "And2"), ("||", "Or2"),
    ("=", "Eq"), ("==", "Eq2"), ("<", "Lt"), (">", "Gt"), ("<=", "LtEq"), (">=", "GtEq"), ("!=", "Neq"),
    (":=", "ColonEq"), ("+=", "AddEq"), ("-=", "SubEq"), ("*=", "MulEq"), ("/=", "DivEq"),
    ("(", "LPar"), (")", "RPar"), ("[", "LSBracket"), ("]", "RSBracker"), ("{", "LBracket"), ("}", "RBracket"),
    ("\"", "DQuote"), ("'", "Quote"), ("$", "Dollar"), ("?", "Question"), ("\\", "Backslash"),
    (":", "Colon"), (";", "SemiColon"), (".", "Dot"), (",", "Comma"), ("#", "Sharp"), ("@", "At"), ("´", "Tick"), ("`", "BTick"),
    ("\n", "EOL"), ("\r\n", "WinEOL"), ("\r", "CR"), ("\t", "Tab"), (" ", "Space"), ("\\", "Backslash"), ("\0", "Null"),
    ("->", "Arrow"), ("=>", "DArrow"),
];

pub struct RtsGen<'l, 'p> {
    lexer: Lexer<'l, Cursor<String>>,
    parser: Parser<'p>,
    t_name_dictionary: Option<HashMap<String, String>>,
}

impl RtsGen<'_, '_> {
    pub fn new() -> Self {
        let t_name_dictionary = Some(HashMap::from_iter(T_NAME_DICTIONARY.iter().map(|(a, b)| (a.to_string(), b.to_string()))));
        RtsGen::with_guess_names(t_name_dictionary)
    }

    pub fn with_guess_names(t_name_dictionary: Option<HashMap<String, String>>) -> Self {
        let lexer = build_lexer();
        let parser = build_parser();
        RtsGen { lexer, parser, t_name_dictionary }
    }

    pub fn parse(&mut self, text: String) -> Result<RuleTreeSet<General>, BufLog> {
        const VERBOSE_WRAPPER: bool = false;

        let mut wrapper = Wrapper::new(RGListener::new(self.t_name_dictionary.as_ref()), VERBOSE_WRAPPER);
        let stream = CharReader::new(Cursor::new(text));
        self.lexer.attach_stream(stream);
        let tokens = self.lexer.tokens().split_channel0(|(_tok, ch, text, pos_span)|
            panic!("unexpected channel {ch} while parsing a file at {pos_span}, \"{text}\"")
        );
        let _ = self.parser.parse_stream(&mut wrapper, tokens); // errors are written in the log, so we can dismiss the error here
        let listener = wrapper.give_listener();
        listener.make_rts()
    }
}

impl Default for RtsGen<'_, '_> {
    fn default() -> Self {
        Self::new()
    }
}

// listener implementation

struct RGListener<'a> {
    log: BufLog,
    nt: HashMap<String, VarId>,
    nt_def_order: Vec<VarId>,
    rules: Vec<GrTree>,
    reserved_nt: Vec<VarId>,
    symbol_table: Option<SymbolTable>,
    t: HashMap<String, TokenId>,
    num_t: usize,
    /// terminal information; `(String, Option<String>)` = (token name, optional string if not variable)
    tokens: Vec<(String, Option<String>)>,
    curr: Option<GrTree>,
    curr_name: Option<String>,
    curr_nt: Option<VarId>,
    t_name_dictionary: Option<&'a HashMap<String, String>>,
}

#[derive(Clone, Copy, PartialEq)]
enum IsNew { No, Yes }

trait ToVarId {
    fn to_var_id(self, panic_message: &str) -> VarId;
}

impl ToVarId for usize {
    fn to_var_id(self, panic_message: &str) -> VarId {
        if self < (VarId::MAX as usize) {
            self as VarId
        } else {
            panic!("{panic_message}")
        }
    }
}

impl<'a> RGListener<'a> {
    fn new(t_name_dictionary: Option<&'a HashMap<String, String>>) -> Self {
        RGListener {
            log: BufLog::new(),
            nt: HashMap::new(),
            nt_def_order: Vec::new(),
            rules: Vec::new(),
            reserved_nt: Vec::new(),
            symbol_table: None,
            t: HashMap::new(),
            num_t: 0,
            tokens: Vec::new(),
            curr: None,
            curr_name: None,
            curr_nt: None,
            t_name_dictionary,
        }
    }

    pub fn make_rts(self) -> Result<RuleTreeSet<General>, BufLog> {
        let RGListener { log, rules, symbol_table, .. } = self;
        if log.has_no_errors() {
            let mut rts = RuleTreeSet::<General>::with_log(log);
            rts.set_symbol_table(symbol_table.unwrap());
            rts.set_start(0);
            for (var, rule) in rules.into_iter().index::<VarId>() {
                rts.set_tree(var, rule);
            }
            Ok(rts)
        } else {
            Err(log)
        }
    }

    /// Gets the nonterminal ID corresponding to the name, creating it if
    /// it doesn't exist.
    fn get_or_create_nt(&mut self, name: String) -> VarId {
        let size = self.nt.len();
        *self.nt.entry(name).or_insert_with(|| {
            self.rules.push(GrTree::new());
            size.to_var_id("too many nonterminals")
        })
    }

    /// Gets the terminal ID corresponding to the name or value, creating it if
    /// it doesn't exist.
    ///
    /// Returns
    /// * `IsNew` = `Yes` if the terminal had to be created, `No` otherwise
    /// * `TokenId` = the terminal ID
    fn get_or_create_t(&mut self, name: String) -> (IsNew, TokenId) {
        let mut is_new = IsNew::No;
        let tok = *self.t.entry(name).or_insert_with(|| {
            is_new = IsNew::Yes;
            let tok = self.num_t.to_var_id("too many terminals"); // VarId = TokenId
            self.num_t += 1;
            tok
        });
        (is_new, tok)
    }

    fn invent_t_name(&self, tok: TokenId, value: &str) -> String {
        self.t_name_dictionary
            .and_then(|g| g.get(value).cloned())
            .unwrap_or_else(|| {
                if value.chars().any(|c| c.is_ascii_alphanumeric()) &&
                    value.chars().all(|c| c.is_ascii_alphanumeric() || c.is_whitespace() || c == '_')
                {
                    let name = value.chars().map(|c| if c.is_whitespace() { '_' } else { c }).collect::<String>();
                    if !value.as_bytes()[0].is_ascii_alphabetic() {
                        format!("Tok{}", name.to_camelcase())
                    } else {
                        name.to_camelcase()
                    }
                } else {
                    format!("Token{tok}")
                }
            })
    }

    /// Finalizes the rules and creates the symbol table.
    fn finalize_ruleset(&mut self) {
        let mut nt_name = vec![String::new(); self.nt.len()];
        let mut dest = vec![0; self.nt.len()];
        self.nt_def_order.iter().enumerate().for_each(|(i, &nt)| dest[nt as usize] = i);
        for (name, var) in &self.nt {
            nt_name[dest[*var as usize]] = name.clone();
        }

        // detects undefined nonterminals
        let mut undefined = self.nt.iter()
            .filter_map(|(name, &var)| if self.rules[var as usize].is_empty() { Some(name.to_string()) } else { None })
            .to_vec();
        if !undefined.is_empty() {
            undefined.sort(); // comes from hashmap
            self.log.add_error(format!("undefined nonterminals: {}", undefined.into_iter().map(|s| format!("'{s}'")).join(", ")));
            return;
        }

        // builds symbol table
        assert_eq!(self.tokens.len(), self.num_t);
        let mut symtab = SymbolTable::new();
        symtab.extend_nonterminals(nt_name);
        let mut t_name = vec![(String::new(), None); self.tokens.len()];
        let mut namefixer = NameFixer::new_empty();
        for (tok, (name, value_maybe)) in self.tokens.iter().enumerate().filter(|(_, (name, _))| !name.is_empty()) {
            namefixer.add(name.clone());
            t_name[tok] = (name.clone(), value_maybe.clone());
        }

        // puts names to constant terminals
        for (tok, (_, cst_maybe)) in self.tokens.iter().enumerate().filter(|(_, (name, _))| name.is_empty()) {
            let new_name = namefixer.get_unique_name(self.invent_t_name(tok as TokenId, cst_maybe.as_ref().unwrap()));
            t_name[tok] = (new_name, cst_maybe.clone());
        }
        symtab.extend_terminals(t_name);
        self.symbol_table = Some(symtab);

        // remove reserved nonterminals
        for v in &self.reserved_nt {
            self.rules[*v as usize].clear();
        }

        // reorders nonterminal IDs by order of definition rather than order of appearance
        self.rules = self.nt_def_order.iter()
            .map(|nt| std::mem::take(self.rules.get_mut(*nt as usize).unwrap()))
            .collect();
        for rule in &mut self.rules {
            for mut node in rule.iter_post_depth_simple_mut() {
                match *node {
                    GrNode::Symbol(Symbol::NT(ref mut old))
                    | GrNode::LForm(ref mut old) => *old = *dest.get(*old as usize).unwrap_or(&(*old as usize)) as VarId,
                    _ => {}
                }
            }
        }
    }
}

impl RtsGenListener for RGListener<'_> {
    fn get_log_mut(&mut self) -> &mut impl Logger {
        &mut self.log
    }

    fn exit(&mut self, _ruleset: SynFile) {
        self.finalize_ruleset();
    }

    fn exit_file(&mut self, _ctx: CtxFile) -> SynFile {
        SynFile()
    }

    fn exit_decls(&mut self, _ctx: CtxDecls) -> SynDecls {
        SynDecls()
    }

    fn exit_decl(&mut self, _ctx: CtxDecl) -> SynDecl {
        SynDecl()
    }

    fn exit_decl_terminal(&mut self, ctx: CtxDeclTerminal) -> SynDeclTerminal {
        match ctx {
            // decl_terminal -> Terminal "=" TerminalCst
            CtxDeclTerminal::V1 { terminal, terminalcst } => {
                if self.t.contains_key(&terminal) {
                    self.log.add_error(format!("token '{terminal}' already declared"));
                } else if self.t.contains_key(&terminalcst) {
                    self.log.add_error(format!("token value {terminalcst} already used"));
                } else {
                    let token = self.num_t.to_var_id("too many terminals");
                    self.num_t += 1;
                    self.tokens.push((terminal.clone(), Some(terminalcst[1..terminalcst.len() - 1].to_string())));
                    self.t.insert(terminal, token);
                    self.t.insert(terminalcst, token);
                }

            }
            // decl_terminal -> Terminal
            CtxDeclTerminal::V2 { terminal } => {
                if self.t.contains_key(&terminal) {
                    self.log.add_error(format!("token '{terminal}' already declared"));
                } else {
                    let token = self.num_t.to_var_id("too many terminals");
                    self.num_t += 1;
                    self.tokens.push((terminal.clone(), None));
                    self.t.insert(terminal, token);
                }
            }
        };
        SynDeclTerminal()
    }

    fn exit_ruleset(&mut self, _ctx: CtxRuleset) -> SynRuleset {
        SynRuleset()
    }

    fn init_rule(&mut self) {
        self.curr_name = None;
        self.curr = Some(VecTree::new());
        self.curr_nt = None;
    }

    fn exit_rule(&mut self, ctx: CtxRule) -> SynRule {
        let (var, id) = match ctx {
            // rule -> rule_nt "->" prs_expr ";"
            CtxRule::V1 { rule_nt: SynRuleNt(var), rts_expr: SynRtsExpr(id_expr) }
            // rule -> rule_nt "=>" rts_expr ";"
            | CtxRule::V2 { rule_nt: SynRuleNt(var), prs_expr: SynPrsExpr(id_expr) } => (var, id_expr),
        };
        let mut tree = self.curr.take().unwrap();
        tree.set_root(id);
        self.rules[var as usize] = tree;
        SynRule()
    }

    fn exit_rule_nt(&mut self, ctx: CtxRuleNt) -> SynRuleNt {
        let CtxRuleNt::V1 { nonterminal } = ctx;
        let mut error = false;
        assert_eq!(self.curr_nt, None);
        let var = if let Some(&var) = self.nt.get(&nonterminal) {
            if !self.rules[var as usize].is_empty() {
                error = true;
                self.log.add_error(format!("nonterminal '{nonterminal}' is defined multiple times"));
            }
            var
        } else {
            self.get_or_create_nt(nonterminal.clone())
        };
        if !error { self.nt_def_order.push(var); }
        self.curr_nt = Some(var);
        self.curr_name = Some(nonterminal);
        SynRuleNt(var)
    }

    fn exit_rts_expr(&mut self, ctx: CtxRtsExpr) -> SynRtsExpr {
        let tree = self.curr.as_mut().unwrap();
        let id = match ctx {
            // rts_expr -> "&" rts_children
            CtxRtsExpr::V1 { rts_children: SynRtsChildren(v) } =>
                tree.addci_iter(None, GrNode::Concat, v.into_iter().map(|SynRtsExpr(id)| id)),
            // rts_expr -> "|" rts_children
            CtxRtsExpr::V2 { rts_children: SynRtsChildren(v) } =>
                tree.addci_iter(None, GrNode::Or, v.into_iter().map(|SynRtsExpr(id)| id)),
            // rts_expr -> "+" rts_children
            CtxRtsExpr::V3 { rts_children: SynRtsChildren(v) } =>
                tree.addci_iter(None, GrNode::Plus, v.into_iter().map(|SynRtsExpr(id)| id)),
            // rts_expr -> "*" rts_children
            CtxRtsExpr::V4 { rts_children: SynRtsChildren(v) } =>
                tree.addci_iter(None, GrNode::Star, v.into_iter().map(|SynRtsExpr(id)| id)),
            // rts_expr -> "?" rts_children
            CtxRtsExpr::V5 { rts_children: SynRtsChildren(v) } =>
                tree.addci_iter(None, GrNode::Maybe, v.into_iter().map(|SynRtsExpr(id)| id)),
            // rts_expr -> item
            CtxRtsExpr::V6 { item: SynItem(id_item) } =>
                id_item,
        };
        SynRtsExpr(id)
    }

    fn exit_rts_children(&mut self, ctx: CtxRtsChildren) -> SynRtsChildren {
        // rts_children -> "(" rts_expr* ")"
        let CtxRtsChildren::V1 { star: SynRtsChildren1(v) } = ctx;
        SynRtsChildren(v)
    }

    fn exit_prs_expr(&mut self, ctx: CtxPrsExpr) -> SynPrsExpr {
        let tree = self.curr.as_mut().unwrap();
        let id = match ctx {
            // prs_expr -> prs_expr "+"
            CtxPrsExpr::V1 { prs_expr: SynPrsExpr(id) } =>
                tree.addci(None, GrNode::Plus, id),
            // prs_expr -> prs_expr "*"
            CtxPrsExpr::V2 { prs_expr: SynPrsExpr(id) } =>
                tree.addci(None, GrNode::Star, id),
            // prs_expr -> prs_expr "?"
            CtxPrsExpr::V3 { prs_expr: SynPrsExpr(id) } =>
                tree.addci(None, GrNode::Maybe, id),
            // prs_expr -> prs_expr prs_expr
            CtxPrsExpr::V4 { prs_expr: [SynPrsExpr(mut left), SynPrsExpr(right)] } => {
                if *tree.get(left) != GrNode::Concat {
                    left = tree.addci(None, GrNode::Concat, left);
                }
                tree.attach_child(left, right);
                left
            }
            // prs_expr -> prs_expr "|" prs_expr
            CtxPrsExpr::V5 { prs_expr: [SynPrsExpr(mut left), SynPrsExpr(right)] } => {
                if *tree.get(left) != GrNode::Or {
                    left = tree.addci(None, GrNode::Or, left);
                }
                tree.attach_child(left, right);
                left
            }
            // prs_expr -> "(" prs_expr ")"
            CtxPrsExpr::V6 { prs_expr: SynPrsExpr(id) } => id,
            // prs_expr -> item
            CtxPrsExpr::V7 { item: SynItem(id) } => id,
        };
        SynPrsExpr(id)
    }

    fn exit_item(&mut self, ctx: CtxItem) -> SynItem {
        let id = match ctx {
            // item -> Nonterminal
            CtxItem::V1 { nonterminal } => {
                let var = self.get_or_create_nt(nonterminal);
                self.curr.as_mut().unwrap().add(None, GrNode::Symbol(Symbol::NT(var)))
            }
            // item -> NTx (NT symbol without any check or creation process)
            CtxItem::V2 { ntx } => {
                let x = match VarId::from_str(&ntx[3..ntx.len() - 1]) {
                    Ok(x) => x,
                    Err(e) => {
                        self.log.add_error(format!("in {}, integer literal {ntx} can't be parsed: {e}", self.curr_name.as_ref().unwrap()));
                        VarId::MAX
                    }
                };
                self.curr.as_mut().unwrap().add(None, GrNode::Symbol(Symbol::NT(x)))
            }
            // item -> Terminal
            CtxItem::V3 { terminal } => {
                let (is_new, tok) = self.get_or_create_t(terminal.clone());
                if let IsNew::Yes = is_new {
                    self.tokens.push((terminal, None));
                }
                self.curr.as_mut().unwrap().add(None, GrNode::Symbol(Symbol::T(tok)))
            }
            // item -> TerminalCst
            CtxItem::V4 { terminalcst } => {
                let (is_new, tok) = self.get_or_create_t(terminalcst.clone());
                if let IsNew::Yes = is_new {
                    // the names will be set later, to give priority to variable terminal names in case of conflict
                    match decode_str(&terminalcst[1..terminalcst.len() - 1]) {
                        Ok(text) => {
                            self.tokens.push((String::new(), Some(text)));
                        }
                        Err(msg) => {
                            self.log.add_error(format!("in {}, string literal {terminalcst}: {msg}", self.curr_name.as_ref().unwrap()));
                            self.tokens.push((String::new(), Some("???".to_string())));
                        }
                    }
                }
                self.curr.as_mut().unwrap().add(None, GrNode::Symbol(Symbol::T(tok)))
            }
            // item -> Tx (T symbol without any check or creation process)
            CtxItem::V5 { tx } => {
                let x = match VarId::from_str(&tx[2..tx.len() - 1]) {
                    Ok(x) => x,
                    Err(e) => {
                        self.log.add_error(format!("in {}, integer literal {tx} can't be parsed: {e}", self.curr_name.as_ref().unwrap()));
                        VarId::MAX
                    }
                };
                self.curr.as_mut().unwrap().add(None, GrNode::Symbol(Symbol::T(x)))
            }
            // item -> Empty
            CtxItem::V6 { .. } =>
                self.curr.as_mut().unwrap().add(None, GrNode::Symbol(Symbol::Empty)),
            // item -> LTag
            CtxItem::V7 { ltag } => {
                // `ltag` contains "<L=name>" or "<L>"
                let var = if ltag.len() > 3 {
                    let name = &ltag[3..ltag.len()-1];
                    let var = self.get_or_create_nt(name.to_string());
                    self.nt_def_order.push(var);
                    self.rules[var as usize].add_root(GrNode::Symbol(Symbol::Empty));
                    self.reserved_nt.push(var);
                    var
                } else {
                    self.curr_nt.unwrap()
                };
                self.curr.as_mut().unwrap().add(None, GrNode::LForm(var))
            }
            // item -> "<P>"
            CtxItem::V8 => self.curr.as_mut().unwrap().add(None, GrNode::PrecEq),
            // item -> "<R>"
            CtxItem::V9 => self.curr.as_mut().unwrap().add(None, GrNode::RAssoc),
            // `item -> "<G>"`
            CtxItem::V10 => self.curr.as_mut().unwrap().add(None, GrNode::Greedy),
        };
        SynItem(id)
    }
}

/// Decodes a string literal (without its surrounding quotes). There must be at least two characters in `strlit`.
fn decode_str(strlit: &str) -> Result<String, String> {
    let mut result = String::new();
    let mut chars = strlit.chars();
    while let Some(c) = chars.next() {
        match c {
            '\\' => {
                result.push(match chars.next().ok_or(format!("'\\' incomplete escape code in string literal '{strlit}'"))? {
                    'n' => '\n',
                    'r' => '\r',
                    't' => '\t',
                    '\"' => '\"',
                    '\\' => '\\',
                    'u' => {
                        if !matches!(chars.next(), Some('{')) { return Err(format!("malformed unicode literal in string literal '{strlit}' (missing '{{')")); }
                        let mut hex = String::new();
                        loop {
                            let Some(h) = chars.next() else { return Err(format!("malformed unicode literal in string literal '{strlit}' (missing '}}')")); };
                            if h == '}' { break; }
                            hex.push(h);
                        };
                        let code = u32::from_str_radix(&hex, 16).map_err(|_| format!("'{hex}' isn't a valid hexadecimal value"))?;
                        char::from_u32(code).ok_or_else(|| format!("'{hex}' isn't a valid unicode hexadecimal value"))?
                    }
                    unknown => return Err(format!("unknown escape code '\\{unknown}' in string literal '{strlit}'"))
                });
            }
            _ => result.push(c)
        }
    }
    Ok(result)
}

// -------------------------------------------------------------------------
// User types used in the listener interface:
// (initially copied/uncommented from the generated parser code)

pub mod listener_types {
    use crate::VarId;

    /// User-defined type for `file`
    #[derive(Debug, PartialEq)] pub struct SynFile();
    /// User-defined type for `decls`
    #[derive(Debug, PartialEq)] pub struct SynDecls();
    /// User-defined type for `decl`
    #[derive(Debug, PartialEq)] pub struct SynDecl();
    /// User-defined type for `decl_terminal`
    #[derive(Debug, PartialEq)] pub struct SynDeclTerminal();
    /// User-defined type for `ruleset`
    #[derive(Debug, PartialEq)] pub struct SynRuleset();
    /// User-defined type for `rule`
    #[derive(Debug, PartialEq)] pub struct SynRule();
    /// User-defined type for `rule_nt`
    #[derive(Debug, PartialEq)] pub struct SynRuleNt(pub VarId);
    /// User-defined type for `rts_expr`
    #[derive(Debug, PartialEq)] pub struct SynRtsExpr(pub usize);
    /// User-defined type for `rts_children`
    #[derive(Debug, PartialEq)] pub struct SynRtsChildren(pub Vec<SynRtsExpr>);
    /// User-defined type for `prs_expr`
    #[derive(Debug, PartialEq)] pub struct SynPrsExpr(pub usize);
    /// User-defined type for `item`
    #[derive(Debug, PartialEq)] pub struct SynItem(pub usize);
}

// -------------------------------------------------------------------------

pub mod rtsgen_lexer {
    // Generated code, don't modify manually anything between the tags below
    use crate as lexigram_lib;

    // [rtsgen_lexer]

    use std::collections::HashMap;
    use std::io::Read;
    use lexigram_lib::lexer::{ActionOption, Lexer, ModeOption, StateId, Terminal};
    use lexigram_lib::segmap::{GroupId, Seg, SegMap};

    const NBR_GROUPS: u32 = 43;
    const INITIAL_STATE: StateId = 0;
    const FIRST_END_STATE: StateId = 23;
    const NBR_STATES: StateId = 56;
    static ASCII_TO_GROUP: [GroupId; 128] = [
         31,  31,  31,  31,  31,  31,  31,  31,  31,  22,  39,  31,  31,  39,  31,  31,   // 0-15
         31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,   // 16-31
          0,  31,   1,  31,  31,  31,   2,  31,   3,   4,   5,   6,   7,   8,  31,   9,   // 32-47
         37,  30,  30,  30,  30,  30,  30,  30,  30,  30,  31,  10,  11,  12,  23,  13,   // 48-63
         31,  29,  29,  29,  29,  29,  29,  14,  34,  34,  34,  34,  26,  34,  15,  34,   // 64-79
         27,  34,  28,  34,  16,  34,  34,  34,  34,  34,  34,  31,  24,  31,  31,  35,   // 80-95
         31,  33,  33,  33,  33,  41,  33,  36,  36,  36,  36,  40,  36,  36,  42,  38,   // 96-111
         36,  36,  17,  36,  18,  32,  36,  36,  36,  36,  36,  19,  20,  25,  31,  31,   // 112-127
    ];
    static UTF8_TO_GROUP: [(char, GroupId); 2] = [
        ('ε', 21),
        ('€', 21),
    ];
    static SEG_TO_GROUP: [(Seg, GroupId); 4] = [
        (Seg(128, 948), 31),
        (Seg(950, 8363), 31),
        (Seg(8365, 55295), 31),
        (Seg(57344, 1114111), 31),
    ];
    static TERMINAL_TABLE: [Terminal;33] = [
        Terminal { action: ActionOption::Skip, channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(2), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(10), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(11), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(5), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(4), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(9), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(12), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(8), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(6), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(19), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(19), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(19), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(20), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(20), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(3), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(7), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Skip, channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Skip, channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(0), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(1), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(13), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(14), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(15), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(16), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(20), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(20), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(20), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(17), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(18), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(19), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(21), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
        Terminal { action: ActionOption::Token(22), channel: 0, mode: ModeOption::None, mode_state: None, pop: false },
    ];
    static STATE_TABLE: [StateId; 2409] = [
         23,   1,  24,  25,  26,  27,  28,  29,   2,   3,  30,   4,  31,  32,  33,  34,  35,  36,  37,   5,  38,  39,  23,  56,  56,  56,  33,  33,  33,  33,  56,  56,  36,  36,  33,  56,  36,  56,  36,  23,  36,  36,  36, // state 0
         14,  56,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  56,  14,  15,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  56,  14,  14,  14, // state 1
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  42,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 2
         56,  56,  56,  56,  56,   6,  56,  56,  56,  40,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 3
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,   8,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,   9,  10,  11,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 4
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  39,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 5
          6,   6,   6,   6,   6,   7,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6, // state 6
          6,   6,   6,   6,   6,   7,   6,   6,   6,  41,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6, // state 7
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  47,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 8
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  12,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  44,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 9
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  45,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 10
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  46,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 11
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  13,  13,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  13,  13,  56,  56,  13,  56,  13,  56,  13,  13,  13, // state 12
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  13,  13,  56,  56,  56,  56,  44,  56,  56,  56,  56,  56,  56,  13,  56,  13,  13,  56,  13,  13,  13,  13,  56,  13,  13,  13, // state 13
         14,  52,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  56,  14,  15,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  56,  14,  14,  14, // state 14
         56,  14,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  14,  14,  56,  56,  56,  56,  56,  14,  56,  56,  56,  56,  56,  56,  56,  16,  56,  56,  56,  56,  56,  56,  56,  56,  56,  14, // state 15
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  17,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 16
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  18,  18,  56,  56,  18,  56,  56,  56,  18,  56,  56,  56,  18,  56, // state 17
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  14,  56,  56,  56,  18,  18,  56,  56,  18,  56,  56,  56,  18,  56,  56,  56,  18,  56, // state 18
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  20,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 19
         56,  56,  56,  56,  54,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  20,  56,  56,  56,  56,  56,  56,  20,  56,  56,  56,  56,  56, // state 20
         56,  56,  56,  56,  55,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  21,  56,  56,  56,  56,  56,  56,  21,  56,  56,  56,  56,  56, // state 21
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  21,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 22
         23,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  23,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  23,  56,  56,  56, // state 23 <skip>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 24 <end:2>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 25 <end:10>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 26 <end:11>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 27 <end:5>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 28 <end:4>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 29 <end:9>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 30 <end:12>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  43,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 31 <end:8>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 32 <end:6>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  33,  33,  33,  33,  33,  56,  56,  56,  56,  56,  56,  56,  33,  33,  33,  33,  33,  56,  33,  33,  33,  33,  33,  33,  33,  56,  33,  33,  33, // state 33 <end:19>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  33,  33,  53,  33,  33,  56,  56,  56,  56,  56,  56,  56,  33,  33,  33,  33,  33,  56,  33,  33,  33,  33,  33,  33,  33,  56,  33,  33,  33, // state 34 <end:19>
         56,  56,  56,  19,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  33,  33,  33,  33,  33,  56,  56,  56,  56,  56,  56,  56,  33,  33,  33,  33,  33,  56,  33,  33,  33,  33,  33,  33,  33,  56,  33,  33,  33, // state 35 <end:19>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  36,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  56,  36,  36,  56,  36,  36,  36,  36,  56,  36,  36,  36, // state 36 <end:20>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  36,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  56,  36,  36,  56,  36,  36,  36,  48,  56,  36,  36,  36, // state 37 <end:20>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 38 <end:3>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 39 <end:7>
         40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  40,  56,  40,  40,  40, // state 40 <skip>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 41 <skip>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 42 <end:0>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 43 <end:1>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 44 <end:13>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 45 <end:14>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 46 <end:15>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 47 <end:16>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  36,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  56,  36,  36,  56,  36,  36,  36,  36,  56,  49,  36,  36, // state 48 <end:20>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  36,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  56,  36,  36,  56,  36,  36,  36,  36,  56,  36,  50,  36, // state 49 <end:20>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  36,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  56,  36,  36,  56,  36,  36,  36,  36,  56,  36,  36,  51, // state 50 <end:20>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  36,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  36,  56,  36,  36,  56,  36,  36,  36,  36,  56,  36,  36,  36, // state 51 <end:17>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 52 <end:18>
         56,  56,  56,  22,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  33,  33,  33,  33,  33,  56,  56,  56,  56,  56,  56,  56,  33,  33,  33,  33,  33,  56,  33,  33,  33,  33,  33,  33,  33,  56,  33,  33,  33, // state 53 <end:19>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 54 <end:21>
         56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56, // state 55 <end:22>
         56 // error group in [nbr_state * nbr_group + nbr_group]
    ];

    pub fn build_lexer<R: Read>() -> Lexer<'static, R> {
        Lexer::new(
            // parameters
            NBR_GROUPS,
            INITIAL_STATE,
            FIRST_END_STATE,
            NBR_STATES,
            // tables
            &ASCII_TO_GROUP,
            HashMap::<char, GroupId>::from(UTF8_TO_GROUP),
            SegMap::<GroupId>::from(SEG_TO_GROUP),
            &STATE_TABLE,
            &TERMINAL_TABLE,
        )
    }

    // [rtsgen_lexer]
}

// -------------------------------------------------------------------------

pub mod rtsgen_parser {
    // Generated code, don't modify manually anything between the tags below
    use crate as lexigram_lib;

    // [rtsgen_parser]

    use lexigram_lib::{AltId, TokenId, VarId, fixed_sym_table::FixedSymTable, lexer::PosSpan, log::Logger, parser::{Call, ListenerWrapper, OpCode, Parser, Terminate}};
    use super::listener_types::*;

    const PARSER_NUM_T: usize = 23;
    const PARSER_NUM_NT: usize = 23;
    static SYMBOLS_T: [(&str, Option<&str>); PARSER_NUM_T] = [("Arrow", Some("->")), ("DArrow", Some("=>")), ("Concat", Some("&")), ("Or", Some("|")), ("Plus", Some("+")), ("Star", Some("*")), ("Question", Some("?")), ("Empty", None), ("Equal", Some("=")), ("Comma", Some(",")), ("LPar", Some("(")), ("RPar", Some(")")), ("Semicolon", Some(";")), ("LTag", None), ("PTag", Some("<P>")), ("RTag", Some("<R>")), ("GTag", Some("<G>")), ("Token", Some("token")), ("TerminalCst", None), ("Terminal", None), ("Nonterminal", None), ("Tx", None), ("NTx", None)];
    static SYMBOLS_NT: [&str; PARSER_NUM_NT] = ["file", "decls", "decl_iter", "decl", "decl_terminal", "ruleset", "rule_iter", "rule", "rule_nt", "rts_expr", "rts_children", "prs_expr", "item", "decl_1", "rts_children_1", "prs_expr_1", "prs_expr_2", "prs_expr_3", "prs_expr_4", "prs_expr_5", "prs_expr_6", "decl_terminal_1", "rule_1"];
    static ALT_VAR: [VarId; 56] = [0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 9, 9, 9, 9, 9, 9, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 15, 15, 16, 17, 17, 17, 17, 17, 18, 19, 19, 19, 19, 20, 20, 21, 21, 22, 22];
    static PARSING_TABLE: [AltId; 552] = [56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 0, 56, 56, 0, 56, 56, 0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 56, 56, 1, 56, 56, 1, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 3, 56, 56, 3, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 4, 56, 56, 57, 56, 56, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 56, 56, 57, 56, 56, 56, 56, 56, 56, 5, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 6, 56, 56, 6, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 7, 56, 56, 8, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 9, 56, 56, 57, 57, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 10, 56, 56, 56, 56, 56, 11, 12, 13, 14, 15, 16, 56, 56, 56, 57, 57, 16, 16, 16, 16, 56, 16, 16, 16, 16, 16, 56, 56, 56, 57, 57, 57, 57, 57, 57, 56, 56, 17, 57, 57, 57, 57, 57, 57, 56, 57, 57, 57, 57, 57, 56, 56, 56, 56, 56, 56, 56, 56, 18, 56, 56, 18, 57, 57, 18, 18, 18, 18, 56, 18, 18, 18, 18, 18, 56, 56, 56, 57, 57, 57, 57, 57, 24, 56, 56, 57, 57, 57, 25, 26, 27, 28, 56, 22, 21, 19, 23, 20, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 29, 56, 56, 30, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 31, 31, 31, 31, 31, 31, 56, 56, 56, 32, 56, 31, 31, 31, 31, 56, 31, 31, 31, 31, 31, 56, 56, 56, 56, 37, 33, 34, 35, 36, 56, 56, 36, 38, 38, 36, 36, 36, 36, 56, 36, 36, 36, 36, 36, 56, 56, 56, 56, 57, 57, 57, 57, 39, 56, 56, 39, 57, 57, 39, 39, 39, 39, 56, 39, 39, 39, 39, 39, 56, 56, 56, 56, 44, 40, 41, 42, 43, 56, 56, 43, 44, 44, 43, 43, 43, 43, 56, 43, 43, 43, 43, 43, 56, 56, 56, 56, 57, 57, 57, 57, 45, 56, 56, 45, 57, 57, 45, 45, 45, 45, 56, 45, 45, 45, 45, 45, 56, 56, 56, 56, 49, 46, 47, 48, 49, 56, 56, 49, 49, 49, 49, 49, 49, 49, 56, 49, 49, 49, 49, 49, 56, 56, 56, 56, 57, 57, 57, 57, 51, 56, 56, 50, 57, 57, 51, 51, 51, 51, 56, 51, 51, 51, 51, 51, 56, 56, 56, 56, 56, 56, 56, 56, 56, 52, 53, 56, 56, 53, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 54, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 56, 56, 57];
    static OPCODES: [&[OpCode]; 56] = [&[OpCode::Exit(0), OpCode::NT(5), OpCode::NT(1)], &[OpCode::Exit(1), OpCode::NT(2)], &[OpCode::Loop(2), OpCode::Exit(2), OpCode::NT(3)], &[OpCode::Exit(3)], &[OpCode::Exit(4), OpCode::T(12), OpCode::NT(13), OpCode::NT(4), OpCode::T(17)], &[OpCode::NT(21), OpCode::T(19)], &[OpCode::Exit(6), OpCode::NT(6)], &[OpCode::Loop(6), OpCode::Exit(7), OpCode::NT(7)], &[OpCode::Exit(8)], &[OpCode::NT(22), OpCode::NT(8)], &[OpCode::Exit(10), OpCode::T(20)], &[OpCode::Exit(11), OpCode::NT(10), OpCode::T(2)], &[OpCode::Exit(12), OpCode::NT(10), OpCode::T(3)], &[OpCode::Exit(13), OpCode::NT(10), OpCode::T(4)], &[OpCode::Exit(14), OpCode::NT(10), OpCode::T(5)], &[OpCode::Exit(15), OpCode::NT(10), OpCode::T(6)], &[OpCode::Exit(16), OpCode::NT(12)], &[OpCode::Exit(17), OpCode::T(11), OpCode::NT(14), OpCode::T(10)], &[OpCode::NT(15), OpCode::Exit(18), OpCode::NT(20)], &[OpCode::Exit(19), OpCode::T(20)], &[OpCode::Exit(20), OpCode::T(22)], &[OpCode::Exit(21), OpCode::T(19)], &[OpCode::Exit(22), OpCode::T(18)], &[OpCode::Exit(23), OpCode::T(21)], &[OpCode::Exit(24), OpCode::T(7)], &[OpCode::Exit(25), OpCode::T(13)], &[OpCode::Exit(26), OpCode::T(14)], &[OpCode::Exit(27), OpCode::T(15)], &[OpCode::Exit(28), OpCode::T(16)], &[OpCode::Loop(13), OpCode::Exit(29), OpCode::NT(4), OpCode::T(9)], &[OpCode::Exit(30)], &[OpCode::Loop(14), OpCode::Exit(31), OpCode::NT(9)], &[OpCode::Exit(32)], &[OpCode::Loop(15), OpCode::Exit(33), OpCode::T(4)], &[OpCode::Loop(15), OpCode::Exit(34), OpCode::T(5)], &[OpCode::Loop(15), OpCode::Exit(35), OpCode::T(6)], &[OpCode::Loop(15), OpCode::Exit(36), OpCode::NT(18)], &[OpCode::Loop(15), OpCode::Exit(37), OpCode::NT(16), OpCode::T(3)], &[OpCode::Exit(38)], &[OpCode::NT(17), OpCode::Exit(39), OpCode::NT(20)], &[OpCode::Loop(17), OpCode::Exit(40), OpCode::T(4)], &[OpCode::Loop(17), OpCode::Exit(41), OpCode::T(5)], &[OpCode::Loop(17), OpCode::Exit(42), OpCode::T(6)], &[OpCode::Loop(17), OpCode::Exit(43), OpCode::NT(18)], &[OpCode::Exit(44)], &[OpCode::NT(19), OpCode::Exit(45), OpCode::NT(20)], &[OpCode::Loop(19), OpCode::Exit(46), OpCode::T(4)], &[OpCode::Loop(19), OpCode::Exit(47), OpCode::T(5)], &[OpCode::Loop(19), OpCode::Exit(48), OpCode::T(6)], &[OpCode::Exit(49)], &[OpCode::Exit(50), OpCode::T(11), OpCode::NT(11), OpCode::T(10)], &[OpCode::Exit(51), OpCode::NT(12)], &[OpCode::Exit(52), OpCode::T(18), OpCode::T(8)], &[OpCode::Exit(53)], &[OpCode::Exit(54), OpCode::T(12), OpCode::NT(11), OpCode::T(0)], &[OpCode::Exit(55), OpCode::T(12), OpCode::NT(9), OpCode::T(1)]];
    static INIT_OPCODES: [OpCode; 2] = [OpCode::End, OpCode::NT(0)];
    static START_SYMBOL: VarId = 0;

    pub fn build_parser() -> Parser<'static> {{
        let symbol_table = FixedSymTable::new(
            SYMBOLS_T.into_iter().map(|(s, os)| (s.to_string(), os.map(|s| s.to_string()))).collect(),
            SYMBOLS_NT.into_iter().map(|s| s.to_string()).collect()
        );
        Parser::new(
            PARSER_NUM_NT, PARSER_NUM_T + 1,
            &ALT_VAR,
            Vec::new(),
            OPCODES.into_iter().map(|strip| strip.to_vec()).collect(),
            INIT_OPCODES.to_vec(),
            &PARSING_TABLE,
            symbol_table,
            START_SYMBOL
        )
    }}

    #[derive(Debug)]
    pub enum CtxFile {
        /// `file -> decls ruleset`
        V1 { decls: SynDecls, ruleset: SynRuleset },
    }
    #[derive(Debug)]
    pub enum CtxDecls {
        /// `decls -> (<L> decl)*`
        V1,
    }
    #[derive(Debug)]
    pub enum CtxDeclIter {
        /// `<L> decl` iteration in `decls -> ( ►► <L> decl ◄◄ )*`
        V1 { decl: SynDecl },
    }
    #[derive(Debug)]
    pub enum CtxDecl {
        /// `decl -> "token" decl_terminal ("," decl_terminal)* ";"`
        V1 { star: SynDecl1 },
    }
    #[derive(Debug)]
    pub enum CtxDeclTerminal {
        /// `decl_terminal -> Terminal "=" TerminalCst`
        V1 { terminal: String, terminalcst: String },
        /// `decl_terminal -> Terminal`
        V2 { terminal: String },
    }
    #[derive(Debug)]
    pub enum CtxRuleset {
        /// `ruleset -> (<L> rule)*`
        V1,
    }
    #[derive(Debug)]
    pub enum CtxRuleIter {
        /// `<L> rule` iteration in `ruleset -> ( ►► <L> rule ◄◄ )*`
        V1 { rule: SynRule },
    }
    #[derive(Debug)]
    pub enum CtxRule {
        /// `rule -> rule_nt "=>" rts_expr ";"`
        V1 { rule_nt: SynRuleNt, rts_expr: SynRtsExpr },
        /// `rule -> rule_nt "->" prs_expr ";"`
        V2 { rule_nt: SynRuleNt, prs_expr: SynPrsExpr },
    }
    #[derive(Debug)]
    pub enum CtxRuleNt {
        /// `rule_nt -> Nonterminal`
        V1 { nonterminal: String },
    }
    #[derive(Debug)]
    pub enum CtxRtsExpr {
        /// `rts_expr -> "&" rts_children`
        V1 { rts_children: SynRtsChildren },
        /// `rts_expr -> "|" rts_children`
        V2 { rts_children: SynRtsChildren },
        /// `rts_expr -> "+" rts_children`
        V3 { rts_children: SynRtsChildren },
        /// `rts_expr -> "*" rts_children`
        V4 { rts_children: SynRtsChildren },
        /// `rts_expr -> "?" rts_children`
        V5 { rts_children: SynRtsChildren },
        /// `rts_expr -> item`
        V6 { item: SynItem },
    }
    #[derive(Debug)]
    pub enum CtxRtsChildren {
        /// `rts_children -> "(" rts_expr* ")"`
        V1 { star: SynRtsChildren1 },
    }
    #[derive(Debug)]
    pub enum CtxPrsExpr {
        /// `prs_expr -> prs_expr "+"`
        V1 { prs_expr: SynPrsExpr },
        /// `prs_expr -> prs_expr "*"`
        V2 { prs_expr: SynPrsExpr },
        /// `prs_expr -> prs_expr "?"`
        V3 { prs_expr: SynPrsExpr },
        /// `prs_expr -> prs_expr prs_expr`
        V4 { prs_expr: [SynPrsExpr; 2] },
        /// `prs_expr -> prs_expr "|" prs_expr`
        V5 { prs_expr: [SynPrsExpr; 2] },
        /// `prs_expr -> "(" prs_expr ")"`
        V6 { prs_expr: SynPrsExpr },
        /// `prs_expr -> item`
        V7 { item: SynItem },
    }
    #[derive(Debug)]
    pub enum CtxItem {
        /// `item -> Nonterminal`
        V1 { nonterminal: String },
        /// `item -> NTx`
        V2 { ntx: String },
        /// `item -> Terminal`
        V3 { terminal: String },
        /// `item -> TerminalCst`
        V4 { terminalcst: String },
        /// `item -> Tx`
        V5 { tx: String },
        /// `item -> Empty`
        V6 { empty: String },
        /// `item -> LTag`
        V7 { ltag: String },
        /// `item -> "<P>"`
        V8,
        /// `item -> "<R>"`
        V9,
        /// `item -> "<G>"`
        V10,
    }

    /// Computed `("," decl_terminal)*` array in `decl -> "token" decl_terminal  ►► ("," decl_terminal)* ◄◄  ";"`
    #[derive(Debug, PartialEq)]
    pub struct SynDecl1(pub Vec<SynDeclTerminal>);
    /// Computed `rts_expr*` array in `rts_children -> "("  ►► rts_expr* ◄◄  ")"`
    #[derive(Debug, PartialEq)]
    pub struct SynRtsChildren1(pub Vec<SynRtsExpr>);

    #[derive(Debug)]
    enum EnumSynValue { File(SynFile), Decls(SynDecls), Decl(SynDecl), DeclTerminal(SynDeclTerminal), Ruleset(SynRuleset), Rule(SynRule), RuleNt(SynRuleNt), RtsExpr(SynRtsExpr), RtsChildren(SynRtsChildren), PrsExpr(SynPrsExpr), Item(SynItem), Decl1(SynDecl1), RtsChildren1(SynRtsChildren1) }

    impl EnumSynValue {
        fn get_file(self) -> SynFile {
            if let EnumSynValue::File(val) = self { val } else { panic!() }
        }
        fn get_decls(self) -> SynDecls {
            if let EnumSynValue::Decls(val) = self { val } else { panic!() }
        }
        fn get_decl(self) -> SynDecl {
            if let EnumSynValue::Decl(val) = self { val } else { panic!() }
        }
        fn get_decl_terminal(self) -> SynDeclTerminal {
            if let EnumSynValue::DeclTerminal(val) = self { val } else { panic!() }
        }
        fn get_ruleset(self) -> SynRuleset {
            if let EnumSynValue::Ruleset(val) = self { val } else { panic!() }
        }
        fn get_rule(self) -> SynRule {
            if let EnumSynValue::Rule(val) = self { val } else { panic!() }
        }
        fn get_rule_nt(self) -> SynRuleNt {
            if let EnumSynValue::RuleNt(val) = self { val } else { panic!() }
        }
        fn get_rts_expr(self) -> SynRtsExpr {
            if let EnumSynValue::RtsExpr(val) = self { val } else { panic!() }
        }
        fn get_rts_children(self) -> SynRtsChildren {
            if let EnumSynValue::RtsChildren(val) = self { val } else { panic!() }
        }
        fn get_prs_expr(self) -> SynPrsExpr {
            if let EnumSynValue::PrsExpr(val) = self { val } else { panic!() }
        }
        fn get_item(self) -> SynItem {
            if let EnumSynValue::Item(val) = self { val } else { panic!() }
        }
        fn get_decl1(self) -> SynDecl1 {
            if let EnumSynValue::Decl1(val) = self { val } else { panic!() }
        }
        fn get_rts_children1(self) -> SynRtsChildren1 {
            if let EnumSynValue::RtsChildren1(val) = self { val } else { panic!() }
        }
    }

    pub trait RtsGenListener {
        /// Checks if the listener requests an abort. This happens if an error is too difficult to recover from
        /// and may corrupt the stack content. In that case, the parser immediately stops and returns `ParserError::AbortRequest`.
        fn check_abort_request(&self) -> Terminate { Terminate::None }
        fn get_log_mut(&mut self) -> &mut impl Logger;
        #[allow(unused_variables)]
        fn intercept_token(&mut self, token: TokenId, text: &str) -> TokenId { token }
        #[allow(unused_variables)]
        fn exit(&mut self, file: SynFile) {}
        #[allow(unused_variables)]
        fn abort(&mut self, terminate: Terminate) {}
        fn init_file(&mut self) {}
        fn exit_file(&mut self, ctx: CtxFile) -> SynFile;
        fn init_decls(&mut self) {}
        fn exit_decls(&mut self, ctx: CtxDecls) -> SynDecls;
        fn init_decl_iter(&mut self) {}
        #[allow(unused_variables)]
        fn exit_decl_iter(&mut self, ctx: CtxDeclIter) {}
        fn init_decl(&mut self) {}
        fn exit_decl(&mut self, ctx: CtxDecl) -> SynDecl;
        fn init_decl_terminal(&mut self) {}
        fn exit_decl_terminal(&mut self, ctx: CtxDeclTerminal) -> SynDeclTerminal;
        fn init_ruleset(&mut self) {}
        fn exit_ruleset(&mut self, ctx: CtxRuleset) -> SynRuleset;
        fn init_rule_iter(&mut self) {}
        #[allow(unused_variables)]
        fn exit_rule_iter(&mut self, ctx: CtxRuleIter) {}
        fn init_rule(&mut self) {}
        fn exit_rule(&mut self, ctx: CtxRule) -> SynRule;
        fn init_rule_nt(&mut self) {}
        fn exit_rule_nt(&mut self, ctx: CtxRuleNt) -> SynRuleNt;
        fn init_rts_expr(&mut self) {}
        fn exit_rts_expr(&mut self, ctx: CtxRtsExpr) -> SynRtsExpr;
        fn init_rts_children(&mut self) {}
        fn exit_rts_children(&mut self, ctx: CtxRtsChildren) -> SynRtsChildren;
        fn init_prs_expr(&mut self) {}
        fn exit_prs_expr(&mut self, ctx: CtxPrsExpr) -> SynPrsExpr;
        fn init_item(&mut self) {}
        fn exit_item(&mut self, ctx: CtxItem) -> SynItem;
    }

    pub struct Wrapper<T> {
        verbose: bool,
        listener: T,
        stack: Vec<EnumSynValue>,
        max_stack: usize,
        stack_t: Vec<String>,
    }

    impl<T: RtsGenListener> ListenerWrapper for Wrapper<T> {
        fn switch(&mut self, call: Call, nt: VarId, alt_id: AltId, t_data: Option<Vec<String>>) {
            if self.verbose {
                println!("switch: call={call:?}, nt={nt}, alt={alt_id}, t_data={t_data:?}");
            }
            if let Some(mut t_data) = t_data {
                self.stack_t.append(&mut t_data);
            }
            match call {
                Call::Enter => {
                    match nt {
                        0 => self.listener.init_file(),             // file
                        1 => self.listener.init_decls(),            // decls
                        2 => self.listener.init_decl_iter(),        // decl_iter
                        3 => self.listener.init_decl(),             // decl
                        13 => self.init_decl1(),                    // decl_1
                        4 => self.listener.init_decl_terminal(),    // decl_terminal
                        21 => {}                                    // decl_terminal_1
                        5 => self.listener.init_ruleset(),          // ruleset
                        6 => self.listener.init_rule_iter(),        // rule_iter
                        7 => self.listener.init_rule(),             // rule
                        22 => {}                                    // rule_1
                        8 => self.listener.init_rule_nt(),          // rule_nt
                        9 => self.listener.init_rts_expr(),         // rts_expr
                        10 => self.listener.init_rts_children(),    // rts_children
                        14 => self.init_rts_children1(),            // rts_children_1
                        11 => self.listener.init_prs_expr(),        // prs_expr
                        15 ..= 20 => {}                             // prs_expr_1, prs_expr_2, prs_expr_3, prs_expr_4, prs_expr_5, prs_expr_6
                        12 => self.listener.init_item(),            // item
                        _ => panic!("unexpected enter nonterminal id: {nt}")
                    }
                }
                Call::Loop => {}
                Call::Exit => {
                    match alt_id {
                        0 => self.exit_file(),                      // file -> decls ruleset
                        1 => self.exit_decls(),                     // decls -> decl_iter
                        2 => self.exit_decl_iter(),                 // decl_iter -> <L> decl decl_iter
                        3 => {}                                     // decl_iter -> <L> ε (not used)
                        4 => self.exit_decl(),                      // decl -> "token" decl_terminal decl_1 ";"
                        29 => self.exit_decl1(),                    // decl_1 -> "," decl_terminal decl_1
                        30 => {}                                    // decl_1 -> ε
                        52 |                                        // decl_terminal_1 -> "=" TerminalCst
                        53 => self.exit_decl_terminal(alt_id),      // decl_terminal_1 -> ε
                     /* 5 */                                        // decl_terminal -> Terminal decl_terminal_1 (never called)
                        6 => self.exit_ruleset(),                   // ruleset -> rule_iter
                        7 => self.exit_rule_iter(),                 // rule_iter -> <L> rule rule_iter
                        8 => {}                                     // rule_iter -> <L> ε (not used)
                        54 |                                        // rule_1 -> "->" prs_expr ";"
                        55 => self.exit_rule(alt_id),               // rule_1 -> "=>" rts_expr ";"
                     /* 9 */                                        // rule -> rule_nt rule_1 (never called)
                        10 => self.exit_rule_nt(),                  // rule_nt -> Nonterminal
                        11 |                                        // rts_expr -> "&" rts_children
                        12 |                                        // rts_expr -> "|" rts_children
                        13 |                                        // rts_expr -> "+" rts_children
                        14 |                                        // rts_expr -> "*" rts_children
                        15 |                                        // rts_expr -> "?" rts_children
                        16 => self.exit_rts_expr(alt_id),           // rts_expr -> item
                        17 => self.exit_rts_children(),             // rts_children -> "(" rts_children_1 ")"
                        31 => self.exit_rts_children1(),            // rts_children_1 -> rts_expr rts_children_1
                        32 => {}                                    // rts_children_1 -> ε
                        33 |                                        // prs_expr_1 -> "+" prs_expr_1
                        34 |                                        // prs_expr_1 -> "*" prs_expr_1
                        35 |                                        // prs_expr_1 -> "?" prs_expr_1
                        36 |                                        // prs_expr_1 -> prs_expr_4 prs_expr_1
                        37 => self.exit_prs_expr1(alt_id),          // prs_expr_1 -> "|" prs_expr_2 prs_expr_1
                        40 |                                        // prs_expr_3 -> "+" prs_expr_3 (duplicate of 33)
                        46 => self.exit_prs_expr1(33),              // prs_expr_5 -> "+" prs_expr_5 (duplicate of 33)
                        41 |                                        // prs_expr_3 -> "*" prs_expr_3 (duplicate of 34)
                        47 => self.exit_prs_expr1(34),              // prs_expr_5 -> "*" prs_expr_5 (duplicate of 34)
                        42 |                                        // prs_expr_3 -> "?" prs_expr_3 (duplicate of 35)
                        48 => self.exit_prs_expr1(35),              // prs_expr_5 -> "?" prs_expr_5 (duplicate of 35)
                        43 => self.exit_prs_expr1(36),              // prs_expr_3 -> prs_expr_4 prs_expr_3 (duplicate of 36)
                        50 |                                        // prs_expr_6 -> "(" prs_expr ")"
                        51 => self.exit_prs_expr6(alt_id),          // prs_expr_6 -> item
                        18 => {}                                    // prs_expr -> prs_expr_6 prs_expr_1 (not used)
                        38 => {}                                    // prs_expr_1 -> ε (not used)
                        39 => {}                                    // prs_expr_2 -> prs_expr_6 prs_expr_3 (not used)
                        44 => {}                                    // prs_expr_3 -> ε (not used)
                        45 => {}                                    // prs_expr_4 -> prs_expr_6 prs_expr_5 (not used)
                        49 => {}                                    // prs_expr_5 -> ε (not used)
                        19 |                                        // item -> Nonterminal
                        20 |                                        // item -> NTx
                        21 |                                        // item -> Terminal
                        22 |                                        // item -> TerminalCst
                        23 |                                        // item -> Tx
                        24 |                                        // item -> Empty
                        25 |                                        // item -> LTag
                        26 |                                        // item -> "<P>"
                        27 |                                        // item -> "<R>"
                        28 => self.exit_item(alt_id),               // item -> "<G>"
                        _ => panic!("unexpected exit alternative id: {alt_id}")
                    }
                }
                Call::End(terminate) => {
                    match terminate {
                        Terminate::None => {
                            let val = self.stack.pop().unwrap().get_file();
                            self.listener.exit(val);
                        }
                        Terminate::Abort | Terminate::Conclude => self.listener.abort(terminate),
                    }
                }
            }
            self.max_stack = std::cmp::max(self.max_stack, self.stack.len());
            if self.verbose {
                println!("> stack_t:   {}", self.stack_t.join(", "));
                println!("> stack:     {}", self.stack.iter().map(|it| format!("{it:?}")).collect::<Vec<_>>().join(", "));
            }
        }

        fn check_abort_request(&self) -> Terminate {
            self.listener.check_abort_request()
        }

        fn abort(&mut self) {
            self.stack.clear();
            self.stack_t.clear();
        }

        fn get_log_mut(&mut self) -> &mut impl Logger {
            self.listener.get_log_mut()
        }

        fn is_stack_empty(&self) -> bool {
            self.stack.is_empty()
        }

        fn is_stack_t_empty(&self) -> bool {
            self.stack_t.is_empty()
        }

        fn intercept_token(&mut self, token: TokenId, text: &str, _span: &PosSpan) -> TokenId {
            self.listener.intercept_token(token, text)
        }
    }

    impl<T: RtsGenListener> Wrapper<T> {
        pub fn new(listener: T, verbose: bool) -> Self {
            Wrapper { verbose, listener, stack: Vec::new(), max_stack: 0, stack_t: Vec::new() }
        }

        pub fn get_listener(&self) -> &T {
            &self.listener
        }

        pub fn get_listener_mut(&mut self) -> &mut T {
            &mut self.listener
        }

        pub fn give_listener(self) -> T {
            self.listener
        }

        pub fn set_verbose(&mut self, verbose: bool) {
            self.verbose = verbose;
        }

        fn exit_file(&mut self) {
            let ruleset = self.stack.pop().unwrap().get_ruleset();
            let decls = self.stack.pop().unwrap().get_decls();
            let ctx = CtxFile::V1 { decls, ruleset };
            let val = self.listener.exit_file(ctx);
            self.stack.push(EnumSynValue::File(val));
        }

        fn exit_decls(&mut self) {
            let ctx = CtxDecls::V1;
            let val = self.listener.exit_decls(ctx);
            self.stack.push(EnumSynValue::Decls(val));
        }

        fn exit_decl_iter(&mut self) {
            let decl = self.stack.pop().unwrap().get_decl();
            let ctx = CtxDeclIter::V1 { decl };
            self.listener.exit_decl_iter(ctx);
        }

        fn exit_decl(&mut self) {
            let star = self.stack.pop().unwrap().get_decl1();
            let ctx = CtxDecl::V1 { star };
            let val = self.listener.exit_decl(ctx);
            self.stack.push(EnumSynValue::Decl(val));
        }

        fn init_decl1(&mut self) {
            let decl_terminal = self.stack.pop().unwrap().get_decl_terminal();
            self.stack.push(EnumSynValue::Decl1(SynDecl1(vec![decl_terminal])));
        }

        fn exit_decl1(&mut self) {
            let decl_terminal = self.stack.pop().unwrap().get_decl_terminal();
            let Some(EnumSynValue::Decl1(SynDecl1(star_acc))) = self.stack.last_mut() else {
                panic!("expected SynDecl1 item on wrapper stack");
            };
            star_acc.push(decl_terminal);
        }

        fn exit_decl_terminal(&mut self, alt_id: AltId) {
            let ctx = match alt_id {
                52 => {
                    let terminalcst = self.stack_t.pop().unwrap();
                    let terminal = self.stack_t.pop().unwrap();
                    CtxDeclTerminal::V1 { terminal, terminalcst }
                }
                53 => {
                    let terminal = self.stack_t.pop().unwrap();
                    CtxDeclTerminal::V2 { terminal }
                }
                _ => panic!("unexpected alt id {alt_id} in fn exit_decl_terminal")
            };
            let val = self.listener.exit_decl_terminal(ctx);
            self.stack.push(EnumSynValue::DeclTerminal(val));
        }

        fn exit_ruleset(&mut self) {
            let ctx = CtxRuleset::V1;
            let val = self.listener.exit_ruleset(ctx);
            self.stack.push(EnumSynValue::Ruleset(val));
        }

        fn exit_rule_iter(&mut self) {
            let rule = self.stack.pop().unwrap().get_rule();
            let ctx = CtxRuleIter::V1 { rule };
            self.listener.exit_rule_iter(ctx);
        }

        fn exit_rule(&mut self, alt_id: AltId) {
            let ctx = match alt_id {
                54 => {
                    let prs_expr = self.stack.pop().unwrap().get_prs_expr();
                    let rule_nt = self.stack.pop().unwrap().get_rule_nt();
                    CtxRule::V2 { rule_nt, prs_expr }
                }
                55 => {
                    let rts_expr = self.stack.pop().unwrap().get_rts_expr();
                    let rule_nt = self.stack.pop().unwrap().get_rule_nt();
                    CtxRule::V1 { rule_nt, rts_expr }
                }
                _ => panic!("unexpected alt id {alt_id} in fn exit_rule")
            };
            let val = self.listener.exit_rule(ctx);
            self.stack.push(EnumSynValue::Rule(val));
        }

        fn exit_rule_nt(&mut self) {
            let nonterminal = self.stack_t.pop().unwrap();
            let ctx = CtxRuleNt::V1 { nonterminal };
            let val = self.listener.exit_rule_nt(ctx);
            self.stack.push(EnumSynValue::RuleNt(val));
        }

        fn exit_rts_expr(&mut self, alt_id: AltId) {
            let ctx = match alt_id {
                11 => {
                    let rts_children = self.stack.pop().unwrap().get_rts_children();
                    CtxRtsExpr::V1 { rts_children }
                }
                12 => {
                    let rts_children = self.stack.pop().unwrap().get_rts_children();
                    CtxRtsExpr::V2 { rts_children }
                }
                13 => {
                    let rts_children = self.stack.pop().unwrap().get_rts_children();
                    CtxRtsExpr::V3 { rts_children }
                }
                14 => {
                    let rts_children = self.stack.pop().unwrap().get_rts_children();
                    CtxRtsExpr::V4 { rts_children }
                }
                15 => {
                    let rts_children = self.stack.pop().unwrap().get_rts_children();
                    CtxRtsExpr::V5 { rts_children }
                }
                16 => {
                    let item = self.stack.pop().unwrap().get_item();
                    CtxRtsExpr::V6 { item }
                }
                _ => panic!("unexpected alt id {alt_id} in fn exit_rts_expr")
            };
            let val = self.listener.exit_rts_expr(ctx);
            self.stack.push(EnumSynValue::RtsExpr(val));
        }

        fn exit_rts_children(&mut self) {
            let star = self.stack.pop().unwrap().get_rts_children1();
            let ctx = CtxRtsChildren::V1 { star };
            let val = self.listener.exit_rts_children(ctx);
            self.stack.push(EnumSynValue::RtsChildren(val));
        }

        fn init_rts_children1(&mut self) {
            let val = SynRtsChildren1(Vec::new());
            self.stack.push(EnumSynValue::RtsChildren1(val));
        }

        fn exit_rts_children1(&mut self) {
            let rts_expr = self.stack.pop().unwrap().get_rts_expr();
            let Some(EnumSynValue::RtsChildren1(SynRtsChildren1(star_acc))) = self.stack.last_mut() else {
                panic!("expected SynRtsChildren1 item on wrapper stack");
            };
            star_acc.push(rts_expr);
        }

        fn exit_prs_expr1(&mut self, alt_id: AltId) {
            let ctx = match alt_id {
                33 => {
                    let prs_expr = self.stack.pop().unwrap().get_prs_expr();
                    CtxPrsExpr::V1 { prs_expr }
                }
                34 => {
                    let prs_expr = self.stack.pop().unwrap().get_prs_expr();
                    CtxPrsExpr::V2 { prs_expr }
                }
                35 => {
                    let prs_expr = self.stack.pop().unwrap().get_prs_expr();
                    CtxPrsExpr::V3 { prs_expr }
                }
                36 => {
                    let prs_expr_2 = self.stack.pop().unwrap().get_prs_expr();
                    let prs_expr_1 = self.stack.pop().unwrap().get_prs_expr();
                    CtxPrsExpr::V4 { prs_expr: [prs_expr_1, prs_expr_2] }
                }
                37 => {
                    let prs_expr_2 = self.stack.pop().unwrap().get_prs_expr();
                    let prs_expr_1 = self.stack.pop().unwrap().get_prs_expr();
                    CtxPrsExpr::V5 { prs_expr: [prs_expr_1, prs_expr_2] }
                }
                _ => panic!("unexpected alt id {alt_id} in fn exit_prs_expr1")
            };
            let val = self.listener.exit_prs_expr(ctx);
            self.stack.push(EnumSynValue::PrsExpr(val));
        }

        fn exit_prs_expr6(&mut self, alt_id: AltId) {
            let ctx = match alt_id {
                50 => {
                    let prs_expr = self.stack.pop().unwrap().get_prs_expr();
                    CtxPrsExpr::V6 { prs_expr }
                }
                51 => {
                    let item = self.stack.pop().unwrap().get_item();
                    CtxPrsExpr::V7 { item }
                }
                _ => panic!("unexpected alt id {alt_id} in fn exit_prs_expr6")
            };
            let val = self.listener.exit_prs_expr(ctx);
            self.stack.push(EnumSynValue::PrsExpr(val));
        }

        fn exit_item(&mut self, alt_id: AltId) {
            let ctx = match alt_id {
                19 => {
                    let nonterminal = self.stack_t.pop().unwrap();
                    CtxItem::V1 { nonterminal }
                }
                20 => {
                    let ntx = self.stack_t.pop().unwrap();
                    CtxItem::V2 { ntx }
                }
                21 => {
                    let terminal = self.stack_t.pop().unwrap();
                    CtxItem::V3 { terminal }
                }
                22 => {
                    let terminalcst = self.stack_t.pop().unwrap();
                    CtxItem::V4 { terminalcst }
                }
                23 => {
                    let tx = self.stack_t.pop().unwrap();
                    CtxItem::V5 { tx }
                }
                24 => {
                    let empty = self.stack_t.pop().unwrap();
                    CtxItem::V6 { empty }
                }
                25 => {
                    let ltag = self.stack_t.pop().unwrap();
                    CtxItem::V7 { ltag }
                }
                26 => {
                    CtxItem::V8
                }
                27 => {
                    CtxItem::V9
                }
                28 => {
                    CtxItem::V10
                }
                _ => panic!("unexpected alt id {alt_id} in fn exit_item")
            };
            let val = self.listener.exit_item(ctx);
            self.stack.push(EnumSynValue::Item(val));
        }
    }

    // [rtsgen_parser]
}

// -------------------------------------------------------------------------
