use std::fmt::Display;

/// Token classes
// Generated by lemon (parse.h).
// Renamed manually.
// To be keep in sync.
#[non_exhaustive]
#[allow(non_camel_case_types, missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
#[repr(u16)]
pub enum TokenType {
    TK_EOF = 0,
    TK_SEMI = 1,
    TK_EXPLAIN = 2,
    TK_QUERY = 3,
    TK_PLAN = 4,
    TK_BEGIN = 5,
    TK_TRANSACTION = 6,
    TK_DEFERRED = 7,
    TK_IMMEDIATE = 8,
    TK_EXCLUSIVE = 9,
    TK_COMMIT = 10,
    TK_END = 11,
    TK_ROLLBACK = 12,
    TK_SAVEPOINT = 13,
    TK_RELEASE = 14,
    TK_TO = 15,
    TK_TABLE = 16,
    TK_CREATE = 17,
    TK_IF = 18,
    TK_NOT = 19,
    TK_EXISTS = 20,
    TK_TEMP = 21,
    TK_LP = 22,
    TK_RP = 23,
    TK_AS = 24,
    TK_COMMA = 25,
    TK_WITHOUT = 26,
    TK_ABORT = 27,
    TK_ACTION = 28,
    TK_AFTER = 29,
    TK_ANALYZE = 30,
    TK_ASC = 31,
    TK_ATTACH = 32,
    TK_BEFORE = 33,
    TK_BY = 34,
    TK_CASCADE = 35,
    TK_CAST = 36,
    TK_CONFLICT = 37,
    TK_DATABASE = 38,
    TK_DESC = 39,
    TK_DETACH = 40,
    TK_EACH = 41,
    TK_FAIL = 42,
    TK_OR = 43,
    TK_AND = 44,
    TK_IS = 45,
    TK_ISNOT = 46,
    TK_MATCH = 47,
    TK_LIKE_KW = 48,
    TK_BETWEEN = 49,
    TK_IN = 50,
    TK_ISNULL = 51,
    TK_NOTNULL = 52,
    TK_NE = 53,
    TK_EQ = 54,
    TK_GT = 55,
    TK_LE = 56,
    TK_LT = 57,
    TK_GE = 58,
    TK_ESCAPE = 59,
    TK_ID = 60,
    TK_COLUMNKW = 61,
    TK_DO = 62,
    TK_FOR = 63,
    TK_IGNORE = 64,
    TK_INITIALLY = 65,
    TK_INSTEAD = 66,
    TK_NO = 67,
    TK_KEY = 68,
    TK_OF = 69,
    TK_OFFSET = 70,
    TK_PRAGMA = 71,
    TK_RAISE = 72,
    TK_RECURSIVE = 73,
    TK_REPLACE = 74,
    TK_RESTRICT = 75,
    TK_ROW = 76,
    TK_ROWS = 77,
    TK_TRIGGER = 78,
    TK_VACUUM = 79,
    TK_VIEW = 80,
    TK_VIRTUAL = 81,
    TK_WITH = 82,
    TK_NULLS = 83,
    TK_FIRST = 84,
    TK_LAST = 85,
    TK_CURRENT = 86,
    TK_FOLLOWING = 87,
    TK_PARTITION = 88,
    TK_PRECEDING = 89,
    TK_RANGE = 90,
    TK_UNBOUNDED = 91,
    TK_EXCLUDE = 92,
    TK_GROUPS = 93,
    TK_OTHERS = 94,
    TK_TIES = 95,
    TK_GENERATED = 96,
    TK_ALWAYS = 97,
    TK_MATERIALIZED = 98,
    TK_REINDEX = 99,
    TK_RENAME = 100,
    TK_CTIME_KW = 101,
    TK_ANY = 102,
    TK_BITAND = 103,
    TK_BITOR = 104,
    TK_LSHIFT = 105,
    TK_RSHIFT = 106,
    TK_PLUS = 107,
    TK_MINUS = 108,
    TK_STAR = 109,
    TK_SLASH = 110,
    TK_REM = 111,
    TK_CONCAT = 112,
    TK_PTR = 113,
    TK_COLLATE = 114,
    TK_BITNOT = 115,
    TK_ON = 116,
    TK_INDEXED = 117,
    TK_STRING = 118,
    TK_JOIN_KW = 119,
    TK_CONSTRAINT = 120,
    TK_DEFAULT = 121,
    TK_NULL = 122,
    TK_PRIMARY = 123,
    TK_UNIQUE = 124,
    TK_CHECK = 125,
    TK_REFERENCES = 126,
    TK_AUTOINCR = 127,
    TK_INSERT = 128,
    TK_DELETE = 129,
    TK_UPDATE = 130,
    TK_SET = 131,
    TK_DEFERRABLE = 132,
    TK_FOREIGN = 133,
    TK_DROP = 134,
    TK_UNION = 135,
    TK_ALL = 136,
    TK_EXCEPT = 137,
    TK_INTERSECT = 138,
    TK_SELECT = 139,
    TK_VALUES = 140,
    TK_DISTINCT = 141,
    TK_DOT = 142,
    TK_FROM = 143,
    TK_JOIN = 144,
    TK_USING = 145,
    TK_ORDER = 146,
    TK_GROUP = 147,
    TK_HAVING = 148,
    TK_LIMIT = 149,
    TK_WHERE = 150,
    TK_RETURNING = 151,
    TK_INTO = 152,
    TK_NOTHING = 153,
    TK_BLOB = 154,
    TK_FLOAT = 155,
    TK_INTEGER = 156,
    TK_VARIABLE = 157,
    TK_CASE = 158,
    TK_WHEN = 159,
    TK_THEN = 160,
    TK_ELSE = 161,
    TK_INDEX = 162,
    TK_ALTER = 163,
    TK_ADD = 164,
    TK_WINDOW = 165,
    TK_OVER = 166,
    TK_FILTER = 167,
    TK_ILLEGAL = 185,
    TK_CONCURRENT = 186,
}

