repetitive 0.1.5

Macro for generating repetitive code
Documentation
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote_spanned};
use syn::{
    Error, Ident, Lifetime, LitBool, LitChar, LitFloat, LitInt, LitStr, Token, parse::ParseStream,
};

use super::*;

#[derive(Debug, Clone)]
pub enum FragmentValue {
    Int(i128),
    Float(f64),
    Bool(bool),
    String(String),
    Char(char),
    Ident(String),
    List(Vec<FragmentValue>),
    Tokens(Tokens),
}

#[derive(Debug, Clone)]
pub struct FragmentValueExpr {
    pub span: Span,
    pub value: FragmentValue,
}

impl FragmentValueExpr {
    pub fn option_lit(input: ParseStream) -> syn::Result<Option<Self>> {
        if input.peek(LitInt) {
            return Ok(Some(Self::int_lit(input.parse().unwrap())));
        }
        if input.peek(LitFloat) {
            return Ok(Some(Self::float_lit(input.parse().unwrap())));
        }
        if input.peek(LitBool) {
            return Ok(Some(Self::bool_lit(input.parse().unwrap())));
        }
        if input.peek(LitChar) {
            return Ok(Some(Self::char_lit(input.parse().unwrap())));
        }
        if input.peek(LitStr) {
            return Ok(Some(Self::str_lit(input.parse().unwrap())));
        }
        if input.peek(Lifetime) {
            return Ok(Some(Self::ident_lit(input.parse().unwrap())));
        }
        if input.peek(Token![~]) {
            let punct_span = input.parse::<Token![~]>().unwrap().span;
            let ident = input.parse::<Ident>()?;

            let lifetime = Lifetime {
                apostrophe: punct_span,
                ident,
            };

            return Ok(Some(Self::ident_lit(lifetime)));
        }

        Ok(None)
    }
    pub fn int_lit(lit: LitInt) -> Self {
        Self {
            span: lit.span(),
            value: FragmentValue::Int(lit.base10_digits().parse().unwrap()),
        }
    }
    pub fn float_lit(lit: LitFloat) -> Self {
        Self {
            span: lit.span(),
            value: FragmentValue::Float(lit.base10_digits().parse().unwrap()),
        }
    }
    pub fn bool_lit(lit: LitBool) -> Self {
        Self {
            span: lit.span(),
            value: FragmentValue::Bool(lit.value),
        }
    }
    pub fn char_lit(lit: LitChar) -> Self {
        Self {
            span: lit.span(),
            value: FragmentValue::Char(lit.value()),
        }
    }
    pub fn str_lit(lit: LitStr) -> Self {
        Self {
            span: lit.span(),
            value: FragmentValue::String(lit.value()),
        }
    }
    pub fn ident_lit(lit: Lifetime) -> Self {
        Self {
            span: lit.span(),
            value: FragmentValue::Ident(lit.ident.to_string()),
        }
    }

    pub fn into_expr(self) -> FragmentExpr {
        FragmentExpr {
            span: self.span,
            kind: FragmentExprKind::Value(self.value),
        }
    }
}
impl FragmentValue {
    pub fn kind(&self) -> &str {
        match self {
            FragmentValue::Int(_) => "int",
            FragmentValue::Float(_) => "float",
            FragmentValue::Bool(_) => "bool",
            FragmentValue::String(_) => "string",
            FragmentValue::Char(_) => "char",
            FragmentValue::Ident(_) => "ident",
            FragmentValue::List(_) => "list",
            FragmentValue::Tokens(_) => "tokens",
        }
    }
}

impl Paste for FragmentValueExpr {
    fn paste(
        &self,
        output: &mut TokenStream,
        ctx: &mut Context,
        namespace: &mut Namespace,
    ) -> syn::Result<()> {
        Ok(match &self.value {
            FragmentValue::Int(val) => {
                let lit = LitInt::new(val.abs().to_string().as_str(), self.span);
                if *val < 0 {
                    quote_spanned! { self.span => -#lit }.to_tokens(output);
                } else {
                    lit.to_tokens(output);
                }
            }
            FragmentValue::Float(val) => {
                let lit = LitFloat::new(&format!("{:?}", val.abs()), self.span);
                if *val < 0.0 {
                    quote_spanned! { self.span => -#lit }.to_tokens(output);
                } else {
                    lit.to_tokens(output);
                }
            }
            FragmentValue::Bool(val) => LitBool::new(*val, self.span).to_tokens(output),
            FragmentValue::String(val) => LitStr::new(val, self.span).to_tokens(output),
            FragmentValue::Char(val) => LitChar::new(*val, self.span).to_tokens(output),
            FragmentValue::Ident(val) => Ident::new(val, self.span).to_tokens(output),

            FragmentValue::Tokens(val) => val.paste(output, ctx, namespace)?,

            FragmentValue::List(_) => {
                return Err(Error::new(self.span, "cannot paste `list`"));
            }
        })
    }
}