macro_rules! impl_keyword {
    (
        $vis:vis enum $name:ident {
            $($variant:ident => $s:literal),* $(,)?
        }
    ) => {
        #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
        $vis enum $name {
            $($variant),*
        }

        impl $name {
            pub fn parse(s: &str) -> Option<Self> {
                match s {
                    $(
                    $s => Some(Self::$variant),
                    )*
                    _ => None,
                }
            }
        }

        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                f.write_str(match self {
                    $(
                        Self::$variant => $s
                    ),*
                })
            }
        }
    };
}

impl_keyword! {
    pub enum Keyword {
        Lambda => "lambda",
        Defun => "defun",
        If => "if",
        Cond => "cond",
        While => "while",
        Otherwise => "&otherwise",
        Optional => "&optional",
        Rest => "&rest",
        Setq => "setq",
        Let => "let",
        LetStar => "let*",
        Defmacro => "defmacro",
        Quote => "quote",
        Progn => "progn",
        Loop => "loop",
        Break => "break",
        Continue => "continue",
        Declare => "declare",
        Error => "&error",
        Return => "return",
        // Cons => "cons",
    }
}