impl TokenType {
    /// Return the associated string (mainly for testing)
    pub const fn as_str(&self) -> Option<&'static str> {
        match self {
            TokenType::TK_ABORT => Some("ABORT"),
            TokenType::TK_ACTION => Some("ACTION"),
            TokenType::TK_ADD => Some("ADD"),
            TokenType::TK_AFTER => Some("AFTER"),
            TokenType::TK_ALL => Some("ALL"),
            TokenType::TK_ALTER => Some("ALTER"),
            TokenType::TK_ANALYZE => Some("ANALYZE"),
            TokenType::TK_ALWAYS => Some("ALWAYS"),
            TokenType::TK_AND => Some("AND"),
            TokenType::TK_AS => Some("AS"),
            TokenType::TK_ASC => Some("ASC"),
            TokenType::TK_ATTACH => Some("ATTACH"),
            TokenType::TK_AUTOINCR => Some("AUTOINCREMENT"),
            TokenType::TK_BEFORE => Some("BEFORE"),
            TokenType::TK_BEGIN => Some("BEGIN"),
            TokenType::TK_BETWEEN => Some("BETWEEN"),
            TokenType::TK_BY => Some("BY"),
            TokenType::TK_CASCADE => Some("CASCADE"),
            TokenType::TK_CASE => Some("CASE"),
            TokenType::TK_CAST => Some("CAST"),
            TokenType::TK_CHECK => Some("CHECK"),
            TokenType::TK_COLLATE => Some("COLLATE"),
            TokenType::TK_COLUMNKW => Some("COLUMN"),
            TokenType::TK_COMMIT => Some("COMMIT"),
            TokenType::TK_CONFLICT => Some("CONFLICT"),
            TokenType::TK_CONSTRAINT => Some("CONSTRAINT"),
            TokenType::TK_CREATE => Some("CREATE"),
            TokenType::TK_CURRENT => Some("CURRENT"),
            TokenType::TK_DATABASE => Some("DATABASE"),
            TokenType::TK_DEFAULT => Some("DEFAULT"),
            TokenType::TK_DEFERRABLE => Some("DEFERRABLE"),
            TokenType::TK_DEFERRED => Some("DEFERRED"),
            TokenType::TK_DELETE => Some("DELETE"),
            TokenType::TK_DESC => Some("DESC"),
            TokenType::TK_DETACH => Some("DETACH"),
            TokenType::TK_DISTINCT => Some("DISTINCT"),
            TokenType::TK_DO => Some("DO"),
            TokenType::TK_DROP => Some("DROP"),
            TokenType::TK_EACH => Some("EACH"),
            TokenType::TK_ELSE => Some("ELSE"),
            TokenType::TK_END => Some("END"),
            TokenType::TK_ESCAPE => Some("ESCAPE"),
            TokenType::TK_EXCEPT => Some("EXCEPT"),
            TokenType::TK_EXCLUDE => Some("EXCLUDE"),
            TokenType::TK_EXCLUSIVE => Some("EXCLUSIVE"),
            TokenType::TK_CONCURRENT => Some("CONCURRENT"),
            TokenType::TK_EXISTS => Some("EXISTS"),
            TokenType::TK_EXPLAIN => Some("EXPLAIN"),
            TokenType::TK_FAIL => Some("FAIL"),
            TokenType::TK_FILTER => Some("FILTER"),
            TokenType::TK_FIRST => Some("FIRST"),
            TokenType::TK_FOLLOWING => Some("FOLLOWING"),
            TokenType::TK_FOR => Some("FOR"),
            TokenType::TK_FOREIGN => Some("FOREIGN"),
            TokenType::TK_FROM => Some("FROM"),
            TokenType::TK_GENERATED => Some("GENERATED"),
            TokenType::TK_GROUP => Some("GROUP"),
            TokenType::TK_GROUPS => Some("GROUPS"),
            TokenType::TK_HAVING => Some("HAVING"),
            TokenType::TK_IF => Some("IF"),
            TokenType::TK_IGNORE => Some("IGNORE"),
            TokenType::TK_IMMEDIATE => Some("IMMEDIATE"),
            TokenType::TK_IN => Some("IN"),
            TokenType::TK_INDEX => Some("INDEX"),
            TokenType::TK_INDEXED => Some("INDEXED"),
            TokenType::TK_INITIALLY => Some("INITIALLY"),
            TokenType::TK_INSERT => Some("INSERT"),
            TokenType::TK_INSTEAD => Some("INSTEAD"),
            TokenType::TK_INTERSECT => Some("INTERSECT"),
            TokenType::TK_INTO => Some("INTO"),
            TokenType::TK_IS => Some("IS"),
            TokenType::TK_ISNULL => Some("ISNULL"),
            TokenType::TK_JOIN => Some("JOIN"),
            TokenType::TK_KEY => Some("KEY"),
            TokenType::TK_LAST => Some("LAST"),
            TokenType::TK_LIMIT => Some("LIMIT"),
            TokenType::TK_MATCH => Some("MATCH"),
            TokenType::TK_MATERIALIZED => Some("MATERIALIZED"),
            TokenType::TK_NO => Some("NO"),
            TokenType::TK_NOT => Some("NOT"),
            TokenType::TK_NOTHING => Some("NOTHING"),
            TokenType::TK_NOTNULL => Some("NOTNULL"),
            TokenType::TK_NULL => Some("NULL"),
            TokenType::TK_NULLS => Some("NULLS"),
            TokenType::TK_OF => Some("OF"),
            TokenType::TK_OFFSET => Some("OFFSET"),
            TokenType::TK_ON => Some("ON"),
            TokenType::TK_OR => Some("OR"),
            TokenType::TK_ORDER => Some("ORDER"),
            TokenType::TK_OTHERS => Some("OTHERS"),
            TokenType::TK_OVER => Some("OVER"),
            TokenType::TK_PARTITION => Some("PARTITION"),
            TokenType::TK_PLAN => Some("PLAN"),
            TokenType::TK_PRAGMA => Some("PRAGMA"),
            TokenType::TK_PRECEDING => Some("PRECEDING"),
            TokenType::TK_PRIMARY => Some("PRIMARY"),
            TokenType::TK_QUERY => Some("QUERY"),
            TokenType::TK_RAISE => Some("RAISE"),
            TokenType::TK_RANGE => Some("RANGE"),
            TokenType::TK_RECURSIVE => Some("RECURSIVE"),
            TokenType::TK_REFERENCES => Some("REFERENCES"),
            TokenType::TK_REINDEX => Some("REINDEX"),
            TokenType::TK_RELEASE => Some("RELEASE"),
            TokenType::TK_RENAME => Some("RENAME"),
            TokenType::TK_REPLACE => Some("REPLACE"),
            TokenType::TK_RETURNING => Some("RETURNING"),
            TokenType::TK_RESTRICT => Some("RESTRICT"),
            TokenType::TK_ROLLBACK => Some("ROLLBACK"),
            TokenType::TK_ROW => Some("ROW"),
            TokenType::TK_ROWS => Some("ROWS"),
            TokenType::TK_SAVEPOINT => Some("SAVEPOINT"),
            TokenType::TK_SELECT => Some("SELECT"),
            TokenType::TK_SET => Some("SET"),
            TokenType::TK_TABLE => Some("TABLE"),
            TokenType::TK_TEMP => Some("TEMP"), // or TEMPORARY
            TokenType::TK_TIES => Some("TIES"),
            TokenType::TK_THEN => Some("THEN"),
            TokenType::TK_TO => Some("TO"),
            TokenType::TK_TRANSACTION => Some("TRANSACTION"),
            TokenType::TK_TRIGGER => Some("TRIGGER"),
            TokenType::TK_UNBOUNDED => Some("UNBOUNDED"),
            TokenType::TK_UNION => Some("UNION"),
            TokenType::TK_UNIQUE => Some("UNIQUE"),
            TokenType::TK_UPDATE => Some("UPDATE"),
            TokenType::TK_USING => Some("USING"),
            TokenType::TK_VACUUM => Some("VACUUM"),
            TokenType::TK_VALUES => Some("VALUES"),
            TokenType::TK_VIEW => Some("VIEW"),
            TokenType::TK_VIRTUAL => Some("VIRTUAL"),
            TokenType::TK_WHEN => Some("WHEN"),
            TokenType::TK_WHERE => Some("WHERE"),
            TokenType::TK_WINDOW => Some("WINDOW"),
            TokenType::TK_WITH => Some("WITH"),
            TokenType::TK_WITHOUT => Some("WITHOUT"),
            TokenType::TK_BITAND => Some("&"),
            TokenType::TK_BITNOT => Some("~"),
            TokenType::TK_BITOR => Some("|"),
            TokenType::TK_COMMA => Some(","),
            TokenType::TK_CONCAT => Some("||"),
            TokenType::TK_DOT => Some("."),
            TokenType::TK_EQ => Some("="), // or ==
            TokenType::TK_GT => Some(">"),
            TokenType::TK_GE => Some(">="),
            TokenType::TK_LP => Some("("),
            TokenType::TK_LSHIFT => Some("<<"),
            TokenType::TK_LE => Some("<="),
            TokenType::TK_LT => Some("<"),
            TokenType::TK_MINUS => Some("-"),
            TokenType::TK_NE => Some("!="), // or <>
            TokenType::TK_PLUS => Some("+"),
            TokenType::TK_REM => Some("%"),
            TokenType::TK_RP => Some(")"),
            TokenType::TK_RSHIFT => Some(">>"),
            TokenType::TK_SEMI => Some(";"),
            TokenType::TK_SLASH => Some("/"),
            TokenType::TK_STAR => Some("*"),
            _ => None,
        }
    }
}

