repetitive 0.2.0

Macro for generating repetitive code
Documentation
use proc_macro2::{Span, TokenStream};

use super::*;

#[derive(Debug, Clone)]
pub enum Error {
    ParseError(syn::Error),

    IsKeyword {
        span: Span,
        keyword: String,
    },

    ExpectedFound {
        span: Span,
        expected: &'static str,
        found: &'static str,
    },

    ExpectedRhsFound {
        span: Span,
        lhs: &'static str,
        op: &'static str,
        expected: &'static str,
        found: &'static str,
    },

    CannotPerform {
        span: Span,
        op: &'static str,
        kind: &'static str,
    },

    ArgCount {
        op: &'static str,
        span: Span,
        expected: usize,
        inputs_desc: Option<&'static str>,
        found: usize,
    },

    PatternKindMismatch {
        span: Span,
        expected: &'static str,
        found: &'static str,
    },
    PatternValueMismatch {
        span: Span,
    },
    PatternListLengthMismatch {
        span: Span,
        expected: usize,
        found: usize,
    },

    NoMatches {
        span: Span,
        value: String,
    },

    NameAlreadyExists(Name),
    NameNotFound(Name),
}

impl Error {
    pub fn into_syn_error(self, ctx: &mut Context) -> syn::Error {
        match self {
            Error::ParseError(error) => error,

            Error::IsKeyword { span, keyword } => {
                syn::Error::new(span, format!("expected name, `{keyword}` is a keyword"))
            }

            Error::ExpectedFound {
                span,
                expected,
                found,
            } => syn::Error::new(span, format!("expected `{expected}`, found `{found}`")),

            Error::ExpectedRhsFound {
                span,
                lhs,
                op,
                expected,
                found,
            } => syn::Error::new(
                span,
                format!("expected rhs of `{lhs}` {op} to be `{expected}`, found `{found}`"),
            ),

            Error::ArgCount {
                op,
                span,
                expected,
                inputs_desc,
                found,
            } => {
                if let Some(inputs_desc) = inputs_desc {
                    syn::Error::new(
                        span,
                        format!(
                            "expected {expected} arguments for {op} ({inputs_desc}), found {found}"
                        ),
                    )
                } else {
                    syn::Error::new(
                        span,
                        format!("expected {expected} arguments for {op}, found {found}"),
                    )
                }
            }

            Error::CannotPerform { span, op, kind } => {
                syn::Error::new(span, format!("cannot perform {op} on `{kind}`"))
            }

            Error::PatternKindMismatch {
                span,
                expected,
                found,
            } => syn::Error::new(
                span,
                format!("value does not match pattern. expected `{expected}`, found `{found}`"),
            ),

            Error::PatternValueMismatch { span } => syn::Error::new(
                span,
                "value does not match pattern. expected a specific value",
            ),

            Error::PatternListLengthMismatch {
                span,
                expected,
                found,
            } => syn::Error::new(
                span,
                format!(
                    "value does not match pattern. expected list length {expected}, found {found}"
                ),
            ),

            Error::NoMatches { span, value } => {
                syn::Error::new(span, format!("no matches found for `{value}`"))
            }

            Error::NameAlreadyExists(name) => syn::Error::new(
                name.span,
                format!("name `{}` already exists", ctx.unintern(name.id.strid)),
            ),

            Error::NameNotFound(name) => syn::Error::new(
                name.span,
                format!("name `{}` not found", ctx.unintern(name.id.strid)),
            ),
        }
    }

    pub fn into_compile_error(self, ctx: &mut Context) -> TokenStream {
        self.into_syn_error(ctx).into_compile_error()
    }
}