impl Display for TokenType {
    // for debugging purposes
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use TokenType::*;
        let s = match self {
            TK_EOF => "TK_EOF",
            TK_SEMI => "TK_SEMI",
            TK_EXPLAIN => "TK_EXPLAIN",
            TK_QUERY => "TK_QUERY",
            TK_PLAN => "TK_PLAN",
            TK_BEGIN => "TK_BEGIN",
            TK_TRANSACTION => "TK_TRANSACTION",
            TK_DEFERRED => "TK_DEFERRED",
            TK_IMMEDIATE => "TK_IMMEDIATE",
            TK_EXCLUSIVE => "TK_EXCLUSIVE",
            TK_CONCURRENT => "TK_CONCURRENT",
            TK_COMMIT => "TK_COMMIT",
            TK_END => "TK_END",
            TK_ROLLBACK => "TK_ROLLBACK",
            TK_SAVEPOINT => "TK_SAVEPOINT",
            TK_RELEASE => "TK_RELEASE",
            TK_TO => "TK_TO",
            TK_TABLE => "TK_TABLE",
            TK_CREATE => "TK_CREATE",
            TK_IF => "TK_IF",
            TK_NOT => "TK_NOT",
            TK_EXISTS => "TK_EXISTS",
            TK_TEMP => "TK_TEMP",
            TK_LP => "TK_LP",
            TK_RP => "TK_RP",
            TK_AS => "TK_AS",
            TK_COMMA => "TK_COMMA",
            TK_WITHOUT => "TK_WITHOUT",
            TK_ABORT => "TK_ABORT",
            TK_ACTION => "TK_ACTION",
            TK_AFTER => "TK_AFTER",
            TK_ANALYZE => "TK_ANALYZE",
            TK_ASC => "TK_ASC",
            TK_ATTACH => "TK_ATTACH",
            TK_BEFORE => "TK_BEFORE",
            TK_BY => "TK_BY",
            TK_CASCADE => "TK_CASCADE",
            TK_CAST => "TK_CAST",
            TK_CONFLICT => "TK_CONFLICT",
            TK_DATABASE => "TK_DATABASE",
            TK_DESC => "TK_DESC",
            TK_DETACH => "TK_DETACH",
            TK_EACH => "TK_EACH",
            TK_FAIL => "TK_FAIL",
            TK_OR => "TK_OR",
            TK_AND => "TK_AND",
            TK_IS => "TK_IS",
            TK_ISNOT => "TK_ISNOT",
            TK_MATCH => "TK_MATCH",
            TK_LIKE_KW => "TK_LIKE_KW",
            TK_BETWEEN => "TK_BETWEEN",
            TK_IN => "TK_IN",
            TK_ISNULL => "TK_ISNULL",
            TK_NOTNULL => "TK_NOTNULL",
            TK_NE => "TK_NE",
            TK_EQ => "TK_EQ",
            TK_GT => "TK_GT",
            TK_LE => "TK_LE",
            TK_LT => "TK_LT",
            TK_GE => "TK_GE",
            TK_ESCAPE => "TK_ESCAPE",
            TK_ID => "TK_ID",
            TK_COLUMNKW => "TK_COLUMNKW",
            TK_DO => "TK_DO",
            TK_FOR => "TK_FOR",
            TK_IGNORE => "TK_IGNORE",
            TK_INITIALLY => "TK_INITIALLY",
            TK_INSTEAD => "TK_INSTEAD",
            TK_NO => "TK_NO",
            TK_KEY => "TK_KEY",
            TK_OF => "TK_OF",
            TK_OFFSET => "TK_OFFSET",
            TK_PRAGMA => "TK_PRAGMA",
            TK_RAISE => "TK_RAISE",
            TK_RECURSIVE => "TK_RECURSIVE",
            TK_REPLACE => "TK_REPLACE",
            TK_RESTRICT => "TK_RESTRICT",
            TK_ROW => "TK_ROW",
            TK_ROWS => "TK_ROWS",
            TK_TRIGGER => "TK_TRIGGER",
            TK_VACUUM => "TK_VACUUM",
            TK_VIEW => "TK_VIEW",
            TK_VIRTUAL => "TK_VIRTUAL",
            TK_WITH => "TK_WITH",
            TK_NULLS => "TK_NULLS",
            TK_FIRST => "TK_FIRST",
            TK_LAST => "TK_LAST",
            TK_CURRENT => "TK_CURRENT",
            TK_FOLLOWING => "TK_FOLLOWING",
            TK_PARTITION => "TK_PARTITION",
            TK_PRECEDING => "TK_PRECEDING",
            TK_RANGE => "TK_RANGE",
            TK_UNBOUNDED => "TK_UNBOUNDED",
            TK_EXCLUDE => "TK_EXCLUDE",
            TK_GROUPS => "TK_GROUPS",
            TK_OTHERS => "TK_OTHERS",
            TK_TIES => "TK_TIES",
            TK_GENERATED => "TK_GENERATED",
            TK_ALWAYS => "TK_ALWAYS",
            TK_MATERIALIZED => "TK_MATERIALIZED",
            TK_REINDEX => "TK_REINDEX",
            TK_RENAME => "TK_RENAME",
            TK_CTIME_KW => "TK_CTIME_KW",
            TK_ANY => "TK_ANY",
            TK_BITAND => "TK_BITAND",
            TK_BITOR => "TK_BITOR",
            TK_LSHIFT => "TK_LSHIFT",
            TK_RSHIFT => "TK_RSHIFT",
            TK_PLUS => "TK_PLUS",
            TK_MINUS => "TK_MINUS",
            TK_STAR => "TK_STAR",
            TK_SLASH => "TK_SLASH",
            TK_REM => "TK_REM",
            TK_CONCAT => "TK_CONCAT",
            TK_PTR => "TK_PTR",
            TK_COLLATE => "TK_COLLATE",
            TK_BITNOT => "TK_BITNOT",
            TK_ON => "TK_ON",
            TK_INDEXED => "TK_INDEXED",
            TK_STRING => "TK_STRING",
            TK_JOIN_KW => "TK_JOIN_KW",
            TK_CONSTRAINT => "TK_CONSTRAINT",
            TK_DEFAULT => "TK_DEFAULT",
            TK_NULL => "TK_NULL",
            TK_PRIMARY => "TK_PRIMARY",
            TK_UNIQUE => "TK_UNIQUE",
            TK_CHECK => "TK_CHECK",
            TK_REFERENCES => "TK_REFERENCES",
            TK_AUTOINCR => "TK_AUTOINCR",
            TK_INSERT => "TK_INSERT",
            TK_DELETE => "TK_DELETE",
            TK_UPDATE => "TK_UPDATE",
            TK_SET => "TK_SET",
            TK_DEFERRABLE => "TK_DEFERRABLE",
            TK_FOREIGN => "TK_FOREIGN",
            TK_DROP => "TK_DROP",
            TK_UNION => "TK_UNION",
            TK_ALL => "TK_ALL",
            TK_EXCEPT => "TK_EXCEPT",
            TK_INTERSECT => "TK_INTERSECT",
            TK_SELECT => "TK_SELECT",
            TK_VALUES => "TK_VALUES",
            TK_DISTINCT => "TK_DISTINCT",
            TK_DOT => "TK_DOT",
            TK_FROM => "TK_FROM",
            TK_JOIN => "TK_JOIN",
            TK_USING => "TK_USING",
            TK_ORDER => "TK_ORDER",
            TK_GROUP => "TK_GROUP",
            TK_HAVING => "TK_HAVING",
            TK_LIMIT => "TK_LIMIT",
            TK_WHERE => "TK_WHERE",
            TK_RETURNING => "TK_RETURNING",
            TK_INTO => "TK_INTO",
            TK_NOTHING => "TK_NOTHING",
            TK_BLOB => "TK_BLOB",
            TK_FLOAT => "TK_FLOAT",
            TK_INTEGER => "TK_INTEGER",
            TK_VARIABLE => "TK_VARIABLE",
            TK_CASE => "TK_CASE",
            TK_WHEN => "TK_WHEN",
            TK_THEN => "TK_THEN",
            TK_ELSE => "TK_ELSE",
            TK_INDEX => "TK_INDEX",
            TK_ALTER => "TK_ALTER",
            TK_ADD => "TK_ADD",
            TK_WINDOW => "TK_WINDOW",
            TK_OVER => "TK_OVER",
            TK_FILTER => "TK_FILTER",
            TK_ILLEGAL => "TK_ILLEGAL",
        };
        write!(f, "{s}")
    }
}

impl TokenType {
    /// if your parsing process expects next token to be TK_ID, remember to call this function !!!
    #[inline(always)]
    pub fn fallback_id_if_ok(self) -> Self {
        use TokenType::*;
        match self {
            TK_ABORT | TK_ACTION | TK_AFTER | TK_ANALYZE | TK_ASC | TK_ATTACH | TK_BEFORE
            | TK_BEGIN | TK_BY | TK_CASCADE | TK_CAST | TK_CONFLICT | TK_DATABASE | TK_DEFERRED
            | TK_DESC | TK_DETACH | TK_DO | TK_EACH | TK_END | TK_EXCLUSIVE | TK_CONCURRENT
            | TK_EXPLAIN | TK_FAIL | TK_FOR | TK_IGNORE | TK_IMMEDIATE | TK_INITIALLY
            | TK_INSTEAD | TK_LIKE_KW | TK_MATCH | TK_NO | TK_PLAN | TK_QUERY | TK_KEY | TK_OF
            | TK_OFFSET | TK_PRAGMA | TK_RAISE | TK_RECURSIVE | TK_RELEASE | TK_REPLACE
            | TK_RESTRICT | TK_ROW | TK_ROWS | TK_ROLLBACK | TK_SAVEPOINT | TK_TEMP
            | TK_TRIGGER | TK_VACUUM | TK_VIEW | TK_VIRTUAL | TK_WITH | TK_NULLS | TK_FIRST
            | TK_LAST | TK_CURRENT | TK_FOLLOWING | TK_PARTITION | TK_PRECEDING | TK_RANGE
            | TK_UNBOUNDED | TK_EXCLUDE | TK_GROUPS | TK_OTHERS | TK_TIES | TK_ALWAYS
            | TK_MATERIALIZED | TK_REINDEX | TK_RENAME | TK_CTIME_KW | TK_IF => TK_ID,
            // | TK_COLUMNKW | TK_UNION | TK_EXCEPT | TK_INTERSECT | TK_GENERATED | TK_WITHOUT
            // see comments in `next_token` of parser
            _ => self,
        }
    }

    /// Get user-friendly display name for error messages
    pub fn user_friendly_name(&self) -> &'static str {
        match self.as_str() {
            Some(s) => s,
            None => match self {
                TokenType::TK_ID => "identifier",
                TokenType::TK_STRING => "string",
                TokenType::TK_INTEGER => "integer",
                TokenType::TK_FLOAT => "float",
                TokenType::TK_BLOB => "blob",
                TokenType::TK_VARIABLE => "variable",
                TokenType::TK_ILLEGAL => "illegal token",
                TokenType::TK_EOF => "end of file",
                TokenType::TK_LIKE_KW => "LIKE",
                TokenType::TK_JOIN_KW => "JOIN",
                TokenType::TK_CTIME_KW => "datetime function",
                TokenType::TK_ISNOT => "IS NOT",
                TokenType::TK_ISNULL => "ISNULL",
                TokenType::TK_NOTNULL => "NOTNULL",
                TokenType::TK_PTR => "->",
                _ => "unknown token",
            },
        }
    }

    /// Format multiple tokens for error messages
    pub fn format_expected_tokens(tokens: &[TokenType]) -> String {
        if tokens.is_empty() {
            return "nothing".to_string();
        }
        if tokens.len() == 1 {
            return tokens[0].user_friendly_name().to_string();
        }

        let names: Vec<&str> = tokens.iter().map(|t| t.user_friendly_name()).collect();
        if names.len() == 2 {
            format!("{} or {}", names[0], names[1])
        } else {
            let (last, rest) = names.split_last().unwrap();
            format!("{}, or {}", rest.join(", "), last)
        }
    }
}
